Ask Your Question
0

How to detect unclosed hexagon?

asked 2019-04-09 03:26:57 -0600

P51D gravatar image

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:

Original Image

With the Standard hough line function I got this result (the lines are extrapolated).

Standard HoughLine Detection with extrapolated lines

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 flag offensive close merge delete

Comments

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.

kbarni gravatar imagekbarni ( 2019-04-11 08:39:26 -0600 )edit

2 answers

Sort by » oldest newest most voted
0

answered 2019-04-18 09:02:41 -0600

supra56 gravatar image

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

img = cv2.imread('hexagon.png')
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: edges img

edit flag offensive delete link more

Comments

I used same practical. Same You can also convert to c++

supra56 gravatar imagesupra56 ( 2019-04-18 09:11:53 -0600 )edit
0

answered 2019-04-13 15:13:30 -0600

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
                        float startRadius = 0;
                        float endRadius = max(imgSize.width, imgSize.height);
                        // color change threshold
                        int edgeChangeThreshold = 200;
                        // num radial lines to check
                        int numRadials = 120;
                        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;
                            Point2f p1(ctr.x + startRadius * cos(ar), ctr.y - startRadius * sin(ar));
                            Point2f p2(ctr.x + endRadius * cos(ar), ctr.y - endRadius * sin(ar));
                            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[2], line[3]);
                            Point2f linePt2 = linePt1 + Point2f(line[0], line[1]) * 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)
edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2019-04-09 03:26:57 -0600

Seen: 1,522 times

Last updated: Apr 18 '19