void paperRegistration::detectFigures(cv::vector<cv::vector<cv::Point>>& squares, cv::vector<cv::vector<cv::Point>>& triangles, float minLength, float maxLength, int tresh_binary) { if (currentDeviceImg.empty()) return; //cv::Mat image = currentDeviceImg; //cv::Mat image = cv::imread("C:/Users/sophie/Desktop/meinz.png", CV_LOAD_IMAGE_GRAYSCALE);// cv::imread(path, CV_LOAD_IMAGE_GRAYSCALE); //resize(image, image, cv::Size(500,700)); squares.clear(); triangles.clear(); cv::Mat gray; cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(7,7)); cv::vector<cv::vector<cv::Point> > contours; //compute binary image //use dilatation and erosion to improve edges threshold(currentDeviceImg, gray, tresh_binary, 255, cv::THRESH_BINARY_INV); dilate(gray, gray, element, cv::Point(-1,-1)); erode(gray, gray, element, cv::Point(-1,-1)); // find contours and store them all as a list cv::findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); //test each contour cv::vector<cv::Point> approx; cv::vector<cv::vector<cv::Point> >::iterator iterEnd = contours.end(); for(cv::vector<cv::vector<cv::Point> >::iterator iter = contours.begin(); iter != iterEnd; ++iter) { // approximate contour with accuracy proportional // to the contour perimeter cv::approxPolyDP(*iter, approx, arcLength(*iter, true)*0.03, true); //contours should be convex if (isContourConvex(approx)) { // square contours should have 4 vertices after approximation and // relatively large length (to filter out noisy contours) if( approx.size() == 4) { bool rectangular = true; for( int j = 3; j < 6; j++ ) { // if cosines of all angles are small // (all angles are ~90 degree) then write // vertices to result if (fabs(90 - fabs(computeAngle(approx[j%4], approx[j-3], approx[j-2]))) > 7) { rectangular = false; break; } } if (!rectangular) continue; float side1 = computeLength(approx[0], approx[1]); float side2 = computeLength(approx[1], approx[2]); if (side1 > minLength && side1 < maxLength && side2 > minLength && side2 < maxLength) squares.push_back(approx); } // triangle contours should have 3 vertices after approximation and // relatively large length (to filter out noisy contours) else if ( approx.size() == 3) { float side1 = computeLength(approx[0], approx[1]); float side2 = computeLength(approx[1], approx[2]); float side3 = computeLength(approx[2], approx[0]); if (side1 > minLength && side1 < maxLength && side2 > minLength && side2 < maxLength && side3 > minLength && side3 < maxLength) triangles.push_back(approx); } } } }
void DkPageSegmentation::findRectangles(const cv::Mat& img, std::vector<DkPolyRect>& rects, int channel, int threshold) const { cv::Mat imgL; cv::normalize(img, imgL, 255, 0, cv::NORM_MINMAX); // downscale if (scale != 1.0f) cv::resize(imgL, imgL, cv::Size(), scale, scale, CV_INTER_LINEAR); std::vector<std::vector<cv::Point> > contours; int threshStep = dsc::round(255.0 / numThresh); //std::cout << "thresh step: " << threshStep << std::endl; cv::Mat gray; std::vector<DkPolyRect> rectsL; std::vector<int> indexes; if (threshold == -1) { // use less thresholds for a/b channels if (channel > 0) threshStep *= 2; for (int idx = 0; idx < 255; idx += threshStep) indexes.push_back(idx); } else indexes.push_back(threshold); // try several threshold levels for (int thr : indexes) { if (thr == 0) { int thresh = 80; Canny(imgL, gray, thresh, thresh*3, 5); // dilate canny output to remove potential // holes between edge segments //dilate(gray, gray, cv::Mat(), cv::Point(-1,-1)); //cv::imwrite("C:/VSProjects/DocScan/img/tests/edge.png", gray); } else gray = imgL >= thr; cv::erode(gray, gray, cv::Mat(), cv::Point(-1,-1)); // find contours and store them all as a list findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); if (looseDetection) { std::vector<std::vector<cv::Point> > hull; for (int i = 0; i < (int)contours.size(); i++) { double cArea = contourArea(cv::Mat(contours[i])); if (fabs(cArea) > mMinArea*scale*scale && (!mMaxArea || fabs(cArea) < mMaxArea*(scale*scale))) { std::vector<cv::Point> cHull; cv::convexHull(cv::Mat(contours[i]), cHull, false); hull.push_back(cHull); } } contours = hull; } std::vector<cv::Point> approx; // DEBUG ------------------------ //cv::Mat pImg = imgL.clone(); //cv::cvtColor(pImg, pImg, CV_GRAY2BGR); // DEBUG ------------------------ // test each contour for (size_t i = 0; i < contours.size(); i++) { // approxicv::Mate contour with accuracy proportional // to the contour perimeter approxPolyDP(cv::Mat(contours[i]), approx, arcLength(cv::Mat(contours[i]), true)*0.02, true); double cArea = contourArea(cv::Mat(approx)); // DEBUG ------------------------ //if (fabs(cArea) < mMaxArea) //fillConvexPoly(pImg, &approx[0], (int)approx.size(), cv::Scalar(255,0,0)); // DEBUG ------------------------ // square contours should have 4 vertices after approxicv::Mation // relatively large area (to filter out noisy contours) // and be convex. // Note: absolute value of an area is used because // area may be positive or negative - in accordance with the // contour orientation if (approx.size() == 4 && fabs(cArea) > mMinArea*scale*scale && (!mMaxArea || fabs(cArea) < mMaxArea*scale*scale) && isContourConvex(cv::Mat(approx))) { DkPolyRect cr(approx); //std::cout << mMinArea*scale*scale << " < " << fabs(cArea) << " < " << mMaxArea*scale*scale << std::endl; // if cosines of all angles are small // (all angles are ~90 degree) if(/*cr.maxSide() < std::max(tImg.rows, tImg.cols)*maxSideFactor && */ (!maxSide || cr.maxSide() < maxSide*scale) && cr.getMaxCosine() < 0.3 ) { cr.setChannel(channel); cr.setThreshold(thr); rectsL.push_back(cr); } } } // DEBUG ------------------------ //cv::cvtColor(pImg, pImg, CV_RGB2BGR); //cv::imwrite("C:/VSProjects/DocScan/img/tests/poly" + Utils::num2str(thr) + ".png", pImg); // DEBUG ------------------------ } for (size_t idx = 0; idx < rectsL.size(); idx++) rectsL[idx].scale(1.0f/scale); // filter rectangles which are found because of the image border for (const DkPolyRect& p : rectsL) { DkBox b = p.getBBox(); if (b.size().height < img.rows*maxSideFactor && b.size().width < img.cols*maxSideFactor) { rects.push_back(p); } } //cv::normalize(dbgImg, dbgImg, 255, 0, cv::NORM_MINMAX); }
bool ProcessingThread::CrossDetect(Mat gray, vector<Point2f> &cross) { double tresholdmin = 0.6; int tresholdmin_int = 6; int tresholdmax_int = 6; int tresholdCannyMin = 1400; int tresholdCannyMax = 1500; bool found = true; vector<Mat> contours; vector<Point> approx; //Mat gray; //cvtColor(img, gray, CV_BGR2GRAY); Mat bw; Canny(gray, bw, tresholdCannyMin, tresholdCannyMax, 5); findContours(bw.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); for (int i = 0; i < contours.size(); i++) { approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true); if (fabs(contourArea(contours[i])) < 100 || isContourConvex(approx) || (approx.size() != 8)) continue; double x0 = approx[0].x; double x1 = approx[1].x; double x2 = approx[2].x; double x3 = approx[3].x; double x4 = approx[4].x; double x5 = approx[5].x; double x6 = approx[6].x; double x7 = approx[7].x; double y0 = approx[0].y; double y1 = approx[1].y; double y2 = approx[2].y; double y3 = approx[3].y; double y4 = approx[4].y; double y5 = approx[5].y; double y6 = approx[6].y; double y7 = approx[7].y; double length_top = (((abs(x0 - x1) + abs(x0 - x7)) / 2) + ((abs(y0 - y1) + abs(y0 - y7)) / 2)) / 2; double length_bot = (((abs(x3 - x4) + abs(x4 - x5)) / 2) + ((abs(y3 - y4) + abs(y4 - y5)) / 2)) / 2; double ratio1 = ((((length_top + length_bot) / length_top - 0.5) + ((length_top + length_bot) / length_bot - 0.5))) / 2 - 0.5; double length_left = (((abs(x2 - x1) + abs(x2 - x3)) / 2) + ((abs(y2 - y1) + abs(y2 - y3)) / 2)) / 2; double length_right = (((abs(x6 - x7) + abs(x6 - x5)) / 2) + ((abs(y6 - y7) + abs(y6 - y5)) / 2)) / 2; double ratio2 = ((((length_left + length_right) / length_left - 0.5) + ((length_left + length_right) / length_right - 0.5))) / 2 - 0.5; if (abs((ratio1 + ratio2) / 2 - 1) > 0.2) { found = false; continue; } for (int j = 0; j < approx.size() - 3; j++){ double ang1 = angle(approx[j], approx[j + 1], approx[j + 2]); double ang2 = angle(approx[j + 1], approx[j + 2], approx[j + 3]); //printf("ang1: %f\t, ang2: %f \n", ang1, ang2); if (ang1 > 0.7){ if (!(ang1 > 0.7 && ang2 < 0.3)) { found = false; continue; } } } if (found) { for each(Point pt in approx) cross.push_back((Point2f)pt); return true; } } return found; }