diff --git a/src/core/chars_segment.cpp b/src/core/chars_segment.cpp index 5265585..c40d38e 100644 --- a/src/core/chars_segment.cpp +++ b/src/core/chars_segment.cpp @@ -7,8 +7,8 @@ namespace easypr { -const float DEFAULT_BLUEPERCEMT = 0.3f;//定义蓝色百分比 -const float DEFAULT_WHITEPERCEMT = 0.1f;//定义白色百分比 +const float DEFAULT_BLUEPERCEMT = 0.3f;//瀹氫箟钃濊壊鐧惧垎姣 +const float DEFAULT_WHITEPERCEMT = 0.1f;//瀹氫箟鐧借壊鐧惧垎姣 CCharsSegment::CCharsSegment() { m_LiuDingSize = DEFAULT_LIUDING_SIZE; @@ -19,75 +19,75 @@ CCharsSegment::CCharsSegment() { m_WhitePercent = DEFAULT_WHITEPERCEMT; m_debug = DEFAULT_DEBUG; -}//设置几个类的成员变量,进行初始化 +}//璁剧疆鍑犱釜绫荤殑鎴愬憳鍙橀噺锛岃繘琛屽垵濮嬪寲 bool CCharsSegment::verifyCharSizes(Mat r) { // Char sizes 45x90 - //接收一个OpenCV的Mat对象作为参数,将其赋值给r - float aspect = 45.0f / 90.0f;//预期的字符宽高比 + //鎺ユ敹涓涓狾penCV鐨凪at瀵硅薄浣滀负鍙傛暟锛屽皢鍏惰祴鍊肩粰r + float aspect = 45.0f / 90.0f;//棰勬湡鐨勫瓧绗﹀楂樻瘮 float charAspect = (float)r.cols / (float)r.rows; - //输入图像的宽高比,通过计算输入图像的列数和行数得出。 - float error = 0.7f;//允许的宽高比误差 - float minHeight = 10.f;//字符最小高度 - float maxHeight = 35.f;//字符最大高度 + //杈撳叆鍥惧儚鐨勫楂樻瘮锛岄氳繃璁$畻杈撳叆鍥惧儚鐨勫垪鏁板拰琛屾暟寰楀嚭銆 + float error = 0.7f;//鍏佽鐨勫楂樻瘮璇樊 + float minHeight = 10.f;//瀛楃鏈灏忛珮搴 + float maxHeight = 35.f;//瀛楃鏈澶ч珮搴 // We have a different aspect ratio for number 1, and it can be ~0.2 - float minAspect = 0.05f//最小允许宽高比 + float minAspect = 0.05f//鏈灏忓厑璁稿楂樻瘮 float maxAspect = aspect + aspect * error - //最大允许宽高比,由预期的宽高比加上其误差得出 + //鏈澶у厑璁稿楂樻瘮锛岀敱棰勬湡鐨勫楂樻瘮鍔犱笂鍏惰宸緱鍑 // area of pixels int area = cv::countNonZero(r); - // 输入图像的非零像素数 + // 杈撳叆鍥惧儚鐨勯潪闆跺儚绱犳暟 int bbArea = r.cols * r.rows; //% of pixel in area - //输入图像的总面积,通过乘以其列数和行数得出 + //杈撳叆鍥惧儚鐨勬婚潰绉紝閫氳繃涔樹互鍏跺垪鏁板拰琛屾暟寰楀嚭 int percPixels = area / bbArea; - //非零像素数在总面积中的比例 + //闈為浂鍍忕礌鏁板湪鎬婚潰绉腑鐨勬瘮渚 if (percPixels <= 1 && charAspect > minAspect && charAspect < maxAspect && r.rows >= minHeight && r.rows < maxHeight) return true; else return false; -}//判断输入图像是否可以被视为一个字符,满足特定的字符尺寸和形状要求 +}//鍒ゆ柇杈撳叆鍥惧儚鏄惁鍙互琚涓轰竴涓瓧绗︼紝婊¤冻鐗瑰畾鐨勫瓧绗﹀昂瀵稿拰褰㈢姸瑕佹眰 Mat CCharsSegment::preprocessChar(Mat in) { // Remap image - //接收一个Mat对象作为输入,它对输入的图像进行一些预处理操作。 + //鎺ユ敹涓涓狹at瀵硅薄浣滀负杈撳叆锛屽畠瀵硅緭鍏ョ殑鍥惧儚杩涜涓浜涢澶勭悊鎿嶄綔銆 int h = in.rows; int w = in.cols; - //获取输入图像的高度和宽度 + //鑾峰彇杈撳叆鍥惧儚鐨勯珮搴﹀拰瀹藉害 int charSize = CHAR_SIZE; Mat transformMat = Mat::eye(2, 3, CV_32F); - //定义一个2x3的单位矩阵作为变换矩阵,这个矩阵用于图像的几何变换。 + //瀹氫箟涓涓2x3鐨勫崟浣嶇煩闃典綔涓哄彉鎹㈢煩闃碉紝杩欎釜鐭╅樀鐢ㄤ簬鍥惧儚鐨勫嚑浣曞彉鎹€ int m = max(w, h); transformMat.at(0, 2) = float(m / 2 - w / 2); transformMat.at(1, 2) = float(m / 2 - h / 2); - //根据输入图像的最大尺寸,调整变换矩阵的中央值, - // 以便将图像中心置于新图像的中心。 + //鏍规嵁杈撳叆鍥惧儚鐨勬渶澶у昂瀵革紝璋冩暣鍙樻崲鐭╅樀鐨勪腑澶硷紝 + // 浠ヤ究灏嗗浘鍍忎腑蹇冪疆浜庢柊鍥惧儚鐨勪腑蹇冦 Mat warpImage(m, m, in.type()); warpAffine(in, warpImage, transformMat, warpImage.size(), INTER_LINEAR, BORDER_CONSTANT, Scalar(0)); Mat out; - //warpAffine函数应用仿射变换,生成新的变换后的图像。 + //warpAffine鍑芥暟搴旂敤浠垮皠鍙樻崲锛岀敓鎴愭柊鐨勫彉鎹㈠悗鐨勫浘鍍忋 resize(warpImage, out, Size(charSize, charSize)); - //resize函数调整新图像的尺寸至预设的字符大小。 + //resize鍑芥暟璋冩暣鏂板浘鍍忕殑灏哄鑷抽璁剧殑瀛楃澶у皬銆 return out; } //! choose the bese threshold method for chinese void CCharsSegment::judgeChinese(Mat in, Mat& out, Color plateType) -{ //接收一个Mat对象作为输入,并对其进行阈值处理以识别中文字符 +{ //鎺ユ敹涓涓狹at瀵硅薄浣滀负杈撳叆锛屽苟瀵瑰叾杩涜闃堝煎鐞嗕互璇嗗埆涓枃瀛楃 Mat auxRoi = in; - //表示输入图像的一个子区域,其中可能包含要识别的中文字符 + //琛ㄧず杈撳叆鍥惧儚鐨勪竴涓瓙鍖哄煙锛屽叾涓彲鑳藉寘鍚璇嗗埆鐨勪腑鏂囧瓧绗 float valOstu = -1.f, valAdap = -1.f; Mat roiOstu, roiAdap; - //为Otsu阈值法和自适应阈值法分别定义了一个变量valOstu和valAdap, - // 用于存储阈值 + //涓篛tsu闃堝兼硶鍜岃嚜閫傚簲闃堝兼硶鍒嗗埆瀹氫箟浜嗕竴涓彉閲弙alOstu鍜寁alAdap锛 + // 鐢ㄤ簬瀛樺偍闃堝 bool isChinese = true; if (1) { if (BLUE == plateType) { @@ -102,23 +102,23 @@ void CCharsSegment::judgeChinese(Mat in, Mat& out, Color plateType) else { threshold(auxRoi, roiOstu, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY); } - //根据输入的颜色类型,使用不同的阈值处理方法对auxRoi进行阈值处理 - // 生成二值化的图像roiOstu + //鏍规嵁杈撳叆鐨勯鑹茬被鍨嬶紝浣跨敤涓嶅悓鐨勯槇鍊煎鐞嗘柟娉曞auxRoi杩涜闃堝煎鐞 + // 鐢熸垚浜屽煎寲鐨勫浘鍍弐oiOstu roiOstu = preprocessChar(roiOstu); - //对二值化的图像进行字符识别预处理 - //调用preprocessChar(roiOstu)方法对图像进行进一步处理 + //瀵逛簩鍊煎寲鐨勫浘鍍忚繘琛屽瓧绗﹁瘑鍒澶勭悊 + //璋冪敤preprocessChar(roiOstu)鏂规硶瀵瑰浘鍍忚繘琛岃繘涓姝ュ鐞 if (0) { imshow("roiOstu", roiOstu); waitKey(0); destroyWindow("roiOstu"); } auto character = CharsIdentify::instance()->identifyChinese(roiOstu, valOstu, isChinese); - //对预处理后的图像进行字符识别,并返回识别的结果和阈值。 + //瀵归澶勭悊鍚庣殑鍥惧儚杩涜瀛楃璇嗗埆锛屽苟杩斿洖璇嗗埆鐨勭粨鏋滃拰闃堝笺 } if (1) { if (BLUE == plateType) { adaptiveThreshold(auxRoi, roiAdap, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 3, 0); - //调用图像处理函数对图像进行自适应阈值处理。 + //璋冪敤鍥惧儚澶勭悊鍑芥暟瀵瑰浘鍍忚繘琛岃嚜閫傚簲闃堝煎鐞嗐 } else if (YELLOW == plateType) { adaptiveThreshold(auxRoi, roiAdap, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 3, 0); @@ -130,7 +130,7 @@ void CCharsSegment::judgeChinese(Mat in, Mat& out, Color plateType) adaptiveThreshold(auxRoi, roiAdap, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 3, 0); } roiAdap = preprocessChar(roiAdap); - //对二值化后的图像进行预处理字符操作。 + //瀵逛簩鍊煎寲鍚庣殑鍥惧儚杩涜棰勫鐞嗗瓧绗︽搷浣溿 auto character = CharsIdentify::instance()->identifyChinese(roiAdap, valAdap, isChinese); } @@ -146,20 +146,20 @@ void CCharsSegment::judgeChinese(Mat in, Mat& out, Color plateType) } void CCharsSegment::judgeChineseGray(Mat in, Mat& out, Color plateType) { - out = in;//复制输入图像 + out = in;//澶嶅埗杈撳叆鍥惧儚 } bool slideChineseWindow(Mat& image, Rect mr, Mat& newRoi, Color plateType, float slideLengthRatio, bool useAdapThreshold) { std::vector charCandidateVec; - //用于存储候选的中文字符。 + //鐢ㄤ簬瀛樺偍鍊欓夌殑涓枃瀛楃銆 Rect maxrect = mr; Point tlPoint = mr.tl(); - //获取mr的左上角点,并赋值给tlPoint - bool isChinese = true;//标记图像中是否含有中文字符 + //鑾峰彇mr鐨勫乏涓婅鐐癸紝骞惰祴鍊肩粰tlPoint + bool isChinese = true;//鏍囪鍥惧儚涓槸鍚﹀惈鏈変腑鏂囧瓧绗 int slideLength = int(slideLengthRatio * maxrect.width); - int slideStep = 1;//控制滑动窗口的步长 - int fromX = 0;//指定从哪个位置开始滑动窗口 - fromX = tlPoint.x;//实际的起始位置是左上角的x坐标 + int slideStep = 1;//鎺у埗婊戝姩绐楀彛鐨勬闀 + int fromX = 0;//鎸囧畾浠庡摢涓綅缃紑濮嬫粦鍔ㄧ獥鍙 + fromX = tlPoint.x;//瀹為檯鐨勮捣濮嬩綅缃槸宸︿笂瑙掔殑x鍧愭爣 for (int slideX = -slideLength; slideX < slideLength; slideX += slideStep) { float x_slide = 0; @@ -167,21 +167,21 @@ bool slideChineseWindow(Mat& image, Rect mr, Mat& newRoi, Color plateType, float x_slide = float(fromX + slideX); float y_slide = (float)tlPoint.y; - //用来计算滑动窗口的位置。 + //鐢ㄦ潵璁$畻婊戝姩绐楀彛鐨勪綅缃 Point2f p_slide(x_slide, y_slide); //cv::circle(image, p_slide, 2, Scalar(255), 1); int chineseWidth = int(maxrect.width); int chineseHeight = int(maxrect.height); - //宽度和高度 + //瀹藉害鍜岄珮搴 Rect rect(Point2f(x_slide, y_slide), Size(chineseWidth, chineseHeight)); if (rect.tl().x < 0 || rect.tl().y < 0 || rect.br().x >= image.cols || rect.br().y >= image.rows) continue; - //检查新定义的矩形区域是否在图像的边界内。如果超出了边界,就跳过这次循环。 + //妫鏌ユ柊瀹氫箟鐨勭煩褰㈠尯鍩熸槸鍚﹀湪鍥惧儚鐨勮竟鐣屽唴銆傚鏋滆秴鍑轰簡杈圭晫锛屽氨璺宠繃杩欐寰幆銆 Mat auxRoi = image(rect); - //原始图像中提取出这个矩形区域的子图像auxRoi + //鍘熷鍥惧儚涓彁鍙栧嚭杩欎釜鐭╁舰鍖哄煙鐨勫瓙鍥惧儚auxRoi Mat roiOstu, roiAdap; if (1) { if (BLUE == plateType) { @@ -196,15 +196,15 @@ bool slideChineseWindow(Mat& image, Rect mr, Mat& newRoi, Color plateType, float else { threshold(auxRoi, roiOstu, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY); } - //根据预设的颜色,使用不同的阈值处理方法对提取出的子图像进行阈值处理。 - // 处理后的图像分别保存到roiOstu和roiAdap。 + //鏍规嵁棰勮鐨勯鑹诧紝浣跨敤涓嶅悓鐨勯槇鍊煎鐞嗘柟娉曞鎻愬彇鍑虹殑瀛愬浘鍍忚繘琛岄槇鍊煎鐞嗐 + // 澶勭悊鍚庣殑鍥惧儚鍒嗗埆淇濆瓨鍒皉oiOstu鍜宺oiAdap銆 roiOstu = preprocessChar(roiOstu, kChineseSize); CCharacter charCandidateOstu; - charCandidateOstu.setCharacterPos(rect); // 设置字符的位置信息 - charCandidateOstu.setCharacterMat(roiOstu);// 设置字符的图像信息 - charCandidateOstu.setIsChinese(isChinese);// 设置字符是否为中文字符的信息 - charCandidateVec.push_back(charCandidateOstu);// 将字符信息添加到字符候选向量中以备后续处理使用。 + charCandidateOstu.setCharacterPos(rect); // 璁剧疆瀛楃鐨勪綅缃俊鎭 + charCandidateOstu.setCharacterMat(roiOstu);// 璁剧疆瀛楃鐨勫浘鍍忎俊鎭 + charCandidateOstu.setIsChinese(isChinese);// 璁剧疆瀛楃鏄惁涓轰腑鏂囧瓧绗︾殑淇℃伅 + charCandidateVec.push_back(charCandidateOstu);// 灏嗗瓧绗︿俊鎭坊鍔犲埌瀛楃鍊欓夊悜閲忎腑浠ュ鍚庣画澶勭悊浣跨敤銆 } if (useAdapThreshold) { if (BLUE == plateType) { @@ -220,7 +220,7 @@ bool slideChineseWindow(Mat& image, Rect mr, Mat& newRoi, Color plateType, float adaptiveThreshold(auxRoi, roiAdap, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 3, 0); } roiAdap = preprocessChar(roiAdap, kChineseSize); - //对图像进行阈值处理以获得二值化的图像。处理后的图像保存在roiAdap中。 + //瀵瑰浘鍍忚繘琛岄槇鍊煎鐞嗕互鑾峰緱浜屽煎寲鐨勫浘鍍忋傚鐞嗗悗鐨勫浘鍍忎繚瀛樺湪roiAdap涓 CCharacter charCandidateAdap; charCandidateAdap.setCharacterPos(rect); charCandidateAdap.setCharacterMat(roiAdap); @@ -234,8 +234,8 @@ bool slideChineseWindow(Mat& image, Rect mr, Mat& newRoi, Color plateType, float double overlapThresh = 0.1; NMStoCharacter(charCandidateVec, overlapThresh); - //使用了非极大值抑制(NMS)算法,它通过计算每个字符候选区域与其它所有字符候选区域的交并比 - // 将交并比低于某个阈值的字符候选区域去除 + //浣跨敤浜嗛潪鏋佸ぇ鍊兼姂鍒讹紙NMS锛夌畻娉曪紝瀹冮氳繃璁$畻姣忎釜瀛楃鍊欓夊尯鍩熶笌鍏跺畠鎵鏈夊瓧绗﹀欓夊尯鍩熺殑浜ゅ苟姣 + // 灏嗕氦骞舵瘮浣庝簬鏌愪釜闃堝肩殑瀛楃鍊欓夊尯鍩熷幓闄 if (charCandidateVec.size() >= 1) { std::sort(charCandidateVec.begin(), charCandidateVec.end(), [](const CCharacter& r1, const CCharacter& r2) { @@ -245,60 +245,60 @@ bool slideChineseWindow(Mat& image, Rect mr, Mat& newRoi, Color plateType, float newRoi = charCandidateVec.at(0).getCharacterMat(); return true; } - //如果生成的字符候选向量中至少有一个元素, - // 则将得分最高的字符候选区域的图像提取出来,并返回true;否则返回false。 + //濡傛灉鐢熸垚鐨勫瓧绗﹀欓夊悜閲忎腑鑷冲皯鏈変竴涓厓绱狅紝 + // 鍒欏皢寰楀垎鏈楂樼殑瀛楃鍊欓夊尯鍩熺殑鍥惧儚鎻愬彇鍑烘潵锛屽苟杩斿洖true锛涘惁鍒欒繑鍥瀎alse銆 return false; } bool slideChineseGrayWindow(const Mat& image, Rect& mr, Mat& newRoi, Color plateType, float slideLengthRatio) { std::vector charCandidateVec; - // 定义一个向量来保存字符候选 + // 瀹氫箟涓涓悜閲忔潵淇濆瓨瀛楃鍊欓 Rect maxrect = mr; Point tlPoint = mr.tl(); - // 获取给定的最大矩形区域的左上角点和宽度 + // 鑾峰彇缁欏畾鐨勬渶澶х煩褰㈠尯鍩熺殑宸︿笂瑙掔偣鍜屽搴 bool isChinese = true; - // 默认假设它是中文字符 + // 榛樿鍋囪瀹冩槸涓枃瀛楃 int slideLength = int(slideLengthRatio * maxrect.width); int slideStep = 1; int fromX = 0; fromX = tlPoint.x; - // 根据最大矩形的宽度计算滑动窗口的长度和步长 + // 鏍规嵁鏈澶х煩褰㈢殑瀹藉害璁$畻婊戝姩绐楀彛鐨勯暱搴﹀拰姝ラ暱 for (int slideX = -slideLength; slideX < slideLength; slideX += slideStep) { - // 在指定的范围内进行滑动窗口操作 + // 鍦ㄦ寚瀹氱殑鑼冨洿鍐呰繘琛屾粦鍔ㄧ獥鍙f搷浣 float x_slide = 0; x_slide = float(fromX + slideX); float y_slide = (float)tlPoint.y; - // 计算当前滑动的x和y坐标 + // 璁$畻褰撳墠婊戝姩鐨剎鍜寉鍧愭爣 int chineseWidth = int(maxrect.width); int chineseHeight = int(maxrect.height); - // 获取中国字符的宽度和高度 + // 鑾峰彇涓浗瀛楃鐨勫搴﹀拰楂樺害 Rect rect(Point2f(x_slide, y_slide), Size(chineseWidth, chineseHeight)); - // 根据当前滑动的坐标和中国字符的尺寸创建一个矩形区域 + // 鏍规嵁褰撳墠婊戝姩鐨勫潗鏍囧拰涓浗瀛楃鐨勫昂瀵稿垱寤轰竴涓煩褰㈠尯鍩 if (rect.tl().x < 0 || rect.tl().y < 0 || rect.br().x >= image.cols || rect.br().y >= image.rows) continue; - // 检查这个矩形是否在图像内,如果不在,则跳过当前的循环迭代 + // 妫鏌ヨ繖涓煩褰㈡槸鍚﹀湪鍥惧儚鍐咃紝濡傛灉涓嶅湪锛屽垯璺宠繃褰撳墠鐨勫惊鐜凯浠 Mat auxRoi = image(rect); Mat grayChinese; grayChinese.create(kGrayCharHeight, kGrayCharWidth, CV_8UC1); - // 创建一个灰度图像,尺寸为预设的中文字符的尺寸和通道数 + // 鍒涘缓涓涓伆搴﹀浘鍍忥紝灏哄涓洪璁剧殑涓枃瀛楃鐨勫昂瀵稿拰閫氶亾鏁 resize(auxRoi, grayChinese, grayChinese.size(), 0, 0, INTER_LINEAR); - // 将提取的子图像调整为预设的中文字符的尺寸,并将其保存到灰度图像中 - // 从图像中提取当前矩形区域的子图像 + // 灏嗘彁鍙栫殑瀛愬浘鍍忚皟鏁翠负棰勮鐨勪腑鏂囧瓧绗︾殑灏哄锛屽苟灏嗗叾淇濆瓨鍒扮伆搴﹀浘鍍忎腑 + // 浠庡浘鍍忎腑鎻愬彇褰撳墠鐭╁舰鍖哄煙鐨勫瓙鍥惧儚 CCharacter charCandidateOstu; charCandidateOstu.setCharacterPos(rect); charCandidateOstu.setCharacterMat(grayChinese); charCandidateOstu.setIsChinese(isChinese); - charCandidateVec.push_back(charCandidateOstu);// 将字符候选对象添加到向量中以备后续处理使用 - // 创建一个字符候选对象,并设置其位置、图像和其他属性(这里指定为中文字符) + charCandidateVec.push_back(charCandidateOstu);// 灏嗗瓧绗﹀欓夊璞℃坊鍔犲埌鍚戦噺涓互澶囧悗缁鐞嗕娇鐢 + // 鍒涘缓涓涓瓧绗﹀欓夊璞★紝骞惰缃叾浣嶇疆銆佸浘鍍忓拰鍏朵粬灞炴э紙杩欓噷鎸囧畾涓轰腑鏂囧瓧绗︼級 } CharsIdentify::instance()->classifyChineseGray(charCandidateVec); - // 对所有的字符候选进行分类(这里假设是中文字符分类) + // 瀵规墍鏈夌殑瀛楃鍊欓夎繘琛屽垎绫伙紙杩欓噷鍋囪鏄腑鏂囧瓧绗﹀垎绫伙級 double overlapThresh = 0.1; NMStoCharacter(charCandidateVec, overlapThresh); - // 对所有的字符候选进行非极大值抑制(NMS)以消除多余的字符候选区域, - // 这里的阈值设置为0.1(根据实际情况可能需要进行调整) + // 瀵规墍鏈夌殑瀛楃鍊欓夎繘琛岄潪鏋佸ぇ鍊兼姂鍒讹紙NMS锛変互娑堥櫎澶氫綑鐨勫瓧绗﹀欓夊尯鍩燂紝 + // 杩欓噷鐨勯槇鍊艰缃负0.1锛堟牴鎹疄闄呮儏鍐靛彲鑳介渶瑕佽繘琛岃皟鏁达級 if (charCandidateVec.size() >= 1) { std::sort(charCandidateVec.begin(), charCandidateVec.end(), [](const CCharacter& r1, const CCharacter& r2) { @@ -309,23 +309,23 @@ bool slideChineseGrayWindow(const Mat& image, Rect& mr, Mat& newRoi, Color plate mr = charCandidateVec.at(0).getCharacterPos(); return true; } - // 如果字符候选向量中至少有一个元素,则对它们进行排序, - // 并提取出得分最高的字符候选区域,将其图像保存到newRoi中, - // 并更新mr为最高得分字符候选的位置,然后返回true;否则返回false。 - // 注意这里使用了一个lambda表达式作为排序函数, - // 根据字符候选的得分进行降序排序。 + // 濡傛灉瀛楃鍊欓夊悜閲忎腑鑷冲皯鏈変竴涓厓绱狅紝鍒欏瀹冧滑杩涜鎺掑簭锛 + // 骞舵彁鍙栧嚭寰楀垎鏈楂樼殑瀛楃鍊欓夊尯鍩燂紝灏嗗叾鍥惧儚淇濆瓨鍒皀ewRoi涓紝 + // 骞舵洿鏂癿r涓烘渶楂樺緱鍒嗗瓧绗﹀欓夌殑浣嶇疆锛岀劧鍚庤繑鍥瀟rue锛涘惁鍒欒繑鍥瀎alse銆 + // 娉ㄦ剰杩欓噷浣跨敤浜嗕竴涓猯ambda琛ㄨ揪寮忎綔涓烘帓搴忓嚱鏁帮紝 + // 鏍规嵁瀛楃鍊欓夌殑寰楀垎杩涜闄嶅簭鎺掑簭銆 return false; } int CCharsSegment::charsSegment(Mat input, vector& resultVec, Color color) { if (!input.data) return 0x01; - + //妫鏌ヨ緭鍏ュ浘鍍忔槸鍚︽湁鏁版嵁 Color plateType = color; - Mat input_grey; + Mat input_grey; //瀛樺偍鐏板害鍥惧儚銆 cvtColor(input, input_grey, CV_BGR2GRAY); - + //灏嗚緭鍏ュ浘鍍忚浆鎹负鐏板害鍥惧儚锛屽苟淇濆瓨鍒癷nput_grey涓 if (0) { imshow("plate", input_grey); waitKey(0); @@ -336,6 +336,7 @@ int CCharsSegment::charsSegment(Mat input, vector& resultVec, Color color) img_threshold = input_grey.clone(); spatial_ostu(img_threshold, 8, 2, plateType); + //瀵瑰浘鍍忚繘琛孫tsu闃堝煎垎鍓 if (0) { imshow("plate", img_threshold); @@ -346,23 +347,28 @@ int CCharsSegment::charsSegment(Mat input, vector& resultVec, Color color) // remove liuding and hor lines // also judge weather is plate use jump count if (!clearLiuDing(img_threshold)) return 0x02; - + //娓呴櫎鍥惧儚涓殑涓浜涙棤鏁堝尯鍩 Mat img_contours; img_threshold.copyTo(img_contours); - + //灏唅mg_threshold澶嶅埗鍒癷mg_contours涓 vector > contours; + //瀹氫箟涓涓簩缁村悜閲廲ontours锛岀敤浜庝繚瀛樿疆寤撲俊鎭 findContours(img_contours, contours, // a vector of contours CV_RETR_EXTERNAL, // retrieve the external contours CV_CHAIN_APPROX_NONE); // all pixels of each contours - + //浣跨敤OpenCV鐨刦indContours鍑芥暟鏌ユ壘鍥惧儚涓殑杞粨銆 + // 杩欓噷鎸囧畾浜嗘绱㈡ā寮忎负澶栭儴杞粨锛屽苟涓旀寚瀹氫簡杞粨鐨勮繎浼兼柟娉曘 vector >::iterator itc = contours.begin(); + //瀹氫箟涓涓凯浠e櫒itc锛屽苟鍒濆鍖栦负杞粨鍚戦噺鐨勮捣濮嬩綅缃 vector vecRect; - - while (itc != contours.end()) { + //瀹氫箟涓涓悜閲弙ecRect锛岀敤浜庝繚瀛樻瘡涓疆寤撶殑杈圭晫妗嗐 + while (itc != contours.end()) {//閬嶅巻杞粨鍚戦噺 Rect mr = boundingRect(Mat(*itc)); + //瀵逛簬褰撳墠杞粨锛屼娇鐢∣penCV鐨刡oundingRect鍑芥暟璁$畻鍏惰竟鐣屾锛 + // 骞朵繚瀛樺埌鍙橀噺mr涓 Mat auxRoi(img_threshold, mr); - + //鏍规嵁褰撳墠杞粨鐨勮竟鐣屾锛屼粠鍥惧儚涓彁鍙栦竴涓瓙鍥惧儚銆 if (verifyCharSizes(auxRoi)) vecRect.push_back(mr); ++itc; } @@ -371,16 +377,18 @@ int CCharsSegment::charsSegment(Mat input, vector& resultVec, Color color) if (vecRect.size() == 0) return 0x03; vector sortedRect(vecRect); + //鍒涘缓涓涓柊鐨勫悜閲弒ortedRect锛屽苟灏唙ecRect鐨勫唴瀹瑰鍒跺埌杩欎釜鏂扮殑鍚戦噺涓 std::sort(sortedRect.begin(), sortedRect.end(), [](const Rect& r1, const Rect& r2) { return r1.x < r2.x; }); - + //浣跨敤lambda鍑芥暟灏唖ortedRect鎸夌収x鍧愭爣浠庡皬鍒板ぇ杩涜鎺掑簭銆 size_t specIndex = 0; specIndex = GetSpecificRect(sortedRect); - + //鑾峰彇鐗瑰畾鐨勭煩褰 Rect chineseRect; if (specIndex < sortedRect.size()) chineseRect = GetChineseRect(sortedRect[specIndex]); + //鑾峰彇鐗瑰畾绱㈠紩鐨勭煩褰㈠苟瀛樺偍鍒癱hineseRect else return 0x04; @@ -390,11 +398,13 @@ int CCharsSegment::charsSegment(Mat input, vector& resultVec, Color color) waitKey(0); destroyWindow("plate"); } + //缁樺埗鐭╁舰chineseRect鍦ㄥ浘鍍忎笂骞舵樉绀哄嚭鏉 + //杩欓儴鍒嗕唬鐮佹案杩滀笉浼氳鎵ц vector newSortedRect; newSortedRect.push_back(chineseRect); RebuildRect(sortedRect, newSortedRect, specIndex); - + //瀵瑰浘鍍忎腑鐨勭煩褰㈠尯鍩熻繘琛岄噸鏂版瀯寤烘垨澶勭悊鐨勩 if (newSortedRect.size() == 0) return 0x05; bool useSlideWindow = true; @@ -402,12 +412,14 @@ int CCharsSegment::charsSegment(Mat input, vector& resultVec, Color color) //bool useAdapThreshold = CParams::instance()->getParam1b(); for (size_t i = 0; i < newSortedRect.size(); i++) { + //寰幆閬嶅巻鏂扮殑鎺掑簭鐭╁舰鍚戦噺涓殑姣忎竴涓煩褰€ Rect mr = newSortedRect[i]; - + //鑾峰彇褰撳墠鐭╁舰鐨勫潗鏍囦俊鎭 // Mat auxRoi(img_threshold, mr); Mat auxRoi(input_grey, mr); + //鏍规嵁缁欏畾鐨勫浘鍍忓拰鐭╁舰鍖哄煙鍒涘缓ROI Mat newRoi; - + //绗簩涓槸鐢ㄦ潵瀛樺偍澶勭悊鍚庣殑鍥惧儚鐨勩 if (i == 0) { if (useSlideWindow) { float slideLengthRatio = 0.1f; @@ -431,15 +443,24 @@ int CCharsSegment::charsSegment(Mat input, vector& resultVec, Color color) else { threshold(auxRoi, newRoi, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY); } - + //鏍规嵁涓嶅悓鐨勯鑹叉潵鎵ц涓嶅悓鐨勯槇鍊煎鐞嗘搷浣滐紝 + // 鐒跺悗瀵瑰鐞嗗悗鐨勫浘鍍忚繘琛岄澶 newRoi = preprocessChar(newRoi); } if (0) { if (i == 0) { imshow("input_grey", input_grey); + // 浣跨敤imshow鍑芥暟鏄剧ず鍚嶄负"input_grey"鐨勭獥鍙o紝骞跺湪鍏朵腑鏄剧ず鍥惧儚"input_grey"銆 + // 鐢ㄤ簬鍒涘缓鍜屾樉绀虹獥鍙c + waitKey(0); + //杩欐槸璋冪敤OpenCV鐨剋aitKey鍑芥暟锛岀瓑寰呯敤鎴锋寜閿 + // 璇ュ嚱鏁扮殑鍙傛暟鏄0锛岃繖鎰忓懗鐫瀹冨皢鏃犻檺鏈熷湴绛夊緟鐢ㄦ埛鎸夐敭銆 + // 涓鏃︾敤鎴锋寜涓嬮敭锛岃鍑芥暟灏嗚繑鍥炴寜涓嬬殑閿殑ASCII鍊笺 + destroyWindow("input_grey"); + //杩欎釜鍑芥暟浼氶攢姣佺獥鍙e苟閲婃斁鍏跺唴瀛樸 } if (i == 0) { imshow("newRoi", newRoi); @@ -449,6 +470,9 @@ int CCharsSegment::charsSegment(Mat input, vector& resultVec, Color color) } resultVec.push_back(newRoi); + // 灏嗘柊鐨凴oi娣诲姞鍒板悕涓簉esultVec鐨勫悜閲忎腑銆 + // 瀛樺偍涓绯诲垪鍏冪礌銆傝繖閲屽皢鏂扮殑Roi鍥惧儚娣诲姞鍒拌鍚戦噺涓 + } return 0; @@ -457,44 +481,53 @@ int CCharsSegment::charsSegment(Mat input, vector& resultVec, Color color) int CCharsSegment::projectSegment(const Mat& input, Color color, vector& out_indexs) { if (!input.data) return 0x01; - Color plateType = color; - Mat input_grey; - cvtColor(input, input_grey, CV_BGR2GRAY); - SHOW_IMAGE(input_grey, 0); + Color plateType = color; // 灏嗚緭鍏ョ殑棰滆壊璧嬪肩粰plateType + Mat input_grey; // 瀹氫箟涓涓狹at瀵硅薄鐢ㄤ簬瀛樺偍鐏板害鍥惧儚 + cvtColor(input, input_grey, CV_BGR2GRAY); // 灏嗚緭鍏ュ浘鍍忚浆鎹负鐏板害鍥惧儚 + SHOW_IMAGE(input_grey, 0); // 鏄剧ず鐏板害鍥惧儚 - Mat img_threshold; - img_threshold = input_grey.clone(); - spatial_ostu(img_threshold, 8, 2, plateType); - SHOW_IMAGE(img_threshold, 0); + Mat img_threshold; // 瀹氫箟涓涓狹at瀵硅薄鐢ㄤ簬瀛樺偍闃堝煎寲鐨勫浘鍍 + img_threshold = input_grey.clone(); // 灏嗙伆搴﹀浘鍍忓鍒跺埌img_threshold涓 + spatial_ostu(img_threshold, 8, 2, plateType); // 瀵瑰浘鍍忚繘琛岀┖闂磋嚜閫傚簲闃堝煎寲澶勭悊锛 + SHOW_IMAGE(img_threshold, 0); // 鏄剧ず闃堝煎寲鍚庣殑鍥惧儚 // remove liuding and hor lines // also judge weather is plate use jump count - if (!clearLiuDing(img_threshold)) return 0x02; - SHOW_IMAGE(img_threshold, 0); - - Mat vhist = ProjectedHistogram(img_threshold, VERTICAL, 0); - Mat showHist = showHistogram(vhist); - SHOW_IMAGE(showHist, 1); - - vector values; - vector indexs; - int size = vhist.cols; - for (int i = 0; i < size; i++) { - float val = vhist.at(i); - values.push_back(1.f - val); + // 杩涜涓浜涘舰鐘剁殑娓呯悊鍜屽垽鏂槸鍚︿负杞︾墝鐨勮烦璺冭鏁 + if (!clearLiuDing(img_threshold)) return 0x02; + // 浣跨敤clearLiuDing鍑芥暟娓呯悊鍥惧儚涓殑澶氫綑閮ㄥ垎锛 + SHOW_IMAGE(img_threshold, 0); + // 鏄剧ず娓呯悊鍚庣殑鍥惧儚 + + Mat vhist = ProjectedHistogram(img_threshold, VERTICAL, 0); + // 瀵瑰浘鍍忚繘琛屽瀭鐩寸洿鏂瑰浘鎶曞奖锛岀粨鏋滀繚瀛樺湪vhist涓 + Mat showHist = showHistogram(vhist); + // 鏄剧ず鐩存柟鍥撅紝浣嗘槸姝よ浠g爜鍦ㄥ悗缁殑浠g爜涓苟娌℃湁琚娇鐢 + SHOW_IMAGE(showHist, 1); // 鏄剧ず鐩存柟鍥 + + vector values; // 瀹氫箟涓涓悜閲忕敤浜庡瓨鍌ㄦ瘡涓儚绱犲埌鐩存柟鍥炬渶澶у肩殑璺濈 + vector indexs; // 瀹氫箟涓涓悜閲忕敤浜庡瓨鍌ㄩ潪鏈澶у肩殑绱㈠紩 + int size = vhist.cols; // 鑾峰彇鐩存柟鍥惧垪鐨勬暟閲忥紝浣滀负鍚庣画寰幆鐨勬鏁 + + for (int i = 0; i < size; i++) { // 閬嶅巻姣忎釜鍍忕礌鍦ㄧ洿鏂瑰浘涓殑浣嶇疆 + float val = vhist.at(i); // 鑾峰彇褰撳墠鍍忕礌鍦ㄧ洿鏂瑰浘涓殑鍊 + values.push_back(1.f - val); + // 璁$畻褰撳墠鍍忕礌鍒扮洿鏂瑰浘鏈澶у肩殑璺濈锛屽苟娣诲姞鍒皏alues鍚戦噺涓 } - Mat img_test = img_threshold.clone(); - NMSfor1D(values, indexs); - - out_indexs.resize(size); - for (int j = 0; j < size; j++) - out_indexs.at(j) = 0; - for (int i = 0; i < size; i++) { - float val = vhist.at(i); - if (indexs.at(i) && val < 0.1f) { - out_indexs.at(i) = 1; + Mat img_test = img_threshold.clone(); // 澶嶅埗闃堝煎寲鍚庣殑鍥惧儚鍒颁竴涓柊鐨凪at瀵硅薄涓 + NMSfor1D(values, indexs); // 瀵箆alues鍚戦噺杩涜闈炴瀬澶у兼姂鍒讹紙NMS锛 + + out_indexs.resize(size); // 閲嶆柊璋冩暣out_indexs鍚戦噺鐨勫昂瀵革紝涓哄悗缁殑璧嬪煎仛鍑嗗 + for (int j = 0; j < size; j++) + out_indexs.at(j) = 0; // 灏唎ut_indexs鍚戦噺涓殑鎵鏈夊煎垵濮嬪寲涓0 + + for (int i = 0; i < size; i++) { // 閬嶅巻姣忎釜鍍忕礌鍦ㄧ洿鏂瑰浘涓殑浣嶇疆 + float val = vhist.at(i); // 鑾峰彇褰撳墠鍍忕礌鍦ㄧ洿鏂瑰浘涓殑鍊 + if (indexs.at(i) && val < 0.1f) { // 濡傛灉褰撳墠鍍忕礌鏄潪鏋佸ぇ鍊间笖鍏跺煎皬浜0.1f + out_indexs.at(i) = 1; // 鍒欏皢out_indexs鍚戦噺涓殑鐩稿簲浣嶇疆璁剧疆涓1 for (int j = 0; j < img_test.rows; j++) { img_test.at(j, i) = (char)255; + // 灏嗚浣嶇疆鐨勫儚绱犲艰缃负255锛堢櫧鑹诧級 } } } @@ -506,72 +539,106 @@ int CCharsSegment::projectSegment(const Mat& input, Color color, vector& ou bool verifyCharRectSizes(Rect r) { // Char sizes 45x90 float aspect = 45.0f / 90.0f; + //瀹氫箟涓涓彉閲廰spect锛屽叾鍊间负0.5锛岃〃绀哄瓧绗︾殑棰勬湡瀹介珮姣斻 float charAspect = (float)r.width / (float)r.height; + //璁$畻杈撳叆鐭╁舰鐨勫楂樻瘮锛屽苟灏嗗叾瀛樺偍鍦ㄥ彉閲廲harAspect涓 float error = 0.5f; + //琛ㄧず鍏佽鐨勫楂樻瘮璇樊銆 float minHeight = kPlateResizeHeight * 0.5f; + //琛ㄧず鐭╁舰鐨勬渶灏忛珮搴 float maxHeight = kPlateResizeHeight * 1.f; + //琛ㄧず鐭╁舰鐨勬渶澶ч珮搴 // We have a different aspect ratio for number 1, and it can be ~0.2 float minAspect = 0.10f; //0.2f; - + //琛ㄧず鍏佽鐨勬渶灏忓楂樻瘮 float maxAspect = 0.85f; // aspect + aspect * error; //0.8f; - + //琛ㄧず鍏佽鐨勬渶澶у楂樻瘮 int ch = r.tl().y + r.height / 2; + //璁$畻鐭╁舰鐨勪腑蹇冪偣绾靛潗鏍 int min_ch = int(kPlateResizeHeight * 0.3f); + //琛ㄧず瀛楃涓績鐐圭殑鏈灏忕旱鍧愭爣 int max_ch = int(kPlateResizeHeight * 0.7f); + //琛ㄧず瀛楃涓績鐐圭殑鏈澶х旱鍧愭爣 if (ch > max_ch || ch < min_ch) return false; - + //濡傛灉瀛楃涓績鐐圭殑绾靛潗鏍囪秴鍑哄厑璁哥殑鑼冨洿锛屽垯杩斿洖false銆 float h = (float)r.height; + //灏嗚緭鍏ョ煩褰㈢殑height杞崲涓烘诞鐐规暟 if (h > maxHeight || h < minHeight) return false; + //鐭╁舰鐨刪eight瓒呭嚭鍏佽鐨勮寖鍥达紝鍒欒繑鍥瀎alse銆 if (charAspect < minAspect || charAspect > maxAspect) return false; - + //濡傛灉鐭╁舰鐨勫楂樻瘮瓒呭嚭鍏佽鐨勮寖鍥达紝鍒欒繑鍥瀎alse銆 return true; } Mat preprocessCharMat(Mat in, int char_size) { // Remap image - int h = in.rows; - int w = in.cols; + // 瀵瑰浘鍍忚繘琛屾槧灏勫彉鎹 + int h = in.rows; // 鑾峰彇杈撳叆鍥惧儚鐨勮鏁 + int w = in.cols; // 鑾峰彇杈撳叆鍥惧儚鐨勫垪鏁 - int charSize = char_size; + int charSize = char_size; // 灏嗕紶鍏ョ殑瀛楃澶у皬鍙傛暟淇濆瓨涓篶harSize - Mat transformMat = Mat::eye(2, 3, CV_32F); - int m = max(w, h); - transformMat.at(0, 2) = float(m / 2 - w / 2); - transformMat.at(1, 2) = float(m / 2 - h / 2); + // 鍒涘缓涓涓2x3鐨勫崟浣嶇煩闃碉紝浣滀负鍥惧儚鍙樻崲鐨勮浆鎹㈢煩闃 + Mat transformMat = Mat::eye(2, 3, CV_32F); - Mat warpImage(m, m, in.type()); - warpAffine(in, warpImage, transformMat, warpImage.size(), INTER_LINEAR, - BORDER_CONSTANT, Scalar(0)); + // 鎵惧嚭杈撳叆鍥惧儚鐨勬渶澶у昂瀵革紙楂樻垨瀹斤級 + int m = max(w, h); - Mat out; - cv::resize(warpImage, out, Size(charSize, charSize)); + // 鏍规嵁鏈澶у昂瀵革紝璁剧疆杞崲鐭╅樀鐨勬渶鍚庝袱琛岋紙骞崇Щ鍙傛暟锛 + // 杩欐牱鍋氱殑鐩殑鏄皢杈撳叆鍥惧儚鐨勪腑蹇冪Щ鍔ㄥ埌鍙樻崲鍚庣殑鍥惧儚鐨勪腑蹇 + transformMat.at(0, 2) = float(m / 2 - w / 2); + transformMat.at(1, 2) = float(m / 2 - h / 2); - return out; + // 鍒涘缓涓涓笌杈撳叆鍥惧儚鐩稿悓绫诲瀷鍜屽ぇ灏忕殑杈撳嚭鍥惧儚 + Mat warpImage(m, m, in.type()); + + // 浣跨敤涓婇潰瀹氫箟鐨勮浆鎹㈢煩闃碉紝瀵硅緭鍏ュ浘鍍忔墽琛屼豢灏勫彉鎹紙warpAffine锛 + warpAffine(in, warpImage, transformMat, warpImage.size(), INTER_LINEAR, + BORDER_CONSTANT, Scalar(0)); + + // 鏍规嵁鎸囧畾鐨勫瓧绗﹀ぇ灏忥紝璋冩暣鍙樻崲鍚庣殑鍥惧儚澶у皬 + Mat out; + cv::resize(warpImage, out, Size(charSize, charSize)); + + // 杩斿洖澶勭悊鍚庣殑鍥惧儚 + return out; } Mat clearLiuDingAndBorder(const Mat& grayImage, Color color) { SHOW_IMAGE(grayImage, 0); + //鏄剧ず杈撳叆鐨勭伆搴﹀浘鍍 Mat img_threshold; + //瀹氫箟涓涓狹at瀵硅薄img_threshold锛岀敤浜庡瓨鏀鹃槇鍊煎寲鍚庣殑鍥惧儚銆 img_threshold = grayImage.clone(); + //灏嗚緭鍏ョ殑鐏板害鍥惧儚澶嶅埗鍒癷mg_threshold涓 spatial_ostu(img_threshold, 1, 1, color); + //瀵瑰浘鍍忚繘琛岀┖闂磋嚜閫傚簲闃堝煎寲锛坰patial OSTU锛夛紝 + // 杩欓噷鐨勫弬鏁1鍜1鍙兘琛ㄧず鐨勬槸楂樻柉鏍哥殑澶у皬锛岃宑olor鍒欒〃绀洪鑹茬┖闂淬 clearLiuDing(img_threshold); + //涓轰簡鍘婚櫎鍒樺畾鍣0 Rect cropRect; + //瀛樻斁瑁佸壀鍖哄煙鐨勫潗鏍囥 clearBorder(img_threshold, cropRect); + //涓轰簡娓呴櫎鍥惧儚鐨勮竟妗 Mat cropedGrayImage; + //瀛樻斁瑁佸壀鍚庣殑鐏板害鍥惧儚 resize(grayImage(cropRect), cropedGrayImage, Size(kPlateResizeWidth, kPlateResizeHeight)); + //瀵硅鍓悗鐨勭伆搴﹀浘鍍忚繘琛屽ぇ灏忚皟鏁淬 SHOW_IMAGE(cropedGrayImage, 0); + //鏄剧ず璋冩暣澶у皬鍚庣殑鐏板害鍥惧儚銆 return cropedGrayImage; + //杩斿洖澶勭悊鍚庣殑鐏板害鍥惧儚銆 } void NMStoCharacterByRatio(std::vector &inVec, double overlap, const Rect groundRect) { // rechange the score - for (auto& character : inVec) { - double score = character.getCharacterScore(); + for (auto& character : inVec) {//瀵筰nVec涓殑姣忎釜瀛楃杩涜鎿嶄綔 + double score = character.getCharacterScore();//鑾峰彇褰撳墠瀛楃鐨勫緱鍒 //cout << "score:" << score << endl; - Rect rect = character.getCharacterPos(); + Rect rect = character.getCharacterPos();//鑾峰彇褰撳墠瀛楃鐨勪綅缃俊鎭 int w = rect.width; int h = rect.height; int gw = groundRect.width; @@ -581,13 +648,14 @@ void NMStoCharacterByRatio(std::vector &inVec, double overlap, const int w_diff = abs(w - gw); int h_diff = abs(h - gh); - + //璁$畻褰撳墠瀛楃妗嗕笌鍦伴潰鐪熷疄妗嗙殑IOU锛堜氦骞舵瘮锛 //float w_ratio = (float)w / (float)gw; //float h_ratio = (float)h / (float)gh; float w_ratio = 1 - (float)w_diff / (float)gw; float h_ratio = 1 - (float)h_diff / (float)gh; - + //鍒嗗埆琛ㄧず瀛楃妗嗙殑瀹藉害鍜岄珮搴︿笌鍦伴潰鐪熷疄妗嗙殑瀹介珮姣斻 + // 杩欎袱涓瘮渚嬩細褰卞搷鏈缁堢殑鏉冮噸寰楀垎銆 float a = 0.5f; float b = 0.5f; //cout << "str:" << character.getCharacterStr() << endl; @@ -595,17 +663,20 @@ void NMStoCharacterByRatio(std::vector &inVec, double overlap, const if ("1" == character.getCharacterStr()) { a = 0.3f; //0.2f; b = 0.7f; //0.8f; + //濡傛灉瀛楃鏄'1'锛岄偅涔堜細瀵瑰叾IOU杩涜涓涓皟鏁淬 } float c = 0.1f; //float weighted_score = a * (float)score + b * w_ratio + c * h_ratio; float weighted_score = a * (float)score + b * w_ratio + c * h_ratio; + //璁$畻鏉冮噸寰楀垎 SHOW_IMAGE(character.getCharacterMat(), 0); character.setCharacterScore((double)weighted_score); + //璁剧疆鏂扮殑鏉冮噸寰楀垎銆 //cout << "weighted_score:" << character.getCharacterScore() << endl; } std::sort(inVec.begin(), inVec.end()); - + //瀵箆ector杩涜鎺掑簭锛屼互渚垮悗缁殑NMS鎿嶄綔銆 std::vector::iterator it = inVec.begin(); for (; it != inVec.end(); ++it) { CCharacter charSrc = *it; @@ -625,20 +696,26 @@ void NMStoCharacterByRatio(std::vector &inVec, double overlap, const ++itc; } } - } + }//濡傛灉瀹冧笌鍚庨潰鐨勫瓧绗︾殑IOU澶т簬棰勮鐨勯噸鍙犻槇鍊硷紝閭d箞灏卞皢鍚庨潰鐨勫瓧绗︿粠vector涓垹闄ゃ + //杩欐牱鍙互淇濊瘉鏈缁坴ector涓瘡涓涓瓧绗﹂兘涓嶄笌鍏跺畠瀛楃鏈夊ぇ鐨勯噸鍙 } int getNearestIndex(Point center, const vector& groundCenters) { int gc_size = int(groundCenters.size()); + //鑾峰彇 groundCenters 鍚戦噺鐨勫ぇ灏忥紝骞跺皢鍏惰浆鎹负鏁存暟绫诲瀷骞跺瓨鍌ㄥ湪鍙橀噺 gc_size 涓 int index = 0; + //鐢ㄤ簬瀛樺偍鏈鎺ヨ繎 center 鐨勫湴蹇冨潗鏍囩殑绱㈠紩 int min_length = INT_MAX; - for (int p = 0; p < gc_size; p++) { - Point gc_point = groundCenters.at(p); + //鐢ㄤ簬瀛樺偍涓 center 璺濈鏈鐭殑鍦板績鍧愭爣鐨勮窛绂荤殑骞虫柟 + for (int p = 0; p < gc_size; p++) {//閬嶅巻鎵鏈夊湴蹇冨潗鏍 + Point gc_point = groundCenters.at(p);//鑾峰彇绱㈠紩涓 p 鐨勫湴蹇冨潗鏍囷紝骞跺皢鍏跺瓨鍌ㄥ湪鍙橀噺 gc_point 涓 int length_square = (gc_point.x - center.x) * (gc_point.x - center.x) + (gc_point.y - center.y) * (gc_point.y - center.y); + //璁$畻褰撳墠鍦板績鍧愭爣 gc_point 涓 center 涔嬮棿鐨勮窛绂荤殑骞虫柟銆 //int length_square = abs(gc_point.x - center.x); if (length_square < min_length) { min_length = length_square; + //褰撳墠鍦板績鍧愭爣涓 center 鐨勮窛绂荤殑骞虫柟璁剧疆涓烘柊鐨勬渶灏忚窛绂汇 index = p; } } diff --git a/src/util/kv.cpp b/src/util/kv.cpp index 84ee6c9..edacd3e 100644 --- a/src/util/kv.cpp +++ b/src/util/kv.cpp @@ -3,11 +3,11 @@ namespace easypr { -Kv::Kv() { } +Kv::Kv() { } //Kv绫荤殑鏋勯犲嚱鏁 -void Kv::load(const std::string &file) { - this->clear(); - std::ifstream reader(file); +void Kv::load(const std::string &file) { //涓涓垚鍛樺嚱鏁帮紝鐢ㄤ簬浠庢寚瀹氱殑鏂囦欢涓姞杞介敭鍊煎 + this->clear();//娓呯┖褰撳墠鐨勯敭鍊煎 + std::ifstream reader(file);//鎵撳紑鏂囦欢 assert(reader); if (reader.is_open()) { @@ -15,17 +15,17 @@ void Kv::load(const std::string &file) { std::string line; std::getline(reader, line); if (line.empty()) continue; - - const auto parse = [](const std::string &str) { +//鎵撳紑鏂囦欢骞惰鍙栨瘡涓琛 + const auto parse = [](const std::string &str) {//瑙f瀽閿拰鍊 std::string tmp, key, value; for (size_t i = 0, len = str.length(); i < len; ++i) { const char ch = str[i]; - if (ch == ' ') { + if (ch == ' ') {//閬囧埌绌烘牸鏃 if (i > 0 && str[i - 1] != ' ' && key.empty()) { key = tmp; tmp.clear(); } - } + }//灏嗕箣鍓嶇殑瀛楃涓蹭綔涓洪敭锛岀┖鏍煎悗鐨勫瓧绗︿覆浣滀负鍊 else { tmp.push_back(ch); } @@ -37,45 +37,45 @@ void Kv::load(const std::string &file) { }; auto kv = parse(line); - this->add(kv.first, kv.second); + this->add(kv.first, kv.second);//瑙f瀽鍑虹殑閿煎娣诲姞鍒板瓨鍌ㄤ腑 } - reader.close(); + reader.close();//鍏抽棴鏂囦欢 } } -std::string Kv::get(const std::string &key) { +std::string Kv::get(const std::string &key) {//鏄竴涓垚鍛樺嚱鏁帮紝鐢ㄤ簬鑾峰彇缁欏畾閿殑鍊 if (data_.find(key) == data_.end()) { - std::cerr << "[Kv] cannot find " << key << std::endl; - return ""; + std::cerr << "[Kv] cannot find " << key << std::endl;//濡傛灉閿笉瀛樺湪锛屽畠浼氭墦鍗颁竴涓敊璇秷鎭 + return "";//杩斿洖涓涓┖瀛楃涓层 } - return data_.at(key); + return data_.at(key);//鑾峰彇缁欏畾閿殑鍊 } -void Kv::add(const std::string &key, const std::string &value) { - if (data_.find(key) != data_.end()) { +void Kv::add(const std::string &key, const std::string &value) {//鏄竴涓垚鍛樺嚱鏁帮紝鐢ㄤ簬娣诲姞涓涓敭鍊煎 + if (data_.find(key) != data_.end()) {//濡傛灉閿凡缁忓瓨鍦 fprintf(stderr, "[Kv] find duplicate: %s = %s , ignore\n", key.c_str(), - value.c_str()); + value.c_str());//浼氭墦鍗颁竴涓敊璇秷鎭苟蹇界暐杩欎釜娣诲姞鎿嶄綔 } else { std::string v(value); -#ifdef OS_WINDOWS - v = utils::utf8_to_gbk(value.c_str()); +#ifdef OS_WINDOWS//濡傛灉鍦╓indows鎿嶄綔绯荤粺涓 + v = utils::utf8_to_gbk(value.c_str()); //灏嗗间粠UTF-8缂栫爜杞崲涓篏BK缂栫爜銆 #endif - data_[key] = v; + data_[key] = v;//娣诲姞涓涓敭鍊煎 } } -void Kv::remove(const std::string &key) { - if (data_.find(key) == data_.end()) { - std::cerr << "[Kv] cannot find " << key << std::endl; +void Kv::remove(const std::string &key) {//鏄竴涓垚鍛樺嚱鏁帮紝鐢ㄤ簬鍒犻櫎涓涓敭鍊煎銆 + if (data_.find(key) == data_.end()) {//濡傛灉閿笉瀛樺湪 + std::cerr << "[Kv] cannot find " << key << std::endl;//鎵撳嵃涓涓敊璇秷鎭 return; } - data_.erase(key); + data_.erase(key);//鍒犻櫎涓涓敭鍊煎銆 } -void Kv::clear() { - data_.clear(); +void Kv::clear() {//鏄竴涓垚鍛樺嚱鏁帮紝鐢ㄤ簬娓呯┖鎵鏈夌殑閿煎銆 + data_.clear();//鐢ㄤ簬娓呯┖鎵鏈夌殑閿煎銆 } }