EasyPR 是一个车牌识别库,识别率高,功能齐全,非常适合直接拿来使用。 官方地址: https://github.com/liuruoze/EasyPR
这里记录一下 EasyPR 在 Linux 底下编译及再次封装供 Python 使用的过程。
安装相应的编译工具包
sudo apt install build-essential cmake
EasyPR 依赖于 OpenCV ,且其官方未提供 Linux 版本的 OpenCV 二进制库,因此需要自行编译。对于 EasyPR 项目,最新测试通过的 OpenCV 版本为 3.4.8, 下面以 OpenCV 3.4.8 版本为例。
方法1. 从 OpenCV 官方下载页面找到 3.4.8 版本的 Source 包,并下载解压。
方法2. 从 github 上签出所有源码。
# 下载 git clone https://github.com/opencv/opencv.git cd opencv # 查看 tag 列表 git tag # 签出特定版本。 git checkout 3.4.8
这里假设把源码放在了 ~/src/opencv 目录下,路径按自己实际路径。
编译方式:
# 进入 opencv 源码的上层路径。 cd ~/src # 在 opencv 源码的同级目录下创建一个 opencv-build-3.4.8 目录。 没有在 opencv 里面创建 build 目录,是方便后续 checkout 其他版本时,还保留当前编译好的版本。 mkdir opencv-build-3.4.8 cd opencv-build-3.4.8 # cmake # 1. 由于是跟 opencv 同级,所以源码路径为 ../opencv 。 # 2. 安装目录设置为自己的 home 目录,方便随时删除,而且 make install 不需要 sudo 权限。 # 3. ippicv 下载较慢,使用本地共享中的文件。 # 4. 不编译 cuda 。 # 以上各个选项按自己喜好增加或删除。 cmake ../opencv \ -D CMAKE_INSTALL_PREFIX=~/.local/opencv-3.4.8 \ -D OPENCV_IPPICV_URL=file:///ext/data/shared/3rdparty/ippicv/ \ -D WITH_CUDA=no # 以 8 个线程进行编译 make -j8 # 安装。此时会把 opencv 安装到 ~/.local/opencv-3.4.8 目录下。 make install
此时 OpenCV 准备完毕。
用 git 从 EasyPR 官方下载最新代码,这里把源码存放在 ~/src/EasyPR 目录中。
# 下载 git clone https://github.com/liuruoze/EasyPR.git
我们需要的是动态库,因此需要对源码进行部分修改。
1. 文件 include/easypr/config.h
,把 OpenCV 版本宏改成 3.2 以上。
#define CV_VERSION_THREE_ZERO ==> #define CV_VERSION_THREE_TWO
2. 文件 CMakeLists.txt
,easypr 模块改成动态编译,同时修改 OpenCV 查找路径。
add_library(easypr STATIC ${SOURCE_FILES}) ==> add_library(easypr SHARED ${SOURCE_FILES})
# 添加下列代码,指定 opencv 的库路径 set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "~/.local/opencv-3.4.8")
3. 文件 thirdparty/CMakeLists.txt
,thirdparty 模块改成动态编译。
add_library(thirdparty STATIC ${SOURCE_FILES}) ==> add_library(thirdparty SHARED ${SOURCE_FILES})
4. 编译
直接运行 build.sh
./build.sh
此时会生成 build 目录,里面的 build/libeasypr.so 和 build/thirdparty/libthirdparty.so 就是我们需要的最终文件。
1. 新建开发目录,如 ~/src/libpr。
mkdir ~/src/libpr cd ~/src/libpr
2. 把前面生成的库放到一起,方便打包调用。
# 把 easypr 的库移动到 libeasypr 中。 mkdir ~/src/libpr/libeasypr cd ~/src/libpr/libeasypr cp ~/src/EasyPR/build/libeasypr.so . cp ~/src/EasyPR/build/thirdparty/libthirdparty.so . # 把 opencv 的库移动到 libopencv-3.4.4 中。 cp -r ~/.local/opencv-3.4.8/lib /opt/src/libpr/libopencv-3.4.8
3. 编写自己的 c++ 程序(示例)
#include <iostream> #include "easypr.h" using namespace easypr; static std::vector<std::string> plate_recognize_self(const char* image, const char* model_svm, const char* model_ann, const bool life_mode = true) { cv::Mat img = cv::imread(image); assert(!img.empty()); CPlateRecognize pr; pr.setResultShow(false); pr.setLifemode(true); pr.setMaxPlates(1); pr.setDetectType(PR_DETECT_CMSER | PR_DETECT_COLOR); std::vector<std::string> results; std::vector<CPlate> plates; pr.plateRecognize(img, plates, 0); for (auto plate : plates) { results.push_back(plate.getPlateStr()); results.push_back(std::to_string(plate.getPlatePos().center.x)); results.push_back(std::to_string(plate.getPlatePos().center.y)); results.push_back(std::to_string(plate.getPlatePos().size.width)); results.push_back(std::to_string(plate.getPlatePos().size.height)); } if (plates.size() == 1) { if (1) { std::stringstream ss(std::stringstream::in | std::stringstream::out); ss << "result.jpg"; imwrite(ss.str(), plates.at(0).getPlateMat()); } } return std::move(results); } char* wrap_for_python_plate_recognize(const char* image, const char* model_svm, const char* model_ann, const int life_mode) { std::vector<std::string> results= plate_recognize_self(image, model_svm, model_ann, life_mode); std::string str = "nil"; if(! results.empty()) { std::ostringstream oss; for (std::vector<std::string>::const_iterator it = results.begin(); it != results.end(); it ++) oss << (*it) << "$"; str = oss.str(); } char *ret = new char[str.length() + 1]; strcpy(ret, str.c_str()); return ret; } int main() { const char* image = "./test.jpg"; wrap_for_python_plate_recognize(image, "", "", 0) return 0; }
4. 编译
g++ -Wall -std=c++11 -fPIC --shared -o libpr.so test.cpp \ -I ~/src/EasyPR/include \ -L ~/src/EasyPR/build \ -L ~/src/EasyPR/build/thirdparty \ -I ~/.local/opencv-3.4.8/include \ -L ~/.local/opencv-3.4.8/lib \ -leasypr \ -lthirdparty \ -lopencv_core \ -lopencv_objdetect \ -lopencv_ml \ -lopencv_imgcodecs \ -lopencv_highgui \ -Wno-unused-function \ -Wno-unused-variable
此时会生成 libpr.so 库文件
5. 编写自己的 python 程序。(示例)
import ctypes import math import os try: libpr = ctypes.cdll.LoadLibrary('./libpr.so') except Exception as e: print(str(e)) # 设定 libpr 的参数类型和返回值类型 libpr.wrap_for_python_plate_recognize.restype = ctypes.c_char_p libpr.wrap_for_python_plate_recognize.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_int] func_plate_recognize = libpr.wrap_for_python_plate_recognize if __name__ == '__main__': file_path = b"./test.jpg" result = func_plate_recognize(file_path, b'', b'', 0) print(result.decode("UTF-8"))
6. 运行程序
特别注意 : EasyPR 需要依赖它目录下的 model 定义,需要把 model 目录整个拷贝过来。
# 准备工作 cp -r ~/src/EasyPR/model . export LD_LIBRARY_PATH=`pwd`/libeasypr:`pwd`/libopencv-3.4.8:$LD_LIBRARY_PATH
# 运行 python3 test.py