| @@ -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}) | |||
| @@ -12,25 +12,40 @@ | |||
| #include "FastDeskew.h" | |||
| #include "FineMapping.h" | |||
| #include "Recognizer.h" | |||
| #include "SegmentationFreeRecognizer.h" | |||
| namespace pr{ | |||
| const std::vector<std::string> 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<std::string> plateRes; | |||
| std::vector<PlateInfo> RunPiplineAsImage(cv::Mat plateImage); | |||
| std::vector<PlateInfo> RunPiplineAsImage(cv::Mat plateImage,int method); | |||
| @@ -10,17 +10,14 @@ namespace pr { | |||
| typedef std::vector<cv::Mat> 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<std::pair<CharType,cv::Mat>> plateChars; | |||
| std::vector<std::pair<CharType,cv::Mat>> plateChars; | |||
| std::vector<std::pair<CharType,cv::Mat>> 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)<<std::endl; | |||
| } | |||
| else if(plate.first == INVALID) | |||
| { | |||
| decode+='*'; | |||
| } | |||
| } | |||
| name = decode; | |||
| @@ -113,12 +114,10 @@ namespace pr { | |||
| return decode; | |||
| } | |||
| private: | |||
| cv::Mat licensePlate; | |||
| cv::Rect ROI; | |||
| std::string name; | |||
| std::string name ; | |||
| PlateColor Type; | |||
| }; | |||
| } | |||
| @@ -13,7 +13,9 @@ namespace pr{ | |||
| class GeneralRecognizer{ | |||
| public: | |||
| virtual label recognizeCharacter(cv::Mat character) = 0; | |||
| // virtual cv::Mat SegmentationFreeForSinglePlate(cv::Mat plate) = 0; | |||
| void SegmentBasedSequenceRecognition(PlateInfo &plateinfo); | |||
| void SegmentationFreeSequenceRecognition(PlateInfo &plateInfo); | |||
| }; | |||
| @@ -0,0 +1,28 @@ | |||
| // | |||
| // Created by 庾金科 on 28/11/2017. | |||
| // | |||
| #ifndef SWIFTPR_SEGMENTATIONFREERECOGNIZER_H | |||
| #define SWIFTPR_SEGMENTATIONFREERECOGNIZER_H | |||
| #include "Recognizer.h" | |||
| namespace pr{ | |||
| class SegmentationFreeRecognizer{ | |||
| public: | |||
| const int CHAR_INPUT_W = 14; | |||
| const int CHAR_INPUT_H = 30; | |||
| const int CHAR_LEN = 84; | |||
| SegmentationFreeRecognizer(std::string prototxt,std::string caffemodel); | |||
| std::pair<std::string,float> SegmentationFreeForSinglePlate(cv::Mat plate,std::vector<std::string> mapping_table); | |||
| private: | |||
| cv::dnn::Net net; | |||
| }; | |||
| } | |||
| #endif //SWIFTPR_SEGMENTATIONFREERECOGNIZER_H | |||
| @@ -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 "<<contours_nums<<std::endl; | |||
| if(contours_nums<41) | |||
| { | |||
| @@ -166,7 +162,7 @@ namespace pr{ | |||
| } | |||
| cv::Mat rgb; | |||
| cv::copyMakeBorder(PreInputProposal, rgb, 30, 30, 0, 0, cv::BORDER_REPLICATE); | |||
| cv::copyMakeBorder(PreInputProposal, rgb, PADDING_UP_DOWN, PADDING_UP_DOWN, 0, 0, cv::BORDER_REPLICATE); | |||
| // cv::imshow("rgb",rgb); | |||
| // cv::waitKey(0); | |||
| // | |||
| @@ -174,8 +170,8 @@ namespace pr{ | |||
| std::pair<int, int> A; | |||
| std::pair<int, int> 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; | |||
| @@ -7,18 +7,20 @@ | |||
| namespace pr { | |||
| std::vector<std::string> 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<PlateInfo> PipelinePR:: RunPiplineAsImage(cv::Mat plateImage) { | |||
| std::vector<PlateInfo> PipelinePR:: RunPiplineAsImage(cv::Mat plateImage,int method) { | |||
| std::vector<PlateInfo> results; | |||
| std::vector<pr::PlateInfo> 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<cv::Rect> 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<cv::Rect> 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<cv::Rect> rects; | |||
| std::pair<std::string,float> 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) { | |||
| @@ -36,10 +36,10 @@ namespace pr{ | |||
| // w += w * 0.28 | |||
| // y -= h * 0.6 | |||
| // h += h * 1.1; | |||
| int zeroadd_w = static_cast<int>(plate.width*0.28); | |||
| int zeroadd_h = static_cast<int>(plate.height*1.2); | |||
| int zeroadd_x = static_cast<int>(plate.width*0.14); | |||
| int zeroadd_y = static_cast<int>(plate.height*0.6); | |||
| int zeroadd_w = static_cast<int>(plate.width*0.30); | |||
| int zeroadd_h = static_cast<int>(plate.height*2); | |||
| int zeroadd_x = static_cast<int>(plate.width*0.15); | |||
| int zeroadd_y = static_cast<int>(plate.height*1); | |||
| plate.x-=zeroadd_x; | |||
| plate.y-=zeroadd_y; | |||
| plate.height += zeroadd_h; | |||
| @@ -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<std::vector<cv::Point>> 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<<sections<<std::endl; | |||
| @@ -6,17 +6,20 @@ | |||
| namespace pr{ | |||
| void GeneralRecognizer::SegmentBasedSequenceRecognition(PlateInfo &plateinfo){ | |||
| for(auto char_instance:plateinfo.plateChars) | |||
| { | |||
| std::pair<CharType,cv::Mat> 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<CharType,cv::Mat> res; | |||
| cv::Mat code_table= recognizeCharacter(char_instance.second); | |||
| res.first = char_instance.first; | |||
| code_table.copyTo(res.second); | |||
| plateinfo.appendPlateCoding(res); | |||
| } | |||
| @@ -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<std::string,float> decodeResults(cv::Mat code_table,std::vector<std::string> 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<int> seq(sequencelength); | |||
| std::vector<std::pair<int,float>> 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<int,float> 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<seq_decode_res[1].second; | |||
| name+=mapping_table[seq_decode_res[c].first]; | |||
| sum_confidence+=seq_decode_res[c].second; | |||
| plate_lenghth++; | |||
| } | |||
| for(; i < seq_decode_res.size();i++) | |||
| { | |||
| name+=mapping_table[seq_decode_res[i].first]; | |||
| sum_confidence +=seq_decode_res[i].second; | |||
| plate_lenghth++; | |||
| } | |||
| std::pair<std::string,float> res; | |||
| res.second = sum_confidence/plate_lenghth; | |||
| res.first = name; | |||
| return res; | |||
| } | |||
| std::string decodeResults(cv::Mat code_table,std::vector<std::string> 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<int> 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<<name; | |||
| return name; | |||
| } | |||
| std::pair<std::string,float> SegmentationFreeRecognizer::SegmentationFreeForSinglePlate(cv::Mat Image,std::vector<std::string> 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); | |||
| } | |||
| } | |||
| @@ -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<pr::PlateInfo> 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交流。 | |||