How to detect unclosed hexagon?

Hi all

During my studies I worked with matlab so I'm new to opencv…

I would like to detect an unclosed Hexagon in a given BW Image. After some reading tutorials I found the Hough-Line detection as possible solution. But I'm still strugling. I have the Feeling that the opencv is mutch more not userfrendly than matlab. there the same Code workes fine, but the opencv implementation of hough-line detection is strange.

This is the original Image: With the Standard hough line function I got this result (the lines are extrapolated). I found no way to check if the dominant line (first in resulting Vector) is realy part of the inner Hexagon or not. and next there is no possibility to average the found lines so there is only one per Edge. Next I tried to detect if the angels are as expected (the angel difference to the first dominant Hexagon line is Always 120° or even 60° if you look to the oposite direction).

Any succestion, how I could solve this Problem?

Btw. I try to do this in C# so the Code is as following:

double dCannyThreshold = 10;
UMat oCannyEdges = new UMat();
p__oImage.Save("Orig.png");
CvInvoke.Canny(p__oImage, oCannyEdges, dCannyThreshold, dCannyThreshold * 2);

/////////////////////////////////////////////////////
// Hough Line detection
/*
LineSegment2D[] aoLines = CvInvoke.HoughLinesP(
oCannyEdges,
10,                              // Distance resolution of the accumulator in pixels (rho)
Math.PI / 180,                  // 1° Angle resolution of the accumulator in radians (theta)
150,                            // Accumulator threshold parameter. Only those lines are returned that get enough votes
100,                            // Minimum line length. Line segments shorter than that are rejected.
10);                            // Maximum allowed gap between points on the same line to link them.
*/

LineSegment2D[] aoLines;
using (var aoVector = new Emgu.CV.Util.VectorOfPointF())
{
CvInvoke.HoughLines(
oCannyEdges,
aoVector,
1,                          // Distance resolution of the accumulator in pixels (rho)
Math.PI / 180.0,            // 1° Angle resolution of the accumulator in radians
100);                       // Accumulator threshold parameter. Only those lines are returned that get enough votes
}

Best regards

P51D

edit retag close merge delete

I don't really understand what do you mean by "unclosed hexagon"

Maybe some simpler methods (like connected component analysis) might be easier to see if the interior and exterior are connected.

Sort by » oldest newest most voted Here is code:

#!usr/bin/env python3.5
#OpenCV 4.1.0
#using rapberry pi 3, linux, kernel 4.19.34
#Date: 18th April, 2019

import cv2
import numpy as np

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 100, 150, apertureSize=3)

minLineLength = 12
maxLineGap = 8
lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 5, minLineLength, maxLineGap, 25)
for line in lines:
for x1, y1, x2, y2 in line:
cv2.line(img, (x1, y1), (x2, y2), (0, 255, 0), 2)

cv2.imshow("image", edges)
cv2.imshow('img', img)
cv2.waitKey(0)

Output:  more

OpenCV has a useful tool called line iterator that can set up an imaginary line between 2 points. You can step along the pixels of this line and examine the pixel intensity and compare its change from the previous pixel. If we set up line iterators radially from the center outward every few degrees and search for changes from white to black, we can find points along the edges. Then we can use OpenCV's FitLine function to find groups of edge points that fit one of the lines of the hexagon. Below is the code I used to get a first line of a hexagon. The only thing not in OpenCV is the function PointLineDistance that just gets the perpendicular distance of a point from a line. To finish this, find the other 5 lines of the hexagon, then find the intersection points.

// create a color markup image to view results
Size imgSize = srcImg.size();
Mat markupImg;
cvtColor(srcImg, markupImg, CV_GRAY2BGR);

// edge points we find using line iterator
vector<Point> edgePoints;

// assume center is near middle of image
Point2f ctr(imgSize.width / 2, imgSize.height / 2);
// step from middle to outer edges of image
// color change threshold
int edgeChangeThreshold = 200;
// num radial lines to check
float dAngle = 360.0 / numRadials;
for (float angle = 0; angle < 360; angle += dAngle) {
// set up a line iterator from ctr to edge in direction of angle
float ar = angle * DTOR;
LineIterator li(srcImg, p1, p2);

// get the current value of line point
// and step along line looking for intensity change greater than threshold
uchar prevVal = *(*li++);
uchar currVal;
for (int i = 1; i < li.count; i++, ++li) {
currVal = *(*li);
if (abs(currVal - prevVal) > edgeChangeThreshold) {
// found intensity change, store this point and stop iteration along this radial
edgePoints.push_back(li.pos());
break;
}
}
}

for (auto& pt : edgePoints) {
circle(markupImg, pt, 3, Scalar(255, 0, 255));
}

// this will hold the edge points that fit the first line of the hexagon
vector<Point> firstLinePts;
// take 3 adjacent pts at random and try to fit a line
vector<Point> randomPts(3);
bool ptsFit = false;
while (!ptsFit) {
int randIndex = rand() % edgePoints.size() - 4;
for (int i = 0; i < randomPts.size(); ++i) {
randomPts[i] = edgePoints[randIndex + i];
}

// try to fit a line with these 3 points
Vec4f line;
fitLine(randomPts, line, CV_DIST_L2, 0, 0.01, 0.01);
Point2f linePt1(line, line);
Point2f linePt2 = linePt1 + Point2f(line, line) * 50;

// search for points in edge point list that are close enough to be on the fitted line
for (auto& pt : edgePoints) {
float dist = PointLineDistance(pt, linePt1, linePt2);
if (dist < 4) {
firstLinePts.push_back(pt);
}
}
// if we found enough that fit, assume we have a line of the hexagon
if (firstLinePts.size() > (numRadials / 6 / 2)) {
ptsFit = true;
}
}

for (auto& pt : firstLinePts ...
more