Mat TextContours::drawDebugImage(Mat baseImage) { Mat img_contours(baseImage.size(), CV_8U); baseImage.copyTo(img_contours); cvtColor(img_contours, img_contours, CV_GRAY2RGB); vector<vector<Point> > allowedContours; for (unsigned int i = 0; i < this->contours.size(); i++) { if (this->goodIndices[i]) allowedContours.push_back(this->contours[i]); } drawContours(img_contours, this->contours, -1, // draw all contours cv::Scalar(255,0,0), // in blue 1); // with a thickness of 1 drawContours(img_contours, allowedContours, -1, // draw all contours cv::Scalar(0,255,0), // in green 1); // with a thickness of 1 return img_contours; }
CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* config) { this->config = config; this->confidence = 0; if (this->config->debugCharSegmenter) cout << "Starting CharacterSegmenter" << endl; //CharacterRegion charRegion(img, debug); timespec startTime; getTime(&startTime); Mat img_gray(img.size(), CV_8U); cvtColor( img, img_gray, CV_BGR2GRAY ); //normalize(img_gray, img_gray, 0, 255, CV_MINMAX ); medianBlur(img_gray, img_gray, 3); if (invertedColors) bitwise_not(img_gray, img_gray); charAnalysis = new CharacterAnalysis(img_gray, config); charAnalysis->analyze(); if (this->config->debugCharSegmenter) { displayImage(config, "CharacterSegmenter Thresholds", drawImageDashboard(charAnalysis->thresholds, CV_8U, 3)); } if (this->config->debugCharSegmenter) { Mat img_contours(charAnalysis->bestThreshold.size(), CV_8U); charAnalysis->bestThreshold.copyTo(img_contours); cvtColor(img_contours, img_contours, CV_GRAY2RGB); vector<vector<Point> > allowedContours; for (int i = 0; i < charAnalysis->bestContours.size(); i++) { if (charAnalysis->bestCharSegments[i]) allowedContours.push_back(charAnalysis->bestContours[i]); } drawContours(img_contours, charAnalysis->bestContours, -1, // draw all contours cv::Scalar(255,0,0), // in blue 1); // with a thickness of 1 drawContours(img_contours, allowedContours, -1, // draw all contours cv::Scalar(0,255,0), // in green 1); // with a thickness of 1 if (charAnalysis->linePolygon.size() > 0) { line(img_contours, charAnalysis->linePolygon[0], charAnalysis->linePolygon[1], Scalar(255, 0, 255), 1); line(img_contours, charAnalysis->linePolygon[3], charAnalysis->linePolygon[2], Scalar(255, 0, 255), 1); } Mat bordered = addLabel(img_contours, "Best Contours"); imgDbgGeneral.push_back(bordered); } // Figure out the average character width float totalCharWidth = 0; float totalCharHeight = 0; if (charAnalysis->linePolygon.size() > 0) { this->top = LineSegment(charAnalysis->linePolygon[0].x, charAnalysis->linePolygon[0].y, charAnalysis->linePolygon[1].x, charAnalysis->linePolygon[1].y); this->bottom = LineSegment(charAnalysis->linePolygon[3].x, charAnalysis->linePolygon[3].y, charAnalysis->linePolygon[2].x, charAnalysis->linePolygon[2].y); for (int i = 0; i < charAnalysis->bestContours.size(); i++) { if (charAnalysis->bestCharSegments[i] == false) continue; Rect mr = boundingRect(charAnalysis->bestContours[i]); totalCharWidth += mr.width; totalCharHeight += mr.height; } int numSamples = charAnalysis->bestCharSegmentsCount; float avgCharWidth = totalCharWidth / numSamples; float avgCharHeight = totalCharHeight / numSamples; removeSmallContours(charAnalysis->thresholds, charAnalysis->allContours, avgCharWidth, avgCharHeight); // Do the histogram analysis to figure out char regions timespec startTime; getTime(&startTime); vector<Mat> allHistograms; vector<Rect> allBoxes; for (int i = 0; i < charAnalysis->allContours.size(); i++) { Mat histogramMask = Mat::zeros(charAnalysis->thresholds[i].size(), CV_8U); fillConvexPoly(histogramMask, charAnalysis->linePolygon.data(), charAnalysis->linePolygon.size(), Scalar(255,255,255)); VerticalHistogram vertHistogram(charAnalysis->thresholds[i], histogramMask); if (this->config->debugCharSegmenter) { Mat histoCopy(vertHistogram.debugImg.size(), vertHistogram.debugImg.type()); //vertHistogram.copyTo(histoCopy); cvtColor(vertHistogram.debugImg, histoCopy, CV_GRAY2RGB); allHistograms.push_back(histoCopy); } // float score = 0; vector<Rect> charBoxes = getHistogramBoxes(vertHistogram.debugImg, avgCharWidth, avgCharHeight, &score); if (this->config->debugCharSegmenter) { for (int cboxIdx = 0; cboxIdx < charBoxes.size(); cboxIdx++) { rectangle(allHistograms[i], charBoxes[cboxIdx], Scalar(0, 255, 0)); } Mat histDashboard = drawImageDashboard(allHistograms, allHistograms[0].type(), 3); displayImage(config, "Char seg histograms", histDashboard); } for (int z = 0; z < charBoxes.size(); z++) allBoxes.push_back(charBoxes[z]); //drawAndWait(&histogramMask); } float biggestCharWidth = avgCharWidth; // Compute largest char width for (int i = 0; i < allBoxes.size(); i++) { if (allBoxes[i].width > biggestCharWidth) biggestCharWidth = allBoxes[i].width; } if (config->debugTiming) { timespec endTime; getTime(&endTime); cout << " -- Character Segmentation Create and Score Histograms Time: " << diffclock(startTime, endTime) << "ms." << endl; } //ColorFilter colorFilter(img, charAnalysis->getCharacterMask()); vector<Rect> candidateBoxes = getBestCharBoxes(charAnalysis->thresholds[0], allBoxes, biggestCharWidth); if (this->config->debugCharSegmenter) { // Setup the dashboard images to show the cleaning filters for (int i = 0; i < charAnalysis->thresholds.size(); i++) { Mat cleanImg = Mat::zeros(charAnalysis->thresholds[i].size(), charAnalysis->thresholds[i].type()); Mat boxMask = getCharBoxMask(charAnalysis->thresholds[i], candidateBoxes); charAnalysis->thresholds[i].copyTo(cleanImg); bitwise_and(cleanImg, boxMask, cleanImg); cvtColor(cleanImg, cleanImg, CV_GRAY2BGR); for (int c = 0; c < candidateBoxes.size(); c++) rectangle(cleanImg, candidateBoxes[c], Scalar(0, 255, 0), 1); imgDbgCleanStages.push_back(cleanImg); } } getTime(&startTime); filterEdgeBoxes(charAnalysis->thresholds, candidateBoxes, biggestCharWidth, avgCharHeight); candidateBoxes = filterMostlyEmptyBoxes(charAnalysis->thresholds, candidateBoxes); candidateBoxes = combineCloseBoxes(candidateBoxes, biggestCharWidth); cleanCharRegions(charAnalysis->thresholds, candidateBoxes); cleanMostlyFullBoxes(charAnalysis->thresholds, candidateBoxes); //cleanBasedOnColor(thresholds, colorFilter.colorMask, candidateBoxes); candidateBoxes = filterMostlyEmptyBoxes(charAnalysis->thresholds, candidateBoxes); this->characters = candidateBoxes; if (config->debugTiming) { timespec endTime; getTime(&endTime); cout << " -- Character Segmentation Box cleaning/filtering Time: " << diffclock(startTime, endTime) << "ms." << endl; } if (this->config->debugCharSegmenter) { Mat imgDash = drawImageDashboard(charAnalysis->thresholds, CV_8U, 3); displayImage(config, "Segmentation after cleaning", imgDash); Mat generalDash = drawImageDashboard(this->imgDbgGeneral, this->imgDbgGeneral[0].type(), 2); displayImage(config, "Segmentation General", generalDash); Mat cleanImgDash = drawImageDashboard(this->imgDbgCleanStages, this->imgDbgCleanStages[0].type(), 3); displayImage(config, "Segmentation Clean Filters", cleanImgDash); } } if (config->debugTiming) { timespec endTime; getTime(&endTime); cout << "Character Segmenter Time: " << diffclock(startTime, endTime) << "ms." << endl; } }
void CvScan::charsSegement( IplImage *src, vector<Mat> &vector){ if (src == NULL) { return; } IplImage *pimg = cvCreateImage(cvSize(src->width*1.1, src->height*1.1), src->depth, src->nChannels); /* int m_otsu = otsu(pimg); printf("m_otsu:%d\n",m_otsu); cvReleaseImage(&pimg); pimg = cvCreateImage(cvGetSize(src), src->depth, src->nChannels); cvThreshold(src, pimg, m_otsu, 255, CV_THRESH_BINARY); //cvZero(pimg); //*/ //IplImage imgHSV = *cvCreateImage(cvGetSize(pimg), 8, 1); //cv::Mat matImg(&imgHSV,true); cv::Mat img_contours(pimg->width,pimg->height,CV_8UC1,Scalar::all(0)); img_contours.data = (uchar *)pimg->imageData; std::vector< std::vector< CvPoint> > contours; findContours(img_contours, contours, // a vector of contours CV_RETR_EXTERNAL, // retrieve the external contours CV_CHAIN_APPROX_NONE); // all pixels of each contours //Start to iterate to each contour founded std::vector<std::vector<CvPoint>>::iterator itc = contours.begin(); std::vector<CvRect> vecRect; //Remove patch that are no inside limits of aspect ratio and area. //将不符合特定尺寸的图块排除出去 while (itc != contours.end()){ Rect mr = boundingRect(cv::Mat(*itc)); cv::Mat auxRoi(img_contours, mr); if (verifyMatCharSizes(auxRoi)) vecRect.push_back(mr); ++itc; } if (vecRect.size() == 0) return ; std::vector<CvRect> sortedRect; ////对符合尺寸的图块按照从左到右进行排序 sortRect(vecRect, sortedRect); for (int i = 0; i < sortedRect.size(); i++){ CvRect mr = sortedRect[i]; cv::Mat auxRoi(img_contours, mr); auxRoi = preprocessChar(auxRoi); vector.push_back(auxRoi); } /* 另一个方法 //*/ return ; }
void CharacterAnalysis::analyze() { thresholds = produceThresholds(img_gray, config); /* // Morph Close the gray image to make it easier to detect blobs int morph_elem = 1; int morph_size = 1; Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) ); for (int i = 0; i < thresholds.size(); i++) { //morphologyEx( mask, mask, MORPH_CLOSE, element ); morphologyEx( thresholds[i], thresholds[i], MORPH_OPEN, element ); //dilate( thresholds[i], thresholds[i], element ); } */ timespec startTime; getTime(&startTime); for (int i = 0; i < thresholds.size(); i++) { vector<vector<Point> > contours; vector<Vec4i> hierarchy; Mat tempThreshold(thresholds[i].size(), CV_8U); thresholds[i].copyTo(tempThreshold); findContours(tempThreshold, contours, // a vector of contours hierarchy, CV_RETR_TREE, // retrieve all contours CV_CHAIN_APPROX_SIMPLE ); // all pixels of each contours allContours.push_back(contours); allHierarchy.push_back(hierarchy); } if (config->debugTiming) { timespec endTime; getTime(&endTime); cout << " -- Character Analysis Find Contours Time: " << diffclock(startTime, endTime) << "ms." << endl; } //Mat img_equalized = equalizeBrightness(img_gray); getTime(&startTime); for (int i = 0; i < thresholds.size(); i++) { vector<bool> goodIndices = this->filter(thresholds[i], allContours[i], allHierarchy[i]); charSegments.push_back(goodIndices); if (config->debugCharAnalysis) cout << "Threshold " << i << " had " << getGoodIndicesCount(goodIndices) << " good indices." << endl; } if (config->debugTiming) { timespec endTime; getTime(&endTime); cout << " -- Character Analysis Filter Time: " << diffclock(startTime, endTime) << "ms." << endl; } this->plateMask = findOuterBoxMask(); if (hasPlateMask) { // Filter out bad contours now that we have an outer box mask... for (int i = 0; i < thresholds.size(); i++) { charSegments[i] = filterByOuterMask(allContours[i], allHierarchy[i], charSegments[i]); } } int bestFitScore = -1; int bestFitIndex = -1; for (int i = 0; i < thresholds.size(); i++) { //vector<bool> goodIndices = this->filter(thresholds[i], allContours[i], allHierarchy[i]); //charSegments.push_back(goodIndices); int segmentCount = getGoodIndicesCount(charSegments[i]); if (segmentCount > bestFitScore) { bestFitScore = segmentCount; bestFitIndex = i; bestCharSegments = charSegments[i]; bestThreshold = thresholds[i]; bestContours = allContours[i]; bestHierarchy = allHierarchy[i]; bestCharSegmentsCount = segmentCount; } } if (this->config->debugCharAnalysis) cout << "Best fit score: " << bestFitScore << " Index: " << bestFitIndex << endl; if (bestFitScore <= 1) return; //getColorMask(img, allContours, allHierarchy, charSegments); if (this->config->debugCharAnalysis) { Mat img_contours(bestThreshold.size(), CV_8U); bestThreshold.copyTo(img_contours); cvtColor(img_contours, img_contours, CV_GRAY2RGB); vector<vector<Point> > allowedContours; for (int i = 0; i < bestContours.size(); i++) { if (bestCharSegments[i]) allowedContours.push_back(bestContours[i]); } drawContours(img_contours, bestContours, -1, // draw all contours cv::Scalar(255,0,0), // in blue 1); // with a thickness of 1 drawContours(img_contours, allowedContours, -1, // draw all contours cv::Scalar(0,255,0), // in green 1); // with a thickness of 1 displayImage(config, "Matching Contours", img_contours); } //charsegments = this->getPossibleCharRegions(img_threshold, allContours, allHierarchy, STARTING_MIN_HEIGHT + (bestFitIndex * HEIGHT_STEP), STARTING_MAX_HEIGHT + (bestFitIndex * HEIGHT_STEP)); this->linePolygon = getBestVotedLines(img_gray, bestContours, bestCharSegments); if (this->linePolygon.size() > 0) { this->topLine = LineSegment(this->linePolygon[0].x, this->linePolygon[0].y, this->linePolygon[1].x, this->linePolygon[1].y); this->bottomLine = LineSegment(this->linePolygon[3].x, this->linePolygon[3].y, this->linePolygon[2].x, this->linePolygon[2].y); //this->charArea = getCharSegmentsBetweenLines(bestThreshold, bestContours, this->linePolygon); filterBetweenLines(bestThreshold, bestContours, bestHierarchy, linePolygon, bestCharSegments); this->charArea = getCharArea(); if (this->charArea.size() > 0) { this->charBoxTop = LineSegment(this->charArea[0].x, this->charArea[0].y, this->charArea[1].x, this->charArea[1].y); this->charBoxBottom = LineSegment(this->charArea[3].x, this->charArea[3].y, this->charArea[2].x, this->charArea[2].y); this->charBoxLeft = LineSegment(this->charArea[3].x, this->charArea[3].y, this->charArea[0].x, this->charArea[0].y); this->charBoxRight = LineSegment(this->charArea[2].x, this->charArea[2].y, this->charArea[1].x, this->charArea[1].y); } } this->thresholdsInverted = isPlateInverted(); }