diff --git a/deploy/paddleocr-go/README.md b/deploy/paddleocr-go/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..1332c3c0b31c7b6943dfe616deeffc447d6be218
--- /dev/null
+++ b/deploy/paddleocr-go/README.md
@@ -0,0 +1,328 @@
+# PaddleOCR-GO
+
+本服务是[PaddleOCR](https://github.com/PaddlePaddle/PaddleOCR)的golang部署版本。
+
+## 1. 环境准备
+
+### 运行环境
+
+- go: 1.14
+- OpenCV: 4.3.0
+- PaddlePaddle: 1.8.4
+- 编译环境:cmake 3.15.4 | gcc 4.8.5
+- 基于Centos 7.4运行环境编译,Windows请自行解决`OpenCV`和`PaddlePaddle`的编译问题
+
+*另外,以下编译以`.bashrc`个人环境变量配置文件,如果使用`zsh`,请自行更换为`.zshrc`*
+
+### 1.1 安装golang
+
+从官网下载[golang](https://golang.org/dl/),建议选择1.13版本以上进行安装。下载完成后,直接解压你需要的安装目录,并配置相关环境变量,此处以1.14版本为例。
+
+```shell
+# 下载golang
+wget https://golang.org/dl/go1.14.10.linux-amd64.tar.gz
+
+# 解压到 /usr/local 目录下
+tar -xzvf go1.14.10.linux-amd64.tar.gz -C /usr/local
+
+# 配置GOROOT,即go的安装目录
+echo "export GOROOT=/usr/local/go" >> ~/.bashrc
+# 配置GOPATH,即go相关package的安装目录,可自定义一个目录
+echo "export GOPATH=$HOME/golang" >> ~/.bashrc
+# 配置GOPROXY,即go mod包管理器的下载代理,同时打开mod模式
+echo "export GO111MODULE=on" >> ~/.bashrc
+echo "export GOPROXY=https://mirrors.aliyun.com/goproxy/" >> ~/.bashrc
+source ~/.bashrc
+```
+
+### 1.2 编译OpenCV库
+
+go语言中,OpenCV的使用主要以[gocv](https://github.com/hybridgroup/gocv)包为主,gocv使用cgo调用OpenCV提供接口,因此还是需要编译OpenCV库。
+
+**踩坑指南之一:[gocv官方实现](https://github.com/hybridgroup/gocv)中,部分接口并没有与原版C++的OpenCV的API保持一致,导致图片处理结果会出现一定的数值偏差。为处理这种偏差,[该仓库](https://github.com/LKKlein/gocv)fork了一份gocv官方源码,并对部分这些不一致的API进行了修正,保证结果与其他语言的一致性。**
+
+对于OpenCV的编译,gocv官方提供了[Makefile](https://github.com/LKKlein/gocv/blob/lk/Makefile),可以一键进行安装,具体安装步骤详见[官方指南](https://github.com/LKKlein/gocv/blob/lk/README_ORIGIN.md#ubuntulinux)。
+
+这里提供逐步安装的方式,方便排查错误。
+
+- 下载并解压OpenCV-4.3.0和OpenCV-Contrib-4.3.0
+
+```shell
+# 创建opencv安装目录
+mkdir -p ~/opencv
+
+# 下载OpenCV
+cd ~/opencv
+curl -sL https://github.com/opencv/opencv/archive/4.3.0.zip > opencv.zip
+unzip -q opencv.zip
+rm -rf opencv.zip
+
+# 下载OpenCV-Contrib
+curl -sL https://github.com/opencv/opencv_contrib/archive/4.3.0.zip > opencv-contrib.zip
+unzip -q opencv-contrib.zip
+rm -rf opencv-contrib.zip
+```
+
+- 安装相关依赖
+
+```shell
+sudo yum -y install pkgconfig cmake git gtk2-devel libpng-devel libjpeg-devel libtiff-devel tbb tbb-devel libdc1394-devel
+```
+
+- 编译安装
+
+```shell
+mkdir -p ~/.local/opencv-4.3.0
+cd ~/opencv/opencv-4.3.0
+mkdir build
+cd build
+cmake -D WITH_IPP=OFF \
+ -D WITH_OPENGL=OFF \
+ -D WITH_QT=OFF \
+ -D BUILD_EXAMPLES=OFF \
+ -D BUILD_TESTS=OFF \
+ -D BUILD_PERF_TESTS=OFF \
+ -D BUILD_opencv_java=OFF \
+ -D BUILD_opencv_python=OFF \
+ -D BUILD_opencv_python2=OFF \
+ -D BUILD_opencv_python3=OFF \
+ -D OPENCV_GENERATE_PKGCONFIG=ON \
+ -D CMAKE_INSTALL_PREFIX=$HOME/.local/opencv-4.3.0 \
+ -D OPENCV_ENABLE_NONFREE=ON \
+ -D OPENCV_EXTRA_MODULES_PATH=$HOME/opencv/opencv_contrib-4.3.0/modules ..
+make -j8
+make install
+sudo ldconfig
+```
+
+make进行编译时,可能出现因`xfeatures2d`的两个模块下载失败导致的编译失败,这里只需要手动下载这部分文件到`$HOME/opencv/opencv_contrib-4.3.0/modules/xfeatures2d/src`目录下,然后重新执行`make -j8`即可。这部分文件地址可参考[这里](https://github.com/opencv/opencv_contrib/issues/1301#issuecomment-447181426)给出的链接。
+
+- 配置环境变量
+
+```shell
+echo "export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$HOME/.local/opencv-4.3.0/lib64/pkgconfig" >> ~/.bashrc
+echo "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/.local/opencv-4.3.0/lib64" >> ~/.bashrc
+source ~/.bashrc
+```
+
+- 验证安装
+
+```shell
+# 安装gocv包,先mod init
+go mod init opencv
+go get -u github.com/LKKlein/gocv
+
+# 验证安装结果
+cd $GOPATH/pkg/mod/github.com/!l!k!klein/gocv@v0.28.0
+go run ./cmd/version/main.go
+
+# 输出
+# gocv version: 0.28.0
+# opencv lib version: 4.3.0
+```
+
+### 1.3 编译PaddlePaddle的C语言API
+
+go语言只能通过cgo调用C语言API,而不能直接与C++进行交互,因此需要编译PaddlePaddle的C语言API。当然,也可以自己写C语言调用C++的代码和头文件,这样就可以直接使用PaddlePaddle提供的已编译的C++推理库,无需自己手动编译,详见[该仓库](https://github.com/LKKlein/paddleocr-go/tree/dev_cxx)。
+
+- 获取PaddlePaddle源代码
+
+```shell
+cd ~
+git clone --recurse-submodules https://github.com/paddlepaddle/paddle
+
+# 切换到v1.8.4版本
+cd paddle
+git checkout v1.8.4
+
+# 目前版本无论单卡还是多卡都需要先安装nccl
+git clone https://github.com/NVIDIA/nccl.git
+make -j8
+make install
+```
+
+- 编译Paddle源代码
+
+**踩坑指南之二:PaddlePaddle的C语言API实现有一个bug,即获取输入输出变量名时只能获取到第一个模型的变量名,后续模型都无法获取输入输出变量名,进而无法获取到模型输出,详情见[issue](https://github.com/PaddlePaddle/Paddle/issues/28309)。因此,编译前需要手动将`paddle/fluid/inference/capi/pd_predictor.cc`文件中`210行`与`215行`的`static`删除。**
+
+在处理完该bug之后,才能进行后续编译。相关编译参数见[官方文档](https://www.paddlepaddle.org.cn/documentation/docs/zh/advanced_guide/inference_deployment/inference/build_and_install_lib_cn.html#id12),注意部分参数需要相关依赖,请确保依赖完整再启用。
+
+```shell
+# 创建c++推理库文件夹
+mkdir -p ~/paddle_inference
+export PADDLE_ROOT=`$HOME/paddle_inference`
+
+# 执行编译
+mkdir build
+cd build
+cmake -DFLUID_INFERENCE_INSTALL_DIR=$PADDLE_ROOT \
+ -DWITH_CONTRIB=OFF \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DWITH_PYTHON=OFF \
+ -DWITH_MKL=ON \
+ -DWITH_GPU=ON \
+ -DON_INFER=ON \
+ --WITH_MKLDNN=ON \
+ --WITH_XBYAK=ON \
+ --WITH_DSO=OFF ..
+make
+make inference_lib_dist
+```
+
+编译完成后,可以在`build/fluid_inference_c_install_dir`目录下,看到以下生成的文件
+
+```
+build/fluid_inference_c_install_dir
+├── paddle
+├── third_party
+└── version.txt
+```
+
+其中`paddle`就是Paddle库的C语言预测API,`version.txt`中包含当前预测库的版本信息。
+
+
+## 2. paddleocr-go预测库
+
+### 2.1 安装paddleocr-go
+
+直接执行安装命令
+
+```shell
+go get github.com/PaddlePaddle/PaddleOCR/deploy/paddleocr-go
+```
+
+### 2.2 相关使用API
+
+在go中使用import引入包
+
+```go
+import github.com/PaddlePaddle/PaddleOCR/deploy/paddleocr-go/ocr
+```
+
+- 预测结果结构体
+
+```go
+type OCRText struct {
+ BBox [][]int `json:"bbox"`
+ Text string `json:"text"`
+ Score float64 `json:"score"`
+}
+```
+
+一张图的OCR结果包含多个`OCRText`结果,每个结果包含预测框、预测文本、预测文本得分。
+
+- OCR预测类
+
+
+```go
+func NewOCRSystem(confFile string, a map[string]interface{}) *OCRSystem
+```
+
+`OCRSystem`是主要对外提供API的结构;
+
+`confFile`是yaml配置文件的路径,可在配置文件中修改相关预测参数,也可以传空字符串,这时会全部使用默认配置;
+
+`a`是可以在代码中直接定义的配置参数,优先级高于配置文件,会覆盖配置文件和默认配置的参数。
+
+- 单张图预测API
+
+```go
+func (ocr *OCRSystem) PredictOneImage(img gocv.Mat) []OCRText
+```
+
+
+- 图片文件夹预测API
+
+```go
+func (ocr *OCRSystem) PredictDirImages(dirname string) map[string][]OCRText
+```
+
+`dirname`图片文件夹的目录,默认会预测改目录下所有`jpg`和`png`图片,并返回每张图的预测结果。
+
+- OCR Server
+
+```go
+func (ocr *OCRSystem) StartServer(port string)
+```
+
+开启OCR预测Server,开启后,使用`post`请求上传需要识别的图片至`http://$ip:$port/ocr`即可直接获取该图片上所有文本的识别结果。其中,`$ip`是开启服务的主机`ip`或`127.0.0.1`的本地ip, `$port`是传入的端口参数。
+
+
+## 3. 预测demo
+
+### 3.1 修改预测配置
+
+当前给定的配置文件`config/conf.yaml`中,包含了默认的OCR预测配置参数,可根据个人需要更改相关参数。
+
+比如,将`use_gpu`改为`false`,使用CPU执行预测;将`det_model_dir`, `rec_model_dir`, `cls_model_dir`都更改为自己的本地模型路径,也或者是更改字典`rec_char_dict_path`的路径。配置参数包含了预测引擎、检测模型、检测阈值、方向分类模型、识别模型及阈值的相关参数,具体参数的意义可参见[PaddleOCR](https://github.com/PaddlePaddle/PaddleOCR/blob/develop/doc/doc_ch/whl.md#%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E)。
+
+### 3.2 编译预测demo
+
+- 下载`paddleocr-go`代码
+
+```shell
+git clone https://github.com/PaddlePaddle/PaddleOCR
+cd PaddleOCR/deploy/paddleocr-go
+```
+
+- 准备paddle_c环境
+
+```shell
+cp -r ~/paddle/build/fluid_inference_c_install_dir/* paddle_c/
+```
+
+- 编译demo
+
+```shell
+go build demo.go
+```
+
+### 3.3 执行预测demo
+
+预测demo提供了三种预测方式,分别是单张图预测、文件夹批量预测、OCR Server预测。三者命令行优先级依次降低。
+
+#### 3.3.1 单张图预测
+
+```shell
+./demo --config config/conf.yaml --image images/test.jpg
+```
+
+执行完成,会输出以下内容:
+
+
+
+#### 3.3.2 文件夹批量预测
+
+```shell
+./demo --config config/conf.yaml --image_dir ./images
+```
+
+执行完成,会输出以下内容:
+
+
+
+#### 3.3.3 开启OCR Server
+
+```shell
+./demo --use_servering --port=18600
+```
+
+开启服务后,可以在其他客户端中通过`post`请求进行ocr预测。此处以`Python`客户端为例,如下所示
+
+```python
+import requests
+
+files = {'image': open('images/test.jpg','rb')}
+url = "http://127.0.0.1:18600/ocr"
+
+r = requests.post(url, files=files)
+print(r.text)
+```
+
+执行完成可以得到以下结果
+
+
+
+最后,在Python中将上述结果可视化可以得到以下结果
+
+
diff --git a/deploy/paddleocr-go/config/conf.yaml b/deploy/paddleocr-go/config/conf.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c6b5b7914bfc51cb0e14a614bf696c34083097cf
--- /dev/null
+++ b/deploy/paddleocr-go/config/conf.yaml
@@ -0,0 +1,47 @@
+# params for prediction engine
+use_gpu: true
+ir_optim: true
+enable_mkldnn: false
+# use_zero_copy_run: true
+use_tensorrt: false
+num_cpu_threads: 6
+gpu_id: 0
+gpu_mem: 2000
+
+# params for text detector
+det_algorithm: "DB"
+det_model_dir: "https://paddleocr.bj.bcebos.com/20-09-22/mobile/det/ch_ppocr_mobile_v1.1_det_infer.tar"
+det_max_side_len: 960
+
+# DB parmas
+det_db_thresh: 0.3
+det_db_box_thresh: 0.5
+det_db_unclip_ratio: 2.0
+
+# EAST parmas
+det_east_score_thresh: 0.8
+det_east_cover_thresh: 0.1
+det_east_nms_thresh: 0.2
+
+# params for text recognizer
+rec_algorithm: "CRNN"
+rec_model_dir: "https://paddleocr.bj.bcebos.com/20-09-22/mobile/rec/ch_ppocr_mobile_v1.1_rec_infer.tar"
+rec_image_shape: [3, 32, 320]
+rec_char_type: "ch"
+rec_batch_num: 30
+max_text_length: 25
+rec_char_dict_path: "config/ppocr_keys_v1.txt"
+use_space_char: true
+
+# params for text classifier
+use_angle_cls: false
+cls_model_dir: "https://paddleocr.bj.bcebos.com/20-09-22/cls/ch_ppocr_mobile_v1.1_cls_infer.tar"
+cls_image_shape: [3, 48, 192]
+label_list: ["0", "180"]
+cls_batch_num: 30
+cls_thresh: 0.9
+
+lang: ch
+det: true
+rec: true
+cls: false
\ No newline at end of file
diff --git a/deploy/paddleocr-go/config/ppocr_keys_v1.txt b/deploy/paddleocr-go/config/ppocr_keys_v1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..84b885d8352226e49b1d5d791b8f43a663e246aa
--- /dev/null
+++ b/deploy/paddleocr-go/config/ppocr_keys_v1.txt
@@ -0,0 +1,6623 @@
+'
+疗
+绚
+诚
+娇
+溜
+题
+贿
+者
+廖
+更
+纳
+加
+奉
+公
+一
+就
+汴
+计
+与
+路
+房
+原
+妇
+2
+0
+8
+-
+7
+其
+>
+:
+]
+,
+,
+骑
+刈
+全
+消
+昏
+傈
+安
+久
+钟
+嗅
+不
+影
+处
+驽
+蜿
+资
+关
+椤
+地
+瘸
+专
+问
+忖
+票
+嫉
+炎
+韵
+要
+月
+田
+节
+陂
+鄙
+捌
+备
+拳
+伺
+眼
+网
+盎
+大
+傍
+心
+东
+愉
+汇
+蹿
+科
+每
+业
+里
+航
+晏
+字
+平
+录
+先
+1
+3
+彤
+鲶
+产
+稍
+督
+腴
+有
+象
+岳
+注
+绍
+在
+泺
+文
+定
+核
+名
+水
+过
+理
+让
+偷
+率
+等
+这
+发
+”
+为
+含
+肥
+酉
+相
+鄱
+七
+编
+猥
+锛
+日
+镀
+蒂
+掰
+倒
+辆
+栾
+栗
+综
+涩
+州
+雌
+滑
+馀
+了
+机
+块
+司
+宰
+甙
+兴
+矽
+抚
+保
+用
+沧
+秩
+如
+收
+息
+滥
+页
+疑
+埠
+!
+!
+姥
+异
+橹
+钇
+向
+下
+跄
+的
+椴
+沫
+国
+绥
+獠
+报
+开
+民
+蜇
+何
+分
+凇
+长
+讥
+藏
+掏
+施
+羽
+中
+讲
+派
+嘟
+人
+提
+浼
+间
+世
+而
+古
+多
+倪
+唇
+饯
+控
+庚
+首
+赛
+蜓
+味
+断
+制
+觉
+技
+替
+艰
+溢
+潮
+夕
+钺
+外
+摘
+枋
+动
+双
+单
+啮
+户
+枇
+确
+锦
+曜
+杜
+或
+能
+效
+霜
+盒
+然
+侗
+电
+晁
+放
+步
+鹃
+新
+杖
+蜂
+吒
+濂
+瞬
+评
+总
+隍
+对
+独
+合
+也
+是
+府
+青
+天
+诲
+墙
+组
+滴
+级
+邀
+帘
+示
+已
+时
+骸
+仄
+泅
+和
+遨
+店
+雇
+疫
+持
+巍
+踮
+境
+只
+亨
+目
+鉴
+崤
+闲
+体
+泄
+杂
+作
+般
+轰
+化
+解
+迂
+诿
+蛭
+璀
+腾
+告
+版
+服
+省
+师
+小
+规
+程
+线
+海
+办
+引
+二
+桧
+牌
+砺
+洄
+裴
+修
+图
+痫
+胡
+许
+犊
+事
+郛
+基
+柴
+呼
+食
+研
+奶
+律
+蛋
+因
+葆
+察
+戏
+褒
+戒
+再
+李
+骁
+工
+貂
+油
+鹅
+章
+啄
+休
+场
+给
+睡
+纷
+豆
+器
+捎
+说
+敏
+学
+会
+浒
+设
+诊
+格
+廓
+查
+来
+霓
+室
+溆
+¢
+诡
+寥
+焕
+舜
+柒
+狐
+回
+戟
+砾
+厄
+实
+翩
+尿
+五
+入
+径
+惭
+喹
+股
+宇
+篝
+|
+;
+美
+期
+云
+九
+祺
+扮
+靠
+锝
+槌
+系
+企
+酰
+阊
+暂
+蚕
+忻
+豁
+本
+羹
+执
+条
+钦
+H
+獒
+限
+进
+季
+楦
+于
+芘
+玖
+铋
+茯
+未
+答
+粘
+括
+样
+精
+欠
+矢
+甥
+帷
+嵩
+扣
+令
+仔
+风
+皈
+行
+支
+部
+蓉
+刮
+站
+蜡
+救
+钊
+汗
+松
+嫌
+成
+可
+.
+鹤
+院
+从
+交
+政
+怕
+活
+调
+球
+局
+验
+髌
+第
+韫
+谗
+串
+到
+圆
+年
+米
+/
+*
+友
+忿
+检
+区
+看
+自
+敢
+刃
+个
+兹
+弄
+流
+留
+同
+没
+齿
+星
+聆
+轼
+湖
+什
+三
+建
+蛔
+儿
+椋
+汕
+震
+颧
+鲤
+跟
+力
+情
+璺
+铨
+陪
+务
+指
+族
+训
+滦
+鄣
+濮
+扒
+商
+箱
+十
+召
+慷
+辗
+所
+莞
+管
+护
+臭
+横
+硒
+嗓
+接
+侦
+六
+露
+党
+馋
+驾
+剖
+高
+侬
+妪
+幂
+猗
+绺
+骐
+央
+酐
+孝
+筝
+课
+徇
+缰
+门
+男
+西
+项
+句
+谙
+瞒
+秃
+篇
+教
+碲
+罚
+声
+呐
+景
+前
+富
+嘴
+鳌
+稀
+免
+朋
+啬
+睐
+去
+赈
+鱼
+住
+肩
+愕
+速
+旁
+波
+厅
+健
+茼
+厥
+鲟
+谅
+投
+攸
+炔
+数
+方
+击
+呋
+谈
+绩
+别
+愫
+僚
+躬
+鹧
+胪
+炳
+招
+喇
+膨
+泵
+蹦
+毛
+结
+5
+4
+谱
+识
+陕
+粽
+婚
+拟
+构
+且
+搜
+任
+潘
+比
+郢
+妨
+醪
+陀
+桔
+碘
+扎
+选
+哈
+骷
+楷
+亿
+明
+缆
+脯
+监
+睫
+逻
+婵
+共
+赴
+淝
+凡
+惦
+及
+达
+揖
+谩
+澹
+减
+焰
+蛹
+番
+祁
+柏
+员
+禄
+怡
+峤
+龙
+白
+叽
+生
+闯
+起
+细
+装
+谕
+竟
+聚
+钙
+上
+导
+渊
+按
+艾
+辘
+挡
+耒
+盹
+饪
+臀
+记
+邮
+蕙
+受
+各
+医
+搂
+普
+滇
+朗
+茸
+带
+翻
+酚
+(
+光
+堤
+墟
+蔷
+万
+幻
+〓
+瑙
+辈
+昧
+盏
+亘
+蛀
+吉
+铰
+请
+子
+假
+闻
+税
+井
+诩
+哨
+嫂
+好
+面
+琐
+校
+馊
+鬣
+缂
+营
+访
+炖
+占
+农
+缀
+否
+经
+钚
+棵
+趟
+张
+亟
+吏
+茶
+谨
+捻
+论
+迸
+堂
+玉
+信
+吧
+瞠
+乡
+姬
+寺
+咬
+溏
+苄
+皿
+意
+赉
+宝
+尔
+钰
+艺
+特
+唳
+踉
+都
+荣
+倚
+登
+荐
+丧
+奇
+涵
+批
+炭
+近
+符
+傩
+感
+道
+着
+菊
+虹
+仲
+众
+懈
+濯
+颞
+眺
+南
+释
+北
+缝
+标
+既
+茗
+整
+撼
+迤
+贲
+挎
+耱
+拒
+某
+妍
+卫
+哇
+英
+矶
+藩
+治
+他
+元
+领
+膜
+遮
+穗
+蛾
+飞
+荒
+棺
+劫
+么
+市
+火
+温
+拈
+棚
+洼
+转
+果
+奕
+卸
+迪
+伸
+泳
+斗
+邡
+侄
+涨
+屯
+萋
+胭
+氡
+崮
+枞
+惧
+冒
+彩
+斜
+手
+豚
+随
+旭
+淑
+妞
+形
+菌
+吲
+沱
+争
+驯
+歹
+挟
+兆
+柱
+传
+至
+包
+内
+响
+临
+红
+功
+弩
+衡
+寂
+禁
+老
+棍
+耆
+渍
+织
+害
+氵
+渑
+布
+载
+靥
+嗬
+虽
+苹
+咨
+娄
+库
+雉
+榜
+帜
+嘲
+套
+瑚
+亲
+簸
+欧
+边
+6
+腿
+旮
+抛
+吹
+瞳
+得
+镓
+梗
+厨
+继
+漾
+愣
+憨
+士
+策
+窑
+抑
+躯
+襟
+脏
+参
+贸
+言
+干
+绸
+鳄
+穷
+藜
+音
+折
+详
+)
+举
+悍
+甸
+癌
+黎
+谴
+死
+罩
+迁
+寒
+驷
+袖
+媒
+蒋
+掘
+模
+纠
+恣
+观
+祖
+蛆
+碍
+位
+稿
+主
+澧
+跌
+筏
+京
+锏
+帝
+贴
+证
+糠
+才
+黄
+鲸
+略
+炯
+饱
+四
+出
+园
+犀
+牧
+容
+汉
+杆
+浈
+汰
+瑷
+造
+虫
+瘩
+怪
+驴
+济
+应
+花
+沣
+谔
+夙
+旅
+价
+矿
+以
+考
+s
+u
+呦
+晒
+巡
+茅
+准
+肟
+瓴
+詹
+仟
+褂
+译
+桌
+混
+宁
+怦
+郑
+抿
+些
+余
+鄂
+饴
+攒
+珑
+群
+阖
+岔
+琨
+藓
+预
+环
+洮
+岌
+宀
+杲
+瀵
+最
+常
+囡
+周
+踊
+女
+鼓
+袭
+喉
+简
+范
+薯
+遐
+疏
+粱
+黜
+禧
+法
+箔
+斤
+遥
+汝
+奥
+直
+贞
+撑
+置
+绱
+集
+她
+馅
+逗
+钧
+橱
+魉
+[
+恙
+躁
+唤
+9
+旺
+膘
+待
+脾
+惫
+购
+吗
+依
+盲
+度
+瘿
+蠖
+俾
+之
+镗
+拇
+鲵
+厝
+簧
+续
+款
+展
+啃
+表
+剔
+品
+钻
+腭
+损
+清
+锶
+统
+涌
+寸
+滨
+贪
+链
+吠
+冈
+伎
+迥
+咏
+吁
+览
+防
+迅
+失
+汾
+阔
+逵
+绀
+蔑
+列
+川
+凭
+努
+熨
+揪
+利
+俱
+绉
+抢
+鸨
+我
+即
+责
+膦
+易
+毓
+鹊
+刹
+玷
+岿
+空
+嘞
+绊
+排
+术
+估
+锷
+违
+们
+苟
+铜
+播
+肘
+件
+烫
+审
+鲂
+广
+像
+铌
+惰
+铟
+巳
+胍
+鲍
+康
+憧
+色
+恢
+想
+拷
+尤
+疳
+知
+S
+Y
+F
+D
+A
+峄
+裕
+帮
+握
+搔
+氐
+氘
+难
+墒
+沮
+雨
+叁
+缥
+悴
+藐
+湫
+娟
+苑
+稠
+颛
+簇
+后
+阕
+闭
+蕤
+缚
+怎
+佞
+码
+嘤
+蔡
+痊
+舱
+螯
+帕
+赫
+昵
+升
+烬
+岫
+、
+疵
+蜻
+髁
+蕨
+隶
+烛
+械
+丑
+盂
+梁
+强
+鲛
+由
+拘
+揉
+劭
+龟
+撤
+钩
+呕
+孛
+费
+妻
+漂
+求
+阑
+崖
+秤
+甘
+通
+深
+补
+赃
+坎
+床
+啪
+承
+吼
+量
+暇
+钼
+烨
+阂
+擎
+脱
+逮
+称
+P
+神
+属
+矗
+华
+届
+狍
+葑
+汹
+育
+患
+窒
+蛰
+佼
+静
+槎
+运
+鳗
+庆
+逝
+曼
+疱
+克
+代
+官
+此
+麸
+耧
+蚌
+晟
+例
+础
+榛
+副
+测
+唰
+缢
+迹
+灬
+霁
+身
+岁
+赭
+扛
+又
+菡
+乜
+雾
+板
+读
+陷
+徉
+贯
+郁
+虑
+变
+钓
+菜
+圾
+现
+琢
+式
+乐
+维
+渔
+浜
+左
+吾
+脑
+钡
+警
+T
+啵
+拴
+偌
+漱
+湿
+硕
+止
+骼
+魄
+积
+燥
+联
+踢
+玛
+则
+窿
+见
+振
+畿
+送
+班
+钽
+您
+赵
+刨
+印
+讨
+踝
+籍
+谡
+舌
+崧
+汽
+蔽
+沪
+酥
+绒
+怖
+财
+帖
+肱
+私
+莎
+勋
+羔
+霸
+励
+哼
+帐
+将
+帅
+渠
+纪
+婴
+娩
+岭
+厘
+滕
+吻
+伤
+坝
+冠
+戊
+隆
+瘁
+介
+涧
+物
+黍
+并
+姗
+奢
+蹑
+掣
+垸
+锴
+命
+箍
+捉
+病
+辖
+琰
+眭
+迩
+艘
+绌
+繁
+寅
+若
+毋
+思
+诉
+类
+诈
+燮
+轲
+酮
+狂
+重
+反
+职
+筱
+县
+委
+磕
+绣
+奖
+晋
+濉
+志
+徽
+肠
+呈
+獐
+坻
+口
+片
+碰
+几
+村
+柿
+劳
+料
+获
+亩
+惕
+晕
+厌
+号
+罢
+池
+正
+鏖
+煨
+家
+棕
+复
+尝
+懋
+蜥
+锅
+岛
+扰
+队
+坠
+瘾
+钬
+@
+卧
+疣
+镇
+譬
+冰
+彷
+频
+黯
+据
+垄
+采
+八
+缪
+瘫
+型
+熹
+砰
+楠
+襁
+箐
+但
+嘶
+绳
+啤
+拍
+盥
+穆
+傲
+洗
+盯
+塘
+怔
+筛
+丿
+台
+恒
+喂
+葛
+永
+¥
+烟
+酒
+桦
+书
+砂
+蚝
+缉
+态
+瀚
+袄
+圳
+轻
+蛛
+超
+榧
+遛
+姒
+奘
+铮
+右
+荽
+望
+偻
+卡
+丶
+氰
+附
+做
+革
+索
+戚
+坨
+桷
+唁
+垅
+榻
+岐
+偎
+坛
+莨
+山
+殊
+微
+骇
+陈
+爨
+推
+嗝
+驹
+澡
+藁
+呤
+卤
+嘻
+糅
+逛
+侵
+郓
+酌
+德
+摇
+※
+鬃
+被
+慨
+殡
+羸
+昌
+泡
+戛
+鞋
+河
+宪
+沿
+玲
+鲨
+翅
+哽
+源
+铅
+语
+照
+邯
+址
+荃
+佬
+顺
+鸳
+町
+霭
+睾
+瓢
+夸
+椁
+晓
+酿
+痈
+咔
+侏
+券
+噎
+湍
+签
+嚷
+离
+午
+尚
+社
+锤
+背
+孟
+使
+浪
+缦
+潍
+鞅
+军
+姹
+驶
+笑
+鳟
+鲁
+》
+孽
+钜
+绿
+洱
+礴
+焯
+椰
+颖
+囔
+乌
+孔
+巴
+互
+性
+椽
+哞
+聘
+昨
+早
+暮
+胶
+炀
+隧
+低
+彗
+昝
+铁
+呓
+氽
+藉
+喔
+癖
+瑗
+姨
+权
+胱
+韦
+堑
+蜜
+酋
+楝
+砝
+毁
+靓
+歙
+锲
+究
+屋
+喳
+骨
+辨
+碑
+武
+鸠
+宫
+辜
+烊
+适
+坡
+殃
+培
+佩
+供
+走
+蜈
+迟
+翼
+况
+姣
+凛
+浔
+吃
+飘
+债
+犟
+金
+促
+苛
+崇
+坂
+莳
+畔
+绂
+兵
+蠕
+斋
+根
+砍
+亢
+欢
+恬
+崔
+剁
+餐
+榫
+快
+扶
+‖
+濒
+缠
+鳜
+当
+彭
+驭
+浦
+篮
+昀
+锆
+秸
+钳
+弋
+娣
+瞑
+夷
+龛
+苫
+拱
+致
+%
+嵊
+障
+隐
+弑
+初
+娓
+抉
+汩
+累
+蓖
+"
+唬
+助
+苓
+昙
+押
+毙
+破
+城
+郧
+逢
+嚏
+獭
+瞻
+溱
+婿
+赊
+跨
+恼
+璧
+萃
+姻
+貉
+灵
+炉
+密
+氛
+陶
+砸
+谬
+衔
+点
+琛
+沛
+枳
+层
+岱
+诺
+脍
+榈
+埂
+征
+冷
+裁
+打
+蹴
+素
+瘘
+逞
+蛐
+聊
+激
+腱
+萘
+踵
+飒
+蓟
+吆
+取
+咙
+簋
+涓
+矩
+曝
+挺
+揣
+座
+你
+史
+舵
+焱
+尘
+苏
+笈
+脚
+溉
+榨
+诵
+樊
+邓
+焊
+义
+庶
+儋
+蟋
+蒲
+赦
+呷
+杞
+诠
+豪
+还
+试
+颓
+茉
+太
+除
+紫
+逃
+痴
+草
+充
+鳕
+珉
+祗
+墨
+渭
+烩
+蘸
+慕
+璇
+镶
+穴
+嵘
+恶
+骂
+险
+绋
+幕
+碉
+肺
+戳
+刘
+潞
+秣
+纾
+潜
+銮
+洛
+须
+罘
+销
+瘪
+汞
+兮
+屉
+r
+林
+厕
+质
+探
+划
+狸
+殚
+善
+煊
+烹
+〒
+锈
+逯
+宸
+辍
+泱
+柚
+袍
+远
+蹋
+嶙
+绝
+峥
+娥
+缍
+雀
+徵
+认
+镱
+谷
+=
+贩
+勉
+撩
+鄯
+斐
+洋
+非
+祚
+泾
+诒
+饿
+撬
+威
+晷
+搭
+芍
+锥
+笺
+蓦
+候
+琊
+档
+礁
+沼
+卵
+荠
+忑
+朝
+凹
+瑞
+头
+仪
+弧
+孵
+畏
+铆
+突
+衲
+车
+浩
+气
+茂
+悖
+厢
+枕
+酝
+戴
+湾
+邹
+飚
+攘
+锂
+写
+宵
+翁
+岷
+无
+喜
+丈
+挑
+嗟
+绛
+殉
+议
+槽
+具
+醇
+淞
+笃
+郴
+阅
+饼
+底
+壕
+砚
+弈
+询
+缕
+庹
+翟
+零
+筷
+暨
+舟
+闺
+甯
+撞
+麂
+茌
+蔼
+很
+珲
+捕
+棠
+角
+阉
+媛
+娲
+诽
+剿
+尉
+爵
+睬
+韩
+诰
+匣
+危
+糍
+镯
+立
+浏
+阳
+少
+盆
+舔
+擘
+匪
+申
+尬
+铣
+旯
+抖
+赘
+瓯
+居
+ˇ
+哮
+游
+锭
+茏
+歌
+坏
+甚
+秒
+舞
+沙
+仗
+劲
+潺
+阿
+燧
+郭
+嗖
+霏
+忠
+材
+奂
+耐
+跺
+砀
+输
+岖
+媳
+氟
+极
+摆
+灿
+今
+扔
+腻
+枝
+奎
+药
+熄
+吨
+话
+q
+额
+慑
+嘌
+协
+喀
+壳
+埭
+视
+著
+於
+愧
+陲
+翌
+峁
+颅
+佛
+腹
+聋
+侯
+咎
+叟
+秀
+颇
+存
+较
+罪
+哄
+岗
+扫
+栏
+钾
+羌
+己
+璨
+枭
+霉
+煌
+涸
+衿
+键
+镝
+益
+岢
+奏
+连
+夯
+睿
+冥
+均
+糖
+狞
+蹊
+稻
+爸
+刿
+胥
+煜
+丽
+肿
+璃
+掸
+跚
+灾
+垂
+樾
+濑
+乎
+莲
+窄
+犹
+撮
+战
+馄
+软
+络
+显
+鸢
+胸
+宾
+妲
+恕
+埔
+蝌
+份
+遇
+巧
+瞟
+粒
+恰
+剥
+桡
+博
+讯
+凯
+堇
+阶
+滤
+卖
+斌
+骚
+彬
+兑
+磺
+樱
+舷
+两
+娱
+福
+仃
+差
+找
+桁
+÷
+净
+把
+阴
+污
+戬
+雷
+碓
+蕲
+楚
+罡
+焖
+抽
+妫
+咒
+仑
+闱
+尽
+邑
+菁
+爱
+贷
+沥
+鞑
+牡
+嗉
+崴
+骤
+塌
+嗦
+订
+拮
+滓
+捡
+锻
+次
+坪
+杩
+臃
+箬
+融
+珂
+鹗
+宗
+枚
+降
+鸬
+妯
+阄
+堰
+盐
+毅
+必
+杨
+崃
+俺
+甬
+状
+莘
+货
+耸
+菱
+腼
+铸
+唏
+痤
+孚
+澳
+懒
+溅
+翘
+疙
+杷
+淼
+缙
+骰
+喊
+悉
+砻
+坷
+艇
+赁
+界
+谤
+纣
+宴
+晃
+茹
+归
+饭
+梢
+铡
+街
+抄
+肼
+鬟
+苯
+颂
+撷
+戈
+炒
+咆
+茭
+瘙
+负
+仰
+客
+琉
+铢
+封
+卑
+珥
+椿
+镧
+窨
+鬲
+寿
+御
+袤
+铃
+萎
+砖
+餮
+脒
+裳
+肪
+孕
+嫣
+馗
+嵇
+恳
+氯
+江
+石
+褶
+冢
+祸
+阻
+狈
+羞
+银
+靳
+透
+咳
+叼
+敷
+芷
+啥
+它
+瓤
+兰
+痘
+懊
+逑
+肌
+往
+捺
+坊
+甩
+呻
+〃
+沦
+忘
+膻
+祟
+菅
+剧
+崆
+智
+坯
+臧
+霍
+墅
+攻
+眯
+倘
+拢
+骠
+铐
+庭
+岙
+瓠
+′
+缺
+泥
+迢
+捶
+?
+?
+郏
+喙
+掷
+沌
+纯
+秘
+种
+听
+绘
+固
+螨
+团
+香
+盗
+妒
+埚
+蓝
+拖
+旱
+荞
+铀
+血
+遏
+汲
+辰
+叩
+拽
+幅
+硬
+惶
+桀
+漠
+措
+泼
+唑
+齐
+肾
+念
+酱
+虚
+屁
+耶
+旗
+砦
+闵
+婉
+馆
+拭
+绅
+韧
+忏
+窝
+醋
+葺
+顾
+辞
+倜
+堆
+辋
+逆
+玟
+贱
+疾
+董
+惘
+倌
+锕
+淘
+嘀
+莽
+俭
+笏
+绑
+鲷
+杈
+择
+蟀
+粥
+嗯
+驰
+逾
+案
+谪
+褓
+胫
+哩
+昕
+颚
+鲢
+绠
+躺
+鹄
+崂
+儒
+俨
+丝
+尕
+泌
+啊
+萸
+彰
+幺
+吟
+骄
+苣
+弦
+脊
+瑰
+〈
+诛
+镁
+析
+闪
+剪
+侧
+哟
+框
+螃
+守
+嬗
+燕
+狭
+铈
+缮
+概
+迳
+痧
+鲲
+俯
+售
+笼
+痣
+扉
+挖
+满
+咋
+援
+邱
+扇
+歪
+便
+玑
+绦
+峡
+蛇
+叨
+〖
+泽
+胃
+斓
+喋
+怂
+坟
+猪
+该
+蚬
+炕
+弥
+赞
+棣
+晔
+娠
+挲
+狡
+创
+疖
+铕
+镭
+稷
+挫
+弭
+啾
+翔
+粉
+履
+苘
+哦
+楼
+秕
+铂
+土
+锣
+瘟
+挣
+栉
+习
+享
+桢
+袅
+磨
+桂
+谦
+延
+坚
+蔚
+噗
+署
+谟
+猬
+钎
+恐
+嬉
+雒
+倦
+衅
+亏
+璩
+睹
+刻
+殿
+王
+算
+雕
+麻
+丘
+柯
+骆
+丸
+塍
+谚
+添
+鲈
+垓
+桎
+蚯
+芥
+予
+飕
+镦
+谌
+窗
+醚
+菀
+亮
+搪
+莺
+蒿
+羁
+足
+J
+真
+轶
+悬
+衷
+靛
+翊
+掩
+哒
+炅
+掐
+冼
+妮
+l
+谐
+稚
+荆
+擒
+犯
+陵
+虏
+浓
+崽
+刍
+陌
+傻
+孜
+千
+靖
+演
+矜
+钕
+煽
+杰
+酗
+渗
+伞
+栋
+俗
+泫
+戍
+罕
+沾
+疽
+灏
+煦
+芬
+磴
+叱
+阱
+榉
+湃
+蜀
+叉
+醒
+彪
+租
+郡
+篷
+屎
+良
+垢
+隗
+弱
+陨
+峪
+砷
+掴
+颁
+胎
+雯
+绵
+贬
+沐
+撵
+隘
+篙
+暖
+曹
+陡
+栓
+填
+臼
+彦
+瓶
+琪
+潼
+哪
+鸡
+摩
+啦
+俟
+锋
+域
+耻
+蔫
+疯
+纹
+撇
+毒
+绶
+痛
+酯
+忍
+爪
+赳
+歆
+嘹
+辕
+烈
+册
+朴
+钱
+吮
+毯
+癜
+娃
+谀
+邵
+厮
+炽
+璞
+邃
+丐
+追
+词
+瓒
+忆
+轧
+芫
+谯
+喷
+弟
+半
+冕
+裙
+掖
+墉
+绮
+寝
+苔
+势
+顷
+褥
+切
+衮
+君
+佳
+嫒
+蚩
+霞
+佚
+洙
+逊
+镖
+暹
+唛
+&
+殒
+顶
+碗
+獗
+轭
+铺
+蛊
+废
+恹
+汨
+崩
+珍
+那
+杵
+曲
+纺
+夏
+薰
+傀
+闳
+淬
+姘
+舀
+拧
+卷
+楂
+恍
+讪
+厩
+寮
+篪
+赓
+乘
+灭
+盅
+鞣
+沟
+慎
+挂
+饺
+鼾
+杳
+树
+缨
+丛
+絮
+娌
+臻
+嗳
+篡
+侩
+述
+衰
+矛
+圈
+蚜
+匕
+筹
+匿
+濞
+晨
+叶
+骋
+郝
+挚
+蚴
+滞
+增
+侍
+描
+瓣
+吖
+嫦
+蟒
+匾
+圣
+赌
+毡
+癞
+恺
+百
+曳
+需
+篓
+肮
+庖
+帏
+卿
+驿
+遗
+蹬
+鬓
+骡
+歉
+芎
+胳
+屐
+禽
+烦
+晌
+寄
+媾
+狄
+翡
+苒
+船
+廉
+终
+痞
+殇
+々
+畦
+饶
+改
+拆
+悻
+萄
+£
+瓿
+乃
+訾
+桅
+匮
+溧
+拥
+纱
+铍
+骗
+蕃
+龋
+缬
+父
+佐
+疚
+栎
+醍
+掳
+蓄
+x
+惆
+颜
+鲆
+榆
+〔
+猎
+敌
+暴
+谥
+鲫
+贾
+罗
+玻
+缄
+扦
+芪
+癣
+落
+徒
+臾
+恿
+猩
+托
+邴
+肄
+牵
+春
+陛
+耀
+刊
+拓
+蓓
+邳
+堕
+寇
+枉
+淌
+啡
+湄
+兽
+酷
+萼
+碚
+濠
+萤
+夹
+旬
+戮
+梭
+琥
+椭
+昔
+勺
+蜊
+绐
+晚
+孺
+僵
+宣
+摄
+冽
+旨
+萌
+忙
+蚤
+眉
+噼
+蟑
+付
+契
+瓜
+悼
+颡
+壁
+曾
+窕
+颢
+澎
+仿
+俑
+浑
+嵌
+浣
+乍
+碌
+褪
+乱
+蔟
+隙
+玩
+剐
+葫
+箫
+纲
+围
+伐
+决
+伙
+漩
+瑟
+刑
+肓
+镳
+缓
+蹭
+氨
+皓
+典
+畲
+坍
+铑
+檐
+塑
+洞
+倬
+储
+胴
+淳
+戾
+吐
+灼
+惺
+妙
+毕
+珐
+缈
+虱
+盖
+羰
+鸿
+磅
+谓
+髅
+娴
+苴
+唷
+蚣
+霹
+抨
+贤
+唠
+犬
+誓
+逍
+庠
+逼
+麓
+籼
+釉
+呜
+碧
+秧
+氩
+摔
+霄
+穸
+纨
+辟
+妈
+映
+完
+牛
+缴
+嗷
+炊
+恩
+荔
+茆
+掉
+紊
+慌
+莓
+羟
+阙
+萁
+磐
+另
+蕹
+辱
+鳐
+湮
+吡
+吩
+唐
+睦
+垠
+舒
+圜
+冗
+瞿
+溺
+芾
+囱
+匠
+僳
+汐
+菩
+饬
+漓
+黑
+霰
+浸
+濡
+窥
+毂
+蒡
+兢
+驻
+鹉
+芮
+诙
+迫
+雳
+厂
+忐
+臆
+猴
+鸣
+蚪
+栈
+箕
+羡
+渐
+莆
+捍
+眈
+哓
+趴
+蹼
+埕
+嚣
+骛
+宏
+淄
+斑
+噜
+严
+瑛
+垃
+椎
+诱
+压
+庾
+绞
+焘
+廿
+抡
+迄
+棘
+夫
+纬
+锹
+眨
+瞌
+侠
+脐
+竞
+瀑
+孳
+骧
+遁
+姜
+颦
+荪
+滚
+萦
+伪
+逸
+粳
+爬
+锁
+矣
+役
+趣
+洒
+颔
+诏
+逐
+奸
+甭
+惠
+攀
+蹄
+泛
+尼
+拼
+阮
+鹰
+亚
+颈
+惑
+勒
+〉
+际
+肛
+爷
+刚
+钨
+丰
+养
+冶
+鲽
+辉
+蔻
+画
+覆
+皴
+妊
+麦
+返
+醉
+皂
+擀
+〗
+酶
+凑
+粹
+悟
+诀
+硖
+港
+卜
+z
+杀
+涕
+±
+舍
+铠
+抵
+弛
+段
+敝
+镐
+奠
+拂
+轴
+跛
+袱
+e
+t
+沉
+菇
+俎
+薪
+峦
+秭
+蟹
+历
+盟
+菠
+寡
+液
+肢
+喻
+染
+裱
+悱
+抱
+氙
+赤
+捅
+猛
+跑
+氮
+谣
+仁
+尺
+辊
+窍
+烙
+衍
+架
+擦
+倏
+璐
+瑁
+币
+楞
+胖
+夔
+趸
+邛
+惴
+饕
+虔
+蝎
+§
+哉
+贝
+宽
+辫
+炮
+扩
+饲
+籽
+魏
+菟
+锰
+伍
+猝
+末
+琳
+哚
+蛎
+邂
+呀
+姿
+鄞
+却
+歧
+仙
+恸
+椐
+森
+牒
+寤
+袒
+婆
+虢
+雅
+钉
+朵
+贼
+欲
+苞
+寰
+故
+龚
+坭
+嘘
+咫
+礼
+硷
+兀
+睢
+汶
+’
+铲
+烧
+绕
+诃
+浃
+钿
+哺
+柜
+讼
+颊
+璁
+腔
+洽
+咐
+脲
+簌
+筠
+镣
+玮
+鞠
+谁
+兼
+姆
+挥
+梯
+蝴
+谘
+漕
+刷
+躏
+宦
+弼
+b
+垌
+劈
+麟
+莉
+揭
+笙
+渎
+仕
+嗤
+仓
+配
+怏
+抬
+错
+泯
+镊
+孰
+猿
+邪
+仍
+秋
+鼬
+壹
+歇
+吵
+炼
+<
+尧
+射
+柬
+廷
+胧
+霾
+凳
+隋
+肚
+浮
+梦
+祥
+株
+堵
+退
+L
+鹫
+跎
+凶
+毽
+荟
+炫
+栩
+玳
+甜
+沂
+鹿
+顽
+伯
+爹
+赔
+蛴
+徐
+匡
+欣
+狰
+缸
+雹
+蟆
+疤
+默
+沤
+啜
+痂
+衣
+禅
+w
+i
+h
+辽
+葳
+黝
+钗
+停
+沽
+棒
+馨
+颌
+肉
+吴
+硫
+悯
+劾
+娈
+马
+啧
+吊
+悌
+镑
+峭
+帆
+瀣
+涉
+咸
+疸
+滋
+泣
+翦
+拙
+癸
+钥
+蜒
++
+尾
+庄
+凝
+泉
+婢
+渴
+谊
+乞
+陆
+锉
+糊
+鸦
+淮
+I
+B
+N
+晦
+弗
+乔
+庥
+葡
+尻
+席
+橡
+傣
+渣
+拿
+惩
+麋
+斛
+缃
+矮
+蛏
+岘
+鸽
+姐
+膏
+催
+奔
+镒
+喱
+蠡
+摧
+钯
+胤
+柠
+拐
+璋
+鸥
+卢
+荡
+倾
+^
+_
+珀
+逄
+萧
+塾
+掇
+贮
+笆
+聂
+圃
+冲
+嵬
+M
+滔
+笕
+值
+炙
+偶
+蜱
+搐
+梆
+汪
+蔬
+腑
+鸯
+蹇
+敞
+绯
+仨
+祯
+谆
+梧
+糗
+鑫
+啸
+豺
+囹
+猾
+巢
+柄
+瀛
+筑
+踌
+沭
+暗
+苁
+鱿
+蹉
+脂
+蘖
+牢
+热
+木
+吸
+溃
+宠
+序
+泞
+偿
+拜
+檩
+厚
+朐
+毗
+螳
+吞
+媚
+朽
+担
+蝗
+橘
+畴
+祈
+糟
+盱
+隼
+郜
+惜
+珠
+裨
+铵
+焙
+琚
+唯
+咚
+噪
+骊
+丫
+滢
+勤
+棉
+呸
+咣
+淀
+隔
+蕾
+窈
+饨
+挨
+煅
+短
+匙
+粕
+镜
+赣
+撕
+墩
+酬
+馁
+豌
+颐
+抗
+酣
+氓
+佑
+搁
+哭
+递
+耷
+涡
+桃
+贻
+碣
+截
+瘦
+昭
+镌
+蔓
+氚
+甲
+猕
+蕴
+蓬
+散
+拾
+纛
+狼
+猷
+铎
+埋
+旖
+矾
+讳
+囊
+糜
+迈
+粟
+蚂
+紧
+鲳
+瘢
+栽
+稼
+羊
+锄
+斟
+睁
+桥
+瓮
+蹙
+祉
+醺
+鼻
+昱
+剃
+跳
+篱
+跷
+蒜
+翎
+宅
+晖
+嗑
+壑
+峻
+癫
+屏
+狠
+陋
+袜
+途
+憎
+祀
+莹
+滟
+佶
+溥
+臣
+约
+盛
+峰
+磁
+慵
+婪
+拦
+莅
+朕
+鹦
+粲
+裤
+哎
+疡
+嫖
+琵
+窟
+堪
+谛
+嘉
+儡
+鳝
+斩
+郾
+驸
+酊
+妄
+胜
+贺
+徙
+傅
+噌
+钢
+栅
+庇
+恋
+匝
+巯
+邈
+尸
+锚
+粗
+佟
+蛟
+薹
+纵
+蚊
+郅
+绢
+锐
+苗
+俞
+篆
+淆
+膀
+鲜
+煎
+诶
+秽
+寻
+涮
+刺
+怀
+噶
+巨
+褰
+魅
+灶
+灌
+桉
+藕
+谜
+舸
+薄
+搀
+恽
+借
+牯
+痉
+渥
+愿
+亓
+耘
+杠
+柩
+锔
+蚶
+钣
+珈
+喘
+蹒
+幽
+赐
+稗
+晤
+莱
+泔
+扯
+肯
+菪
+裆
+腩
+豉
+疆
+骜
+腐
+倭
+珏
+唔
+粮
+亡
+润
+慰
+伽
+橄
+玄
+誉
+醐
+胆
+龊
+粼
+塬
+陇
+彼
+削
+嗣
+绾
+芽
+妗
+垭
+瘴
+爽
+薏
+寨
+龈
+泠
+弹
+赢
+漪
+猫
+嘧
+涂
+恤
+圭
+茧
+烽
+屑
+痕
+巾
+赖
+荸
+凰
+腮
+畈
+亵
+蹲
+偃
+苇
+澜
+艮
+换
+骺
+烘
+苕
+梓
+颉
+肇
+哗
+悄
+氤
+涠
+葬
+屠
+鹭
+植
+竺
+佯
+诣
+鲇
+瘀
+鲅
+邦
+移
+滁
+冯
+耕
+癔
+戌
+茬
+沁
+巩
+悠
+湘
+洪
+痹
+锟
+循
+谋
+腕
+鳃
+钠
+捞
+焉
+迎
+碱
+伫
+急
+榷
+奈
+邝
+卯
+辄
+皲
+卟
+醛
+畹
+忧
+稳
+雄
+昼
+缩
+阈
+睑
+扌
+耗
+曦
+涅
+捏
+瞧
+邕
+淖
+漉
+铝
+耦
+禹
+湛
+喽
+莼
+琅
+诸
+苎
+纂
+硅
+始
+嗨
+傥
+燃
+臂
+赅
+嘈
+呆
+贵
+屹
+壮
+肋
+亍
+蚀
+卅
+豹
+腆
+邬
+迭
+浊
+}
+童
+螂
+捐
+圩
+勐
+触
+寞
+汊
+壤
+荫
+膺
+渌
+芳
+懿
+遴
+螈
+泰
+蓼
+蛤
+茜
+舅
+枫
+朔
+膝
+眙
+避
+梅
+判
+鹜
+璜
+牍
+缅
+垫
+藻
+黔
+侥
+惚
+懂
+踩
+腰
+腈
+札
+丞
+唾
+慈
+顿
+摹
+荻
+琬
+~
+斧
+沈
+滂
+胁
+胀
+幄
+莜
+Z
+匀
+鄄
+掌
+绰
+茎
+焚
+赋
+萱
+谑
+汁
+铒
+瞎
+夺
+蜗
+野
+娆
+冀
+弯
+篁
+懵
+灞
+隽
+芡
+脘
+俐
+辩
+芯
+掺
+喏
+膈
+蝈
+觐
+悚
+踹
+蔗
+熠
+鼠
+呵
+抓
+橼
+峨
+畜
+缔
+禾
+崭
+弃
+熊
+摒
+凸
+拗
+穹
+蒙
+抒
+祛
+劝
+闫
+扳
+阵
+醌
+踪
+喵
+侣
+搬
+仅
+荧
+赎
+蝾
+琦
+买
+婧
+瞄
+寓
+皎
+冻
+赝
+箩
+莫
+瞰
+郊
+笫
+姝
+筒
+枪
+遣
+煸
+袋
+舆
+痱
+涛
+母
+〇
+启
+践
+耙
+绲
+盘
+遂
+昊
+搞
+槿
+诬
+纰
+泓
+惨
+檬
+亻
+越
+C
+o
+憩
+熵
+祷
+钒
+暧
+塔
+阗
+胰
+咄
+娶
+魔
+琶
+钞
+邻
+扬
+杉
+殴
+咽
+弓
+〆
+髻
+】
+吭
+揽
+霆
+拄
+殖
+脆
+彻
+岩
+芝
+勃
+辣
+剌
+钝
+嘎
+甄
+佘
+皖
+伦
+授
+徕
+憔
+挪
+皇
+庞
+稔
+芜
+踏
+溴
+兖
+卒
+擢
+饥
+鳞
+煲
+‰
+账
+颗
+叻
+斯
+捧
+鳍
+琮
+讹
+蛙
+纽
+谭
+酸
+兔
+莒
+睇
+伟
+觑
+羲
+嗜
+宜
+褐
+旎
+辛
+卦
+诘
+筋
+鎏
+溪
+挛
+熔
+阜
+晰
+鳅
+丢
+奚
+灸
+呱
+献
+陉
+黛
+鸪
+甾
+萨
+疮
+拯
+洲
+疹
+辑
+叙
+恻
+谒
+允
+柔
+烂
+氏
+逅
+漆
+拎
+惋
+扈
+湟
+纭
+啕
+掬
+擞
+哥
+忽
+涤
+鸵
+靡
+郗
+瓷
+扁
+廊
+怨
+雏
+钮
+敦
+E
+懦
+憋
+汀
+拚
+啉
+腌
+岸
+f
+痼
+瞅
+尊
+咀
+眩
+飙
+忌
+仝
+迦
+熬
+毫
+胯
+篑
+茄
+腺
+凄
+舛
+碴
+锵
+诧
+羯
+後
+漏
+汤
+宓
+仞
+蚁
+壶
+谰
+皑
+铄
+棰
+罔
+辅
+晶
+苦
+牟
+闽
+\
+烃
+饮
+聿
+丙
+蛳
+朱
+煤
+涔
+鳖
+犁
+罐
+荼
+砒
+淦
+妤
+黏
+戎
+孑
+婕
+瑾
+戢
+钵
+枣
+捋
+砥
+衩
+狙
+桠
+稣
+阎
+肃
+梏
+诫
+孪
+昶
+婊
+衫
+嗔
+侃
+塞
+蜃
+樵
+峒
+貌
+屿
+欺
+缫
+阐
+栖
+诟
+珞
+荭
+吝
+萍
+嗽
+恂
+啻
+蜴
+磬
+峋
+俸
+豫
+谎
+徊
+镍
+韬
+魇
+晴
+U
+囟
+猜
+蛮
+坐
+囿
+伴
+亭
+肝
+佗
+蝠
+妃
+胞
+滩
+榴
+氖
+垩
+苋
+砣
+扪
+馏
+姓
+轩
+厉
+夥
+侈
+禀
+垒
+岑
+赏
+钛
+辐
+痔
+披
+纸
+碳
+“
+坞
+蠓
+挤
+荥
+沅
+悔
+铧
+帼
+蒌
+蝇
+a
+p
+y
+n
+g
+哀
+浆
+瑶
+凿
+桶
+馈
+皮
+奴
+苜
+佤
+伶
+晗
+铱
+炬
+优
+弊
+氢
+恃
+甫
+攥
+端
+锌
+灰
+稹
+炝
+曙
+邋
+亥
+眶
+碾
+拉
+萝
+绔
+捷
+浍
+腋
+姑
+菖
+凌
+涞
+麽
+锢
+桨
+潢
+绎
+镰
+殆
+锑
+渝
+铬
+困
+绽
+觎
+匈
+糙
+暑
+裹
+鸟
+盔
+肽
+迷
+綦
+『
+亳
+佝
+俘
+钴
+觇
+骥
+仆
+疝
+跪
+婶
+郯
+瀹
+唉
+脖
+踞
+针
+晾
+忒
+扼
+瞩
+叛
+椒
+疟
+嗡
+邗
+肆
+跆
+玫
+忡
+捣
+咧
+唆
+艄
+蘑
+潦
+笛
+阚
+沸
+泻
+掊
+菽
+贫
+斥
+髂
+孢
+镂
+赂
+麝
+鸾
+屡
+衬
+苷
+恪
+叠
+希
+粤
+爻
+喝
+茫
+惬
+郸
+绻
+庸
+撅
+碟
+宄
+妹
+膛
+叮
+饵
+崛
+嗲
+椅
+冤
+搅
+咕
+敛
+尹
+垦
+闷
+蝉
+霎
+勰
+败
+蓑
+泸
+肤
+鹌
+幌
+焦
+浠
+鞍
+刁
+舰
+乙
+竿
+裔
+。
+茵
+函
+伊
+兄
+丨
+娜
+匍
+謇
+莪
+宥
+似
+蝽
+翳
+酪
+翠
+粑
+薇
+祢
+骏
+赠
+叫
+Q
+噤
+噻
+竖
+芗
+莠
+潭
+俊
+羿
+耜
+O
+郫
+趁
+嗪
+囚
+蹶
+芒
+洁
+笋
+鹑
+敲
+硝
+啶
+堡
+渲
+揩
+』
+携
+宿
+遒
+颍
+扭
+棱
+割
+萜
+蔸
+葵
+琴
+捂
+饰
+衙
+耿
+掠
+募
+岂
+窖
+涟
+蔺
+瘤
+柞
+瞪
+怜
+匹
+距
+楔
+炜
+哆
+秦
+缎
+幼
+茁
+绪
+痨
+恨
+楸
+娅
+瓦
+桩
+雪
+嬴
+伏
+榔
+妥
+铿
+拌
+眠
+雍
+缇
+‘
+卓
+搓
+哌
+觞
+噩
+屈
+哧
+髓
+咦
+巅
+娑
+侑
+淫
+膳
+祝
+勾
+姊
+莴
+胄
+疃
+薛
+蜷
+胛
+巷
+芙
+芋
+熙
+闰
+勿
+窃
+狱
+剩
+钏
+幢
+陟
+铛
+慧
+靴
+耍
+k
+浙
+浇
+飨
+惟
+绗
+祜
+澈
+啼
+咪
+磷
+摞
+诅
+郦
+抹
+跃
+壬
+吕
+肖
+琏
+颤
+尴
+剡
+抠
+凋
+赚
+泊
+津
+宕
+殷
+倔
+氲
+漫
+邺
+涎
+怠
+$
+垮
+荬
+遵
+俏
+叹
+噢
+饽
+蜘
+孙
+筵
+疼
+鞭
+羧
+牦
+箭
+潴
+c
+眸
+祭
+髯
+啖
+坳
+愁
+芩
+驮
+倡
+巽
+穰
+沃
+胚
+怒
+凤
+槛
+剂
+趵
+嫁
+v
+邢
+灯
+鄢
+桐
+睽
+檗
+锯
+槟
+婷
+嵋
+圻
+诗
+蕈
+颠
+遭
+痢
+芸
+怯
+馥
+竭
+锗
+徜
+恭
+遍
+籁
+剑
+嘱
+苡
+龄
+僧
+桑
+潸
+弘
+澶
+楹
+悲
+讫
+愤
+腥
+悸
+谍
+椹
+呢
+桓
+葭
+攫
+阀
+翰
+躲
+敖
+柑
+郎
+笨
+橇
+呃
+魁
+燎
+脓
+葩
+磋
+垛
+玺
+狮
+沓
+砜
+蕊
+锺
+罹
+蕉
+翱
+虐
+闾
+巫
+旦
+茱
+嬷
+枯
+鹏
+贡
+芹
+汛
+矫
+绁
+拣
+禺
+佃
+讣
+舫
+惯
+乳
+趋
+疲
+挽
+岚
+虾
+衾
+蠹
+蹂
+飓
+氦
+铖
+孩
+稞
+瑜
+壅
+掀
+勘
+妓
+畅
+髋
+W
+庐
+牲
+蓿
+榕
+练
+垣
+唱
+邸
+菲
+昆
+婺
+穿
+绡
+麒
+蚱
+掂
+愚
+泷
+涪
+漳
+妩
+娉
+榄
+讷
+觅
+旧
+藤
+煮
+呛
+柳
+腓
+叭
+庵
+烷
+阡
+罂
+蜕
+擂
+猖
+咿
+媲
+脉
+【
+沏
+貅
+黠
+熏
+哲
+烁
+坦
+酵
+兜
+×
+潇
+撒
+剽
+珩
+圹
+乾
+摸
+樟
+帽
+嗒
+襄
+魂
+轿
+憬
+锡
+〕
+喃
+皆
+咖
+隅
+脸
+残
+泮
+袂
+鹂
+珊
+囤
+捆
+咤
+误
+徨
+闹
+淙
+芊
+淋
+怆
+囗
+拨
+梳
+渤
+R
+G
+绨
+蚓
+婀
+幡
+狩
+麾
+谢
+唢
+裸
+旌
+伉
+纶
+裂
+驳
+砼
+咛
+澄
+樨
+蹈
+宙
+澍
+倍
+貔
+操
+勇
+蟠
+摈
+砧
+虬
+够
+缁
+悦
+藿
+撸
+艹
+摁
+淹
+豇
+虎
+榭
+ˉ
+吱
+d
+°
+喧
+荀
+踱
+侮
+奋
+偕
+饷
+犍
+惮
+坑
+璎
+徘
+宛
+妆
+袈
+倩
+窦
+昂
+荏
+乖
+K
+怅
+撰
+鳙
+牙
+袁
+酞
+X
+痿
+琼
+闸
+雁
+趾
+荚
+虻
+涝
+《
+杏
+韭
+偈
+烤
+绫
+鞘
+卉
+症
+遢
+蓥
+诋
+杭
+荨
+匆
+竣
+簪
+辙
+敕
+虞
+丹
+缭
+咩
+黟
+m
+淤
+瑕
+咂
+铉
+硼
+茨
+嶂
+痒
+畸
+敬
+涿
+粪
+窘
+熟
+叔
+嫔
+盾
+忱
+裘
+憾
+梵
+赡
+珙
+咯
+娘
+庙
+溯
+胺
+葱
+痪
+摊
+荷
+卞
+乒
+髦
+寐
+铭
+坩
+胗
+枷
+爆
+溟
+嚼
+羚
+砬
+轨
+惊
+挠
+罄
+竽
+菏
+氧
+浅
+楣
+盼
+枢
+炸
+阆
+杯
+谏
+噬
+淇
+渺
+俪
+秆
+墓
+泪
+跻
+砌
+痰
+垡
+渡
+耽
+釜
+讶
+鳎
+煞
+呗
+韶
+舶
+绷
+鹳
+缜
+旷
+铊
+皱
+龌
+檀
+霖
+奄
+槐
+艳
+蝶
+旋
+哝
+赶
+骞
+蚧
+腊
+盈
+丁
+`
+蜚
+矸
+蝙
+睨
+嚓
+僻
+鬼
+醴
+夜
+彝
+磊
+笔
+拔
+栀
+糕
+厦
+邰
+纫
+逭
+纤
+眦
+膊
+馍
+躇
+烯
+蘼
+冬
+诤
+暄
+骶
+哑
+瘠
+」
+臊
+丕
+愈
+咱
+螺
+擅
+跋
+搏
+硪
+谄
+笠
+淡
+嘿
+骅
+谧
+鼎
+皋
+姚
+歼
+蠢
+驼
+耳
+胬
+挝
+涯
+狗
+蒽
+孓
+犷
+凉
+芦
+箴
+铤
+孤
+嘛
+坤
+V
+茴
+朦
+挞
+尖
+橙
+诞
+搴
+碇
+洵
+浚
+帚
+蜍
+漯
+柘
+嚎
+讽
+芭
+荤
+咻
+祠
+秉
+跖
+埃
+吓
+糯
+眷
+馒
+惹
+娼
+鲑
+嫩
+讴
+轮
+瞥
+靶
+褚
+乏
+缤
+宋
+帧
+删
+驱
+碎
+扑
+俩
+俄
+偏
+涣
+竹
+噱
+皙
+佰
+渚
+唧
+斡
+#
+镉
+刀
+崎
+筐
+佣
+夭
+贰
+肴
+峙
+哔
+艿
+匐
+牺
+镛
+缘
+仡
+嫡
+劣
+枸
+堀
+梨
+簿
+鸭
+蒸
+亦
+稽
+浴
+{
+衢
+束
+槲
+j
+阁
+揍
+疥
+棋
+潋
+聪
+窜
+乓
+睛
+插
+冉
+阪
+苍
+搽
+「
+蟾
+螟
+幸
+仇
+樽
+撂
+慢
+跤
+幔
+俚
+淅
+覃
+觊
+溶
+妖
+帛
+侨
+曰
+妾
+泗
+·
+:
+瀘
+風
+Ë
+(
+)
+∶
+紅
+紗
+瑭
+雲
+頭
+鶏
+財
+許
+•
+¥
+樂
+焗
+麗
+—
+;
+滙
+東
+榮
+繪
+興
+…
+門
+業
+π
+楊
+國
+顧
+é
+盤
+寳
+Λ
+龍
+鳳
+島
+誌
+緣
+結
+銭
+萬
+勝
+祎
+璟
+優
+歡
+臨
+時
+購
+=
+★
+藍
+昇
+鐵
+觀
+勅
+農
+聲
+畫
+兿
+術
+發
+劉
+記
+專
+耑
+園
+書
+壴
+種
+Ο
+●
+褀
+號
+銀
+匯
+敟
+锘
+葉
+橪
+廣
+進
+蒄
+鑽
+阝
+祙
+貢
+鍋
+豊
+夬
+喆
+團
+閣
+開
+燁
+賓
+館
+酡
+沔
+順
++
+硚
+劵
+饸
+陽
+車
+湓
+復
+萊
+氣
+軒
+華
+堃
+迮
+纟
+戶
+馬
+學
+裡
+電
+嶽
+獨
+マ
+シ
+サ
+ジ
+燘
+袪
+環
+❤
+臺
+灣
+専
+賣
+孖
+聖
+攝
+線
+▪
+α
+傢
+俬
+夢
+達
+莊
+喬
+貝
+薩
+劍
+羅
+壓
+棛
+饦
+尃
+璈
+囍
+醫
+G
+I
+A
+#
+N
+鷄
+髙
+嬰
+啓
+約
+隹
+潔
+賴
+藝
+~
+寶
+籣
+麺
+
+嶺
+√
+義
+網
+峩
+長
+∧
+魚
+機
+構
+②
+鳯
+偉
+L
+B
+㙟
+畵
+鴿
+'
+詩
+溝
+嚞
+屌
+藔
+佧
+玥
+蘭
+織
+1
+3
+9
+0
+7
+點
+砭
+鴨
+鋪
+銘
+廳
+弍
+‧
+創
+湯
+坶
+℃
+卩
+骝
+&
+烜
+荘
+當
+潤
+扞
+係
+懷
+碶
+钅
+蚨
+讠
+☆
+叢
+爲
+埗
+涫
+塗
+→
+楽
+現
+鯨
+愛
+瑪
+鈺
+忄
+悶
+藥
+飾
+樓
+視
+孬
+ㆍ
+燚
+苪
+師
+①
+丼
+锽
+│
+韓
+標
+è
+兒
+閏
+匋
+張
+漢
+Ü
+髪
+會
+閑
+檔
+習
+裝
+の
+峯
+菘
+輝
+И
+雞
+釣
+億
+浐
+K
+O
+R
+8
+H
+E
+P
+T
+W
+D
+S
+C
+M
+F
+姌
+饹
+»
+晞
+廰
+ä
+嵯
+鷹
+負
+飲
+絲
+冚
+楗
+澤
+綫
+區
+❋
+←
+質
+靑
+揚
+③
+滬
+統
+産
+協
+﹑
+乸
+畐
+經
+運
+際
+洺
+岽
+為
+粵
+諾
+崋
+豐
+碁
+ɔ
+V
+2
+6
+齋
+誠
+訂
+´
+勑
+雙
+陳
+無
+í
+泩
+媄
+夌
+刂
+i
+c
+t
+o
+r
+a
+嘢
+耄
+燴
+暃
+壽
+媽
+靈
+抻
+體
+唻
+É
+冮
+甹
+鎮
+錦
+ʌ
+蜛
+蠄
+尓
+駕
+戀
+飬
+逹
+倫
+貴
+極
+Я
+Й
+寬
+磚
+嶪
+郎
+職
+|
+間
+n
+d
+剎
+伈
+課
+飛
+橋
+瘊
+№
+譜
+骓
+圗
+滘
+縣
+粿
+咅
+養
+濤
+彳
+®
+%
+Ⅱ
+啰
+㴪
+見
+矞
+薬
+糁
+邨
+鲮
+顔
+罱
+З
+選
+話
+贏
+氪
+俵
+競
+瑩
+繡
+枱
+β
+綉
+á
+獅
+爾
+™
+麵
+戋
+淩
+徳
+個
+劇
+場
+務
+簡
+寵
+h
+實
+膠
+轱
+圖
+築
+嘣
+樹
+㸃
+營
+耵
+孫
+饃
+鄺
+飯
+麯
+遠
+輸
+坫
+孃
+乚
+閃
+鏢
+㎡
+題
+廠
+關
+↑
+爺
+將
+軍
+連
+篦
+覌
+參
+箸
+-
+窠
+棽
+寕
+夀
+爰
+歐
+呙
+閥
+頡
+熱
+雎
+垟
+裟
+凬
+勁
+帑
+馕
+夆
+疌
+枼
+馮
+貨
+蒤
+樸
+彧
+旸
+靜
+龢
+暢
+㐱
+鳥
+珺
+鏡
+灡
+爭
+堷
+廚
+Ó
+騰
+診
+┅
+蘇
+褔
+凱
+頂
+豕
+亞
+帥
+嘬
+⊥
+仺
+桖
+複
+饣
+絡
+穂
+顏
+棟
+納
+▏
+濟
+親
+設
+計
+攵
+埌
+烺
+ò
+頤
+燦
+蓮
+撻
+節
+講
+濱
+濃
+娽
+洳
+朿
+燈
+鈴
+護
+膚
+铔
+過
+補
+Z
+U
+5
+4
+坋
+闿
+䖝
+餘
+缐
+铞
+貿
+铪
+桼
+趙
+鍊
+[
+㐂
+垚
+菓
+揸
+捲
+鐘
+滏
+𣇉
+爍
+輪
+燜
+鴻
+鮮
+動
+鹞
+鷗
+丄
+慶
+鉌
+翥
+飮
+腸
+⇋
+漁
+覺
+來
+熘
+昴
+翏
+鲱
+圧
+鄉
+萭
+頔
+爐
+嫚
+г
+貭
+類
+聯
+幛
+輕
+訓
+鑒
+夋
+锨
+芃
+珣
+䝉
+扙
+嵐
+銷
+處
+ㄱ
+語
+誘
+苝
+歸
+儀
+燒
+楿
+內
+粢
+葒
+奧
+麥
+礻
+滿
+蠔
+穵
+瞭
+態
+鱬
+榞
+硂
+鄭
+黃
+煙
+祐
+奓
+逺
+*
+瑄
+獲
+聞
+薦
+讀
+這
+樣
+決
+問
+啟
+們
+執
+説
+轉
+單
+隨
+唘
+帶
+倉
+庫
+還
+贈
+尙
+皺
+■
+餅
+產
+○
+∈
+報
+狀
+楓
+賠
+琯
+嗮
+禮
+`
+傳
+>
+≤
+嗞
+Φ
+≥
+換
+咭
+∣
+↓
+曬
+ε
+応
+寫
+″
+終
+様
+純
+費
+療
+聨
+凍
+壐
+郵
+ü
+黒
+∫
+製
+塊
+調
+軽
+確
+撃
+級
+馴
+Ⅲ
+涇
+繹
+數
+碼
+證
+狒
+処
+劑
+<
+晧
+賀
+衆
+]
+櫥
+兩
+陰
+絶
+對
+鯉
+憶
+◎
+p
+e
+Y
+蕒
+煖
+頓
+測
+試
+鼽
+僑
+碩
+妝
+帯
+≈
+鐡
+舖
+權
+喫
+倆
+ˋ
+該
+悅
+ā
+俫
+.
+f
+s
+b
+m
+k
+g
+u
+j
+貼
+淨
+濕
+針
+適
+備
+l
+/
+給
+謢
+強
+觸
+衛
+與
+⊙
+$
+緯
+變
+⑴
+⑵
+⑶
+㎏
+殺
+∩
+幚
+─
+價
+▲
+離
+ú
+ó
+飄
+烏
+関
+閟
+﹝
+﹞
+邏
+輯
+鍵
+驗
+訣
+導
+歷
+屆
+層
+▼
+儱
+錄
+熳
+ē
+艦
+吋
+錶
+辧
+飼
+顯
+④
+禦
+販
+気
+対
+枰
+閩
+紀
+幹
+瞓
+貊
+淚
+△
+眞
+墊
+Ω
+獻
+褲
+縫
+緑
+亜
+鉅
+餠
+{
+}
+◆
+蘆
+薈
+█
+◇
+溫
+彈
+晳
+粧
+犸
+穩
+訊
+崬
+凖
+熥
+П
+舊
+條
+紋
+圍
+Ⅳ
+筆
+尷
+難
+雜
+錯
+綁
+識
+頰
+鎖
+艶
+□
+殁
+殼
+⑧
+├
+▕
+鵬
+ǐ
+ō
+ǒ
+糝
+綱
+▎
+μ
+盜
+饅
+醬
+籤
+蓋
+釀
+鹽
+據
+à
+ɡ
+辦
+◥
+彐
+┌
+婦
+獸
+鲩
+伱
+ī
+蒟
+蒻
+齊
+袆
+腦
+寧
+凈
+妳
+煥
+詢
+偽
+謹
+啫
+鯽
+騷
+鱸
+損
+傷
+鎻
+髮
+買
+冏
+儥
+両
+﹢
+∞
+載
+喰
+z
+羙
+悵
+燙
+曉
+員
+組
+徹
+艷
+痠
+鋼
+鼙
+縮
+細
+嚒
+爯
+≠
+維
+"
+鱻
+壇
+厍
+帰
+浥
+犇
+薡
+軎
+²
+應
+醜
+刪
+緻
+鶴
+賜
+噁
+軌
+尨
+镔
+鷺
+槗
+彌
+葚
+濛
+請
+溇
+緹
+賢
+訪
+獴
+瑅
+資
+縤
+陣
+蕟
+栢
+韻
+祼
+恁
+伢
+謝
+劃
+涑
+總
+衖
+踺
+砋
+凉
+籃
+駿
+苼
+瘋
+昽
+紡
+驊
+腎
+﹗
+響
+杋
+剛
+嚴
+禪
+歓
+槍
+傘
+檸
+檫
+炣
+勢
+鏜
+鎢
+銑
+尐
+減
+奪
+惡
+θ
+僮
+婭
+臘
+ū
+ì
+殻
+鉄
+∑
+蛲
+焼
+緖
+續
+紹
+懮
\ No newline at end of file
diff --git a/deploy/paddleocr-go/demo.go b/deploy/paddleocr-go/demo.go
new file mode 100644
index 0000000000000000000000000000000000000000..f2226379a3b10a2a60784755c36e7beed174ce99
--- /dev/null
+++ b/deploy/paddleocr-go/demo.go
@@ -0,0 +1,51 @@
+package main
+
+import (
+ "flag"
+ "log"
+ "paddleocr-go/ocr"
+)
+
+var (
+ confFile string
+ image string
+ imageDir string
+ useServering bool
+ port string
+)
+
+func init() {
+ flag.StringVar(&confFile, "config", "config/conf.yaml", "config from ocr system. If not given, will use default config.")
+ flag.StringVar(&image, "image", "", "image to predict. if not given, will use image_dir")
+ flag.StringVar(&imageDir, "image_dir", "", "imgs in dir to be predicted. if not given, will check servering")
+ flag.BoolVar(&useServering, "use_servering", false, "whether to use ocr server. [default: false]")
+ flag.StringVar(&port, "port", "18600", "which port to serve ocr server. [default: 18600].")
+}
+
+func main() {
+ flag.Parse()
+ sys := ocr.NewOCRSystem(confFile, nil)
+
+ if image != "" {
+ img := ocr.ReadImage(image)
+ results := sys.PredictOneImage(img)
+ for _, res := range results {
+ log.Println(res)
+ }
+ return
+ }
+
+ if imageDir != "" {
+ results := sys.PredictDirImages(imageDir)
+ for k, vs := range results {
+ log.Printf("======== image: %v =======\n", k)
+ for _, res := range vs {
+ log.Println(res)
+ }
+ }
+ }
+
+ if useServering {
+ sys.StartServer(port)
+ }
+}
diff --git a/deploy/paddleocr-go/go.mod b/deploy/paddleocr-go/go.mod
new file mode 100644
index 0000000000000000000000000000000000000000..43b63477ffa1ba59e7b81e4db6112941183f3114
--- /dev/null
+++ b/deploy/paddleocr-go/go.mod
@@ -0,0 +1,9 @@
+module paddleocr-go
+
+go 1.14
+
+require (
+ github.com/LKKlein/gocv v0.28.0
+ github.com/ctessum/go.clipper v0.0.0-20200522184404-9c744fa3e86c
+ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
+)
diff --git a/deploy/paddleocr-go/go.sum b/deploy/paddleocr-go/go.sum
new file mode 100644
index 0000000000000000000000000000000000000000..4f1fd3fa23912e91a9d67d4d34c46661cbfe996d
--- /dev/null
+++ b/deploy/paddleocr-go/go.sum
@@ -0,0 +1,9 @@
+github.com/LKKlein/gocv v0.27.0 h1:JGNBMa2HY7HC0VlVHB4gdFjoc9NlyyrQvlUdBMWWSYw=
+github.com/LKKlein/gocv v0.27.0/go.mod h1:MP408EL7eakRU3vzjsozzfELSX7HDDGdMpWANV1IOHY=
+github.com/LKKlein/gocv v0.28.0 h1:1MMvs9uYf+QGPi86it2pUmN8RRoyMnPLUefKB/Jf1Q0=
+github.com/LKKlein/gocv v0.28.0/go.mod h1:MP408EL7eakRU3vzjsozzfELSX7HDDGdMpWANV1IOHY=
+github.com/ctessum/go.clipper v0.0.0-20200522184404-9c744fa3e86c h1:VXCsVlam0R2Yl7VET2GxZBPdOa7gFRexyhfWb9v9QtM=
+github.com/ctessum/go.clipper v0.0.0-20200522184404-9c744fa3e86c/go.mod h1:KRMo3PCsooJP3LmCwKI76dkd7f3ki3zwYLHR7Iwbi5k=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/deploy/paddleocr-go/images/0.jpg b/deploy/paddleocr-go/images/0.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..b417220d9a6ebf0ed4d5c5578eb0128f8701ab6e
Binary files /dev/null and b/deploy/paddleocr-go/images/0.jpg differ
diff --git a/deploy/paddleocr-go/images/result/img_dir_result.jpg b/deploy/paddleocr-go/images/result/img_dir_result.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..5341f81648d568dc0b844b7779d6cd8a7a4b870f
Binary files /dev/null and b/deploy/paddleocr-go/images/result/img_dir_result.jpg differ
diff --git a/deploy/paddleocr-go/images/result/python_client_result.jpg b/deploy/paddleocr-go/images/result/python_client_result.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..556573a99850552d2859219773ab70589d9ac065
Binary files /dev/null and b/deploy/paddleocr-go/images/result/python_client_result.jpg differ
diff --git a/deploy/paddleocr-go/images/result/python_vis_result.jpg b/deploy/paddleocr-go/images/result/python_vis_result.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..af26bdd117bf21adba3b80a6d73c7ff54b46b2bc
Binary files /dev/null and b/deploy/paddleocr-go/images/result/python_vis_result.jpg differ
diff --git a/deploy/paddleocr-go/images/result/single_img_result.jpg b/deploy/paddleocr-go/images/result/single_img_result.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..686841d71e12a6142c32288fc41bbc03a9edf177
Binary files /dev/null and b/deploy/paddleocr-go/images/result/single_img_result.jpg differ
diff --git a/deploy/paddleocr-go/images/test.jpg b/deploy/paddleocr-go/images/test.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..ed91b8c5ca2a348fe7b138e83114ff81ecb107de
Binary files /dev/null and b/deploy/paddleocr-go/images/test.jpg differ
diff --git a/deploy/paddleocr-go/ocr/core.go b/deploy/paddleocr-go/ocr/core.go
new file mode 100644
index 0000000000000000000000000000000000000000..626eeb5410b419bf6bbd9c8fc64f40d495e9c0d8
--- /dev/null
+++ b/deploy/paddleocr-go/ocr/core.go
@@ -0,0 +1,259 @@
+package ocr
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+ "image"
+ "image/color"
+ "io"
+ "log"
+ "math"
+ "net/http"
+ "paddleocr-go/paddle"
+ "path"
+ "path/filepath"
+ "sort"
+ "strings"
+
+ "github.com/LKKlein/gocv"
+)
+
+type PaddleModel struct {
+ predictor *paddle.Predictor
+ input *paddle.ZeroCopyTensor
+ outputs []*paddle.ZeroCopyTensor
+
+ useGPU bool
+ deviceID int
+ initGPUMem int
+ numThreads int
+ useMKLDNN bool
+ useTensorRT bool
+ useIROptim bool
+}
+
+func NewPaddleModel(args map[string]interface{}) *PaddleModel {
+ return &PaddleModel{
+ useGPU: getBool(args, "use_gpu", false),
+ deviceID: getInt(args, "gpu_id", 0),
+ initGPUMem: getInt(args, "gpu_mem", 1000),
+ numThreads: getInt(args, "num_cpu_threads", 6),
+ useMKLDNN: getBool(args, "enable_mkldnn", false),
+ useTensorRT: getBool(args, "use_tensorrt", false),
+ useIROptim: getBool(args, "ir_optim", true),
+ }
+}
+
+func (model *PaddleModel) LoadModel(modelDir string) {
+ config := paddle.NewAnalysisConfig()
+ config.DisableGlogInfo()
+
+ config.SetModel(modelDir+"/model", modelDir+"/params")
+ if model.useGPU {
+ config.EnableUseGpu(model.initGPUMem, model.deviceID)
+ } else {
+ config.DisableGpu()
+ config.SetCpuMathLibraryNumThreads(model.numThreads)
+ if model.useMKLDNN {
+ config.EnableMkldnn()
+ }
+ }
+
+ // config.EnableMemoryOptim()
+ if model.useIROptim {
+ config.SwitchIrOptim(true)
+ }
+
+ // false for zero copy tensor
+ config.SwitchUseFeedFetchOps(false)
+ config.SwitchSpecifyInputNames(true)
+
+ model.predictor = paddle.NewPredictor(config)
+ model.input = model.predictor.GetInputTensors()[0]
+ model.outputs = model.predictor.GetOutputTensors()
+}
+
+type OCRText struct {
+ BBox [][]int `json:"bbox"`
+ Text string `json:"text"`
+ Score float64 `json:"score"`
+}
+
+type TextPredictSystem struct {
+ detector *DBDetector
+ cls *TextClassifier
+ rec *TextRecognizer
+}
+
+func NewTextPredictSystem(args map[string]interface{}) *TextPredictSystem {
+ sys := &TextPredictSystem{
+ detector: NewDBDetector(getString(args, "det_model_dir", ""), args),
+ rec: NewTextRecognizer(getString(args, "rec_model_dir", ""), args),
+ }
+ if getBool(args, "use_angle_cls", false) {
+ sys.cls = NewTextClassifier(getString(args, "cls_model_dir", ""), args)
+ }
+ return sys
+}
+
+func (sys *TextPredictSystem) sortBoxes(boxes [][][]int) [][][]int {
+ sort.Slice(boxes, func(i, j int) bool {
+ if boxes[i][0][1] < boxes[j][0][1] {
+ return true
+ }
+ if boxes[i][0][1] > boxes[j][0][1] {
+ return false
+ }
+ return boxes[i][0][0] < boxes[j][0][0]
+ })
+
+ for i := 0; i < len(boxes)-1; i++ {
+ if math.Abs(float64(boxes[i+1][0][1]-boxes[i][0][1])) < 10 && boxes[i+1][0][0] < boxes[i][0][0] {
+ boxes[i], boxes[i+1] = boxes[i+1], boxes[i]
+ }
+ }
+ return boxes
+}
+
+func (sys *TextPredictSystem) getRotateCropImage(img gocv.Mat, box [][]int) gocv.Mat {
+ cropW := int(math.Sqrt(math.Pow(float64(box[0][0]-box[1][0]), 2) + math.Pow(float64(box[0][1]-box[1][1]), 2)))
+ cropH := int(math.Sqrt(math.Pow(float64(box[0][0]-box[3][0]), 2) + math.Pow(float64(box[0][1]-box[3][1]), 2)))
+ ptsstd := make([]image.Point, 4)
+ ptsstd[0] = image.Pt(0, 0)
+ ptsstd[1] = image.Pt(cropW, 0)
+ ptsstd[2] = image.Pt(cropW, cropH)
+ ptsstd[3] = image.Pt(0, cropH)
+
+ points := make([]image.Point, 4)
+ points[0] = image.Pt(box[0][0], box[0][1])
+ points[1] = image.Pt(box[1][0], box[1][1])
+ points[2] = image.Pt(box[2][0], box[2][1])
+ points[3] = image.Pt(box[3][0], box[3][1])
+
+ M := gocv.GetPerspectiveTransform(points, ptsstd)
+ defer M.Close()
+ dstimg := gocv.NewMat()
+ gocv.WarpPerspectiveWithParams(img, &dstimg, M, image.Pt(cropW, cropH),
+ gocv.InterpolationCubic, gocv.BorderReplicate, color.RGBA{0, 0, 0, 0})
+
+ if float64(dstimg.Rows()) >= float64(dstimg.Cols())*1.5 {
+ srcCopy := gocv.NewMat()
+ gocv.Transpose(dstimg, &srcCopy)
+ defer dstimg.Close()
+ gocv.Flip(srcCopy, &srcCopy, 0)
+ return srcCopy
+ }
+ return dstimg
+}
+
+func (sys *TextPredictSystem) Run(img gocv.Mat) []OCRText {
+ srcimg := gocv.NewMat()
+ img.CopyTo(&srcimg)
+ boxes := sys.detector.Run(img)
+ if len(boxes) == 0 {
+ return nil
+ }
+
+ boxes = sys.sortBoxes(boxes)
+ cropimages := make([]gocv.Mat, len(boxes))
+ for i := 0; i < len(boxes); i++ {
+ tmpbox := make([][]int, len(boxes[i]))
+ for j := 0; j < len(tmpbox); j++ {
+ tmpbox[j] = make([]int, len(boxes[i][j]))
+ copy(tmpbox[j], boxes[i][j])
+ }
+ cropimg := sys.getRotateCropImage(srcimg, tmpbox)
+ cropimages[i] = cropimg
+ }
+ if sys.cls != nil {
+ cropimages = sys.cls.Run(cropimages)
+ }
+ recResult := sys.rec.Run(cropimages, boxes)
+ return recResult
+}
+
+type OCRSystem struct {
+ args map[string]interface{}
+ tps *TextPredictSystem
+}
+
+func NewOCRSystem(confFile string, a map[string]interface{}) *OCRSystem {
+ args, err := ReadYaml(confFile)
+ if err != nil {
+ log.Printf("Read config file %v failed! Please check. err: %v\n", confFile, err)
+ log.Println("Program will use default config.")
+ args = defaultArgs
+ }
+ for k, v := range a {
+ args[k] = v
+ }
+ return &OCRSystem{
+ args: args,
+ tps: NewTextPredictSystem(args),
+ }
+}
+
+func (ocr *OCRSystem) StartServer(port string) {
+ http.HandleFunc("/ocr", ocr.predictHandler)
+ log.Println("OCR Server has been started on port :", port)
+ err := http.ListenAndServe(":"+port, nil)
+ if err != nil {
+ log.Panicf("http error! error: %v\n", err)
+ }
+}
+
+func (ocr *OCRSystem) predictHandler(w http.ResponseWriter, r *http.Request) {
+ if r.Method != "POST" {
+ w.Write([]byte(errors.New("post method only").Error()))
+ return
+ }
+ r.ParseMultipartForm(32 << 20)
+ var buf bytes.Buffer
+ file, header, err := r.FormFile("image")
+ if err != nil {
+ w.Write([]byte(err.Error()))
+ return
+ }
+ defer file.Close()
+ ext := strings.ToLower(path.Ext(header.Filename))
+ if ext != ".jpg" && ext != ".png" {
+ w.Write([]byte(errors.New("only support image endswith jpg/png").Error()))
+ return
+ }
+
+ io.Copy(&buf, file)
+ img, err2 := gocv.IMDecode(buf.Bytes(), gocv.IMReadColor)
+ if err2 != nil {
+ w.Write([]byte(err2.Error()))
+ return
+ }
+ result := ocr.PredictOneImage(img)
+ if output, err3 := json.Marshal(result); err3 != nil {
+ w.Write([]byte(err3.Error()))
+ } else {
+ w.Write(output)
+ }
+}
+
+func (ocr *OCRSystem) PredictOneImage(img gocv.Mat) []OCRText {
+ return ocr.tps.Run(img)
+}
+
+func (ocr *OCRSystem) PredictDirImages(dirname string) map[string][]OCRText {
+ if dirname == "" {
+ return nil
+ }
+
+ imgs, _ := filepath.Glob(dirname + "/*.jpg")
+ tmpimgs, _ := filepath.Glob(dirname + "/*.png")
+ imgs = append(imgs, tmpimgs...)
+ results := make(map[string][]OCRText, len(imgs))
+ for i := 0; i < len(imgs); i++ {
+ imgname := imgs[i]
+ img := ReadImage(imgname)
+ res := ocr.PredictOneImage(img)
+ results[imgname] = res
+ }
+ return results
+}
diff --git a/deploy/paddleocr-go/ocr/default_args.go b/deploy/paddleocr-go/ocr/default_args.go
new file mode 100644
index 0000000000000000000000000000000000000000..6afd69e7fa01cd9227c3679a3d07dc781e8a2638
--- /dev/null
+++ b/deploy/paddleocr-go/ocr/default_args.go
@@ -0,0 +1,46 @@
+package ocr
+
+var (
+ defaultArgs = map[string]interface{}{
+ "use_gpu": true,
+ "ir_optim": true,
+ "enable_mkldnn": false,
+ "use_tensorrt": false,
+ "num_cpu_threads": 6,
+ "gpu_id": 0,
+ "gpu_mem": 2000,
+
+ "det_algorithm": "DB",
+ "det_model_dir": "https://paddleocr.bj.bcebos.com/20-09-22/mobile/det/ch_ppocr_mobile_v1.1_det_infer.tar",
+ "det_max_side_len": 960,
+
+ "det_db_thresh": 0.3,
+ "det_db_box_thresh": 0.5,
+ "det_db_unclip_ratio": 2.0,
+
+ "det_east_score_thresh": 0.8,
+ "det_east_cover_thresh": 0.1,
+ "det_east_nms_thresh": 0.2,
+
+ "rec_algorithm": "CRNN",
+ "rec_model_dir": "https://paddleocr.bj.bcebos.com/20-09-22/mobile/rec/ch_ppocr_mobile_v1.1_rec_infer.tar",
+ "rec_image_shape": []interface{}{3, 32, 320},
+ "rec_char_type": "ch",
+ "rec_batch_num": 30,
+ "max_text_length": 25,
+ "rec_char_dict_path": "config/ppocr_keys_v1.txt",
+ "use_space_char": true,
+
+ "use_angle_cls": false,
+ "cls_model_dir": "https://paddleocr.bj.bcebos.com/20-09-22/cls/ch_ppocr_mobile_v1.1_cls_infer.tar",
+ "cls_image_shape": []interface{}{3, 48, 192},
+ "label_list": []interface{}{"0", "180"},
+ "cls_batch_num": 30,
+ "cls_thresh": 0.9,
+
+ "lang": "ch",
+ "det": true,
+ "rec": true,
+ "cls": false,
+ }
+)
diff --git a/deploy/paddleocr-go/ocr/ocr_cls.go b/deploy/paddleocr-go/ocr/ocr_cls.go
new file mode 100644
index 0000000000000000000000000000000000000000..c46d6e8e55a6090dfd6839badc1963e8c50d18ea
--- /dev/null
+++ b/deploy/paddleocr-go/ocr/ocr_cls.go
@@ -0,0 +1,105 @@
+package ocr
+
+import (
+ "log"
+ "time"
+
+ "github.com/LKKlein/gocv"
+)
+
+type TextClassifier struct {
+ *PaddleModel
+ batchNum int
+ thresh float64
+ shape []int
+ labels []string
+}
+
+type ClsResult struct {
+ Score float32
+ Label int64
+}
+
+func NewTextClassifier(modelDir string, args map[string]interface{}) *TextClassifier {
+ shapes := []int{3, 48, 192}
+ if v, ok := args["cls_image_shape"]; ok {
+ for i, s := range v.([]interface{}) {
+ shapes[i] = s.(int)
+ }
+ }
+ cls := &TextClassifier{
+ PaddleModel: NewPaddleModel(args),
+ batchNum: getInt(args, "cls_batch_num", 30),
+ thresh: getFloat64(args, "cls_thresh", 0.9),
+ shape: shapes,
+ }
+ if checkModelExists(modelDir) {
+ modelDir, _ = downloadModel("./inference/cls", modelDir)
+ } else {
+ log.Panicf("cls model path: %v not exist! Please check!", modelDir)
+ }
+ cls.LoadModel(modelDir)
+ return cls
+}
+
+func (cls *TextClassifier) Run(imgs []gocv.Mat) []gocv.Mat {
+ batch := cls.batchNum
+ var clsTime int64 = 0
+ clsout := make([]ClsResult, len(imgs))
+ srcimgs := make([]gocv.Mat, len(imgs))
+ c, h, w := cls.shape[0], cls.shape[1], cls.shape[2]
+ for i := 0; i < len(imgs); i += batch {
+ j := i + batch
+ if len(imgs) < j {
+ j = len(imgs)
+ }
+
+ normImgs := make([]float32, (j-i)*c*h*w)
+ for k := i; k < j; k++ {
+ tmp := gocv.NewMat()
+ imgs[k].CopyTo(&tmp)
+ srcimgs[k] = tmp
+ img := clsResize(imgs[k], cls.shape)
+ data := normPermute(img, []float32{0.5, 0.5, 0.5}, []float32{0.5, 0.5, 0.5}, 255.0)
+ copy(normImgs[(k-i)*c*h*w:], data)
+ }
+
+ st := time.Now()
+ cls.input.SetValue(normImgs)
+ cls.input.Reshape([]int32{int32(j - i), int32(c), int32(h), int32(w)})
+
+ cls.predictor.SetZeroCopyInput(cls.input)
+ cls.predictor.ZeroCopyRun()
+ cls.predictor.GetZeroCopyOutput(cls.outputs[0])
+ cls.predictor.GetZeroCopyOutput(cls.outputs[1])
+
+ var probout [][]float32
+ var labelout []int64
+ if len(cls.outputs[0].Shape()) == 2 {
+ probout = cls.outputs[0].Value().([][]float32)
+ } else {
+ labelout = cls.outputs[0].Value().([]int64)
+ }
+
+ if len(cls.outputs[1].Shape()) == 2 {
+ probout = cls.outputs[1].Value().([][]float32)
+ } else {
+ labelout = cls.outputs[1].Value().([]int64)
+ }
+ clsTime += int64(time.Since(st).Milliseconds())
+
+ for no, label := range labelout {
+ score := probout[no][label]
+ clsout[i+no] = ClsResult{
+ Score: score,
+ Label: label,
+ }
+
+ if label%2 == 1 && float64(score) > cls.thresh {
+ gocv.Rotate(srcimgs[i+no], &srcimgs[i+no], gocv.Rotate180Clockwise)
+ }
+ }
+ }
+ log.Println("cls num: ", len(clsout), ", cls time elapse: ", clsTime, "ms")
+ return srcimgs
+}
diff --git a/deploy/paddleocr-go/ocr/ocr_det.go b/deploy/paddleocr-go/ocr/ocr_det.go
new file mode 100644
index 0000000000000000000000000000000000000000..4773d5bed17887c91ac21054b162deae9ce962ce
--- /dev/null
+++ b/deploy/paddleocr-go/ocr/ocr_det.go
@@ -0,0 +1,52 @@
+package ocr
+
+import (
+ "log"
+ "time"
+
+ "github.com/LKKlein/gocv"
+)
+
+type DBDetector struct {
+ *PaddleModel
+ preProcess DetPreProcess
+ postProcess DetPostProcess
+}
+
+func NewDBDetector(modelDir string, args map[string]interface{}) *DBDetector {
+ maxSideLen := getInt(args, "det_max_side_len", 960)
+ thresh := getFloat64(args, "det_db_thresh", 0.3)
+ boxThresh := getFloat64(args, "det_db_box_thresh", 0.5)
+ unClipRatio := getFloat64(args, "det_db_unclip_ratio", 2.0)
+
+ detector := &DBDetector{
+ PaddleModel: NewPaddleModel(args),
+ preProcess: NewDBProcess(make([]int, 0), maxSideLen),
+ postProcess: NewDBPostProcess(thresh, boxThresh, unClipRatio),
+ }
+ if checkModelExists(modelDir) {
+ modelDir, _ = downloadModel("./inference/det", modelDir)
+ } else {
+ log.Panicf("det model path: %v not exist! Please check!", modelDir)
+ }
+ detector.LoadModel(modelDir)
+ return detector
+}
+
+func (det *DBDetector) Run(img gocv.Mat) [][][]int {
+ oriH := img.Rows()
+ oriW := img.Cols()
+ data, resizeH, resizeW := det.preProcess.Run(img)
+ st := time.Now()
+ det.input.SetValue(data)
+ det.input.Reshape([]int32{1, 3, int32(resizeH), int32(resizeW)})
+
+ det.predictor.SetZeroCopyInput(det.input)
+ det.predictor.ZeroCopyRun()
+ det.predictor.GetZeroCopyOutput(det.outputs[0])
+
+ ratioH, ratioW := float64(resizeH)/float64(oriH), float64(resizeW)/float64(oriW)
+ boxes := det.postProcess.Run(det.outputs[0], oriH, oriW, ratioH, ratioW)
+ log.Println("det_box num: ", len(boxes), ", time elapse: ", time.Since(st))
+ return boxes
+}
diff --git a/deploy/paddleocr-go/ocr/ocr_rec.go b/deploy/paddleocr-go/ocr/ocr_rec.go
new file mode 100644
index 0000000000000000000000000000000000000000..661718c87778030bf6efb9d03c51d45a4fb0e30c
--- /dev/null
+++ b/deploy/paddleocr-go/ocr/ocr_rec.go
@@ -0,0 +1,128 @@
+package ocr
+
+import (
+ "log"
+ "time"
+
+ "github.com/LKKlein/gocv"
+)
+
+type TextRecognizer struct {
+ *PaddleModel
+ batchNum int
+ textLen int
+ shape []int
+ charType string
+ labels []string
+}
+
+func NewTextRecognizer(modelDir string, args map[string]interface{}) *TextRecognizer {
+ shapes := []int{3, 32, 320}
+ if v, ok := args["rec_image_shape"]; ok {
+ for i, s := range v.([]interface{}) {
+ shapes[i] = s.(int)
+ }
+ }
+ labelpath := getString(args, "rec_char_dict_path", "./config/ppocr_keys_v1.txt")
+ labels := readLines2StringSlice(labelpath)
+ if getBool(args, "use_space_char", true) {
+ labels = append(labels, " ")
+ }
+ rec := &TextRecognizer{
+ PaddleModel: NewPaddleModel(args),
+ batchNum: getInt(args, "rec_batch_num", 30),
+ textLen: getInt(args, "max_text_length", 25),
+ charType: getString(args, "rec_char_type", "ch"),
+ shape: shapes,
+ labels: labels,
+ }
+ if checkModelExists(modelDir) {
+ modelDir, _ = downloadModel("./inference/rec/ch", modelDir)
+ } else {
+ log.Panicf("rec model path: %v not exist! Please check!", modelDir)
+ }
+ rec.LoadModel(modelDir)
+ return rec
+}
+
+func (rec *TextRecognizer) Run(imgs []gocv.Mat, bboxes [][][]int) []OCRText {
+ recResult := make([]OCRText, 0, len(imgs))
+ batch := rec.batchNum
+ var recTime int64 = 0
+ c, h, w := rec.shape[0], rec.shape[1], rec.shape[2]
+ for i := 0; i < len(imgs); i += batch {
+ j := i + batch
+ if len(imgs) < j {
+ j = len(imgs)
+ }
+
+ maxwhratio := 0.0
+ for k := i; k < j; k++ {
+ h, w := imgs[k].Rows(), imgs[k].Cols()
+ ratio := float64(w) / float64(h)
+ if ratio > maxwhratio {
+ maxwhratio = ratio
+ }
+ }
+
+ if rec.charType == "ch" {
+ w = int(32 * maxwhratio)
+ }
+ normimgs := make([]float32, (j-i)*c*h*w)
+
+ for k := i; k < j; k++ {
+ data := crnnPreprocess(imgs[k], rec.shape, []float32{0.5, 0.5, 0.5},
+ []float32{0.5, 0.5, 0.5}, 255.0, maxwhratio, rec.charType)
+ copy(normimgs[(k-i)*c*h*w:], data)
+ }
+
+ st := time.Now()
+ rec.input.SetValue(normimgs)
+ rec.input.Reshape([]int32{int32(j - i), int32(c), int32(h), int32(w)})
+
+ rec.predictor.SetZeroCopyInput(rec.input)
+ rec.predictor.ZeroCopyRun()
+ rec.predictor.GetZeroCopyOutput(rec.outputs[0])
+ rec.predictor.GetZeroCopyOutput(rec.outputs[1])
+
+ recIdxBatch := rec.outputs[0].Value().([][]int64)
+ recIdxLod := rec.outputs[0].Lod()
+
+ predictBatch := rec.outputs[1].Value().([][]float32)
+ predictLod := rec.outputs[1].Lod()
+ recTime += int64(time.Since(st).Milliseconds())
+
+ for rno := 0; rno < len(recIdxLod)-1; rno++ {
+ predIdx := make([]int, 0, 2)
+ for beg := recIdxLod[rno]; beg < recIdxLod[rno+1]; beg++ {
+ predIdx = append(predIdx, int(recIdxBatch[beg][0]))
+ }
+ if len(predIdx) == 0 {
+ continue
+ }
+ words := ""
+ for n := 0; n < len(predIdx); n++ {
+ words += rec.labels[predIdx[n]]
+ }
+
+ score := 0.0
+ count := 0
+ blankPosition := int(rec.outputs[1].Shape()[1])
+ for beg := predictLod[rno]; beg < predictLod[rno+1]; beg++ {
+ argMaxID, maxVal := argmax(predictBatch[beg])
+ if blankPosition-1-argMaxID > 0 {
+ score += float64(maxVal)
+ count++
+ }
+ }
+ score = score / float64(count)
+ recResult = append(recResult, OCRText{
+ BBox: bboxes[i+rno],
+ Text: words,
+ Score: score,
+ })
+ }
+ }
+ log.Println("rec num: ", len(recResult), ", rec time elapse: ", recTime, "ms")
+ return recResult
+}
diff --git a/deploy/paddleocr-go/ocr/postprocess.go b/deploy/paddleocr-go/ocr/postprocess.go
new file mode 100644
index 0000000000000000000000000000000000000000..64d1518b554e5e115a653a4e24d00bc9c4f06478
--- /dev/null
+++ b/deploy/paddleocr-go/ocr/postprocess.go
@@ -0,0 +1,264 @@
+package ocr
+
+import (
+ "image"
+ "image/color"
+ "math"
+ "paddleocr-go/paddle"
+ "sort"
+
+ "github.com/LKKlein/gocv"
+ clipper "github.com/ctessum/go.clipper"
+)
+
+type xFloatSortBy [][]float32
+
+func (a xFloatSortBy) Len() int { return len(a) }
+func (a xFloatSortBy) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a xFloatSortBy) Less(i, j int) bool { return a[i][0] < a[j][0] }
+
+type xIntSortBy [][]int
+
+func (a xIntSortBy) Len() int { return len(a) }
+func (a xIntSortBy) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a xIntSortBy) Less(i, j int) bool { return a[i][0] < a[j][0] }
+
+type DetPostProcess interface {
+ Run(output *paddle.ZeroCopyTensor, oriH, oriW int, ratioH, ratioW float64) [][][]int
+}
+
+type DBPostProcess struct {
+ thresh float64
+ boxThresh float64
+ maxCandidates int
+ unClipRatio float64
+ minSize int
+}
+
+func NewDBPostProcess(thresh, boxThresh, unClipRatio float64) *DBPostProcess {
+ return &DBPostProcess{
+ thresh: thresh,
+ boxThresh: boxThresh,
+ unClipRatio: unClipRatio,
+ maxCandidates: 1000,
+ minSize: 3,
+ }
+}
+
+func (d *DBPostProcess) getMinBoxes(rect gocv.RotatedRect) [][]float32 {
+ points := gocv.NewMat()
+ gocv.BoxPoints(rect, &points)
+ defer points.Close()
+ array := d.mat2slice(points)
+ sort.Sort(xFloatSortBy(array))
+
+ point1, point2, point3, point4 := array[0], array[1], array[2], array[3]
+ if array[3][1] <= array[2][1] {
+ point2, point3 = array[3], array[2]
+ } else {
+ point2, point3 = array[2], array[3]
+ }
+
+ if array[1][1] <= array[0][1] {
+ point1, point4 = array[1], array[0]
+ } else {
+ point1, point4 = array[0], array[1]
+ }
+
+ array = [][]float32{point1, point2, point3, point4}
+ return array
+}
+
+func (d *DBPostProcess) mat2slice(mat gocv.Mat) [][]float32 {
+ array := make([][]float32, mat.Rows())
+ for i := 0; i < mat.Rows(); i++ {
+ tmp := make([]float32, mat.Cols())
+ for j := 0; j < mat.Cols(); j++ {
+ tmp[j] = mat.GetFloatAt(i, j)
+ }
+ array[i] = tmp
+ }
+ return array
+}
+
+func (d *DBPostProcess) boxScoreFast(array [][]float32, pred gocv.Mat) float64 {
+ height, width := pred.Rows(), pred.Cols()
+ boxX := []float32{array[0][0], array[1][0], array[2][0], array[3][0]}
+ boxY := []float32{array[0][1], array[1][1], array[2][1], array[3][1]}
+
+ xmin := clip(int(math.Floor(float64(minf(boxX)))), 0, width-1)
+ xmax := clip(int(math.Ceil(float64(maxf(boxX)))), 0, width-1)
+ ymin := clip(int(math.Floor(float64(minf(boxY)))), 0, height-1)
+ ymax := clip(int(math.Ceil(float64(maxf(boxY)))), 0, height-1)
+
+ mask := gocv.NewMatWithSize(ymax-ymin+1, xmax-xmin+1, gocv.MatTypeCV8UC1)
+ ppt := make([][]image.Point, 1)
+ ppt[0] = make([]image.Point, 4)
+ ppt[0][0] = image.Point{int(array[0][0]) - xmin, int(array[0][1]) - ymin}
+ ppt[0][1] = image.Point{int(array[1][0]) - xmin, int(array[1][1]) - ymin}
+ ppt[0][2] = image.Point{int(array[2][0]) - xmin, int(array[2][1]) - ymin}
+ ppt[0][3] = image.Point{int(array[3][0]) - xmin, int(array[3][1]) - ymin}
+ gocv.FillPoly(&mask, ppt, color.RGBA{0, 0, 1, 0})
+ croppedImg := pred.Region(image.Rect(xmin, ymin, xmax+1, ymax+1))
+ s := croppedImg.MeanWithMask(mask)
+ return s.Val1
+}
+
+func (d *DBPostProcess) unClip(box [][]float32) gocv.RotatedRect {
+ var area, dist float64
+ for i := 0; i < 4; i++ {
+ area += float64(box[i][0]*box[(i+1)%4][1] - box[i][1]*box[(i+1)%4][0])
+ dist += math.Sqrt(float64(
+ (box[i][0]-box[(i+1)%4][0])*(box[i][0]-box[(i+1)%4][0]) +
+ (box[i][1]-box[(i+1)%4][1])*(box[i][1]-box[(i+1)%4][1]),
+ ))
+ }
+ area = math.Abs(area / 2.0)
+ distance := area * d.unClipRatio / dist
+ offset := clipper.NewClipperOffset()
+ path := make([]*clipper.IntPoint, 4)
+ path[0] = &clipper.IntPoint{X: clipper.CInt(box[0][0]), Y: clipper.CInt(box[0][1])}
+ path[1] = &clipper.IntPoint{X: clipper.CInt(box[1][0]), Y: clipper.CInt(box[1][1])}
+ path[2] = &clipper.IntPoint{X: clipper.CInt(box[2][0]), Y: clipper.CInt(box[2][1])}
+ path[3] = &clipper.IntPoint{X: clipper.CInt(box[3][0]), Y: clipper.CInt(box[3][1])}
+ offset.AddPath(clipper.Path(path), clipper.JtRound, clipper.EtClosedPolygon)
+ soln := offset.Execute(distance)
+
+ points := make([]image.Point, 0, 4)
+ for i := 0; i < len(soln); i++ {
+ for j := 0; j < len(soln[i]); j++ {
+ points = append(points, image.Point{int(soln[i][j].X), int(soln[i][j].Y)})
+ }
+ }
+
+ var res gocv.RotatedRect
+ if len(points) <= 0 {
+ points = make([]image.Point, 4)
+ points[0] = image.Pt(0, 0)
+ points[1] = image.Pt(1, 0)
+ points[2] = image.Pt(1, 1)
+ points[3] = image.Pt(0, 1)
+ res = gocv.RotatedRect{
+ Contour: points,
+ BoundingRect: image.Rect(0, 0, 1, 1),
+ Center: gocv.Point2f{X: 0.5, Y: 0.5},
+ Width: 1,
+ Height: 1,
+ Angle: 0,
+ }
+ } else {
+ res = gocv.MinAreaRect(points)
+ }
+ return res
+}
+
+func (d *DBPostProcess) boxesFromBitmap(pred gocv.Mat, mask gocv.Mat, ratioH float64, ratioW float64) [][][]int {
+ height, width := mask.Rows(), mask.Cols()
+ mask.MultiplyUChar(255)
+ contours := gocv.FindContours(mask, gocv.RetrievalList, gocv.ChainApproxSimple)
+ numContours := len(contours)
+ if numContours > d.maxCandidates {
+ numContours = d.maxCandidates
+ }
+
+ boxes := make([][][]int, 0, numContours)
+ for i := 0; i < numContours; i++ {
+ contour := contours[i]
+ boundingbox := gocv.MinAreaRect(contour)
+ if boundingbox.Width < float32(d.minSize) || boundingbox.Height < float32(d.minSize) {
+ continue
+ }
+ points := d.getMinBoxes(boundingbox)
+ score := d.boxScoreFast(points, pred)
+ if score < d.boxThresh {
+ continue
+ }
+
+ box := d.unClip(points)
+ if box.Width < float32(d.minSize+2) || box.Height < float32(d.minSize+2) {
+ continue
+ }
+
+ cliparray := d.getMinBoxes(box)
+ dstHeight, dstWidth := pred.Rows(), pred.Cols()
+ intcliparray := make([][]int, 4)
+ for i := 0; i < 4; i++ {
+ p := []int{
+ int(float64(clip(int(math.Round(
+ float64(cliparray[i][0]/float32(width)*float32(dstWidth)))), 0, dstWidth)) / ratioW),
+ int(float64(clip(int(math.Round(
+ float64(cliparray[i][1]/float32(height)*float32(dstHeight)))), 0, dstHeight)) / ratioH),
+ }
+ intcliparray[i] = p
+ }
+ boxes = append(boxes, intcliparray)
+ }
+ return boxes
+}
+
+func (d *DBPostProcess) orderPointsClockwise(box [][]int) [][]int {
+ sort.Sort(xIntSortBy(box))
+ leftmost := [][]int{box[0], box[1]}
+ rightmost := [][]int{box[2], box[3]}
+
+ if leftmost[0][1] > leftmost[1][1] {
+ leftmost[0], leftmost[1] = leftmost[1], leftmost[0]
+ }
+
+ if rightmost[0][1] > rightmost[1][1] {
+ rightmost[0], rightmost[1] = rightmost[1], rightmost[0]
+ }
+
+ return [][]int{leftmost[0], rightmost[0], rightmost[1], leftmost[1]}
+}
+
+func (d *DBPostProcess) filterTagDetRes(boxes [][][]int, oriH, oriW int) [][][]int {
+ points := make([][][]int, 0, len(boxes))
+ for i := 0; i < len(boxes); i++ {
+ boxes[i] = d.orderPointsClockwise(boxes[i])
+ for j := 0; j < len(boxes[i]); j++ {
+ boxes[i][j][0] = clip(boxes[i][j][0], 0, oriW-1)
+ boxes[i][j][1] = clip(boxes[i][j][1], 0, oriH-1)
+ }
+ }
+
+ for i := 0; i < len(boxes); i++ {
+ rectW := int(math.Sqrt(math.Pow(float64(boxes[i][0][0]-boxes[i][1][0]), 2.0) +
+ math.Pow(float64(boxes[i][0][1]-boxes[i][1][1]), 2.0)))
+ rectH := int(math.Sqrt(math.Pow(float64(boxes[i][0][0]-boxes[i][3][0]), 2.0) +
+ math.Pow(float64(boxes[i][0][1]-boxes[i][3][1]), 2.0)))
+ if rectW <= 4 || rectH <= 4 {
+ continue
+ }
+ points = append(points, boxes[i])
+ }
+ return points
+}
+
+func (d *DBPostProcess) Run(output *paddle.ZeroCopyTensor, oriH, oriW int, ratioH, ratioW float64) [][][]int {
+ v := output.Value().([][][][]float32)
+
+ shape := output.Shape()
+ height, width := int(shape[2]), int(shape[3])
+
+ pred := gocv.NewMatWithSize(height, width, gocv.MatTypeCV32F)
+ bitmap := gocv.NewMatWithSize(height, width, gocv.MatTypeCV8UC1)
+ thresh := float32(d.thresh)
+ for i := 0; i < height; i++ {
+ for j := 0; j < width; j++ {
+ pred.SetFloatAt(i, j, v[0][0][i][j])
+ if v[0][0][i][j] > thresh {
+ bitmap.SetUCharAt(i, j, 1)
+ } else {
+ bitmap.SetUCharAt(i, j, 0)
+ }
+ }
+ }
+
+ mask := gocv.NewMat()
+ kernel := gocv.GetStructuringElement(gocv.MorphRect, image.Point{2, 2})
+ gocv.Dilate(bitmap, &mask, kernel)
+ boxes := d.boxesFromBitmap(pred, mask, ratioH, ratioW)
+ dtboxes := d.filterTagDetRes(boxes, oriH, oriW)
+ return dtboxes
+}
diff --git a/deploy/paddleocr-go/ocr/preprocess.go b/deploy/paddleocr-go/ocr/preprocess.go
new file mode 100644
index 0000000000000000000000000000000000000000..a0939e76d6b289b7b90759fd1c79695d956afbbc
--- /dev/null
+++ b/deploy/paddleocr-go/ocr/preprocess.go
@@ -0,0 +1,171 @@
+package ocr
+
+import (
+ "image"
+ "image/color"
+ "math"
+
+ "github.com/LKKlein/gocv"
+)
+
+func resizeByShape(img gocv.Mat, resizeShape []int) (gocv.Mat, int, int) {
+ resizeH := resizeShape[0]
+ resizeW := resizeShape[1]
+ gocv.Resize(img, &img, image.Pt(resizeW, resizeH), 0, 0, gocv.InterpolationLinear)
+ return img, resizeH, resizeW
+}
+
+func resizeByMaxLen(img gocv.Mat, maxLen int) (gocv.Mat, int, int) {
+ oriH := img.Rows()
+ oriW := img.Cols()
+ var resizeH, resizeW int = oriH, oriW
+
+ var ratio float64 = 1.0
+ if resizeH > maxLen || resizeW > maxLen {
+ if resizeH > resizeW {
+ ratio = float64(maxLen) / float64(resizeH)
+ } else {
+ ratio = float64(maxLen) / float64(resizeW)
+ }
+ }
+
+ resizeH = int(float64(resizeH) * ratio)
+ resizeW = int(float64(resizeW) * ratio)
+
+ if resizeH%32 == 0 {
+ resizeH = resizeH
+ } else if resizeH/32 <= 1 {
+ resizeH = 32
+ } else {
+ resizeH = (resizeH/32 - 1) * 32
+ }
+
+ if resizeW%32 == 0 {
+ resizeW = resizeW
+ } else if resizeW/32 <= 1 {
+ resizeW = 32
+ } else {
+ resizeW = (resizeW/32 - 1) * 32
+ }
+
+ if resizeW <= 0 || resizeH <= 0 {
+ return gocv.NewMat(), 0, 0
+ }
+
+ gocv.Resize(img, &img, image.Pt(resizeW, resizeH), 0, 0, gocv.InterpolationLinear)
+ return img, resizeH, resizeW
+}
+
+func normPermute(img gocv.Mat, mean []float32, std []float32, scaleFactor float32) []float32 {
+ img.ConvertTo(&img, gocv.MatTypeCV32F)
+ img.DivideFloat(scaleFactor)
+ defer img.Close()
+
+ c := gocv.Split(img)
+ data := make([]float32, img.Rows()*img.Cols()*img.Channels())
+ for i := 0; i < 3; i++ {
+ c[i].SubtractFloat(mean[i])
+ c[i].DivideFloat(std[i])
+ defer c[i].Close()
+ x, _ := c[i].DataPtrFloat32()
+ copy(data[i*img.Rows()*img.Cols():], x)
+ }
+ return data
+}
+
+type DetPreProcess interface {
+ Run(gocv.Mat) ([]float32, int, int)
+}
+
+type DBPreProcess struct {
+ resizeType int
+ imageShape []int
+ maxSideLen int
+ mean []float32
+ std []float32
+ scaleFactor float32
+}
+
+func NewDBProcess(shape []int, sideLen int) *DBPreProcess {
+ db := &DBPreProcess{
+ resizeType: 0,
+ imageShape: shape,
+ maxSideLen: sideLen,
+ mean: []float32{0.485, 0.456, 0.406},
+ std: []float32{0.229, 0.224, 0.225},
+ scaleFactor: 255.0,
+ }
+ if len(shape) > 0 {
+ db.resizeType = 1
+ }
+ if sideLen == 0 {
+ db.maxSideLen = 2400
+ }
+ return db
+}
+
+func (d *DBPreProcess) Run(img gocv.Mat) ([]float32, int, int) {
+ var resizeH, resizeW int
+ if d.resizeType == 0 {
+ img, resizeH, resizeW = resizeByMaxLen(img, d.maxSideLen)
+ } else {
+ img, resizeH, resizeW = resizeByShape(img, d.imageShape)
+ }
+
+ im := normPermute(img, d.mean, d.std, d.scaleFactor)
+ return im, resizeH, resizeW
+}
+
+func clsResize(img gocv.Mat, resizeShape []int) gocv.Mat {
+ imgH, imgW := resizeShape[1], resizeShape[2]
+ h, w := img.Rows(), img.Cols()
+ ratio := float64(w) / float64(h)
+ var resizeW int
+ if math.Ceil(float64(imgH)*ratio) > float64(imgW) {
+ resizeW = imgW
+ } else {
+ resizeW = int(math.Ceil(float64(imgH) * ratio))
+ }
+ gocv.Resize(img, &img, image.Pt(resizeW, imgH), 0, 0, gocv.InterpolationLinear)
+ if resizeW < imgW {
+ gocv.CopyMakeBorder(img, &img, 0, 0, 0, imgW-resizeW, gocv.BorderConstant, color.RGBA{0, 0, 0, 0})
+ }
+ return img
+}
+
+func crnnPreprocess(img gocv.Mat, resizeShape []int, mean []float32, std []float32,
+ scaleFactor float32, whRatio float64, charType string) []float32 {
+ imgH := resizeShape[1]
+ imgW := resizeShape[2]
+ if charType == "ch" {
+ imgW = int(32 * whRatio)
+ }
+ h, w := img.Rows(), img.Cols()
+ ratio := float64(w) / float64(h)
+ var resizeW int
+ if math.Ceil(float64(imgH)*ratio) > float64(imgW) {
+ resizeW = imgW
+ } else {
+ resizeW = int(math.Ceil(float64(imgH) * ratio))
+ }
+ gocv.Resize(img, &img, image.Pt(resizeW, imgH), 0, 0, gocv.InterpolationLinear)
+
+ img.ConvertTo(&img, gocv.MatTypeCV32F)
+ img.DivideFloat(scaleFactor)
+ img.SubtractScalar(gocv.NewScalar(float64(mean[0]), float64(mean[1]), float64(mean[2]), 0))
+ img.DivideScalar(gocv.NewScalar(float64(std[0]), float64(std[1]), float64(std[2]), 0))
+ defer img.Close()
+
+ if resizeW < imgW {
+ gocv.CopyMakeBorder(img, &img, 0, 0, 0, imgW-resizeW, gocv.BorderConstant, color.RGBA{0, 0, 0, 0})
+ }
+
+ c := gocv.Split(img)
+ data := make([]float32, img.Rows()*img.Cols()*img.Channels())
+ for i := 0; i < 3; i++ {
+ defer c[i].Close()
+ x, _ := c[i].DataPtrFloat32()
+ copy(data[i*img.Rows()*img.Cols():], x)
+ }
+ return data
+}
diff --git a/deploy/paddleocr-go/ocr/utils.go b/deploy/paddleocr-go/ocr/utils.go
new file mode 100644
index 0000000000000000000000000000000000000000..0603d2bba54e9eb9cd744121ca2aaa4df144cee1
--- /dev/null
+++ b/deploy/paddleocr-go/ocr/utils.go
@@ -0,0 +1,268 @@
+package ocr
+
+import (
+ "archive/tar"
+ "io"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "os"
+ "path"
+ "path/filepath"
+ "regexp"
+ "strings"
+
+ "github.com/LKKlein/gocv"
+ "gopkg.in/yaml.v3"
+)
+
+func getString(args map[string]interface{}, key string, dv string) string {
+ if f, ok := args[key]; ok {
+ return f.(string)
+ }
+ return dv
+}
+
+func getFloat64(args map[string]interface{}, key string, dv float64) float64 {
+ if f, ok := args[key]; ok {
+ return f.(float64)
+ }
+ return dv
+}
+
+func getInt(args map[string]interface{}, key string, dv int) int {
+ if i, ok := args[key]; ok {
+ return i.(int)
+ }
+ return dv
+}
+
+func getBool(args map[string]interface{}, key string, dv bool) bool {
+ if b, ok := args[key]; ok {
+ return b.(bool)
+ }
+ return dv
+}
+
+func ReadImage(image_path string) gocv.Mat {
+ img := gocv.IMRead(image_path, gocv.IMReadColor)
+ if img.Empty() {
+ log.Printf("Could not read image %s\n", image_path)
+ os.Exit(1)
+ }
+ return img
+}
+
+func clip(value, min, max int) int {
+ if value <= min {
+ return min
+ } else if value >= max {
+ return max
+ }
+ return value
+}
+
+func minf(data []float32) float32 {
+ v := data[0]
+ for _, val := range data {
+ if val < v {
+ v = val
+ }
+ }
+ return v
+}
+
+func maxf(data []float32) float32 {
+ v := data[0]
+ for _, val := range data {
+ if val > v {
+ v = val
+ }
+ }
+ return v
+}
+
+func mini(data []int) int {
+ v := data[0]
+ for _, val := range data {
+ if val < v {
+ v = val
+ }
+ }
+ return v
+}
+
+func maxi(data []int) int {
+ v := data[0]
+ for _, val := range data {
+ if val > v {
+ v = val
+ }
+ }
+ return v
+}
+
+func argmax(arr []float32) (int, float32) {
+ max_value, index := arr[0], 0
+ for i, item := range arr {
+ if item > max_value {
+ max_value = item
+ index = i
+ }
+ }
+ return index, max_value
+}
+
+func checkModelExists(modelPath string) bool {
+ if isPathExist(modelPath+"/model") && isPathExist(modelPath+"/params") {
+ return true
+ }
+ if strings.HasPrefix(modelPath, "http://") ||
+ strings.HasPrefix(modelPath, "ftp://") || strings.HasPrefix(modelPath, "https://") {
+ return true
+ }
+ return false
+}
+
+func downloadFile(filepath, url string) error {
+ resp, err := http.Get(url)
+ if err != nil {
+ return err
+ }
+ defer resp.Body.Close()
+
+ out, err := os.Create(filepath)
+ if err != nil {
+ return err
+ }
+ defer out.Close()
+
+ _, err = io.Copy(out, resp.Body)
+ log.Println("[download_file] from:", url, " to:", filepath)
+ return err
+}
+
+func isPathExist(path string) bool {
+ if _, err := os.Stat(path); err == nil {
+ return true
+ } else if os.IsNotExist(err) {
+ return false
+ }
+ return false
+}
+
+func downloadModel(modelDir, modelPath string) (string, error) {
+ if modelPath != "" && (strings.HasPrefix(modelPath, "http://") ||
+ strings.HasPrefix(modelPath, "ftp://") || strings.HasPrefix(modelPath, "https://")) {
+ reg := regexp.MustCompile("^(http|https|ftp)://[^/]+/(.+)")
+ suffix := reg.FindStringSubmatch(modelPath)[2]
+ outPath := filepath.Join(modelDir, suffix)
+ outDir := filepath.Dir(outPath)
+ if !isPathExist(outDir) {
+ os.MkdirAll(outDir, os.ModePerm)
+ }
+
+ if !isPathExist(outPath) {
+ err := downloadFile(outPath, modelPath)
+ if err != nil {
+ return "", err
+ }
+ }
+ if strings.HasSuffix(outPath, ".tar") {
+ _, f := path.Split(suffix)
+ nextDir := strings.TrimSuffix(f, ".tar")
+ finalPath := modelDir + "/" + nextDir
+ if !checkModelExists(finalPath) {
+ unTar(modelDir, outPath)
+ }
+ return finalPath, nil
+ }
+ return outPath, nil
+ }
+ return modelPath, nil
+}
+
+func unTar(dst, src string) (err error) {
+ fr, err := os.Open(src)
+ if err != nil {
+ return err
+ }
+ defer fr.Close()
+
+ tr := tar.NewReader(fr)
+ for {
+ hdr, err := tr.Next()
+
+ switch {
+ case err == io.EOF:
+ return nil
+ case err != nil:
+ return err
+ case hdr == nil:
+ continue
+ }
+
+ dstFileDir := filepath.Join(dst, hdr.Name)
+
+ switch hdr.Typeflag {
+ case tar.TypeDir:
+ if b := isPathExist(dstFileDir); !b {
+ if err := os.MkdirAll(dstFileDir, 0775); err != nil {
+ return err
+ }
+ }
+ case tar.TypeReg:
+ file, err := os.OpenFile(dstFileDir, os.O_CREATE|os.O_RDWR, os.FileMode(hdr.Mode))
+ if err != nil {
+ return err
+ }
+ _, err2 := io.Copy(file, tr)
+ if err2 != nil {
+ return err2
+ }
+ file.Close()
+ }
+ }
+
+ return nil
+}
+
+func readLines2StringSlice(path string) []string {
+ content, err := ioutil.ReadFile(path)
+ if err != nil {
+ log.Println("read file error!")
+ return nil
+ }
+ lines := strings.Split(string(content), "\n")
+ return lines
+}
+
+func ReadYaml(yamlPath string) (map[string]interface{}, error) {
+ data, err := ioutil.ReadFile(yamlPath)
+ if err != nil {
+ return nil, err
+ }
+ var body interface{}
+ if err := yaml.Unmarshal(data, &body); err != nil {
+ return nil, err
+ }
+
+ body = convertYaml2Map(body)
+ return body.(map[string]interface{}), nil
+}
+
+func convertYaml2Map(i interface{}) interface{} {
+ switch x := i.(type) {
+ case map[interface{}]interface{}:
+ m2 := map[string]interface{}{}
+ for k, v := range x {
+ m2[k.(string)] = convertYaml2Map(v)
+ }
+ return m2
+ case []interface{}:
+ for i, v := range x {
+ x[i] = convertYaml2Map(v)
+ }
+ }
+ return i
+}
diff --git a/deploy/paddleocr-go/paddle/common.go b/deploy/paddleocr-go/paddle/common.go
new file mode 100644
index 0000000000000000000000000000000000000000..4bcd443cf247f54943e53f7795aa649b1896242f
--- /dev/null
+++ b/deploy/paddleocr-go/paddle/common.go
@@ -0,0 +1,28 @@
+package paddle
+
+// #cgo CFLAGS: -I../paddle_c/paddle/include
+// #cgo LDFLAGS: -L${SRCDIR}/../paddle_c/paddle/lib -Wl,-rpath=\$ORIGIN/paddle_c/paddle/lib -lpaddle_fluid_c
+// #include
+// #include "paddle_c_api.h"
+import "C"
+import "fmt"
+
+func ConvertCBooleanToGo(b C.bool) bool {
+ var c_false C.bool
+ if b != c_false {
+ return true
+ }
+ return false
+}
+
+func numel(shape []int32) int32 {
+ n := int32(1)
+ for _, d := range shape {
+ n *= d
+ }
+ return n
+}
+
+func bug(format string, args ...interface{}) error {
+ return fmt.Errorf("Bug %v", fmt.Sprintf(format, args...))
+}
diff --git a/deploy/paddleocr-go/paddle/config.go b/deploy/paddleocr-go/paddle/config.go
new file mode 100644
index 0000000000000000000000000000000000000000..3201923936dca57aa809a058a76e34d00790057d
--- /dev/null
+++ b/deploy/paddleocr-go/paddle/config.go
@@ -0,0 +1,183 @@
+package paddle
+
+// #cgo CFLAGS: -I../paddle_c/paddle/include
+// #cgo LDFLAGS: -L${SRCDIR}/../paddle_c/paddle/lib -Wl,-rpath,$ORIGIN/paddle_c/paddle/lib -lpaddle_fluid_c
+// #include
+// #include
+// #include
+import "C"
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+type Precision C.Precision
+
+const (
+ Precision_FLOAT32 Precision = C.kFloat32
+ Precision_INT8 Precision = C.kInt8
+ Precision_HALF Precision = C.kHalf
+)
+
+type AnalysisConfig struct {
+ c *C.PD_AnalysisConfig
+}
+
+func NewAnalysisConfig() *AnalysisConfig {
+ c_config := C.PD_NewAnalysisConfig()
+ config := &AnalysisConfig{c: c_config}
+ runtime.SetFinalizer(config, (*AnalysisConfig).finalize)
+ return config
+}
+
+func (config *AnalysisConfig) finalize() {
+ C.PD_DeleteAnalysisConfig(config.c)
+}
+
+func (config *AnalysisConfig) SetModel(model, params string) {
+ c_model := C.CString(model)
+ defer C.free(unsafe.Pointer(c_model))
+ var c_params *C.char
+ if params == "" {
+ c_params = nil
+ } else {
+ c_params = C.CString(params)
+ defer C.free(unsafe.Pointer(c_params))
+ }
+
+ C.PD_SetModel(config.c, c_model, c_params)
+}
+
+func (config *AnalysisConfig) ModelDir() string {
+ return C.GoString(C.PD_ModelDir(config.c))
+}
+
+func (config *AnalysisConfig) ProgFile() string {
+ return C.GoString(C.PD_ProgFile(config.c))
+}
+
+func (config *AnalysisConfig) ParamsFile() string {
+ return C.GoString(C.PD_ParamsFile(config.c))
+}
+
+func (config *AnalysisConfig) EnableUseGpu(memory_pool_init_size_mb int, device_id int) {
+ C.PD_EnableUseGpu(config.c, C.int(memory_pool_init_size_mb), C.int(device_id))
+}
+
+func (config *AnalysisConfig) DisableGpu() {
+ C.PD_DisableGpu(config.c)
+}
+
+func (config *AnalysisConfig) UseGpu() bool {
+ return ConvertCBooleanToGo(C.PD_UseGpu(config.c))
+}
+
+func (config *AnalysisConfig) GpuDeviceId() int {
+ return int(C.PD_GpuDeviceId(config.c))
+}
+
+func (config *AnalysisConfig) MemoryPoolInitSizeMb() int {
+ return int(C.PD_MemoryPoolInitSizeMb(config.c))
+}
+
+func (config *AnalysisConfig) EnableCudnn() {
+ C.PD_EnableCUDNN(config.c)
+}
+
+func (config *AnalysisConfig) CudnnEnabled() bool {
+ return ConvertCBooleanToGo(C.PD_CudnnEnabled(config.c))
+}
+
+func (config *AnalysisConfig) SwitchIrOptim(x bool) {
+ C.PD_SwitchIrOptim(config.c, C.bool(x))
+}
+
+func (config *AnalysisConfig) IrOptim() bool {
+ return ConvertCBooleanToGo(C.PD_IrOptim(config.c))
+}
+
+func (config *AnalysisConfig) SwitchUseFeedFetchOps(x bool) {
+ C.PD_SwitchUseFeedFetchOps(config.c, C.bool(x))
+}
+
+func (config *AnalysisConfig) UseFeedFetchOpsEnabled() bool {
+ return ConvertCBooleanToGo(C.PD_UseFeedFetchOpsEnabled(config.c))
+}
+
+func (config *AnalysisConfig) SwitchSpecifyInputNames(x bool) {
+ C.PD_SwitchSpecifyInputNames(config.c, C.bool(x))
+}
+
+func (config *AnalysisConfig) SpecifyInputName() bool {
+ return ConvertCBooleanToGo(C.PD_SpecifyInputName(config.c))
+}
+
+func (config *AnalysisConfig) EnableTensorRtEngine(workspace_size int, max_batch_size int, min_subgraph_size int, precision Precision, use_static bool, use_calib_mode bool) {
+ C.PD_EnableTensorRtEngine(config.c, C.int(workspace_size), C.int(max_batch_size), C.int(min_subgraph_size), C.Precision(precision), C.bool(use_static), C.bool(use_calib_mode))
+}
+
+func (config *AnalysisConfig) TensorrtEngineEnabled() bool {
+ return ConvertCBooleanToGo(C.PD_TensorrtEngineEnabled(config.c))
+}
+
+func (config *AnalysisConfig) SwitchIrDebug(x bool) {
+ C.PD_SwitchIrDebug(config.c, C.bool(x))
+}
+
+func (config *AnalysisConfig) EnableMkldnn() {
+ C.PD_EnableMKLDNN(config.c)
+}
+
+func (config *AnalysisConfig) SetCpuMathLibraryNumThreads(n int) {
+ C.PD_SetCpuMathLibraryNumThreads(config.c, C.int(n))
+}
+
+func (config *AnalysisConfig) CpuMathLibraryNumThreads() int {
+ return int(C.PD_CpuMathLibraryNumThreads(config.c))
+}
+
+func (config *AnalysisConfig) EnableMkldnnQuantizer() {
+ C.PD_EnableMkldnnQuantizer(config.c)
+}
+
+func (config *AnalysisConfig) MkldnnQuantizerEnabled() bool {
+ return ConvertCBooleanToGo(C.PD_MkldnnQuantizerEnabled(config.c))
+}
+
+// SetModelBuffer
+// ModelFromMemory
+
+func (config *AnalysisConfig) EnableMemoryOptim() {
+ C.PD_EnableMemoryOptim(config.c)
+}
+
+func (config *AnalysisConfig) MemoryOptimEnabled() bool {
+ return ConvertCBooleanToGo(C.PD_MemoryOptimEnabled(config.c))
+}
+
+func (config *AnalysisConfig) EnableProfile() {
+ C.PD_EnableProfile(config.c)
+}
+
+func (config *AnalysisConfig) ProfileEnabled() bool {
+ return ConvertCBooleanToGo(C.PD_ProfileEnabled(config.c))
+}
+
+func (config *AnalysisConfig) DisableGlogInfo() {
+ C.PD_DisableGlogInfo(config.c)
+}
+
+func (config *AnalysisConfig) DeletePass(pass string) {
+ c_pass := C.CString(pass)
+ defer C.free(unsafe.Pointer(c_pass))
+ C.PD_DeletePass(config.c, c_pass)
+}
+
+func (config *AnalysisConfig) SetInValid() {
+ C.PD_SetInValid(config.c)
+}
+
+func (config *AnalysisConfig) IsValid() bool {
+ return ConvertCBooleanToGo(C.PD_IsValid(config.c))
+}
diff --git a/deploy/paddleocr-go/paddle/predictor.go b/deploy/paddleocr-go/paddle/predictor.go
new file mode 100644
index 0000000000000000000000000000000000000000..f6cba7bc7756aab7f68cb5f84be1fae659c5f61c
--- /dev/null
+++ b/deploy/paddleocr-go/paddle/predictor.go
@@ -0,0 +1,103 @@
+package paddle
+
+// #cgo CFLAGS: -I../paddle_c/paddle/include
+// #cgo LDFLAGS: -L${SRCDIR}/../paddle_c/paddle/lib -Wl,-rpath,$ORIGIN/paddle_c/paddle/lib -lpaddle_fluid_c
+// #include
+// #include "paddle_c_api.h"
+import "C"
+
+import (
+ "reflect"
+ "runtime"
+ "unsafe"
+)
+
+type Predictor struct {
+ c *C.PD_Predictor
+}
+
+func NewPredictor(config *AnalysisConfig) *Predictor {
+ c_predictor := C.PD_NewPredictor((*config).c)
+ predictor := &Predictor{c: c_predictor}
+ runtime.SetFinalizer(predictor, (*Predictor).finalize)
+ return predictor
+}
+
+func (predictor *Predictor) finalize() {
+ C.PD_DeletePredictor(predictor.c)
+}
+
+func DeletePredictor(predictor *Predictor) {
+ C.PD_DeletePredictor(predictor.c)
+}
+
+func (predictor *Predictor) GetInputNum() int {
+ return int(C.PD_GetInputNum(predictor.c))
+}
+
+func (predictor *Predictor) GetOutputNum() int {
+ return int(C.PD_GetOutputNum(predictor.c))
+}
+
+func (predictor *Predictor) GetInputName(n int) string {
+ return C.GoString(C.PD_GetInputName(predictor.c, C.int(n)))
+}
+
+func (predictor *Predictor) GetOutputName(n int) string {
+ return C.GoString(C.PD_GetOutputName(predictor.c, C.int(n)))
+}
+
+func (predictor *Predictor) GetInputTensors() [](*ZeroCopyTensor) {
+ var result [](*ZeroCopyTensor)
+ for i := 0; i < predictor.GetInputNum(); i++ {
+ tensor := NewZeroCopyTensor()
+ tensor.c.name = C.PD_GetInputName(predictor.c, C.int(i))
+ result = append(result, tensor)
+ }
+ return result
+}
+
+func (predictor *Predictor) GetOutputTensors() [](*ZeroCopyTensor) {
+ var result [](*ZeroCopyTensor)
+ for i := 0; i < predictor.GetOutputNum(); i++ {
+ tensor := NewZeroCopyTensor()
+ tensor.c.name = C.PD_GetOutputName(predictor.c, C.int(i))
+ result = append(result, tensor)
+ }
+ return result
+}
+
+func (predictor *Predictor) GetInputNames() []string {
+ names := make([]string, predictor.GetInputNum())
+ for i := 0; i < len(names); i++ {
+ names[i] = predictor.GetInputName(i)
+ }
+ return names
+}
+
+func (predictor *Predictor) GetOutputNames() []string {
+ names := make([]string, predictor.GetOutputNum())
+ for i := 0; i < len(names); i++ {
+ names[i] = predictor.GetOutputName(i)
+ }
+ return names
+}
+
+func (predictor *Predictor) SetZeroCopyInput(tensor *ZeroCopyTensor) {
+ C.PD_SetZeroCopyInput(predictor.c, tensor.c)
+}
+
+func (predictor *Predictor) GetZeroCopyOutput(tensor *ZeroCopyTensor) {
+ C.PD_GetZeroCopyOutput(predictor.c, tensor.c)
+ tensor.name = C.GoString(tensor.c.name)
+ var shape []int32
+ shape_hdr := (*reflect.SliceHeader)(unsafe.Pointer(&shape))
+ shape_hdr.Data = uintptr(unsafe.Pointer(tensor.c.shape.data))
+ shape_hdr.Len = int(tensor.c.shape.length / C.sizeof_int)
+ shape_hdr.Cap = int(tensor.c.shape.length / C.sizeof_int)
+ tensor.Reshape(shape)
+}
+
+func (predictor *Predictor) ZeroCopyRun() {
+ C.PD_ZeroCopyRun(predictor.c)
+}
diff --git a/deploy/paddleocr-go/paddle/tensor.go b/deploy/paddleocr-go/paddle/tensor.go
new file mode 100644
index 0000000000000000000000000000000000000000..cf462dcd886861f23ab504569662456d86db9107
--- /dev/null
+++ b/deploy/paddleocr-go/paddle/tensor.go
@@ -0,0 +1,249 @@
+package paddle
+
+// #cgo CFLAGS: -I../paddle_c/paddle/include
+// #cgo LDFLAGS: -L${SRCDIR}/../paddle_c/paddle/lib -Wl,-rpath,$ORIGIN/paddle_c/paddle/lib -lpaddle_fluid_c
+// #include
+// #include
+// #include
+// #include
+import "C"
+
+import (
+ "bytes"
+ "encoding/binary"
+ "reflect"
+ "runtime"
+ "unsafe"
+)
+
+type PaddleDType C.PD_DataType
+
+const (
+ FLOAT32 PaddleDType = C.PD_FLOAT32
+ INT32 PaddleDType = C.PD_INT32
+ INT64 PaddleDType = C.PD_INT64
+ UINT8 PaddleDType = C.PD_UINT8
+ UNKDTYPE PaddleDType = C.PD_UNKDTYPE
+)
+
+var types = []struct {
+ gotype reflect.Type
+ dtype PaddleDType
+}{
+ {reflect.TypeOf(float32(0)), FLOAT32},
+ {reflect.TypeOf(int32(0)), INT32},
+ {reflect.TypeOf(int64(0)), INT64},
+ {reflect.TypeOf(uint8(0)), UINT8},
+}
+
+func TypeOfShape(dtype PaddleDType, shape []int32) reflect.Type {
+ var ret reflect.Type
+ for _, t := range types {
+ if dtype == PaddleDType(t.dtype) {
+ ret = t.gotype
+ break
+ }
+ }
+
+ if ret == nil {
+ panic(bug("Data %v type is not support", dtype))
+ }
+
+ for range shape {
+ ret = reflect.SliceOf(ret)
+ }
+ return ret
+}
+
+type ZeroCopyTensor struct {
+ c *C.PD_ZeroCopyTensor
+ name string
+ shape []int32
+}
+
+func NewZeroCopyTensor() *ZeroCopyTensor {
+ c_tensor := C.PD_NewZeroCopyTensor()
+
+ tensor := &ZeroCopyTensor{c: c_tensor}
+ runtime.SetFinalizer(tensor, (*ZeroCopyTensor).finalize)
+ return tensor
+}
+
+func (tensor *ZeroCopyTensor) finalize() {
+ C.PD_DeleteZeroCopyTensor(tensor.c)
+}
+
+func (tensor *ZeroCopyTensor) Shape() []int32 {
+ return tensor.shape
+}
+
+func (tensor *ZeroCopyTensor) Name() string {
+ return C.GoString(tensor.c.name)
+}
+
+func (tensor *ZeroCopyTensor) Rename(name string) {
+ tensor.name = name
+ tensor.c.name = (*C.char)(unsafe.Pointer(tensor.c.name))
+ //tensor.c.name = C.CString(tensor.name)
+ //defer C.free(unsafe.Pointer(tensor.c.name))
+}
+
+func (tensor *ZeroCopyTensor) Reshape(shape []int32) {
+ tensor.shape = make([]int32, len(shape))
+ copy(tensor.shape, shape)
+ length := C.sizeof_int * C.size_t(len(shape))
+ if tensor.c.shape.capacity < C.size_t(length) {
+ if tensor.c.shape.capacity != C.size_t(0) {
+ C.free(tensor.c.shape.data)
+ }
+ tensor.c.shape.data = C.malloc(length)
+ tensor.c.shape.capacity = length
+ }
+ tensor.c.shape.length = length
+ C.memcpy(tensor.c.shape.data, unsafe.Pointer(&shape[0]), length)
+}
+
+func (tensor *ZeroCopyTensor) DataType() PaddleDType {
+ return PaddleDType(tensor.c.dtype)
+}
+
+func (tensor *ZeroCopyTensor) SetValue(value interface{}) {
+ val := reflect.ValueOf(value)
+ shape, dtype := ShapeAndTypeOf(val)
+ num := numel(shape)
+ length := C.size_t(SizeofDataType(dtype) * num)
+ if tensor.c.data.capacity < length {
+ if tensor.c.data.capacity != C.size_t(0) {
+ C.free(tensor.c.data.data)
+ }
+ tensor.c.data.data = C.malloc(length)
+ tensor.c.data.capacity = length
+ }
+ tensor.c.data.length = length
+
+ switch dtype {
+ case PaddleDType(UINT8):
+ data := val.Interface().([]uint8)
+ C.memcpy(tensor.c.data.data, unsafe.Pointer(&data[0]), length)
+ case PaddleDType(INT32):
+ data := val.Interface().([]int32)
+ C.memcpy(tensor.c.data.data, unsafe.Pointer(&data[0]), length)
+ case PaddleDType(INT64):
+ data := val.Interface().([]int64)
+ C.memcpy(tensor.c.data.data, unsafe.Pointer(&data[0]), length)
+ case PaddleDType(FLOAT32):
+ data := val.Interface().([]float32)
+ C.memcpy(tensor.c.data.data, unsafe.Pointer(&data[0]), length)
+ }
+ tensor.c.dtype = C.PD_DataType(dtype)
+}
+
+func TypeOf(dtype PaddleDType, shape []int32) reflect.Type {
+ var ret reflect.Type
+ for _, t := range types {
+ if t.dtype == dtype {
+ ret = t.gotype
+ break
+ }
+ }
+
+ for range shape {
+ ret = reflect.SliceOf(ret)
+ }
+ return ret
+}
+
+func (tensor *ZeroCopyTensor) Value() interface{} {
+ t := TypeOf(PaddleDType(tensor.c.dtype), tensor.shape)
+ value := reflect.New(t)
+ c_bytes := tensor.c.data.data
+ length := tensor.c.data.length
+ var slice []byte
+ if unsafe.Sizeof(unsafe.Pointer(nil)) == 8 {
+ slice = (*[1<<50 - 1]byte)(unsafe.Pointer(c_bytes))[:length:length]
+ } else {
+ slice = (*[1 << 30]byte)(unsafe.Pointer(c_bytes))[:length:length]
+ }
+ r := bytes.NewReader(slice)
+ DecodeTensor(r, tensor.Shape(), t, value)
+ return reflect.Indirect(value).Interface()
+}
+
+func (tensor *ZeroCopyTensor) Lod() []uint {
+ var val []uint
+ valHdr := (*reflect.SliceHeader)(unsafe.Pointer(&val))
+ valHdr.Data = uintptr(unsafe.Pointer(tensor.c.lod.data))
+ valHdr.Len = int(tensor.c.lod.length / C.sizeof_size_t)
+ valHdr.Cap = int(tensor.c.lod.length / C.sizeof_size_t)
+ return val
+}
+
+func Endian() binary.ByteOrder {
+ buf := [2]byte{}
+ *(*uint16)(unsafe.Pointer(&buf[0])) = uint16(0xABCD)
+
+ var endian binary.ByteOrder
+
+ switch buf {
+ case [2]byte{0xCD, 0xAB}:
+ endian = binary.LittleEndian
+ case [2]byte{0xAB, 0xCD}:
+ endian = binary.BigEndian
+ default:
+ panic("Could not determine native endianness.")
+ }
+ return endian
+}
+
+func DecodeTensor(r *bytes.Reader, shape []int32, t reflect.Type, ptr reflect.Value) {
+ switch t.Kind() {
+ case reflect.Uint8, reflect.Int32, reflect.Int64, reflect.Float32:
+ binary.Read(r, Endian(), ptr.Interface())
+ case reflect.Slice:
+ value := reflect.Indirect(ptr)
+ value.Set(reflect.MakeSlice(t, int(shape[0]), int(shape[0])))
+ if len(shape) == 1 && value.Len() > 0 {
+ switch value.Index(0).Kind() {
+ case reflect.Uint8, reflect.Int32, reflect.Int64, reflect.Float32:
+ binary.Read(r, Endian(), value.Interface())
+ return
+ }
+ }
+
+ for i := 0; i < value.Len(); i++ {
+ DecodeTensor(r, shape[1:], t.Elem(), value.Index(i).Addr())
+ }
+ }
+}
+
+func SizeofDataType(dtype PaddleDType) int32 {
+ switch dtype {
+ case UINT8:
+ return int32(C.sizeof_uchar)
+ case INT32:
+ return int32(C.sizeof_int)
+ case INT64:
+ return int32(C.sizeof_longlong)
+ case FLOAT32:
+ return int32(C.sizeof_float)
+ }
+ return -1
+}
+
+func ShapeAndTypeOf(val reflect.Value) (shape []int32, dt PaddleDType) {
+ gotype := val.Type()
+ for gotype.Kind() == reflect.Array || gotype.Kind() == reflect.Slice {
+ shape = append(shape, int32(val.Len()))
+ if val.Len() > 0 {
+ val = val.Index(0)
+ }
+ gotype = gotype.Elem()
+ }
+
+ for _, t := range types {
+ if gotype.Kind() == t.gotype.Kind() {
+ return shape, PaddleDType(t.dtype)
+ }
+ }
+ return shape, dt
+}
diff --git a/deploy/paddleocr-go/paddle_c/README.md b/deploy/paddleocr-go/paddle_c/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..e3565d6fbd54d3d3f39f6b75eac100f666d42f00
--- /dev/null
+++ b/deploy/paddleocr-go/paddle_c/README.md
@@ -0,0 +1,6 @@
+# Paddle C预测库目录
+
+## 编译安装
+使用cmake编译paddle,并打开-DON_INFER=ON,在编译目录下得到paddle_inference_c_install_dir,将该目录下的所有文件复制到本目录下。
+
+详细编译步骤请参见[README.md](../README.md) 或者官方文档指导 https://www.paddlepaddle.org.cn/documentation/docs/zh/advanced_guide/inference_deployment/inference/build_and_install_lib_cn.html#id12
\ No newline at end of file