You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

PlateSegmentation.cpp 13 kB

7 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. //
  2. // Created by 庾金科 on 16/10/2017.
  3. //
  4. #include "PlateSegmentation.h"
  5. #include "niBlackThreshold.h"
  6. //#define DEBUG
  7. namespace pr{
  8. PlateSegmentation::PlateSegmentation(std::string prototxt,std::string caffemodel) {
  9. net = cv::dnn::readNetFromCaffe(prototxt, caffemodel);
  10. }
  11. cv::Mat PlateSegmentation::classifyResponse(const cv::Mat &cropped){
  12. cv::Mat inputBlob = cv::dnn::blobFromImage(cropped, 1/255.0, cv::Size(22,22), cv::Scalar(0,0,0),false);
  13. net.setInput(inputBlob,"data");
  14. return net.forward();
  15. }
  16. void drawHist(float* seq,int size,const char* name){
  17. cv::Mat image(300,size,CV_8U);
  18. image.setTo(0);
  19. float* start =seq;
  20. float* end = seq+size;
  21. float l = *std::max_element(start,end);
  22. for(int i = 0;i<size;i++)
  23. {
  24. int p = int(float(seq[i])/l*300);
  25. cv::line(image,cv::Point(i,300),cv::Point(i,300-p),cv::Scalar(255,255,255));
  26. }
  27. cv::resize(image,image,cv::Size(600,100));
  28. cv::imshow(name,image);
  29. }
  30. inline void computeSafeMargin(int &val,const int &rows){
  31. val = std::min(val,rows);
  32. val = std::max(val,0);
  33. }
  34. cv::Rect boxFromCenter(const cv::Point center,int left,int right,int top,int bottom,cv::Size bdSize)
  35. {
  36. cv::Point p1(center.x - left ,center.y - top);
  37. cv::Point p2( center.x + right, center.y + bottom);
  38. p1.x = std::max(0,p1.x);
  39. p1.y = std::max(0,p1.y);
  40. p2.x = std::min(p2.x,bdSize.width-1);
  41. p2.y = std::min(p2.y,bdSize.height-1);
  42. cv::Rect rect(p1,p2);
  43. return rect;
  44. }
  45. cv::Rect boxPadding(cv::Rect rect,int left,int right,int top,int bottom,cv::Size bdSize)
  46. {
  47. cv::Point center(rect.x+(rect.width>>1),rect.y + (rect.height>>1));
  48. int rebuildLeft = (rect.width>>1 )+ left;
  49. int rebuildRight = (rect.width>>1 )+ right;
  50. int rebuildTop = (rect.height>>1 )+ top;
  51. int rebuildBottom = (rect.height>>1 )+ bottom;
  52. return boxFromCenter(center,rebuildLeft,rebuildRight,rebuildTop,rebuildBottom,bdSize);
  53. }
  54. void PlateSegmentation:: refineRegion(cv::Mat &plateImage,const std::vector<int> &candidatePts,const int padding,std::vector<cv::Rect> &rects){
  55. int w = candidatePts[5] - candidatePts[4];
  56. int cols = plateImage.cols;
  57. int rows = plateImage.rows;
  58. for(int i = 0 ; i < candidatePts.size() ; i++)
  59. {
  60. int left = 0;
  61. int right = 0 ;
  62. if(i == 0 ){
  63. left= candidatePts[i];
  64. right = left+w+padding;
  65. }
  66. else {
  67. left = candidatePts[i] - padding;
  68. right = left + w + padding * 2;
  69. }
  70. computeSafeMargin(right,cols);
  71. computeSafeMargin(left,cols);
  72. cv::Rect roi(left,0,right - left,rows-1);
  73. cv::Mat roiImage;
  74. plateImage(roi).copyTo(roiImage);
  75. if (i>=1)
  76. {
  77. cv::Mat roi_thres;
  78. // cv::threshold(roiImage,roi_thres,0,255,cv::THRESH_OTSU|cv::THRESH_BINARY);
  79. niBlackThreshold(roiImage,roi_thres,255,cv::THRESH_BINARY,15,0.27,BINARIZATION_NIBLACK);
  80. std::vector<std::vector<cv::Point>> contours;
  81. cv::findContours(roi_thres,contours,cv::RETR_LIST,cv::CHAIN_APPROX_SIMPLE);
  82. cv::Point boxCenter(roiImage.cols>>1,roiImage.rows>>1);
  83. cv::Rect final_bdbox;
  84. cv::Point final_center;
  85. int final_dist = INT_MAX;
  86. for(auto contour:contours)
  87. {
  88. cv::Rect bdbox = cv::boundingRect(contour);
  89. cv::Point center(bdbox.x+(bdbox.width>>1),bdbox.y + (bdbox.height>>1));
  90. int dist = (center.x - boxCenter.x)*(center.x - boxCenter.x);
  91. if(dist<final_dist and bdbox.height > rows>>1)
  92. { final_dist =dist;
  93. final_center = center;
  94. final_bdbox = bdbox;
  95. }
  96. }
  97. //rebuild box
  98. if(final_bdbox.height/ static_cast<float>(final_bdbox.width) > 3.5 && final_bdbox.width*final_bdbox.height<10)
  99. final_bdbox = boxFromCenter(final_center,8,8,(rows>>1)-3 , (rows>>1) - 2,roiImage.size());
  100. else {
  101. if(i == candidatePts.size()-1)
  102. final_bdbox = boxPadding(final_bdbox, padding/2, padding, padding/2, padding/2, roiImage.size());
  103. else
  104. final_bdbox = boxPadding(final_bdbox, padding, padding, padding, padding, roiImage.size());
  105. // std::cout<<final_bdbox<<std::endl;
  106. // std::cout<<roiImage.size()<<std::endl;
  107. #ifdef DEBUG
  108. cv::imshow("char_thres",roi_thres);
  109. cv::imshow("char",roiImage(final_bdbox));
  110. cv::waitKey(0);
  111. #endif
  112. }
  113. final_bdbox.x += left;
  114. rects.push_back(final_bdbox);
  115. //
  116. }
  117. else
  118. {
  119. rects.push_back(roi);
  120. }
  121. // else
  122. // {
  123. //
  124. // }
  125. // cv::GaussianBlur(roiImage,roiImage,cv::Size(7,7),3);
  126. //
  127. // cv::imshow("image",roiImage);
  128. // cv::waitKey(0);
  129. }
  130. }
  131. void avgfilter(float *angle_list,int size,int windowsSize) {
  132. float *filterd = new float[size];
  133. for(int i = 0 ; i < size ; i++) filterd [i] = angle_list[i];
  134. // memcpy(filterd,angle_list,size);
  135. cv::Mat kernal_gaussian = cv::getGaussianKernel(windowsSize,3,CV_32F);
  136. float *kernal = (float*)kernal_gaussian.data;
  137. // kernal+=windowsSize;
  138. int r = windowsSize/2;
  139. for (int i = 0; i < size; i++) {
  140. float avg = 0.00f;
  141. for (int j = 0; j < windowsSize; j++) {
  142. if(i+j-r>0&&i+j+r<size-1)
  143. avg += filterd[i + j-r]*kernal[j];
  144. }
  145. // avg = avg / windowsSize;
  146. angle_list[i] = avg;
  147. }
  148. delete filterd;
  149. }
  150. void PlateSegmentation::templateMatchFinding(const cv::Mat &respones,int windowsWidth,std::pair<float,std::vector<int>> &candidatePts){
  151. int rows = respones.rows;
  152. int cols = respones.cols;
  153. float *data = (float*)respones.data;
  154. float *engNum_prob = data;
  155. float *false_prob = data+cols;
  156. float *ch_prob = data+cols*2;
  157. avgfilter(engNum_prob,cols,5);
  158. avgfilter(false_prob,cols,5);
  159. // avgfilter(ch_prob,cols,5);
  160. std::vector<int> candidate_pts(7);
  161. #ifdef DEBUG
  162. drawHist(engNum_prob,cols,"engNum_prob");
  163. drawHist(false_prob,cols,"false_prob");
  164. drawHist(ch_prob,cols,"ch_prob");
  165. cv::waitKey(0);
  166. #endif
  167. int cp_list[7];
  168. float loss_selected = -10;
  169. for(int start = 0 ; start < 20 ; start+=2)
  170. for(int width = windowsWidth-5; width < windowsWidth+5 ; width++ ){
  171. for(int interval = windowsWidth/2; interval < windowsWidth; interval++)
  172. {
  173. int cp1_ch = start;
  174. int cp2_p0 = cp1_ch+ width;
  175. int cp3_p1 = cp2_p0+ width + interval;
  176. int cp4_p2 = cp3_p1 + width;
  177. int cp5_p3 = cp4_p2 + width+1;
  178. int cp6_p4 = cp5_p3 + width+2;
  179. int cp7_p5= cp6_p4+ width+2;
  180. int md1 = (cp1_ch+cp2_p0)>>1;
  181. int md2 = (cp2_p0+cp3_p1)>>1;
  182. int md3 = (cp3_p1+cp4_p2)>>1;
  183. int md4 = (cp4_p2+cp5_p3)>>1;
  184. int md5 = (cp5_p3+cp6_p4)>>1;
  185. int md6 = (cp6_p4+cp7_p5)>>1;
  186. if(cp7_p5>=cols)
  187. continue;
  188. // float loss = ch_prob[cp1_ch]+
  189. // engNum_prob[cp2_p0] +engNum_prob[cp3_p1]+engNum_prob[cp4_p2]+engNum_prob[cp5_p3]+engNum_prob[cp6_p4] +engNum_prob[cp7_p5]
  190. // + (false_prob[md2]+false_prob[md3]+false_prob[md4]+false_prob[md5]+false_prob[md5] + false_prob[md6]);
  191. 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]);
  192. if(loss>loss_selected)
  193. {
  194. loss_selected = loss;
  195. cp_list[0]= cp1_ch;
  196. cp_list[1]= cp2_p0;
  197. cp_list[2]= cp3_p1;
  198. cp_list[3]= cp4_p2;
  199. cp_list[4]= cp5_p3;
  200. cp_list[5]= cp6_p4;
  201. cp_list[6]= cp7_p5;
  202. }
  203. }
  204. }
  205. candidate_pts[0] = cp_list[0];
  206. candidate_pts[1] = cp_list[1];
  207. candidate_pts[2] = cp_list[2];
  208. candidate_pts[3] = cp_list[3];
  209. candidate_pts[4] = cp_list[4];
  210. candidate_pts[5] = cp_list[5];
  211. candidate_pts[6] = cp_list[6];
  212. candidatePts.first = loss_selected;
  213. candidatePts.second = candidate_pts;
  214. };
  215. void PlateSegmentation::segmentPlateBySlidingWindows(cv::Mat &plateImage,int windowsWidth,int stride,cv::Mat &respones){
  216. // cv::resize(plateImage,plateImage,cv::Size(136,36));
  217. cv::Mat plateImageGray;
  218. cv::cvtColor(plateImage,plateImageGray,cv::COLOR_BGR2GRAY);
  219. int padding = plateImage.cols-136 ;
  220. // int padding = 0 ;
  221. int height = plateImage.rows - 1;
  222. int width = plateImage.cols - 1 - padding;
  223. for(int i = 0 ; i < width - windowsWidth +1 ; i +=stride)
  224. {
  225. cv::Rect roi(i,0,windowsWidth,height);
  226. cv::Mat roiImage = plateImageGray(roi);
  227. cv::Mat response = classifyResponse(roiImage);
  228. respones.push_back(response);
  229. }
  230. respones = respones.t();
  231. // std::pair<float,std::vector<int>> images ;
  232. //
  233. //
  234. // std::cout<<images.first<<" ";
  235. // for(int i = 0 ; i < images.second.size() ; i++)
  236. // {
  237. // std::cout<<images.second[i]<<" ";
  238. //// cv::line(plateImageGray,cv::Point(images.second[i],0),cv::Point(images.second[i],36),cv::Scalar(255,255,255),1); //DEBUG
  239. // }
  240. // int w = images.second[5] - images.second[4];
  241. // cv::line(plateImageGray,cv::Point(images.second[5]+w,0),cv::Point(images.second[5]+w,36),cv::Scalar(255,255,255),1); //DEBUG
  242. // cv::line(plateImageGray,cv::Point(images.second[5]+2*w,0),cv::Point(images.second[5]+2*w,36),cv::Scalar(255,255,255),1); //DEBUG
  243. // RefineRegion(plateImageGray,images.second,5);
  244. // std::cout<<w<<std::endl;
  245. // std::cout<<<<std::endl;
  246. // cv::resize(plateImageGray,plateImageGray,cv::Size(600,100));
  247. }
  248. // void filterGaussian(cv::Mat &respones,float sigma){
  249. //
  250. // }
  251. void PlateSegmentation::segmentPlatePipline(PlateInfo &plateInfo,int stride,std::vector<cv::Rect> &Char_rects){
  252. cv::Mat plateImage = plateInfo.getPlateImage(); // get src image .
  253. cv::Mat plateImageGray;
  254. cv::cvtColor(plateImage,plateImageGray,cv::COLOR_BGR2GRAY);
  255. //do binarzation
  256. //
  257. std::pair<float,std::vector<int>> sections ; // segment points variables .
  258. cv::Mat respones; //three response of every sub region from origin image .
  259. segmentPlateBySlidingWindows(plateImage,DEFAULT_WIDTH,1,respones);
  260. templateMatchFinding(respones,DEFAULT_WIDTH/stride,sections);
  261. for(int i = 0; i < sections.second.size() ; i++)
  262. {
  263. sections.second[i]*=stride;
  264. }
  265. // std::cout<<sections<<std::endl;
  266. refineRegion(plateImageGray,sections.second,5,Char_rects);
  267. #ifdef DEBUG
  268. for(int i = 0 ; i < sections.second.size() ; i++)
  269. {
  270. std::cout<<sections.second[i]<<" ";
  271. cv::line(plateImageGray,cv::Point(sections.second[i],0),cv::Point(sections.second[i],36),cv::Scalar(255,255,255),1); //DEBUG
  272. }
  273. cv::imshow("plate",plateImageGray);
  274. cv::waitKey(0);
  275. #endif
  276. // cv::waitKey(0);
  277. }
  278. void PlateSegmentation::ExtractRegions(PlateInfo &plateInfo,std::vector<cv::Rect> &rects){
  279. cv::Mat plateImage = plateInfo.getPlateImage();
  280. for(int i = 0 ; i < rects.size() ; i++){
  281. cv::Mat charImage;
  282. plateImage(rects[i]).copyTo(charImage);
  283. if(charImage.channels())
  284. cv::cvtColor(charImage,charImage,cv::COLOR_BGR2GRAY);
  285. // cv::imshow("image",charImage);
  286. // cv::waitKey(0);
  287. cv::equalizeHist(charImage,charImage);
  288. //
  289. //
  290. std::pair<CharType,cv::Mat> char_instance;
  291. if(i == 0 ){
  292. char_instance.first = CHINESE;
  293. } else if(i == 1){
  294. char_instance.first = LETTER;
  295. }
  296. else{
  297. char_instance.first = LETTER_NUMS;
  298. }
  299. char_instance.second = charImage;
  300. plateInfo.appendPlateChar(char_instance);
  301. }
  302. }
  303. }//namespace pr