From 99bf200138454f643f3e61e6ad81b1cc9efb91c6 Mon Sep 17 00:00:00 2001 From: jackyu <455501914@qq.com> Date: Wed, 31 Jan 2018 02:44:08 +0800 Subject: [PATCH] up e2e cpp --- Prj-Android/app/src/main/cpp/CMakeLists.txt | 37 ------- Prj-Android/app/src/main/cpp/include/Pipeline.h | 19 +++- Prj-Android/app/src/main/cpp/include/PlateInfo.h | 19 ++-- Prj-Android/app/src/main/cpp/include/Recognizer.h | 2 + .../main/cpp/include/SegmentationFreeRecognizer.h | 28 +++++ Prj-Android/app/src/main/cpp/src/FineMapping.cpp | 16 ++- Prj-Android/app/src/main/cpp/src/Pipeline.cpp | 66 ++++++++---- .../app/src/main/cpp/src/PlateDetection.cpp | 8 +- .../app/src/main/cpp/src/PlateSegmentation.cpp | 26 ++--- Prj-Android/app/src/main/cpp/src/Recognizer.cpp | 17 +-- .../main/cpp/src/SegmentationFreeRecognizer.cpp | 118 +++++++++++++++++++++ README.md | 40 ++++++- 12 files changed, 291 insertions(+), 105 deletions(-) delete mode 100644 Prj-Android/app/src/main/cpp/CMakeLists.txt create mode 100644 Prj-Android/app/src/main/cpp/include/SegmentationFreeRecognizer.h create mode 100644 Prj-Android/app/src/main/cpp/src/SegmentationFreeRecognizer.cpp diff --git a/Prj-Android/app/src/main/cpp/CMakeLists.txt b/Prj-Android/app/src/main/cpp/CMakeLists.txt deleted file mode 100644 index 16e7338..0000000 --- a/Prj-Android/app/src/main/cpp/CMakeLists.txt +++ /dev/null @@ -1,37 +0,0 @@ -cmake_minimum_required(VERSION 3.6) -project(SwiftPR) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") -add_library( lib_opencv SHARED IMPORTED ) - - -find_library( # Sets the name of the path variable. - log-lib - - # Specifies the name of the NDK library that - # you want CMake to locate. - log ) - - -include_directories(/Users/yujinke/Downloads/OpenCV-android-sdk-3.3/sdk/native/jni/include) -include_directories(include) - -set_target_properties(lib_opencv PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libopencv_java3.so) - -set(SRC_DETECTION src/PlateDetection.cpp src/util.h include/PlateDetection.h) - -set(SRC_FINEMAPPING src/FineMapping.cpp ) - -set(SRC_FASTDESKEW src/FastDeskew.cpp ) - -set(SRC_SEGMENTATION src/PlateSegmentation.cpp ) - -set(SRC_RECOGNIZE src/Recognizer.cpp src/CNNRecognizer.cpp) - -set(SRC_PIPLINE src/Pipeline.cpp) - - - -add_library(hyperlpr SHARED ${SRC_DETECTION} ${SRC_FINEMAPPING} ${SRC_FASTDESKEW} ${SRC_SEGMENTATION} ${SRC_RECOGNIZE} ${SRC_PIPLINE} javaWarpper.cpp) - -target_link_libraries(hyperlpr lib_opencv ${log-lib}) diff --git a/Prj-Android/app/src/main/cpp/include/Pipeline.h b/Prj-Android/app/src/main/cpp/include/Pipeline.h index 6cae324..4e82955 100644 --- a/Prj-Android/app/src/main/cpp/include/Pipeline.h +++ b/Prj-Android/app/src/main/cpp/include/Pipeline.h @@ -12,25 +12,40 @@ #include "FastDeskew.h" #include "FineMapping.h" #include "Recognizer.h" +#include "SegmentationFreeRecognizer.h" namespace pr{ + + const std::vector CH_PLATE_CODE{"京", "沪", "津", "渝", "冀", "晋", "蒙", "辽", "吉", "黑", "苏", "浙", "皖", "闽", "赣", "鲁", "豫", "鄂", "湘", "粤", "桂", + "琼", "川", "贵", "云", "藏", "陕", "甘", "青", "宁", "新", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", + "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", + "Y", "Z","港","学","使","警","澳","挂","军","北","南","广","沈","兰","成","济","海","民","航","空"}; + + + + const int SEGMENTATION_FREE_METHOD = 0; + const int SEGMENTATION_BASED_METHOD = 1; + class PipelinePR{ public: GeneralRecognizer *generalRecognizer; PlateDetection *plateDetection; PlateSegmentation *plateSegmentation; FineMapping *fineMapping; + SegmentationFreeRecognizer *segmentationFreeRecognizer; + PipelinePR(std::string detector_filename, std::string finemapping_prototxt,std::string finemapping_caffemodel, std::string segmentation_prototxt,std::string segmentation_caffemodel, - std::string charRecognization_proto,std::string charRecognization_caffemodel + std::string charRecognization_proto,std::string charRecognization_caffemodel, + std::string segmentationfree_proto,std::string segmentationfree_caffemodel ); ~PipelinePR(); std::vector plateRes; - std::vector RunPiplineAsImage(cv::Mat plateImage); + std::vector RunPiplineAsImage(cv::Mat plateImage,int method); diff --git a/Prj-Android/app/src/main/cpp/include/PlateInfo.h b/Prj-Android/app/src/main/cpp/include/PlateInfo.h index ee1e5da..f500bb5 100644 --- a/Prj-Android/app/src/main/cpp/include/PlateInfo.h +++ b/Prj-Android/app/src/main/cpp/include/PlateInfo.h @@ -10,17 +10,14 @@ namespace pr { typedef std::vector Character; enum PlateColor { BLUE, YELLOW, WHITE, GREEN, BLACK,UNKNOWN}; - enum CharType {CHINESE,LETTER,LETTER_NUMS}; + enum CharType {CHINESE,LETTER,LETTER_NUMS,INVALID}; class PlateInfo { public: - std::vector> plateChars; + std::vector> plateChars; std::vector> plateCoding; - float confidence = 0; - - PlateInfo(const cv::Mat &plateData, std::string plateName, cv::Rect plateRect, PlateColor plateType) { licensePlate = plateData; name = plateName; @@ -93,17 +90,21 @@ namespace pr { } - if(plate.first == LETTER) { + else if(plate.first == LETTER) { decode += mappingTable[std::max_element(prob+41,prob+65)- prob]; confidence+=*std::max_element(prob+41,prob+65); } - if(plate.first == LETTER_NUMS) { + else if(plate.first == LETTER_NUMS) { decode += mappingTable[std::max_element(prob+31,prob+65)- prob]; confidence+=*std::max_element(prob+31,prob+65); // std::cout<<*std::max_element(prob+31,prob+65)< SegmentationFreeForSinglePlate(cv::Mat plate,std::vector mapping_table); + + + private: + cv::dnn::Net net; + + }; + +} +#endif //SWIFTPR_SEGMENTATIONFREERECOGNIZER_H diff --git a/Prj-Android/app/src/main/cpp/src/FineMapping.cpp b/Prj-Android/app/src/main/cpp/src/FineMapping.cpp index 5e7c5b6..42e4b32 100644 --- a/Prj-Android/app/src/main/cpp/src/FineMapping.cpp +++ b/Prj-Android/app/src/main/cpp/src/FineMapping.cpp @@ -5,8 +5,8 @@ #include "FineMapping.h" namespace pr{ - const int FINEMAPPING_H = 50; - const int FINEMAPPING_W = 120; + const int FINEMAPPING_H = 60 ; + const int FINEMAPPING_W = 140; const int PADDING_UP_DOWN = 30; void drawRect(cv::Mat image,cv::Rect rect) { @@ -71,12 +71,10 @@ namespace pr{ cv::Mat proposal; cv::resize(InputProposal,PreInputProposal,cv::Size(FINEMAPPING_W,FINEMAPPING_H)); - int x = InputProposal.channels(); +// cv::imwrite("res/cache/finemapping.jpg",PreInputProposal); if(InputProposal.channels() == 3) cv::cvtColor(PreInputProposal,proposal,cv::COLOR_BGR2GRAY); - else if(InputProposal.channels() == 4) - cv::cvtColor(PreInputProposal,proposal,cv::COLOR_BGRA2GRAY); else PreInputProposal.copyTo(proposal); @@ -110,7 +108,6 @@ namespace pr{ if (( lwRatio>0.7&&bdbox.width*bdbox.height>100 && bdboxAera<300) || (lwRatio>3.0 && bdboxAera<100 && bdboxAera>10)) { - cv::Point p1(bdbox.x, bdbox.y); cv::Point p2(bdbox.x + bdbox.width, bdbox.y + bdbox.height); line_upper.push_back(p1); @@ -120,7 +117,6 @@ namespace pr{ } } - std:: cout<<"contours_nums "< A; std::pair B; - A = FitLineRansac(line_upper, -2); - B = FitLineRansac(line_lower, 2); + A = FitLineRansac(line_upper, -1); + B = FitLineRansac(line_lower, 1); int leftyB = A.first; int rightyB = A.second; int leftyA = B.first; diff --git a/Prj-Android/app/src/main/cpp/src/Pipeline.cpp b/Prj-Android/app/src/main/cpp/src/Pipeline.cpp index 106638a..ed9647c 100644 --- a/Prj-Android/app/src/main/cpp/src/Pipeline.cpp +++ b/Prj-Android/app/src/main/cpp/src/Pipeline.cpp @@ -7,18 +7,20 @@ namespace pr { - std::vector chars_code{"京","沪","津","渝","冀","晋","蒙","辽","吉","黑","苏","浙","皖","闽","赣","鲁","豫","鄂","湘","粤","桂","琼","川","贵","云","藏","陕","甘","青","宁","新","0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","J","K","L","M","N","P","Q","R","S","T","U","V","W","X","Y","Z"}; - + const int HorizontalPadding = 4; PipelinePR::PipelinePR(std::string detector_filename, std::string finemapping_prototxt, std::string finemapping_caffemodel, std::string segmentation_prototxt, std::string segmentation_caffemodel, - std::string charRecognization_proto, std::string charRecognization_caffemodel) { + std::string charRecognization_proto, std::string charRecognization_caffemodel, + std::string segmentationfree_proto,std::string segmentationfree_caffemodel) { plateDetection = new PlateDetection(detector_filename); fineMapping = new FineMapping(finemapping_prototxt, finemapping_caffemodel); plateSegmentation = new PlateSegmentation(segmentation_prototxt, segmentation_caffemodel); generalRecognizer = new CNNRecognizer(charRecognization_proto, charRecognization_caffemodel); + segmentationFreeRecognizer = new SegmentationFreeRecognizer(segmentationfree_proto,segmentationfree_caffemodel); + } PipelinePR::~PipelinePR() { @@ -27,42 +29,64 @@ namespace pr { delete fineMapping; delete plateSegmentation; delete generalRecognizer; + delete segmentationFreeRecognizer; + } - std::vector PipelinePR:: RunPiplineAsImage(cv::Mat plateImage) { + std::vector PipelinePR:: RunPiplineAsImage(cv::Mat plateImage,int method) { std::vector results; std::vector plates; - plateDetection->plateDetectionRough(plateImage,plates); + plateDetection->plateDetectionRough(plateImage,plates,36,700); for (pr::PlateInfo plateinfo:plates) { cv::Mat image_finemapping = plateinfo.getPlateImage(); - image_finemapping = fineMapping->FineMappingVertical(image_finemapping); - image_finemapping = pr::fastdeskew(image_finemapping, 5); -// -// cv::imshow("image_finemapping", image_finemapping); + + + + //Segmentation-based + + if(method==SEGMENTATION_BASED_METHOD) + { + image_finemapping = fineMapping->FineMappingHorizon(image_finemapping, 2, HorizontalPadding); + cv::resize(image_finemapping, image_finemapping, cv::Size(136+HorizontalPadding, 36)); +// cv::imshow("image_finemapping",image_finemapping); // cv::waitKey(0); + plateinfo.setPlateImage(image_finemapping); + std::vector rects; - image_finemapping = fineMapping->FineMappingHorizon(image_finemapping, 2, 5); + plateSegmentation->segmentPlatePipline(plateinfo, 1, rects); + plateSegmentation->ExtractRegions(plateinfo, rects); + cv::copyMakeBorder(image_finemapping, image_finemapping, 0, 0, 0, 20, cv::BORDER_REPLICATE); + plateinfo.setPlateImage(image_finemapping); + generalRecognizer->SegmentBasedSequenceRecognition(plateinfo); + plateinfo.decodePlateNormal(pr::CH_PLATE_CODE); - cv::resize(image_finemapping, image_finemapping, cv::Size(136, 36)); - plateinfo.setPlateImage(image_finemapping); - std::vector rects; - plateSegmentation->segmentPlatePipline(plateinfo, 1, rects); - plateSegmentation->ExtractRegions(plateinfo, rects); + } + //Segmentation-free + else if(method==SEGMENTATION_FREE_METHOD) + { - cv::copyMakeBorder(image_finemapping, image_finemapping, 0, 0, 0, 20, cv::BORDER_REPLICATE); + image_finemapping = fineMapping->FineMappingHorizon(image_finemapping, 4, HorizontalPadding+3); - plateinfo.setPlateImage(image_finemapping); - generalRecognizer->SegmentBasedSequenceRecognition(plateinfo); - plateinfo.decodePlateNormal(chars_code); - results.push_back(plateinfo); - std::cout << plateinfo.getPlateName() << std::endl; + cv::resize(image_finemapping, image_finemapping, cv::Size(136+HorizontalPadding, 36)); +// cv::imwrite("./test.png",image_finemapping); +// cv::imshow("image_finemapping",image_finemapping); +// cv::waitKey(0); + plateinfo.setPlateImage(image_finemapping); +// std::vector rects; + std::pair res = segmentationFreeRecognizer->SegmentationFreeForSinglePlate(plateinfo.getPlateImage(),pr::CH_PLATE_CODE); + plateinfo.confidence = res.second; + plateinfo.setPlateName(res.first); + } + + + results.push_back(plateinfo); } // for (auto str:results) { diff --git a/Prj-Android/app/src/main/cpp/src/PlateDetection.cpp b/Prj-Android/app/src/main/cpp/src/PlateDetection.cpp index b207190..a908f66 100644 --- a/Prj-Android/app/src/main/cpp/src/PlateDetection.cpp +++ b/Prj-Android/app/src/main/cpp/src/PlateDetection.cpp @@ -36,10 +36,10 @@ namespace pr{ // w += w * 0.28 // y -= h * 0.6 // h += h * 1.1; - int zeroadd_w = static_cast(plate.width*0.28); - int zeroadd_h = static_cast(plate.height*1.2); - int zeroadd_x = static_cast(plate.width*0.14); - int zeroadd_y = static_cast(plate.height*0.6); + int zeroadd_w = static_cast(plate.width*0.30); + int zeroadd_h = static_cast(plate.height*2); + int zeroadd_x = static_cast(plate.width*0.15); + int zeroadd_y = static_cast(plate.height*1); plate.x-=zeroadd_x; plate.y-=zeroadd_y; plate.height += zeroadd_h; diff --git a/Prj-Android/app/src/main/cpp/src/PlateSegmentation.cpp b/Prj-Android/app/src/main/cpp/src/PlateSegmentation.cpp index 11fa632..28c3dfe 100644 --- a/Prj-Android/app/src/main/cpp/src/PlateSegmentation.cpp +++ b/Prj-Android/app/src/main/cpp/src/PlateSegmentation.cpp @@ -94,7 +94,7 @@ namespace pr{ cv::Mat roi_thres; // cv::threshold(roiImage,roi_thres,0,255,cv::THRESH_OTSU|cv::THRESH_BINARY); - niBlackThreshold(roiImage,roi_thres,255,cv::THRESH_BINARY,15,0.3,BINARIZATION_NIBLACK); + niBlackThreshold(roiImage,roi_thres,255,cv::THRESH_BINARY,15,0.27,BINARIZATION_NIBLACK); std::vector> contours; cv::findContours(roi_thres,contours,cv::RETR_LIST,cv::CHAIN_APPROX_SIMPLE); @@ -220,7 +220,7 @@ namespace pr{ int cp_list[7]; - float loss_selected = -1; + float loss_selected = -10; for(int start = 0 ; start < 20 ; start+=2) for(int width = windowsWidth-5; width < windowsWidth+5 ; width++ ){ @@ -248,14 +248,9 @@ namespace pr{ continue; // float loss = ch_prob[cp1_ch]+ // engNum_prob[cp2_p0] +engNum_prob[cp3_p1]+engNum_prob[cp4_p2]+engNum_prob[cp5_p3]+engNum_prob[cp6_p4] +engNum_prob[cp7_p5] -// + (false_prob[md2]+false_prob[md3]+false_prob[md4]+false_prob[md5]+false_prob[md5] + false_prob[md6] -// ); - +// + (false_prob[md2]+false_prob[md3]+false_prob[md4]+false_prob[md5]+false_prob[md5] + false_prob[md6]); float loss = ch_prob[cp1_ch]*3 -(false_prob[cp3_p1]+false_prob[cp4_p2]+false_prob[cp5_p3]+false_prob[cp6_p4]+false_prob[cp7_p5]); - - - if(loss>loss_selected) { loss_selected = loss; @@ -286,15 +281,15 @@ namespace pr{ void PlateSegmentation::segmentPlateBySlidingWindows(cv::Mat &plateImage,int windowsWidth,int stride,cv::Mat &respones){ - cv::resize(plateImage,plateImage,cv::Size(136,36)); +// cv::resize(plateImage,plateImage,cv::Size(136,36)); cv::Mat plateImageGray; cv::cvtColor(plateImage,plateImageGray,cv::COLOR_BGR2GRAY); - + int padding = plateImage.cols-136 ; +// int padding = 0 ; int height = plateImage.rows - 1; - int width = plateImage.cols - 1; - - for(int i = 0 ; i < plateImage.cols - windowsWidth +1 ; i +=stride) + int width = plateImage.cols - 1 - padding; + for(int i = 0 ; i < width - windowsWidth +1 ; i +=stride) { cv::Rect roi(i,0,windowsWidth,height); cv::Mat roiImage = plateImageGray(roi); @@ -350,6 +345,11 @@ namespace pr{ cv::Mat respones; //three response of every sub region from origin image . segmentPlateBySlidingWindows(plateImage,DEFAULT_WIDTH,1,respones); templateMatchFinding(respones,DEFAULT_WIDTH/stride,sections); + for(int i = 0; i < sections.second.size() ; i++) + { + sections.second[i]*=stride; + + } // std::cout< res; + if(char_instance.second.rows*char_instance.second.cols>40) { + label code_table = recognizeCharacter(char_instance.second); + res.first = char_instance.first; + code_table.copyTo(res.second); + plateinfo.appendPlateCoding(res); + } else{ + res.first = INVALID; + plateinfo.appendPlateCoding(res); + } - std::pair res; - cv::Mat code_table= recognizeCharacter(char_instance.second); - res.first = char_instance.first; - code_table.copyTo(res.second); - plateinfo.appendPlateCoding(res); } diff --git a/Prj-Android/app/src/main/cpp/src/SegmentationFreeRecognizer.cpp b/Prj-Android/app/src/main/cpp/src/SegmentationFreeRecognizer.cpp new file mode 100644 index 0000000..8fcd442 --- /dev/null +++ b/Prj-Android/app/src/main/cpp/src/SegmentationFreeRecognizer.cpp @@ -0,0 +1,118 @@ +// +// Created by 庾金科 on 28/11/2017. +// +#include "../include/SegmentationFreeRecognizer.h" + +namespace pr { + SegmentationFreeRecognizer::SegmentationFreeRecognizer(std::string prototxt, std::string caffemodel) { + net = cv::dnn::readNetFromCaffe(prototxt, caffemodel); + } + + + inline int judgeCharRange(int id) + {return id<31 || id>63; + } + + + std::pair decodeResults(cv::Mat code_table,std::vector mapping_table,float thres) + { +// cv::imshow("imagea",code_table); +// cv::waitKey(0); + + cv::MatSize mtsize = code_table.size; + int sequencelength = mtsize[2]; + int labellength = mtsize[1]; + cv::transpose(code_table.reshape(1,1).reshape(1,labellength),code_table); + std::string name = ""; + + + std::vector seq(sequencelength); + std::vector> seq_decode_res; + + for(int i = 0 ; i < sequencelength; i++) { + float *fstart = ((float *) (code_table.data) + i * labellength ); + int id = std::max_element(fstart,fstart+labellength) - fstart; + seq[i] =id; + } + + float sum_confidence = 0; + + int plate_lenghth = 0 ; + + + for(int i = 0 ; i< sequencelength ; i++) + { + if(seq[i]!=labellength-1 && (i==0 || seq[i]!=seq[i-1])) + { + float *fstart = ((float *) (code_table.data) + i * labellength ); + float confidence = *(fstart+seq[i]); + std::pair pair_(seq[i],confidence); + seq_decode_res.push_back(pair_); +// + + } + } + + int i = 0; + + if(judgeCharRange(seq_decode_res[0].first) && judgeCharRange(seq_decode_res[1].first)) + { + i=2; + int c = seq_decode_res[0].second res; + + res.second = sum_confidence/plate_lenghth; + res.first = name; + return res; + + } + + std::string decodeResults(cv::Mat code_table,std::vector mapping_table) + { + cv::MatSize mtsize = code_table.size; + int sequencelength = mtsize[2]; + int labellength = mtsize[1]; + cv::transpose(code_table.reshape(1,1).reshape(1,labellength),code_table); + std::string name = ""; + std::vector seq(sequencelength); + for(int i = 0 ; i < sequencelength; i++) { + float *fstart = ((float *) (code_table.data) + i * labellength ); + int id = std::max_element(fstart,fstart+labellength) - fstart; + seq[i] =id; + } + for(int i = 0 ; i< sequencelength ; i++) + { + if(seq[i]!=labellength-1 && (i==0 || seq[i]!=seq[i-1])) + name+=mapping_table[seq[i]]; + } + + std::cout< SegmentationFreeRecognizer::SegmentationFreeForSinglePlate(cv::Mat Image,std::vector mapping_table) { + cv::transpose(Image,Image); + cv::Mat inputBlob = cv::dnn::blobFromImage(Image, 1 / 255.0, cv::Size(40,160)); + net.setInput(inputBlob, "data"); + cv::Mat char_prob_mat = net.forward(); + return decodeResults(char_prob_mat,mapping_table,0.00); + + } + + +} \ No newline at end of file diff --git a/README.md b/README.md index 4a4872e..a7b8377 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ HyperLPR是一个使用深度学习针对对中文车牌识别的实现,与较 + Win工程中若需要使用静态库,需单独编译 + 本项目的C++实现和Python实现无任何关联,都为单独实现 -+ 在编译C++工程的时候必须要使用OpenCV 3.3(DNN 库),否则无法编译 ++ 在编译C++工程的时候必须要使用OpenCV 3.3(DNN 库),否则无法编译 ### Python 依赖 @@ -81,6 +81,43 @@ cmake ../ sudo make -j ``` +### CPP demo + +```cpp +#include "../include/Pipeline.h" +int main(){ + pr::PipelinePR prc("model/cascade.xml", + "model/HorizonalFinemapping.prototxt","model/HorizonalFinemapping.caffemodel", + "model/Segmentation.prototxt","model/Segmentation.caffemodel", + "model/CharacterRecognization.prototxt","model/CharacterRecognization.caffemodel", + "model/SegmentationFree.prototxt","model/SegmentationFree.caffemodel" + ); + //定义模型文件 + + cv::Mat image = cv::imread("/Users/yujinke/ClionProjects/cpp_ocr_demo/test.png"); + std::vector res = prc.RunPiplineAsImage(image,pr::SEGMENTATION_FREE_METHOD); + //使用端到端模型模型进行识别 识别结果将会保存在res里面 + + for(auto st:res) { + if(st.confidence>0.75) { + std::cout << st.getPlateName() << " " << st.confidence << std::endl; + //输出识别结果 、识别置信度 + cv::Rect region = st.getPlateRect(); + //获取车牌位置 + cv::rectangle(image,cv::Point(region.x,region.y),cv::Point(region.x+region.width,region.y+region.height),cv::Scalar(255,255,0),2); + //画出车牌位置 + + } + } + + cv::imshow("image",image); + cv::waitKey(0); + return 0 ; +} +``` + +### + ### 可识别和待支持的车牌的类型 - [x] 单行蓝牌 @@ -130,3 +167,4 @@ sudo make -j + HyperLPR讨论QQ群:673071218, 加前请备注HyperLPR交流。 +