From 846d4c7a292507e2b21be3961c577da954d9960a Mon Sep 17 00:00:00 2001 From: iss Date: Tue, 2 Jul 2019 19:47:23 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0vs=E5=B7=A5=E7=A8=8B=E5=88=B0?= =?UTF-8?q?=E7=AB=AF=E5=88=B0=E7=AB=AF=E6=A8=A1=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Prj-Win/Prj-Win/Prj-Win.vcxproj | 23 ++- Prj-Win/Prj-Win/Prj-Win.vcxproj.filters | 9 + Prj-Win/lpr/include/CNNRecognizer.h | 2 +- Prj-Win/lpr/include/Pipeline.h | 145 ++++++-------- Prj-Win/lpr/include/PlateDetection.h | 2 +- Prj-Win/lpr/include/PlateInfo.h | 19 +- Prj-Win/lpr/include/PlateSegmentation.h | 4 - Prj-Win/lpr/include/Recognizer.h | 2 + Prj-Win/lpr/include/SegmentationFreeRecognizer.h | 28 +++ Prj-Win/lpr/include/niBlackThreshold.h | 8 +- Prj-Win/lpr/model/README.md | 4 +- Prj-Win/lpr/res/test.jpg | Bin 0 -> 31623 bytes Prj-Win/lpr/src/CNNRecognizer.cpp | 4 +- Prj-Win/lpr/src/FastDeskew.cpp | 35 +--- Prj-Win/lpr/src/FineMapping.cpp | 45 +---- Prj-Win/lpr/src/Pipeline.cpp | 86 +++++++- Prj-Win/lpr/src/PlateDetection.cpp | 39 +--- Prj-Win/lpr/src/PlateSegmentation.cpp | 34 ++-- Prj-Win/lpr/src/Recognizer.cpp | 25 ++- Prj-Win/lpr/src/SegmentationFreeRecognizer.cpp | 89 +++++++++ Prj-Win/lpr/src/util.h | 19 +- Prj-Win/lpr/tests/test_fastdeskew.cpp | 2 +- Prj-Win/lpr/tests/test_finemapping.cpp | 4 +- Prj-Win/lpr/tests/test_pipeline.cpp | 239 ++++++++++++++++++++--- Prj-Win/lpr/tests/test_recognization.cpp | 3 +- Prj-Win/lpr/tests/test_segmentation.cpp | 4 +- Prj-Win/lpr/tests/test_segmentationFree.cpp | 54 +++++ 27 files changed, 628 insertions(+), 300 deletions(-) create mode 100644 Prj-Win/lpr/include/SegmentationFreeRecognizer.h create mode 100644 Prj-Win/lpr/res/test.jpg create mode 100644 Prj-Win/lpr/src/SegmentationFreeRecognizer.cpp create mode 100644 Prj-Win/lpr/tests/test_segmentationFree.cpp diff --git a/Prj-Win/Prj-Win/Prj-Win.vcxproj b/Prj-Win/Prj-Win/Prj-Win.vcxproj index 35affa2..1e8cc08 100644 --- a/Prj-Win/Prj-Win/Prj-Win.vcxproj +++ b/Prj-Win/Prj-Win/Prj-Win.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -22,32 +22,32 @@ {69FAD143-D7C9-4804-A186-90254BD80549} Win32Proj PrjWin - 8.1 + 10.0.17763.0 Application true - v140 + v141 Unicode Application false - v140 + v141 true Unicode Application true - v140 + v141 Unicode Application false - v140 + v141 true Unicode @@ -76,9 +76,9 @@ true - D:\Prj-Win\lpr\include;D:\opencv\build\include\opencv2;D:\opencv\build\include\opencv;D:\opencv\build\include;$(IncludePath) - D:\opencv\build\x64\vc14\lib;$(LibraryPath) - $(SolutionDir)Build + D:\Prj-Win\lpr\include;D:\opencv\build\include;D:\opencv\build\include\opencv2;$(IncludePath) + D:\opencv\build\x64\vc15\lib;$(LibraryPath) + $(SolutionDir)Build\ false @@ -112,7 +112,7 @@ Console true - opencv_world330d.lib;%(AdditionalDependencies) + opencv_world400d.lib;opencv_world400.lib;%(AdditionalDependencies) @@ -161,15 +161,18 @@ + + + diff --git a/Prj-Win/Prj-Win/Prj-Win.vcxproj.filters b/Prj-Win/Prj-Win/Prj-Win.vcxproj.filters index cea3788..94d12dd 100644 --- a/Prj-Win/Prj-Win/Prj-Win.vcxproj.filters +++ b/Prj-Win/Prj-Win/Prj-Win.vcxproj.filters @@ -48,6 +48,9 @@ 源文件 + + 头文件 + @@ -71,5 +74,11 @@ 源文件\test + + 源文件 + + + 源文件 + \ No newline at end of file diff --git a/Prj-Win/lpr/include/CNNRecognizer.h b/Prj-Win/lpr/include/CNNRecognizer.h index ad491a0..a577733 100644 --- a/Prj-Win/lpr/include/CNNRecognizer.h +++ b/Prj-Win/lpr/include/CNNRecognizer.h @@ -1,5 +1,5 @@ // -// Created by 庾金科 on 21/10/2017. +// Created by Jack Yu on 21/10/2017. // #ifndef SWIFTPR_CNNRECOGNIZER_H diff --git a/Prj-Win/lpr/include/Pipeline.h b/Prj-Win/lpr/include/Pipeline.h index 53e4580..ed078b1 100644 --- a/Prj-Win/lpr/include/Pipeline.h +++ b/Prj-Win/lpr/include/Pipeline.h @@ -1,85 +1,60 @@ -// -// Created by �׽�� on 22/10/2017. -// - -#ifndef SWIFTPR_PIPLINE_H -#define SWIFTPR_PIPLINE_H - -#include "PlateDetection.h" -#include "PlateSegmentation.h" -#include "CNNRecognizer.h" -#include "PlateInfo.h" -#include "FastDeskew.h" -#include "FineMapping.h" -#include "Recognizer.h" - -namespace pr{ - class PipelinePR{ - public: - GeneralRecognizer *generalRecognizer; - PlateDetection *plateDetection; - PlateSegmentation *plateSegmentation; - FineMapping *fineMapping; - 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 - ) { - 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); - } - - ~PipelinePR() { - - delete plateDetection; - delete fineMapping; - delete plateSegmentation; - delete generalRecognizer; - } - - 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" }; - - std::vector plateRes; - std::vector RunPiplineAsImage(cv::Mat plateImage) { - std::vector results; - std::vector plates; - plateDetection->plateDetectionRough(plateImage, plates); - - for (pr::PlateInfo plateinfo : plates) { - - cv::Mat image_finemapping = plateinfo.getPlateImage(); - image_finemapping = fineMapping->FineMappingVertical(image_finemapping); - image_finemapping = pr::fastdeskew(image_finemapping, 5); - image_finemapping = fineMapping->FineMappingHorizon(image_finemapping, 2, 5); - 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); - cv::copyMakeBorder(image_finemapping, image_finemapping, 0, 0, 0, 20, cv::BORDER_REPLICATE); - - plateinfo.setPlateImage(image_finemapping); - generalRecognizer->SegmentBasedSequenceRecognition(plateinfo); - plateinfo.decodePlateNormal(chars_code); - results.push_back(plateinfo); - std::cout << plateinfo.getPlateName() << std::endl; - - - } - - // for (auto str:results) { - // std::cout << str << std::endl; - // } - return results; - } - - - - - }; - - -} -#endif //SWIFTPR_PIPLINE_H +// +// Created by ׽ on 22/10/2017. +// + +#ifndef SWIFTPR_PIPLINE_H +#define SWIFTPR_PIPLINE_H + +#include "PlateDetection.h" +#include "PlateSegmentation.h" +#include "CNNRecognizer.h" +#include "PlateInfo.h" +#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 segmentationfree_proto,std::string segmentationfree_caffemodel + ); + ~PipelinePR(); + + + + std::vector plateRes; + std::vector RunPiplineAsImage(cv::Mat plateImage,int method); + + + + + + + + }; + + +} +#endif //SWIFTPR_PIPLINE_H diff --git a/Prj-Win/lpr/include/PlateDetection.h b/Prj-Win/lpr/include/PlateDetection.h index f4cf567..71ad9af 100644 --- a/Prj-Win/lpr/include/PlateDetection.h +++ b/Prj-Win/lpr/include/PlateDetection.h @@ -6,7 +6,7 @@ #define SWIFTPR_PLATEDETECTION_H #include -#include "PlateInfo.h" +#include #include namespace pr{ class PlateDetection{ diff --git a/Prj-Win/lpr/include/PlateInfo.h b/Prj-Win/lpr/include/PlateInfo.h index ee1e5da..f500bb5 100644 --- a/Prj-Win/lpr/include/PlateInfo.h +++ b/Prj-Win/lpr/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-Win/lpr/include/niBlackThreshold.h b/Prj-Win/lpr/include/niBlackThreshold.h index 5ad7e14..54ac06d 100644 --- a/Prj-Win/lpr/include/niBlackThreshold.h +++ b/Prj-Win/lpr/include/niBlackThreshold.h @@ -62,8 +62,9 @@ void niBlackThreshold( InputArray _src, OutputArray _dst, double maxValue, thresh = mean + static_cast(k) * sqrtVarianceMeanSum; break; default: - CV_Error( CV_StsBadArg, "Unknown binarization method" ); - break; +// CV_Error( CV_StsBadArg, "Unknown binarization method" ); + CV_Error(-5, "Unknown binarization method"); + break; } thresh.convertTo(thresh, src.depth()); @@ -99,7 +100,8 @@ void niBlackThreshold( InputArray _src, OutputArray _dst, double maxValue, src.copyTo(dst, mask); break; default: - CV_Error( CV_StsBadArg, "Unknown threshold type" ); +// CV_Error( CV_StsBadArg, "Unknown threshold type" ); + CV_Error(-5, "Unknown threshold type"); break; } } diff --git a/Prj-Win/lpr/model/README.md b/Prj-Win/lpr/model/README.md index 2c524eb..3085edf 100644 --- a/Prj-Win/lpr/model/README.md +++ b/Prj-Win/lpr/model/README.md @@ -10,8 +10,8 @@ HorizonalFinemapping.caffemodel HorizonalFinemapping.prototxt -Segmentation.caffemodel +SegmentationFree.caffemodel -Segmentation.prototxt +SegmentationFree.prototxt 放置在该目录 \ No newline at end of file diff --git a/Prj-Win/lpr/res/test.jpg b/Prj-Win/lpr/res/test.jpg new file mode 100644 index 0000000000000000000000000000000000000000..342a5d988da8f0d778b59c754dbaa88ece38399d GIT binary patch literal 31623 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

xUW|f)=2E1`aV)olqJ3cGwIfPv_@FS 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 namespace pr{ - - - const int ANGLE_MIN = 30 ; + const int ANGLE_MIN = 30 ; const int ANGLE_MAX = 150 ; const int PLATE_H = 36; const int PLATE_W = 136; - + int angle(float x,float y) { return atan2(x,y)*180/3.1415; @@ -51,59 +49,38 @@ namespace pr{ cv::Mat correctPlateImage(cv::Mat skewPlate,float angle,float maxAngle) { - cv::Mat dst; - cv::Size size_o(skewPlate.cols,skewPlate.rows); - - int extend_padding = 0; -// if(angle<0) - extend_padding = static_cast(skewPlate.rows*tan(cv::abs(angle)/180* 3.14) ); -// else -// extend_padding = static_cast(skewPlate.rows/tan(cv::abs(angle)/180* 3.14) ); - -// std::cout<<"extend:"<(skewPlate.rows*tan(cv::abs(angle)/180* 3.14) ); cv::Size size(skewPlate.cols + extend_padding ,skewPlate.rows); - float interval = abs(sin((angle /180) * 3.14)* skewPlate.rows); -// std::cout<0) { cv::Point2f pts2[4] = {cv::Point2f(interval, 0), cv::Point2f(0, size_o.height), cv::Point2f(size_o.width, 0), cv::Point2f(size_o.width - interval, size_o.height)}; cv::Mat M = cv::getPerspectiveTransform(pts1,pts2); cv::warpPerspective(skewPlate,dst,M,size); - - } else { cv::Point2f pts2[4] = {cv::Point2f(0, 0), cv::Point2f(interval, size_o.height), cv::Point2f(size_o.width-interval, 0), cv::Point2f(size_o.width, size_o.height)}; cv::Mat M = cv::getPerspectiveTransform(pts1,pts2); cv::warpPerspective(skewPlate,dst,M,size,cv::INTER_CUBIC); - } return dst; } cv::Mat fastdeskew(cv::Mat skewImage,int blockSize){ - - const int FILTER_WINDOWS_SIZE = 5; std::vector angle_list(180); memset(angle_list.data(),0,angle_list.size()*sizeof(int)); - cv::Mat bak; skewImage.copyTo(bak); if(skewImage.channels() == 3) cv::cvtColor(skewImage,skewImage,cv::COLOR_RGB2GRAY); - if(skewImage.channels() == 1) { cv::Mat eigen; - cv::cornerEigenValsAndVecs(skewImage,eigen,blockSize,5); for( int j = 0; j < skewImage.rows; j+=blockSize ) { for( int i = 0; i < skewImage.cols; i+=blockSize ) @@ -112,12 +89,10 @@ namespace pr{ float y2 = eigen.at(j, i)[5]; int angle_cell = angle(x2,y2); angle_list[(angle_cell + 180)%180]+=1.0; - } } } std::vector filtered = avgfilter(angle_list,5); - int maxPos = std::max_element(filtered.begin(),filtered.end()) - filtered.begin() + FILTER_WINDOWS_SIZE/2; if(maxPos>ANGLE_MAX) maxPos = (-maxPos+90+180)%180; diff --git a/Prj-Win/lpr/src/FineMapping.cpp b/Prj-Win/lpr/src/FineMapping.cpp index 6890eff..2032b15 100644 --- a/Prj-Win/lpr/src/FineMapping.cpp +++ b/Prj-Win/lpr/src/FineMapping.cpp @@ -1,12 +1,8 @@ -// -// Created by 庾金科 on 22/09/2017. -// - #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) { @@ -65,31 +61,21 @@ namespace pr{ } cv::Mat FineMapping::FineMappingVertical(cv::Mat InputProposal,int sliceNum,int upper,int lower,int windows_size){ - - cv::Mat PreInputProposal; cv::Mat proposal; - cv::resize(InputProposal,PreInputProposal,cv::Size(FINEMAPPING_W,FINEMAPPING_H)); if(InputProposal.channels() == 3) cv::cvtColor(PreInputProposal,proposal,cv::COLOR_BGR2GRAY); else PreInputProposal.copyTo(proposal); - -// proposal = PreInputProposal; - // this will improve some sen cv::Mat kernal = cv::getStructuringElement(cv::MORPH_ELLIPSE,cv::Size(1,3)); -// cv::erode(proposal,proposal,kernal); - - float diff = static_cast(upper-lower); diff/=static_cast(sliceNum-1); cv::Mat binary_adaptive; std::vector line_upper; std::vector line_lower; int contours_nums=0; - for(int i = 0 ; i < sliceNum ; i++) { std::vector > contours; @@ -106,7 +92,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); @@ -115,9 +100,6 @@ namespace pr{ } } } - - std:: cout<<"contours_nums "< > contours; float k =lower + i*diff; cv::adaptiveThreshold(proposal,binary_adaptive,255,cv::ADAPTIVE_THRESH_MEAN_C,cv::THRESH_BINARY,windows_size,k); -// cv::imshow("image",binary_adaptive); -// cv::waitKey(0); cv::Mat draw; binary_adaptive.copyTo(draw); cv::findContours(binary_adaptive,contours,cv::RETR_EXTERNAL,cv::CHAIN_APPROX_SIMPLE); @@ -158,30 +137,19 @@ 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; int rightyA = B.second; int cols = rgb.cols; int rows = rgb.rows; -// pts_map1 = np.float32([[cols - 1, rightyA], [0, leftyA],[cols - 1, rightyB], [0, leftyB]]) -// pts_map2 = np.float32([[136,36],[0,36],[136,0],[0,0]]) -// mat = cv2.getPerspectiveTransform(pts_map1,pts_map2) -// image = cv2.warpPerspective(rgb,mat,(136,36),flags=cv2.INTER_CUBIC) std::vector corners(4); corners[0] = cv::Point2f(cols - 1, rightyA); corners[1] = cv::Point2f(0, leftyA); @@ -196,10 +164,7 @@ namespace pr{ cv::Mat quad = cv::Mat::zeros(36, 136, CV_8UC3); cv::warpPerspective(rgb, quad, transform, quad.size()); return quad; - } - - } diff --git a/Prj-Win/lpr/src/Pipeline.cpp b/Prj-Win/lpr/src/Pipeline.cpp index fad9e19..95ae658 100644 --- a/Prj-Win/lpr/src/Pipeline.cpp +++ b/Prj-Win/lpr/src/Pipeline.cpp @@ -1 +1,85 @@ -//// //// Created by �׽�� on 23/10/2017. //// // //#include "../include/Pipeline.h" // // //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" }; // // 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" }; // // // 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) { // 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); // } // // PipelinePR::~PipelinePR() { // // delete plateDetection; // delete fineMapping; // delete plateSegmentation; // delete generalRecognizer; // // } // // std::vector PipelinePR:: RunPiplineAsImage(cv::Mat plateImage) { // std::vector results; // std::vector plates; // plateDetection->plateDetectionRough(plateImage,plates); // // for (pr::PlateInfo plateinfo:plates) { // // cv::Mat image_finemapping = plateinfo.getPlateImage(); // image_finemapping = fineMapping->FineMappingVertical(image_finemapping); // image_finemapping = pr::fastdeskew(image_finemapping, 5); // image_finemapping = fineMapping->FineMappingHorizon(image_finemapping, 2, 5); // 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); // cv::copyMakeBorder(image_finemapping, image_finemapping, 0, 0, 0, 20, cv::BORDER_REPLICATE); // // plateinfo.setPlateImage(image_finemapping); // generalRecognizer->SegmentBasedSequenceRecognition(plateinfo); // plateinfo.decodePlateNormal(chars_code); // results.push_back(plateinfo); // std::cout << plateinfo.getPlateName() << std::endl; // // // } // //// for (auto str:results) { //// std::cout << str << std::endl; //// } // return results; // // }//namespace pr // // // //} \ No newline at end of file +// +// Created by Jack Yu on 23/10/2017. +// + +#include "../include/Pipeline.h" + + +namespace pr { + + + + 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 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() { + + delete plateDetection; + delete fineMapping; + delete plateSegmentation; + delete generalRecognizer; + delete segmentationFreeRecognizer; + + + } + + std::vector PipelinePR:: RunPiplineAsImage(cv::Mat plateImage,int method) { + std::vector results; + std::vector 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); + + + + //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)); + plateinfo.setPlateImage(image_finemapping); + std::vector rects; + 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); + + } + //Segmentation-free + else if(method==SEGMENTATION_FREE_METHOD) + { + image_finemapping = fineMapping->FineMappingHorizon(image_finemapping, 4, HorizontalPadding+3); + cv::resize(image_finemapping, image_finemapping, cv::Size(136+HorizontalPadding, 36)); + plateinfo.setPlateImage(image_finemapping); + std::pair res = segmentationFreeRecognizer->SegmentationFreeForSinglePlate(plateinfo.getPlateImage(),pr::CH_PLATE_CODE); + plateinfo.confidence = res.second; + plateinfo.setPlateName(res.first); + } + results.push_back(plateinfo); + } + + return results; + + }//namespace pr + + + +} diff --git a/Prj-Win/lpr/src/PlateDetection.cpp b/Prj-Win/lpr/src/PlateDetection.cpp index b207190..a25f4db 100644 --- a/Prj-Win/lpr/src/PlateDetection.cpp +++ b/Prj-Win/lpr/src/PlateDetection.cpp @@ -1,45 +1,24 @@ -// -// Created by 庾金科 on 20/09/2017. -// #include "../include/PlateDetection.h" - #include "util.h" - namespace pr{ - - PlateDetection::PlateDetection(std::string filename_cascade){ cascade.load(filename_cascade); }; - - void PlateDetection::plateDetectionRough(cv::Mat InputImage,std::vector &plateInfos,int min_w,int max_w){ - cv::Mat processImage; - - cv::cvtColor(InputImage,processImage,cv::COLOR_BGR2GRAY); - - + cv::cvtColor(InputImage,processImage,cv::COLOR_BGR2GRAY); std::vector platesRegions; -// std::vector plates; cv::Size minSize(min_w,min_w/4); cv::Size maxSize(max_w,max_w/4); -// cv::imshow("input",InputImage); -// cv::waitKey(0); cascade.detectMultiScale( processImage, platesRegions, 1.1, 3, cv::CASCADE_SCALE_IMAGE,minSize,maxSize); for(auto plate:platesRegions) { - // extend rects -// x -= w * 0.14 -// 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; @@ -50,12 +29,4 @@ namespace pr{ } } -// std::vector PlateDetection::plateDetectionRough(cv::Mat InputImage,cv::Rect roi,int min_w,int max_w){ -// cv::Mat roi_region = util::cropFromImage(InputImage,roi); -// return plateDetectionRough(roi_region,min_w,max_w); -// } - - - - }//namespace pr diff --git a/Prj-Win/lpr/src/PlateSegmentation.cpp b/Prj-Win/lpr/src/PlateSegmentation.cpp index 94da476..6c454e5 100644 --- a/Prj-Win/lpr/src/PlateSegmentation.cpp +++ b/Prj-Win/lpr/src/PlateSegmentation.cpp @@ -1,5 +1,5 @@ // -// Created by 庾金科 on 16/10/2017. +// Created by Jack Yu on 16/10/2017. // #include "../include/PlateSegmentation.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> contours; cv::findContours(roi_thres,contours,cv::RETR_LIST,cv::CHAIN_APPROX_SIMPLE); @@ -110,7 +110,7 @@ namespace pr{ cv::Rect bdbox = cv::boundingRect(contour); cv::Point center(bdbox.x+(bdbox.width>>1),bdbox.y + (bdbox.height>>1)); int dist = (center.x - boxCenter.x)*(center.x - boxCenter.x); - if(dist rows>>1) + if(dist rows>>1) { final_dist =dist; final_center = center; final_bdbox = bdbox; @@ -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++ ){ @@ -246,13 +246,10 @@ namespace pr{ if(cp7_p5>=cols) 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]); -// 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]); - - - +// 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]); + 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) { @@ -284,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); @@ -348,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; - cv::Mat code_table= recognizeCharacter(char_instance.second); - res.first = char_instance.first; - code_table.copyTo(res.second); - plateinfo.appendPlateCoding(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); + } } - - - } -} \ No newline at end of file +} diff --git a/Prj-Win/lpr/src/SegmentationFreeRecognizer.cpp b/Prj-Win/lpr/src/SegmentationFreeRecognizer.cpp new file mode 100644 index 0000000..369f63b --- /dev/null +++ b/Prj-Win/lpr/src/SegmentationFreeRecognizer.cpp @@ -0,0 +1,89 @@ +// +// Created by Jack Yu 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::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 (seq_decode_res.size()>1 && 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]]; + } + return name; + } + std::pair 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); + } +} diff --git a/Prj-Win/lpr/src/util.h b/Prj-Win/lpr/src/util.h index 76a452f..67e21ce 100644 --- a/Prj-Win/lpr/src/util.h +++ b/Prj-Win/lpr/src/util.h @@ -1,20 +1,16 @@ // -// Created by 庾金科 on 04/04/2017. +// Created by Jack Yu on 04/04/2017. // #include - namespace util{ - template void swap ( T& a, T& b ) { T c(a); a=b; b=c; } - template T min(T& a,T& b ) { return a>b?b:a; - } cv::Mat cropFromImage(const cv::Mat &image,cv::Rect rect){ @@ -57,23 +53,16 @@ namespace util{ int histSize = 256; float range[] = {0,255}; const float* histRange = {range}; - cv::calcHist( &hsv_planes[0], 1, 0, cv::Mat(), hist, 1, &histSize, &histRange,true, true); return hist; - } + float computeSimilir(const cv::Mat &A,const cv::Mat &B) { - cv::Mat histA,histB; histA = calcHist(A); histB = calcHist(B); - return cv::compareHist(histA,histB,CV_COMP_CORREL); - +// return cv::compareHist(histA,histB,CV_COMP_CORREL); + return cv::compareHist(histA, histB, 0); } - - - - - }//namespace util diff --git a/Prj-Win/lpr/tests/test_fastdeskew.cpp b/Prj-Win/lpr/tests/test_fastdeskew.cpp index faa0d93..3740147 100644 --- a/Prj-Win/lpr/tests/test_fastdeskew.cpp +++ b/Prj-Win/lpr/tests/test_fastdeskew.cpp @@ -1,5 +1,5 @@ // -// Created by 庾金科 on 02/10/2017. +// Created by Jack Yu on 02/10/2017. // diff --git a/Prj-Win/lpr/tests/test_finemapping.cpp b/Prj-Win/lpr/tests/test_finemapping.cpp index 4893efd..dd7e26f 100644 --- a/Prj-Win/lpr/tests/test_finemapping.cpp +++ b/Prj-Win/lpr/tests/test_finemapping.cpp @@ -1,5 +1,5 @@ // -// Created by 庾金科 on 24/09/2017. +// Created by Jack Yu on 24/09/2017. // #include "FineMapping.h" @@ -22,4 +22,4 @@ int main() return 0 ; -} \ No newline at end of file +} diff --git a/Prj-Win/lpr/tests/test_pipeline.cpp b/Prj-Win/lpr/tests/test_pipeline.cpp index fccdf1f..647cbe7 100644 --- a/Prj-Win/lpr/tests/test_pipeline.cpp +++ b/Prj-Win/lpr/tests/test_pipeline.cpp @@ -1,42 +1,229 @@ -// -// Created by 庾金科 on 23/10/2017. +// +// Created by Jack Yu on 23/10/2017. // #include "../include/Pipeline.h" -using namespace pr; +#include +#include -void TEST_PIPELINE(){ - pr::PipelinePR prc("../lpr/model/cascade.xml", - "../lpr/model/HorizonalFinemapping.prototxt","../lpr/model/HorizonalFinemapping.caffemodel", - "../lpr/model/Segmentation.prototxt","../lpr/model/Segmentation.caffemodel", - "../lpr/model/CharacterRecognization.prototxt","../lpr/model/CharacterRecognization.caffemodel" - ); - cv::Mat image = cv::imread("../6.jpg"); - cv::imshow("image",image); - cv::waitKey(0); +using namespace std; - std::vector res = prc.RunPiplineAsImage(image); - float conf = 0 ; - for(auto st:res) { - if(st.confidence>0.1) { - std::cout << st.getPlateName() << " " << st.confidence << std::endl; - conf += st.confidence; - } - } - std::cout< +static unsigned int levenshtein_distance(const T &s1, const T &s2) { + const size_t len1 = s1.size(), len2 = s2.size(); + std::vector col(len2 + 1), prevCol(len2 + 1); + for (unsigned int i = 0; i < prevCol.size(); i++) prevCol[i] = i; + for (unsigned int i = 0; i < len1; i++) { + col[0] = i + 1; + for (unsigned int j = 0; j < len2; j++) + col[j + 1] = min( + min(prevCol[1 + j] + 1, col[j] + 1), + prevCol[j] + (s1[i] == s2[j] ? 0 : 1)); + col.swap(prevCol); + } + return prevCol[len2]; } -int main() + + +void TEST_CAM() { + cv::VideoCapture capture("test1.mp4"); + cv::Mat frame; + pr::PipelinePR prc("../lpr/model/cascade.xml", + "../lpr/model/HorizonalFinemapping.prototxt", "../lpr/model/HorizonalFinemapping.caffemodel", + "../lpr/model/Segmentation.prototxt", "../lpr/model/Segmentation.caffemodel", + "../lpr/model/CharacterRecognization.prototxt", "../lpr/model/CharacterRecognization.caffemodel", + "../lpr/model/SegmentationFree.prototxt", "../lpr/model/SegmentationFree.caffemodel" + ); + while (1) { + //读取下一帧 + if (!capture.read(frame)) { + std::cout << "读取视频失败" << std::endl; + exit(1); + } + // + // cv::transpose(frame,frame); + // cv::flip(frame,frame,2); + + // cv::resize(frame,frame,cv::Size(frame.cols/2,frame.rows/2)); + + + std::vector res = prc.RunPiplineAsImage(frame, pr::SEGMENTATION_FREE_METHOD); + + for (auto st : res) { + if (st.confidence > 0.75) { + std::cout << st.getPlateName() << " " << st.confidence << std::endl; + cv::Rect region = st.getPlateRect(); + + cv::rectangle(frame, 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", frame); + cv::waitKey(1); + } +} + + +void TEST_ACC() { + + pr::PipelinePR prc("../lpr/model/cascade.xml", + "../lpr/model/HorizonalFinemapping.prototxt", "../lpr/model/HorizonalFinemapping.caffemodel", + "../lpr/model/Segmentation.prototxt", "../lpr/model/Segmentation.caffemodel", + "../lpr/model/CharacterRecognization.prototxt", "../lpr/model/CharacterRecognization.caffemodel", + "../lpr/model/SegmentationFree.prototxt", "../lpr/model/SegmentationFree.caffemodel" + ); + + ifstream file; + string imagename; + int n = 0, correct = 0, j = 0, sum = 0; + char filename[] = "/Users/yujinke/Downloads/general_test/1.txt"; + string pathh = "/Users/yujinke/Downloads/general_test/"; + file.open(filename, ios::in); + while (!file.eof()) + { + file >> imagename; + string imgpath = pathh + imagename; + std::cout << "------------------------------------------------" << endl; + cout << "图片名:" << imagename << endl; + cv::Mat image = cv::imread(imgpath); + // cv::imshow("image", image); + // cv::waitKey(0); + + std::vector res = prc.RunPiplineAsImage(image, pr::SEGMENTATION_FREE_METHOD); + + float conf = 0; + vector con; + vector name; + for (auto st : res) { + if (st.confidence > 0.1) { + //std::cout << st.getPlateName() << " " << st.confidence << std::endl; + con.push_back(st.confidence); + name.push_back(st.getPlateName()); + //conf += st.confidence; + } + else + cout << "no string" << endl; + } + // std::cout << conf << std::endl; + int num = con.size(); + float max = 0; + string platestr, chpr, ch; + int diff = 0, dif = 0; + for (int i = 0; i < num; i++) { + + if (con.at(i) > max) + { + max = con.at(i); + platestr = name.at(i); + } + + } + // cout << "max:"< res = prc.RunPiplineAsImage(image, pr::SEGMENTATION_FREE_METHOD); + for (auto st : res) { + if (st.confidence > 0.75) { + std::cout << st.getPlateName() << " " << st.confidence << std::endl; + cv::Rect region = st.getPlateRect(); -} \ No newline at end of file + 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); + +} + + + + +/*void TEST_CAM() +{ + + cv::VideoCapture capture("test1.mp4"); + cv::Mat frame; + + pr::PipelinePR prc("../lpr/model/cascade.xml", + "../lpr/model/HorizonalFinemapping.prototxt", "../lpr/model/HorizonalFinemapping.caffemodel", + "../lpr/model/Segmentation.prototxt", "../lpr/model/Segmentation.caffemodel", + "../lpr/model/CharacterRecognization.prototxt", "../lpr/model/CharacterRecognization.caffemodel", + "../lpr/model/SegmentationFree.prototxt", "../lpr/model/SegmentationFree.caffemodel" + ); + while (1) { + //读取下一帧 + if (!capture.read(frame)) { + std::cout << "读取视频失败" << std::endl; + exit(1); + } + // + // cv::transpose(frame,frame); + // cv::flip(frame,frame,2); + + // cv::resize(frame,frame,cv::Size(frame.cols/2,frame.rows/2)); + + + + std::vector res = prc.RunPiplineAsImage(frame, pr::SEGMENTATION_FREE_METHOD); + + for (auto st : res) { + if (st.confidence > 0.75) { + std::cout << st.getPlateName() << " " << st.confidence << std::endl; + cv::Rect region = st.getPlateRect(); + + cv::rectangle(frame, 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", frame); + cv::waitKey(1); + } +}*/ + + +int main() +{ + // TEST_ACC(); + + // TEST_CAM(); + TEST_PIPELINE(); + return 0; +} diff --git a/Prj-Win/lpr/tests/test_recognization.cpp b/Prj-Win/lpr/tests/test_recognization.cpp index 6d6fe84..9244f95 100644 --- a/Prj-Win/lpr/tests/test_recognization.cpp +++ b/Prj-Win/lpr/tests/test_recognization.cpp @@ -1,5 +1,5 @@ // -// Created by 庾金科 on 23/10/2017. +// Created by Jack Yu on 23/10/2017. // #include "../include/CNNRecognizer.h" @@ -16,6 +16,7 @@ void getMaxClass(cv::Mat &probBlob, int *classId, double *classProb) cv::Point classNumber; cv::minMaxLoc(probBlob, NULL, classProb, NULL, &classNumber); + *classId = classNumber.x; } diff --git a/Prj-Win/lpr/tests/test_segmentation.cpp b/Prj-Win/lpr/tests/test_segmentation.cpp index e903636..b379406 100644 --- a/Prj-Win/lpr/tests/test_segmentation.cpp +++ b/Prj-Win/lpr/tests/test_segmentation.cpp @@ -1,5 +1,5 @@ // -// Created by 庾金科 on 16/10/2017. +// Created by Jack Yu on 16/10/2017. // @@ -40,4 +40,4 @@ int main(){ TEST_SLIDINGWINDOWS_EVAL(); return 0; -} \ No newline at end of file +} diff --git a/Prj-Win/lpr/tests/test_segmentationFree.cpp b/Prj-Win/lpr/tests/test_segmentationFree.cpp new file mode 100644 index 0000000..4f948d2 --- /dev/null +++ b/Prj-Win/lpr/tests/test_segmentationFree.cpp @@ -0,0 +1,54 @@ +// +// Created by Jack Yu on 29/11/2017. +// +#include "../include/SegmentationFreeRecognizer.h" +#include "../include/Pipeline.h" + +#include "../include/PlateInfo.h" + + + +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< res = recognizr.SegmentationFreeForSinglePlate(image,pr::CH_PLATE_CODE); + std::cout<