void fillconvex_ring(Mat& mask, Point2f* points, int count, int inner, int outer) { Point2f* hull; int size = convex_hull(points, count, &hull); // apparently we have to convert Point2f array to integers ... Point* hulli = new Point[size]; for (int i = 0; i < size; i++) { hulli[i].x = (int) hull[i].x; hulli[i].y = (int) hull[i].y; } free(hull); fillConvexPoly(mask, hulli, size, Scalar(1), 1); delete [] hulli; Mat mask2; dilate(mask, mask2, Mat::ones(outer + inner, outer + inner, CV_8U)); fillConvexPoly(mask, hulli, size, Scalar(0), 1); erode(mask2, mask, Mat::ones(inner, inner, CV_8U)); }
static void paint_voronoi( Mat& img, Subdiv2D& subdiv ) { vector<vector<Point2f> > facets; vector<Point2f> centers; subdiv.getVoronoiFacetList(vector<int>(), facets, centers); vector<Point> ifacet; vector<vector<Point> > ifacets(1); for( size_t i = 0; i < facets.size(); i++ ) { ifacet.resize(facets[i].size()); for( size_t j = 0; j < facets[i].size(); j++ ) ifacet[j] = facets[i][j]; Scalar color; color[0] = rand() & 255; color[1] = rand() & 255; color[2] = rand() & 255; fillConvexPoly(img, ifacet, color, 8, 0); ifacets[0] = ifacet; polylines(img, ifacets, true, Scalar(), 1, LINE_AA, 0); circle(img, centers[i], 3, Scalar(), FILLED, LINE_AA, 0); } }
void drawCroppedImage(Mat& sourceImg, vector<Point> ROI){ int max_x = 0; int max_y = 0; int min_x = 99999; int min_y = 99999; Mat mask = cvCreateMat(sourceImg.rows, sourceImg.cols, CV_8UC1); for(int i=0; i<mask.cols; i++) for(int j=0; j<mask.rows; j++) mask.at<uchar>(Point(i,j)) = 0; vector<Point> ROI_Poly; approxPolyDP(ROI, ROI_Poly, 1.0, true); for (int i = 0; i < ROI.size(); i++){ if (ROI[i].x > max_x){ max_x = ROI[i].x;} if (ROI[i].x < min_x){ min_x = ROI[i].x;} if (ROI[i].y > max_y){ max_y = ROI[i].y;} if (ROI[i].y < min_y){ min_y = ROI[i].y;} } fillConvexPoly(mask, &ROI_Poly[0], ROI_Poly.size(), 255, 8, 0); // Sanity check for outside the edges of the source image /*max_x = (max_x > sourceImg.cols) ? sourceImg.cols : max_x; max_y = (max_y > sourceImg.rows) ? sourceImg.rows : max_y; min_x = (min_x < 0 ) ? 0 : min_x; min_y = (min_y < 0 ) ? 0 : min_y; int width = max_x - min_x; int height = max_y - min_y;*/ // int topLeftX = centerX - width * scaleX / 2; // int topLeftY = centerY - height * scaleY / 2; // cout << topLeftX << " " << topLeftY << endl; // topLeftX = max(topLeftX, 0); // topLeftY = max(topLeftY, 0); // Move mask to the origin // translateImg(mask, (-1 * min_x) , (-1 * min_y) );//, 50); // cout << mask.size() << endl; // Mat tmp = sourceImg(Rect(min_x, min_y, width, height) ); // resize(tmp, tmp, Size(width * scaleX, height * scaleY), 0, 0, INTER_CUBIC); // resize(mask, mask, Size(mask.cols * scaleX, mask.rows * scaleY), 0, 0, INTER_CUBIC); // By playing around, it seems that the thing to do is move the mask to the origin, where it is // applied to the dstImg(rectangle). Then that masked image is applied to the rectangle in the // destination image. We don't need to move the mask to line up with the destination image. // tmp.copyTo(dstImg(Rect(topLeftX, topLeftY, width * scaleX, height * scaleY) ) , mask); }
void cameraSettings2d::on_calBack_released() { BackCalibration=true; cConfig->BM->start(); ui->processLabel->setText("Background calibration..."); ui->Instructions->setText("Wait for background calibration process."); cConfig->maskZona.setTo(cv::Scalar::all(0)); fillConvexPoly(cConfig->maskZona,cConfig->zone,4,cvScalar(255)); }
Mat AAM::warpImage(Mat image, vector<int> points) { imshow("before warp", image); //cout<<"imege to warp type: "<<image.type()<<endl; Mat warp_final = Mat::zeros( image.rows, image.cols, image.type() ); vector<Vec6f> trianglesList; this->meanShapeTriangulation.getTriangleList(trianglesList); for(int i=0; i<trianglesList.size(); i++) { Point p1(cvRound(trianglesList[i][0]), cvRound(trianglesList[i][1])); Point p2(cvRound(trianglesList[i][2]), cvRound(trianglesList[i][3])); Point p3(cvRound(trianglesList[i][4]), cvRound(trianglesList[i][5])); //cout<<"trinagle: "<<i<<" "<<p1<<" "<<p2<<" "<<p3<<endl; if(isPointOnImage(p1, image.cols, image.rows) && isPointOnImage(p2, image.cols, image.rows) && isPointOnImage(p3, image.cols, image.rows)) { Mat warp_mask = Mat::zeros( image.rows, image.cols, image.type() ); Mat warp_dst = Mat::zeros( image.rows, image.cols, image.type() ); //cout<<"p1: "<<p1<<endl; // cout<<"p2: "<<p2<<endl; // cout<<"p3: "<<p3<<endl; Point2f verticesDst[3]; verticesDst[0]=p1; verticesDst[1]=p2; verticesDst[2]=p3; Point2f verticesSrc[3]; int p1num=this->meanShapePointsOrder[p1]; int p2num=this->meanShapePointsOrder[p2]; int p3num=this->meanShapePointsOrder[p3]; //cout<<"p1num: "<<p1num<<endl; //cout<<"p2num: "<<p2num<<endl; //cout<<"p3num: "<<p3num<<endl; verticesSrc[0]=Point(points[2*p1num], points[2*p1num+1]); verticesSrc[1]=Point(points[2*p2num], points[2*p2num+1]); verticesSrc[2]=Point(points[2*p3num], points[2*p3num+1]); //cout<<"dst: "<<verticesDst[0]<<" "<<verticesDst[1]<<" "<<verticesDst[2]<<endl; //cout<<"src: "<<verticesSrc[0]<<" "<<verticesSrc[1]<<" "<<verticesSrc[2]<<endl; Mat transformationMatrix=findTransformationMatrix(verticesSrc, verticesDst); //cout<<"transformation matrix: "<<transformationMatrix<<endl; warpAffine(image, warp_dst, transformationMatrix, warp_dst.size()); imshow("warped", warp_dst); Point trianglePoints[3]; trianglePoints[0]=verticesDst[0]; trianglePoints[1]=verticesDst[1]; trianglePoints[2]=verticesDst[2]; fillConvexPoly(warp_mask, trianglePoints, 3, CV_RGB(255,255,255), CV_AA, 0 ); //imshow("warp mask", warp_mask); warp_dst.copyTo(warp_final,warp_mask); } } imshow("warp final", warp_final); return warp_final; }
void cameraSettings2d::on_calcPlane_released() { if(cConfig->zoneSelected){ doPlaneCalculation=true; ui->processLabel->setText("RANSAC Plane Fitting..."); ui->Instructions->setText("Wait for the process to finish."); cConfig->maskZona.setTo(cv::Scalar::all(0)); fillConvexPoly(cConfig->maskZona,cConfig->zone,4,cvScalar(255)); } else{ ui->Instructions->setText("In order to do plane fit calculation \nyou must first select the valid zone."); } }
cv::Mat TextLine::drawDebugImage(cv::Mat baseImage) { cv::Mat debugImage(baseImage.size(), baseImage.type()); baseImage.copyTo(debugImage); cv::cvtColor(debugImage, debugImage, CV_GRAY2BGR); fillConvexPoly(debugImage, linePolygon.data(), linePolygon.size(), Scalar(0,0,165)); fillConvexPoly(debugImage, textArea.data(), textArea.size(), Scalar(125,255,0)); line(debugImage, topLine.p1, topLine.p2, Scalar(255,0,0), 1); line(debugImage, bottomLine.p1, bottomLine.p2, Scalar(255,0,0), 1); line(debugImage, charBoxTop.p1, charBoxTop.p2, Scalar(0,125,125), 1); line(debugImage, charBoxLeft.p1, charBoxLeft.p2, Scalar(0,125,125), 1); line(debugImage, charBoxRight.p1, charBoxRight.p2, Scalar(0,125,125), 1); line(debugImage, charBoxBottom.p1, charBoxBottom.p2, Scalar(0,125,125), 1); return debugImage; }
void findGoodCorners2(const Mat &grayFrame, const SoccerPitchData &data, Mat &currToKeyTrans, Mat &keyToTopTrans) { Mat topToCurrTrans; invert(keyToTopTrans * currToKeyTrans, topToCurrTrans); vector<Point2f> imagePitchOuterContour; perspectiveTransform(data.pitchOuterPoints, imagePitchOuterContour, topToCurrTrans); vector<Point2f> hull; convexHull(imagePitchOuterContour, hull); Mat mask = Mat::zeros(frameSize, CV_8UC1); fillConvexPoly(mask, vector<Point>(hull.begin(), hull.end()), Scalar(1, 0, 0)); dilate(mask, mask, getStructuringElement(MORPH_ELLIPSE, Size(3, 3))); Mat bin; adaptiveThreshold(grayFrame, bin, 255, ADAPTIVE_THRESH_MEAN_C , THRESH_BINARY, 5, -10); vector<Point2f> candidateCorners; goodFeaturesToTrack(bin, candidateCorners, 100, 0.01, 24, mask); cornerSubPix(bin, candidateCorners, Size(5, 5), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS & CV_TERMCRIT_ITER, 40, 0.001)); vector<Point2f> goodPoints; for (Point2f corner : candidateCorners) { if (goodCornerCheck(corner, bin) && !closeToBoundary(corner)) goodPoints.push_back(corner); } if (goodPoints.size() > 0) { vector<Point2f> reprojGoodPoints; perspectiveTransform(goodPoints, reprojGoodPoints, keyToTopTrans * currToKeyTrans); // try to add these new corners into the relocatedCorners for (int i = 0; i < reprojGoodPoints.size(); i++) { // if does not exists already and coincide with reproj of 28 points bool exists = hasSimilarPoint(relocatedPitchPoints, reprojGoodPoints[i], 10) ; int minId = findClosestPoint(data.pitchPoints, reprojGoodPoints[i]); double minDist = norm(reprojGoodPoints[i] - data.pitchPoints[minId]); if ((!exists ) && (minDist < 16) && (minDist < reprojErr[minId])) { relocatedCorners.push_back(goodPoints[i]); relocatedPitchPoints.push_back(data.pitchPoints[minId]); reprojErr[minId] = minDist; } } } cout<<relocatedCorners.size()<<" points relocated"<<endl; }
void fillconvex(Mat& image, Point2f* points, int count, Scalar color) { Point2f* hull; int size = convex_hull(points, count, &hull); // apparently we have to convert Point2f array to integers ... Point* hulli = new Point[size]; for (int i = 0; i < size; i++) { hulli[i].x = (int) hull[i].x; hulli[i].y = (int) hull[i].y; } free(hull); fillConvexPoly(image, hulli, size, color, 1); delete [] hulli; }
Mat vehicle_det::get_mask(Mat & src) { //cout<<__PRETTY_FUNCTION__<<endl; /* ROI by creating mask for the parallelogram */ Mat mask = Mat(src.rows, src.cols, CV_8UC1); // Create black image with the same size as the original for(int i = 0; i < mask.cols; i++) for(int j = 0; j < mask.rows; j++) { mask.at<uchar>(Point(i, j)) = 0; } // Create Polygon from vertices vector<Point> ROI_Poly; approxPolyDP(ROI_Vertices, ROI_Poly, 1.0, true); // Fill polygon white fillConvexPoly(mask, &ROI_Poly[0], ROI_Poly.size(), 255, 8, 0); // Cut out ROI and store it in imageDest return mask; }
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 cameraSettings2d::hacerUpdate(){ ///ACA UPDATE DE TODO LO QUE SE NECESITA camUpdate(); if(isUpdated){ if(zoneSelection){ if(numSelectedPoints<4){ if(ui->glImage->isNewClick){ cConfig->zone[numSelectedPoints].x=ui->glImage->lastPos.x()*640/ui->glImage->width(); cConfig->zone[numSelectedPoints].y=ui->glImage->lastPos.y()*480/ui->glImage->height(); //cout << cConfig->zone[numSelectedPoints].x << "," << cConfig->zone[numSelectedPoints].y << endl; numSelectedPoints++; ui->glImage->isNewClick=false; ui->progressBar->setValue(numSelectedPoints*25); } } else{ numSelectedPoints=0; zoneSelection=false; cConfig->zoneSelected=true; ui->processLabel->setText("Idle process"); ui->progressBar->setValue(0); ui->Instructions->setText("Nothing to do..."); cConfig->maskZona.setTo(cv::Scalar::all(0)); fillConvexPoly(cConfig->maskZona,cConfig->zone,4,cvScalar(255)); Mat temp=cConfig->maskBack & cConfig->maskZona; ui->imgMaskBack->updateImage(false,temp); ui->imgMaskPlane->updateImage(false,cConfig->maskZona); } } if(mixImagesToColor()){ if(BackCalibration){ if(!cConfig->BM->proc(cConfig->variance,depthsS[nC],masks[nC],cConfig->Background,cConfig->maskBack)){ ui->progressBar->setValue(((float)cConfig->BM->nback/(cConfig->BM->total+1))*100); } else{ BackCalibration=false; ui->processLabel->setText("Idle process"); ui->progressBar->setValue(0); ui->Instructions->setText("Nothing to do..."); Mat temp0,temp1; cConfig->Background.convertTo(temp0,CV_8UC1,255); if(cConfig->zoneSelected) temp1=cConfig->maskBack & cConfig->maskZona; else temp1=cConfig->maskBack; ui->imgBack->updateImage(false,temp0); ui->imgMaskBack->updateImage(false,temp1); } } if(zoneSelection){ for(int cir=0;cir<numSelectedPoints;cir++) circle(mixs[nC],cConfig->zone[cir],10,Scalar(0,0,255),-1); } else if(cConfig->zoneSelected){ int *num=new int[1]; num[0]=4; const Point* ptt[1] = { cConfig->zone }; polylines(mixs[nC],ptt,num,1,1,cvScalar(255),2); delete num; } if(doPlaneCalculation){ cam->retrivePointCloud(nC,depths[nC],pCs[nC]); cConfig->VP->calcPlanoPC(pCs[nC],cConfig->maskZona,masks[nC],ui->progressBar); doPlaneCalculation=false; ui->processLabel->setText("Idle process"); ui->progressBar->setValue(0); ui->Instructions->setText("Nothing to do..."); } ui->glImage->updateImage(true,mixs[nC]); if(cConfig->method=="Background"){ sktP->processImage(depthsS[nC],toBlobs,masks[nC]); } else{ cam->retrivePointCloud(nC,depths[nC],pCs[nC]); sktP->processImage(pCs[nC],toBlobs,masks[nC]); } ui->glBlobs->updateImage(false,toBlobs); } if(refiningMask){ if(cConfig->method=="Background"){ cConfig->maskBack=(cConfig->maskBack==255) & (toBlobs==0); cConfig->maskZona=(cConfig->maskZona==255) & (toBlobs==0); ui->imgMaskBack->updateImage(false,cConfig->maskBack); } else{ cConfig->maskZona=(cConfig->maskZona==255) & (toBlobs==0); ui->imgMaskPlane->updateImage(false,cConfig->maskZona); } } } ////////////////////Procesamiento isUpdated=false; }
void Target::findLaser(Mat imgInput, Mat *imgOutput) { Mat hsv_img, binary, cont, imgCopy; imgCopy = imgInput; cvtColor(imgCopy, hsv_img, CV_BGR2HSV); Mat imgThresholded; int iLowH = colorRatio[0]; int iHighH = colorRatio[1]; int iLowS = colorRatio[2]; int iHighS = colorRatio[3]; int iLowV = colorRatio[4]; int iHighV = colorRatio[5]; inRange(hsv_img, Scalar(iLowH, iLowS, iLowV), Scalar(iHighH, iHighS, iHighV), imgThresholded); //Threshold the image //morphological opening (remove small objects from the foreground) erode(imgThresholded, imgThresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5))); dilate(imgThresholded, imgThresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5))); //morphological closing (fill small holes in the foreground) dilate(imgThresholded, imgThresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5))); erode(imgThresholded, imgThresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5))); binary = imgThresholded; vector<vector<Point>> contours; vector<Point> contours_poly; Rect boundRect; binary.copyTo(cont); findContours(cont, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); int max = 0, i_cont = -1; Mat drawing = Mat::zeros(cont.size(), CV_8UC3); for (int i = 0; i< contours.size(); i++) { if (abs(contourArea(Mat(contours[i]))) > max) { max = abs(contourArea(Mat(contours[i]))); i_cont = i; } } if (i_cont >= 0) { approxPolyDP(Mat(contours[i_cont]), contours_poly, 3, true); boundRect = boundingRect(Mat(contours_poly)); fillConvexPoly(imgCopy, contours_poly, contours_poly.size()); rectangle(imgCopy, boundRect.tl(), boundRect.br(), Scalar(125, 250, 125), 2, 8, 0); line(imgCopy, boundRect.tl(), boundRect.br(), Scalar(250, 125, 125), 2, 8, 0); line(imgCopy, Point(boundRect.x + boundRect.width, boundRect.y), Point(boundRect.x, boundRect.y + boundRect.height), Scalar(250, 125, 125), 2, 8, 0); string s; stringstream out; out << boundRect.x + boundRect.width / 2 << "x" << boundRect.y + boundRect.height / 2; Point contour_center; contour_center.x = boundRect.x + boundRect.width / 2; contour_center.y = boundRect.y + boundRect.height / 2; *laser = contour_center; s = out.str(); putText(imgCopy, s, Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(20, 40, 80), 3, 8); drawContours(drawing, contours, i_cont, Scalar(125, 125, 250), 2); } *imgOutput = imgCopy; //imshow("kolory", binary); }
void FindContour::singleCellDetection(const Mat &img, vector<Point> &cir_org, Mat &dispImg1, Mat &dispImg2, int &area, int &perimeter, Point2f &ctroid, float &shape, Mat &cell_alpha, // only the area inside cell (without background) vector<Point> &smooth_contour_curve, // relative position (without counting rect.x and rect.y) vector<Point> &smooth_contour_curve_abs, // absolut position Mat &blebsImg, Rect &rectangle, //vector<int> &blebs, int &frameNum) { frame = &img; vector<Point> cir; //***global coordinates of circle*** //cout << "["; for(unsigned int i = 0; i < cir_org.size(); i++){ cir.push_back(Point(cir_org[i].x / scale, cir_org[i].y / scale)); //cout << int(cir_org[i].x / scale) << ", " << int(cir_org[i].y / scale) << "; "; } //cout << "]" << endl; //enlarge the bounding rect by adding a margin (e) to it rect = enlargeRect(boundingRect(Mat(cir)), 5, img.cols, img.rows); //cout << "rect_roi " << boundingRect(Mat(cir)) << "\n"; //cout << "enlarged rect " << rect << endl; dispImg1 = (*frame)(rect).clone(); Mat sub; //*** the rectangle region of ROI (Gray) *** cv::cvtColor(dispImg1, sub, CV_RGB2GRAY); int width = sub.cols; int height = sub.rows; rectangle = rect; // Mat canny; // CannyWithBlur(sub, canny); // imshow("canny", canny); vector<Point> circle_ROI; //***local coordinates of circle*** for (unsigned int i = 0; i < cir.size(); i++){ Point p = Point(cir[i].x - rect.x, cir[i].y - rect.y); circle_ROI.push_back(p); } Mat adapThreshImg1 = Mat::zeros(height, width, sub.type()); //image edge detection for the sub region (roi rect) adaptiveThreshold(sub, adapThreshImg1, 255.0, ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY_INV, blockSize, constValue); //imshow("adapThreshImg1", adapThreshImg1); // dilation and erosion Mat dilerod; dilErod(adapThreshImg1, dilerod, dilSize); //display image 2 -- dilerod of adaptive threshold image GaussianBlur(dilerod, dilerod, Size(3, 3), 2, 2 ); //mask for filtering out the cell of interest Mat mask_conv = Mat::zeros(height, width, CV_8UC1); fillConvexPoly(mask_conv, circle_ROI, Scalar(255)); //imshow("mask_before", mask_conv); //dilate the mask -> region grows Mat mask_conv_dil; Mat element = getStructuringElement( MORPH_ELLIPSE, Size( 2*dilSize+1, 2*dilSize+1 ), Point(dilSize,dilSize) ); dilate(mask_conv, mask_conv_dil, element); //imshow("mask_dil", mask_conv_dil); //bitwise AND on mask and dilerod bitwise_and(mask_conv_dil, dilerod, dispImg2); // findcontours vector<vector<Point> > contours; vector<Vec4i> hierarchy; unsigned int largest_contour_index; dilErodContours(dispImg2, contours, hierarchy, largest_contour_index, perimeter, dispImg1); // find the area of the cell by counting the white area inside the largest contour Mat cellArea = Mat::zeros(height, width, CV_8UC1); drawContours(cellArea, contours, largest_contour_index, Scalar(255), -1, 8, hierarchy, 0, Point() ); //imshow("cellArea", cellArea); area = countNonZero(cellArea); //cout << "frame " << frameNum << "\n"; //cout << contours[largest_contour_index] << endl; //renew circle points as the convex hull vector<Point> convHull; convexHull(contours[largest_contour_index], convHull); // find the centroid of the contour Moments mu = moments(contours[largest_contour_index]); ctroid = Point2f(mu.m10/mu.m00 + rect.x, mu.m01/mu.m00 + rect.y); // find the shape of the cell by the largest contour and centroid shape = findShape(ctroid, contours[largest_contour_index]); ////---- draw largest contour start ---- //draw the largest contour Mat borderImg = Mat::zeros(height, width, CV_8UC1); drawContours(borderImg, contours, largest_contour_index, Scalar(255), 1, 8, hierarchy, 0, Point()); //QString cellFileName0 = "border" + QString::number(frameNum) + ".png"; //imwrite(cellFileName0.toStdString(), borderImg); Mat cell; bitwise_and(cellArea, sub, cell); //cell_alpha = createAlphaMat(cell); // cell image with exactly the contour detected //vector<int> compression_params; //compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION); //compression_params.push_back(9); // QString cellFileName1 = "cell" + QString::number(frameNum) + ".png"; // imwrite(cellFileName1.toStdString(), cell_alpha, compression_params); ////---- draw largest contour end ---- // find the number and the sizes of blebs of the cell Mat smooth; vector<Point> smoothCurve; int WIN = 25; smooth = curveSmooth(borderImg, WIN, contours[largest_contour_index], smoothCurve, convHull); //smooth = curveSmooth(borderImg, WIN, contours[largest_contour_index], smoothCurve, ctroid/*Point(ctroid.x, ctroid.y)*/); //drawPointVectors(dispImg1, smoothCurve, 1, Scalar(159, 120, 28)); Mat smooth_contour; int w = 10; smooth_contour = curveSmooth(borderImg, w, contours[largest_contour_index], smooth_contour_curve, convHull); //smooth_contour = curveSmooth(borderImg, w, contours[largest_contour_index], smooth_contour_curve, ctroid/*Point(ctroid.x, ctroid.y)*/); //imshow("smooth_contour", smooth_contour); for(unsigned int i = 0; i < smooth_contour_curve.size(); i++){ Point p(smooth_contour_curve[i].x + rect.x, smooth_contour_curve[i].y + rect.y); smooth_contour_curve_abs.push_back(p); } // cout << "ctroid X " << ctroid.x << " Y " << ctroid.y << endl; //// for(unsigned int i = 0; i < contours[largest_contour_index].size(); i++) //// cout << "(" << contours[largest_contour_index][i].x + rect.x << ", " << contours[largest_contour_index][i].y + rect.y << ") "; //// cout << endl; // for(unsigned int i = 0; i < smooth_contour_curve_abs.size(); i++) // cout << "(" << smooth_contour_curve_abs[i].x << ", " << smooth_contour_curve_abs[i].y << ") "; // cout << endl; //cout << mask_conv_dil.type() << " " << sub.type() << endl; Mat cell_convex; bitwise_and(smooth_contour, sub, cell_convex); cell_alpha = createAlphaMat(cell_convex); // imshow("cell_convex_contour", cell_alpha); dispImg2 = cell_convex.clone(); //change dispImg2 from gray to rgb for displaying cvtColor(dispImg2, dispImg2, CV_GRAY2RGB); bitwise_not(smooth, smooth); //Mat blebsImg; bitwise_and(smooth, cellArea, blebsImg); // imshow("blebs", blebsImg); // QString cellFileName2 = "blebs" + QString::number(frameNum) + ".png"; // imwrite(cellFileName2.toStdString(), blebs); //QString cellFileName2 = "dispImg1" + QString::number(frameNum) + ".png"; //imwrite(cellFileName2.toStdString(), dispImg1); cir_org.clear(); for(unsigned int i = 0; i < convHull.size(); i++) cir_org.push_back(Point((convHull[i].x + rect.x)*scale, (convHull[i].y + rect.y)*scale)); }
// get ROI + edgeDectection void FindContour::cellDetection(const Mat &img, vector<Point> &cir_org, Mat &dispImg1, Mat &dispImg2, vector<Point2f> &points1, vector<Point2f> &points2, int &area, int &perimeter, Point2f &ctroid, float &shape, // vector<int> &blebs, int &frameNum){ frame = &img; //rect = boundingRect(Mat(cir)); Mat frameGray; cv::cvtColor(*frame, frameGray, CV_RGB2GRAY); /* QString cellFileName0 = "frame" + QString::number(frameNum) + ".png"; imwrite(cellFileName0.toStdString(), frameGray);*/ vector<Point> cir; //***global coordinates of circle*** for(unsigned int i = 0; i < cir_org.size(); i++){ cir.push_back(Point(cir_org[i].x / scale, cir_org[i].y / scale)); } //cout << "original circle: " << cir_org << "\n" << " scaled circle: " << cir << endl; //enlarge the bounding rect by adding a margin (e) to it rect = enlargeRect(boundingRect(Mat(cir)), 5, img.cols, img.rows); //global circle mask Mat mask_cir_org = Mat::zeros(frame->size(), CV_8UC1); fillConvexPoly(mask_cir_org, cir, Scalar(255)); // flow points vector<unsigned int> cell_pts_global; vector<Point2f> longOptflow_pt1, longOptflow_pt2; Point2f avrg_vec = Point2f(0,0); for(unsigned int i = 0; i < points1.size(); i++){ Point p1 = Point(points1[i].x, points1[i].y); Point p2 = Point(points2[i].x, points2[i].y); if(mask_cir_org.at<uchar>(p1.y,p1.x) == 255 ){ cell_pts_global.push_back(i); if(dist_square(p1, p2) > 2.0){ longOptflow_pt1.push_back(Point2f(p1.x, p1.y)); longOptflow_pt2.push_back(Point2f(p2.x, p2.y)); avrg_vec.x += (p2.x-p1.x); avrg_vec.y += (p2.y-p1.y); } } } // if(longOptflow_pt1.size()!= 0){ // avrg_vec.x = avrg_vec.x / longOptflow_pt1.size(); // avrg_vec.y = avrg_vec.y / longOptflow_pt1.size(); // } Rect trans_rect = translateRect(rect, avrg_vec); // *** // if (the homography is a good one) use the homography to update the rectangle // otherwise use the same rectangle // *** if (longOptflow_pt1.size() >= 4){ Mat H = findHomography(Mat(longOptflow_pt1), Mat(longOptflow_pt2), CV_RANSAC, 2); //cout << "H: " << H << endl; if(determinant(H) >= 0){ vector<Point> rect_corners; rect_corners.push_back(Point(rect.x, rect.y)); rect_corners.push_back(Point(rect.x+rect.width, rect.y)); rect_corners.push_back(Point(rect.x, rect.y+rect.height)); rect_corners.push_back(Point(rect.x+rect.width, rect.y+rect.height)); vector<Point> rect_update_corners = pointTransform(rect_corners, H); trans_rect = boundingRect(rect_update_corners); } } rectangle(frameGray, trans_rect, Scalar(255), 2); imshow("frameGray", frameGray); dispImg1 = (*frame)(rect).clone(); //dispImg2 = Mat(dispImg1.rows, dispImg1.cols, CV_8UC3); Mat sub; //*** the rectangle region of ROI (Gray) *** cv::cvtColor(dispImg1, sub, CV_RGB2GRAY); int width = sub.cols; int height = sub.rows; vector<Point> circle_ROI; //***local coordinates of circle*** for (unsigned int i = 0; i < cir.size(); i++){ Point p = Point(cir[i].x - rect.x, cir[i].y - rect.y); circle_ROI.push_back(p); } Mat adapThreshImg1 = Mat::zeros(height, width, sub.type()); //image edge detection for the sub region (roi rect) adaptiveThreshold(sub, adapThreshImg1, 255.0, ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY_INV, blockSize, constValue); //imshow("adapThreshImg1", adapThreshImg1); // dilation and erosion Mat dilerod; dilErod(adapThreshImg1, dilerod, dilSize); //display image 2 -- dilerod of adaptive threshold image GaussianBlur(dilerod, dilerod, Size(3, 3), 2, 2 ); //mask for filtering out the cell of interest Mat mask_conv = Mat::zeros(height, width, CV_8UC1); fillConvexPoly(mask_conv, circle_ROI, Scalar(255)); //imshow("mask_before", mask_conv); //dilate the mask -> region grows Mat mask_conv_dil; Mat element = getStructuringElement( MORPH_ELLIPSE, Size( 2*2+2, 2*2+1 ), Point(2,2) ); dilate(mask_conv, mask_conv_dil, element); //imshow("mask_dil", mask_conv_dil); /* Mat mask_conv_ero; erode(mask_conv, mask_conv_ero, element); Mat ring_dil, ring_ero; bitwise_xor(mask_conv, mask_conv_dil, ring_dil); bitwise_xor(mask_conv, mask_conv_ero, ring_ero); Mat ring; bitwise_or(ring_dil, ring_ero, ring); imshow("ring", ring); vector<unsigned int> opt_onRing_index; // use optflow info set rectangle for(unsigned int i = 0; i < points2.size(); i++){ Point p2 = Point(points2[i].x, points2[i].y); Point p1 = Point(points1[i].x, points1[i].y); if(ring.at<uchar>(p1.y,p1.x) != 255 && ring.at<uchar>(p2.y,p2.x) != 255) continue; else{ opt_onRing_index.push_back(i); } }*/ /* // draw the optflow on dispImg1 unsigned int size = opt_inside_cl_index.size(); for(unsigned int i = 0; i < size; i++ ){ Point p0( ceil( points1[i].x - rect.x ), ceil( points1[i].y - rect.y ) ); Point p1( ceil( points2[i].x - rect.x ), ceil( points2[i].y - rect.y) ); //std::cout << "(" << p0.x << "," << p0.y << ")" << "\n"; //std::cout << "(" << p1.x << "," << p1.y << ")" << std::endl; //draw lines to visualize the flow double angle = atan2((double) p0.y - p1.y, (double) p0.x - p1.x); double arrowLen = 0.01 * (double) (width); line(dispImg1, p0, p1, CV_RGB(255,255,255), 1 ); Point p; p.x = (int) (p1.x + arrowLen * cos(angle + 3.14/4)); p.y = (int) (p1.y + arrowLen * sin(angle + 3.14/4)); line(dispImg1, p, p1, CV_RGB(255,255,255), 1 ); p.x = (int) (p1.x + arrowLen * cos(angle - 3.14/4)); p.y = (int) (p1.y + arrowLen * sin(angle - 3.14/4)); line(dispImg1, p, Point(2*p1.x - p0.x, 2*p1.y - p0.y), CV_RGB(255,255,255), 1 ); //line(dispImg1, p, p1, CV_RGB(255,255,255), 1 ); }*/ /* //stop growing when meeting with canny edges that outside the circle Mat canny; CannyWithBlur(sub, canny); Mat cannyColor; cvtColor(canny, cannyColor, CV_GRAY2RGB); imwrite("canny.png", canny); vector<Point> outsideCircle; vector<Point> onRing; for(int j = 0; j < height; j++){ for(int i = 0; i < width; i++){ if(canny.at<uchar>(j,i) != 0 && mask_conv.at<uchar>(j,i) == 0){ cannyColor.data[cannyColor.channels()*(cannyColor.cols*j + i)+0] = 81; cannyColor.data[cannyColor.channels()*(cannyColor.cols*j + i)+1] = 172; cannyColor.data[cannyColor.channels()*(cannyColor.cols*j + i)+2] = 251; outsideCircle.push_back(Point(i, j)); if(ring.at<uchar>(j,i) != 0){ cannyColor.data[cannyColor.channels()*(cannyColor.cols*j + i)+0] = 255; cannyColor.data[cannyColor.channels()*(cannyColor.cols*j + i)+1] = 255; cannyColor.data[cannyColor.channels()*(cannyColor.cols*j + i)+2] = 0; onRing.push_back(Point(i,j)); } } } } */ // QString cannyFileName = "canny" + QString::number(frameNum) + ".png"; // imwrite(cannyFileName.toStdString(), cannyColor); //bitwise AND on mask and dilerod bitwise_and(mask_conv/*_dil*/, dilerod, dispImg2); // findcontours vector<vector<Point> > contours; vector<Vec4i> hierarchy; unsigned int largest_contour_index; dilErodContours(dispImg2, contours, hierarchy, largest_contour_index, perimeter, dispImg1); // find the area of the cell by counting the white area inside the largest contour Mat cellArea = Mat::zeros(height, width, CV_8UC1); drawContours(cellArea, contours, largest_contour_index, Scalar(255), -1, 8, hierarchy, 0, Point() ); //imshow("cell", cell); area = countNonZero(cellArea); //cout << "frame " << frameNum << "\n"; //cout << contours[largest_contour_index] << endl; //change dispImg2 from gray to rgb for displaying cvtColor(dispImg2, dispImg2, CV_GRAY2RGB); //renew circle points as the convex hull vector<Point> convHull; convexHull(contours[largest_contour_index], convHull); // find the centroid of the contour Moments mu = moments(contours[largest_contour_index]); ctroid = Point2f(mu.m10/mu.m00 + rect.x, mu.m01/mu.m00 + rect.y); // find the shape of the cell by the largest contour and centroid shape = findShape(ctroid, contours[largest_contour_index]); ////---- draw largest contour start ---- //draw the largest contour Mat borderImg = Mat::zeros(height, width, CV_8UC1); drawContours(borderImg, contours, largest_contour_index, Scalar(255), 1, 8, hierarchy, 0, Point()); //QString cellFileName0 = "border" + QString::number(frameNum) + ".png"; //imwrite(cellFileName0.toStdString(), borderImg); ////---- draw largest contour end ---- // find the number and the sizes of blebs of the cell Mat smooth; vector<Point> smoothCurve; int WIN = 25; vector< vector<Point> > tmp; smooth = curveSmooth(borderImg, WIN, contours[largest_contour_index], smoothCurve, convHull/*ctroid*/); tmp.push_back(smoothCurve); drawContours(dispImg1, tmp, 0, Scalar(255, 0, 0)); bitwise_not(smooth, smooth); Mat blebsImg; bitwise_and(smooth, cellArea, blebsImg); //imshow("blebs", blebs); //QString cellFileName2 = "blebs" + QString::number(frameNum) + ".png"; //imwrite(cellFileName2.toStdString(), blebs); // vector<Point> blebCtrs; // recursive_connected_components(blebsImg, blebs, blebCtrs); // for(unsigned int i = 0; i < blebCtrs.size(); i++){ // circle(dispImg1, blebCtrs[i], 2, Scalar(255, 255, 0)); // } cir_org.clear(); for(unsigned int i = 0; i < convHull.size(); i++) cir_org.push_back(Point((convHull[i].x + rect.x)*scale, (convHull[i].y + rect.y)*scale)); }
Mat FindContour::curveSmooth(Mat &contourImg, int WIN, // half window size for laplacian smoothing vector<Point> &border, vector<Point> &smooth, /*Point cntoid*/vector<Point> &convHull ) { // if(contourImg.type() != CV_8UC1){ // cvtColor( contourImg, contourImg, CV_BGR2GRAY ); // } double width = contourImg.cols; double height = contourImg.rows; Moments mu = moments(convHull); // Moments mu = moments(border); Point cntoid = Point2f(mu.m10/mu.m00/* + rect.x*/, mu.m01/mu.m00/* +rect.y*/); double d_min = max(width, height)*max(width, height); vector<polarPoint> border_polar; for (unsigned int n = 0; n < border.size(); n++) { //find the polar coordinates of the border; border_polar.push_back(cartesianToPolar(cntoid, border[n])); //find the nearest point to the center on the border double d = dist(cntoid, border[n]); if(d < d_min){ d_min = d; } } d_min = sqrt(d_min); // sort border_polar by theta sort(border_polar.begin(), border_polar.end(), sortByTheta); // Laplacian smoothing unsigned int border_size = border_polar.size(); for(unsigned int n = 0; n < border_size; n++){ //cout << border_polar[n].r << " " << border_polar[n].theta << " "; double avg = 0; for(int w = -WIN; w < WIN; w++){ unsigned int pos = std::fabs((w+n+border_size)%border_size); //cout << " pos " << pos << " "; avg += border_polar[pos].r; } avg = avg/WIN/2; polarPoint polar; polar.r = avg; polar.theta = border_polar[n].theta; //cout << polar.r << " " << polar.theta << " "; Point p = polarToCartesian(cntoid, polar); //circle(color, p, 1, Scalar(255, 255, 0)); smooth.push_back(p); //cout << p.x << " " << p.y << "\n"; } Mat smoothCircle = Mat::zeros(height, width, CV_8UC1); fillConvexPoly(smoothCircle, smooth, Scalar(255)); // fillPoly(smoothCircle, smooth, Scalar(255)); //imshow("smoothCircle", smoothCircle); return smoothCircle; }
void ModalityConvex::update(Image& image, PatchSet* patchSet, Rect bounds) { Ptr<PatchSet> patches = Ptr<PatchSet>(reliablePatchesFilter.empty() ? patchSet : patchSet->filter(*reliablePatchesFilter)); if (patches->size() < 3) { //flush(); return; } Mat temp = image.get_float_mask(); temp.setTo(0); if (history.empty()) { history.create(image.height(), image.width(), CV_32F); history.setTo(0); } Point2f* points = new Point2f[patches->size()]; Point2f* hull = NULL; Point2f offset = Point2f(image.width() / 2, image.height() / 2) - patchSet->mean_position(); Point2f mean(0, 0); for (int i = 0; i < patches->size(); i++) { points[i] = patches->get_position(i) + offset; } int size = convex_hull(points, patches->size(), &hull); for (int i = 0; i < size; i++) { mean.x += hull[i].x; mean.y += hull[i].y; } mean.x /= size; mean.y /= size; Point* hulli = new Point[size]; Point* hullei = new Point[size]; for (int i = 0; i < size; i++) { hulli[i].x = (int) hull[i].x; hulli[i].y = (int) hull[i].y; } expand(hull, size, mean, margin); for (int i = 0; i < size; i++) { hullei[i].x = (int) hull[i].x; hullei[i].y = (int) hull[i].y; } fillConvexPoly(temp, hullei, size, Scalar(1 - margin_diminish)); fillConvexPoly(temp, hulli, size, Scalar(1)); delete [] points; free(hull); delete [] hulli; delete [] hullei; history = history * persistence + temp * (1.0f - persistence); }
void pxsnsr(vector<vector<Point>> &contours, Mat &Seg_img_red, Mat &Seg_img_blue) { Rect *r = new Rect[contours.size()]; // 定义外接矩形数组 Mat obj_rec_thr = Mat::zeros(Seg_img_red.size(), CV_8UC3); for (unsigned int i = 0; i < contours.size(); i++) { r[i] = boundingRect(Mat(contours[i]));// boundingRect获取这个外接矩形 } /// 绘出轮廓及其凸包 Mat Seg_img_blue_hull(Seg_img_blue.size(), CV_8U, Scalar(0)); vector<vector<Point> >hull(contours.size()); for (unsigned int i = 0; i< contours.size(); i++) { convexHull(Mat(contours[i]), hull[i], false); fillConvexPoly(Seg_img_blue_hull, &hull[i][0], hull[i].size(), Scalar(1)); } erode(Seg_img_blue_hull, Seg_img_blue_hull, Mat(), Point(-1, -1), dilate_size); // 对图像进行之前的膨胀恢复 Seg_img_blue_hull.convertTo(Seg_img_blue_hull, CV_32F); imshow("Seg_img_blue _hull", Seg_img_blue_hull); double Evaluation = 0; // 对潜在目标的打分值初始化 double Evaluation_max = 0; // 对潜在目标的打分最大值初始化 int index_best = -1; // 最优轮廓标记 <注意此处初始值应为-1> int index = 0; // 轮廓标记 cout << contours.size() << endl; vector<vector<Point>>::const_iterator itContours = contours.begin(); //for (; itContours != contours.end(); ++itContours) while (itContours != contours.end()) { Mat imageROI_red = Seg_img_red(cv::Rect(r[index].x, r[index].y, r[index].width, r[index].height)); Mat imageROI_blue = Seg_img_blue_hull(cv::Rect(r[index].x, r[index].y, r[index].width, r[index].height)); Mat imageROI_red_blue = imageROI_red + imageROI_blue; threshold(imageROI_red_blue, imageROI_red_blue, 1, 1, THRESH_BINARY); // 进行阈值分割(大于阈值1等于2时候取 1) Scalar s1 = sum(imageROI_red_blue); Scalar s2 = sum(imageROI_blue); double sum_red = s1.val[0]; // 获取图像块包含在蓝色中的红色像素数量 double sum_blue = s2.val[0]; // 获取图像块中蓝色像素数量 double pixel_sum_rate = rate(sum_red, sum_blue); // 计算图像块中红蓝像素的比例 cout << "sum_red:" << sum_red << "\t" << "," << "sum_blue:" << sum_blue << "\t"; cout << "pixel_sum_rate:" << pixel_sum_rate << endl; // 将红蓝像素比太低的连通域轮廓删除 if ((pixel_sum_rate < threshold_value_pixel_rate) || (sum_red < 12)) // 如当前轮廓不含一定的红色像素 { itContours = contours.erase(itContours); // 删除当前轮廓 <特别注意:删除当前轮廓后迭代器自动指向后一个> index++; continue; } else // 如当前轮廓含一定的红色像素 { int aaa = contours.size(); // 用于设置条件断点 Evaluation = sum_red; // 目标轮廓简单评价值定义 if (Evaluation > Evaluation_max) { Evaluation_max = Evaluation; index_best++; cout << "index_best - " << index_best << endl; } index++; itContours++; // 继续检索下一个轮廓 <此处必须要代码指定迭代器转向后一个轮廓> } } int ttt = contours.size(); // 用于设置条件断点 // 如果仍然有大于一个潜在目标则选取最优的一个 if (ttt > 1) { int index = 0; vector<vector<Point>>::const_iterator itContours_2 = contours.begin(); while(itContours_2 != contours.end()) { if (index != index_best) itContours_2 = contours.erase(itContours_2); else ++itContours_2; index++; } } delete[] r; }
void CharacterAnalysis::filterBetweenLines(Mat img, TextContours& textContours, vector<TextLine> textLines ) { static float MIN_AREA_PERCENT_WITHIN_LINES = 0.88; static float MAX_DISTANCE_PERCENT_FROM_LINES = 0.15; if (textLines.size() == 0) return; vector<Point> validPoints; // Create a white mask for the area inside the polygon Mat outerMask = Mat::zeros(img.size(), CV_8U); for (unsigned int i = 0; i < textLines.size(); i++) fillConvexPoly(outerMask, textLines[i].linePolygon.data(), textLines[i].linePolygon.size(), Scalar(255,255,255)); // For each contour, determine if enough of it is between the lines to qualify for (unsigned int i = 0; i < textContours.size(); i++) { if (textContours.goodIndices[i] == false) continue; float percentInsideMask = getContourAreaPercentInsideMask(outerMask, textContours.contours, textContours.hierarchy, (int) i); if (percentInsideMask < MIN_AREA_PERCENT_WITHIN_LINES) { // Not enough area is inside the lines. if (config->debugCharAnalysis) cout << "Rejecting due to insufficient area" << endl; textContours.goodIndices[i] = false; continue; } // now check to make sure that the top and bottom of the contour are near enough to the lines // First get the high and low point for the contour // Remember that origin is top-left, so the top Y values are actually closer to 0. Rect brect = boundingRect(textContours.contours[i]); int xmiddle = brect.x + (brect.width / 2); Point topMiddle = Point(xmiddle, brect.y); Point botMiddle = Point(xmiddle, brect.y+brect.height); // Get the absolute distance from the top and bottom lines for (unsigned int i = 0; i < textLines.size(); i++) { Point closestTopPoint = textLines[i].topLine.closestPointOnSegmentTo(topMiddle); Point closestBottomPoint = textLines[i].bottomLine.closestPointOnSegmentTo(botMiddle); float absTopDistance = distanceBetweenPoints(closestTopPoint, topMiddle); float absBottomDistance = distanceBetweenPoints(closestBottomPoint, botMiddle); float maxDistance = textLines[i].lineHeight * MAX_DISTANCE_PERCENT_FROM_LINES; if (absTopDistance < maxDistance && absBottomDistance < maxDistance) { // It's ok, leave it as-is. } else { textContours.goodIndices[i] = false; if (config->debugCharAnalysis) cout << "Rejecting due to top/bottom points that are out of range" << endl; } } } }
vector<bool> CharacterAnalysis::filterBetweenLines(Mat img, vector<vector<Point> > contours, vector<Vec4i> hierarchy, vector<Point> outerPolygon, vector<bool> goodIndices) { static float MIN_AREA_PERCENT_WITHIN_LINES = 0.88; vector<bool> includedIndices(contours.size()); for (int j = 0; j < contours.size(); j++) includedIndices[j] = false; if (outerPolygon.size() == 0) return includedIndices; vector<Point> validPoints; // Figure out the line height LineSegment topLine(outerPolygon[0].x, outerPolygon[0].y, outerPolygon[1].x, outerPolygon[1].y); LineSegment bottomLine(outerPolygon[3].x, outerPolygon[3].y, outerPolygon[2].x, outerPolygon[2].y); float x = ((float) img.cols) / 2; Point midpoint = Point(x, bottomLine.getPointAt(x)); Point acrossFromMidpoint = topLine.closestPointOnSegmentTo(midpoint); float lineHeight = distanceBetweenPoints(midpoint, acrossFromMidpoint); // Create a white mask for the area inside the polygon Mat outerMask = Mat::zeros(img.size(), CV_8U); Mat innerArea = Mat::zeros(img.size(), CV_8U); fillConvexPoly(outerMask, outerPolygon.data(), outerPolygon.size(), Scalar(255,255,255)); for (int i = 0; i < contours.size(); i++) { if (goodIndices[i] == false) continue; // get rid of the outline by drawing a 1 pixel width black line drawContours(innerArea, contours, i, // draw this contour cv::Scalar(255,255,255), // in CV_FILLED, 8, hierarchy, 0 ); bitwise_and(innerArea, outerMask, innerArea); vector<vector<Point> > tempContours; findContours(innerArea, tempContours, CV_RETR_EXTERNAL, // retrieve the external contours CV_CHAIN_APPROX_SIMPLE ); // all pixels of each contours ); double totalArea = contourArea(contours[i]); double areaBetweenLines = 0; for (int tempContourIdx = 0; tempContourIdx < tempContours.size(); tempContourIdx++) { areaBetweenLines += contourArea(tempContours[tempContourIdx]); } if (areaBetweenLines / totalArea >= MIN_AREA_PERCENT_WITHIN_LINES) { includedIndices[i] = true; } innerArea.setTo(Scalar(0,0,0)); } return includedIndices; }