Concave and convex corner points of OpenCV from polygons

Problem

I am working on a project where I need to get bounding rectangles with similar shapes. However, I need fewer possible points, and the boxes must fit the shapes in all corners. Here is the image I made for checking: Blurred, cracked, dumbbell shapes

I don’t care that the spaces go into the form, I just want to clear them and straighten the edges to get the contours of this shape:

I am trying to do threshold() by getting its outlines using findContours() and then using approxPolyDP() to simplify the crazy amount of points that are concussing. So, after I started doing this for three days, how can I just get:

  • Two fields indicating the ends of the dumbbell and the rectangle in the middle, or
  • One contour with twelve points for all angles

The second option would be preferable, since this is really my ultimate goal: to get the points that are at these corners.

A few notes:

  • I am using OpenCV for Python
  • As a rule, many of these forms of all types will be displayed on all input images.
  • They will only have horizontal or vertical positioning. No weird 27 degree angles ...

What I need:

I really don't need someone to write the code for me, I just need some method or algorithm to do this, preferably with some simple examples.

My code

Here is my overly clean code with functions that I don’t even use, but with a digit I would use them in the end:

 import cv2 import numpy as np class traceImage(): def __init__(self, imageLocation): self.threshNum = 127 self.im = cv2.imread(imageLocation) self.imOrig = self.im self.imGray = cv2.cvtColor(self.im, cv2.COLOR_BGR2GRAY) self.ret, self.imThresh = cv2.threshold(self.imGray, self.threshNum, 255, 0) self.contours, self.hierarchy = cv2.findContours(self.imThresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) def createGray(self): self.imGray = cv2.cvtColor(self.im, cv2.COLOR_BGR2GRAY) def adjustThresh(self, threshNum): self.ret, self.imThresh = cv2.threshold(self.imGray, threshNum, 255, 0) def getContours(self): self.contours, self.hierarchy = cv2.findContours(self.imThresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) def approximatePoly(self, percent): i=0 for shape in self.contours: shape = cv2.approxPolyDP(shape, percent*cv2.arcLength(shape, True), True) self.contours[i] = shape i+=1 def drawContours(self, blobWidth, color=(255,255,255)): cv2.drawContours(self.im, self.contours, -1, color, blobWidth) def newWindow(self, name): cv2.namedWindow(name) def showImage(self, window): cv2.imshow(window, self.im) def display(self): while True: cv2.waitKey() def displayUntil(self, key): while True: pressed = cv2.waitKey() if pressed == key: break if __name__ == "__main__": blobWidth = 30 ti = traceImage("dumbell.png") ti.approximatePoly(0.01) for thresh in range(127,256): ti.adjustThresh(thresh) ti.getContours() ti.drawContours(blobWidth) ti.showImage("Image") ti.displayUntil(10) ti.createGray() ti.adjustThresh(127) ti.getContours() ti.approximatePoly(0.0099) ti.drawContours(2, (0,255,0)) ti.showImage("Image") ti.display() 

Code Explanation

I know that I may not be doing something right here, but hey, I'm proud of it :)

So, the idea is that in these dumbbells there are often holes and gaps, so I decided that if I repeated all threshold values ​​from 127 to 255 and drew the outlines on the image with a sufficiently large thickness, any thickness for drawing outlines would be filled the holes are small enough and I could use a new, bobby image to get the edges and then scale the sides to size. That was my thinking. There should be another one, bitter, though ...

Summary

I want to finish with 12 points; one for each corner of the form.

EDIT:

After overturning some erosion and dilatation, it seems that the best option would be to cut the contours at certain points, and then use the bounding rectangles around the cut shapes to get the correct square corners, and then do some calculations to get back to the boxes in one shape. Pretty interesting task ...

EDIT 2:

I found something that works well! I made my own line detection system that detects only horizontal or vertical lines, and then on the detected edge of the line / path, the program draws a black line that runs along the entire image, thereby effectively cutting the image along the straight lines of the path. Once he does, he gets the new outlines of the cut boxes, draws bounding rectangles around the pieces, and then uses the extension to close the gaps. So far, it works well on large forms, but when the pieces are small, it tends to lose a little shape.

+4
source share
2 answers

So, after grumbling with erosion, expansion, closing, opening and viewing the direct contours, I figured out a solution that works. Thanks @Ante and @ a.alsram! Your two ideas combined helped me come to my decision. So how does it work.

Method

The program iterates over each path and for each pair of points in the path, and searches for pairs of points that lie on the same axis and calculates the distance between them. If the distance is greater than the adjustable threshold, the program decides that these points are considered the edge of the form. Then the program uses this edge and draws a black line along the entire path, thereby cutting the path on this edge. The program then re-defines the contours, and since the shape has been cut. These cut pieces are known for their own contours, which are then limited by frames. and finally, all forms expand and blur (close) to join the compartments that were cut off.

This method can be executed several times, but each time there is a little loss of accuracy. But it works for what I need, and of course it was fun! Thanks for the help guys!

natebot13

+1
source

Maybe a simple solution might help. If there is a threshold length, to close the gaps, you can split the image in the grid with a cell length> = threshold and use that have something inside. In this case, there will be only horizontal and vertical lines, and taking care of the grid to follow the original horizontal and vertical lines will cover the main functions of the line.

Update

Take a look at mathematical morphology . I think the close operation with the structuring element (2 * k + 1) x (2 * k + 1) can do what you are looking for.

The algorithm should take threshold parameter k and perform dilatation and erosion. This means changing the image, so for each white pixel, set all the neighbors at a distance k ((2 * k + 1) x (2 * k + 1)) to white, and then change the image so that for each set of pixels a black pixel at a distance of k to black.

It is enough to perform operations with boundary pixels.

0
source

Source: https://habr.com/ru/post/1491214/


All Articles