Python OpenCV - 如何找到带圆角的矩形的矩形轮廓?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/46486078/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
OpenCV - How to find rectangle contour of a rectangle with round corner?
提问by tomfriwel
I'm trying to find the contour of a rectangle object with round corner in a image. I tried HoughLinesP
and findContours
, but did not achieve the desired result.
我试图在图像中找到带有圆角的矩形对象的轮廓。我试过HoughLinesP
和findContours
,但没有达到预期的效果。
I want to find the rectangle like this:
Code:
代码:
import cv2
import matplotlib.pyplot as plt
import util
image = cv2.imread("./img/findrect0.png", 1)
gray = util.grayImage(image)
edges = cv2.Canny(image, 50, 200)
lines = cv2.HoughLinesP(edges, 1, cv2.cv.CV_PI/180, 50, minLineLength=50, maxLineGap=10)[0]
linesImage = image.copy()
util.drawLines(linesImage, lines, thickness=10)
contoursImage = image.copy()
(contours, hierarchy) = cv2.findContours(gray.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
util.drawContours(contoursImage, contours, thickness=10)
util.showOpenCVImagesGrid([image, edges, linesImage, contoursImage], 2, 2, titles=["original image", "canny image", "lines image", "contours image"])
util:
用途:
import cv2
import math
import matplotlib.pyplot as plt
def showOpenCVImagesGrid(images, x, y, titles=None, axis="on"):
fig = plt.figure()
i = 1
for image in images:
copy = image.copy()
channel = len(copy.shape)
cmap = None
if channel == 2:
cmap = "gray"
elif channel == 3:
copy = cv2.cvtColor(copy, cv2.COLOR_BGR2RGB)
elif channel == 4:
copy = cv2.cvtColor(copy, cv2.COLOR_BGRA2RGBA)
fig.add_subplot(x, y, i)
if titles is not None:
plt.title(titles[i-1])
plt.axis(axis)
plt.imshow(copy, cmap=cmap)
i += 1
plt.show()
def grayImage(image):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
return gray
def drawLines(image, lines, thickness=1):
for line in lines:
# print("line="+str(line))
cv2.line(image, (line[0], line[1]), (line[2], line[3]),
(0, 0, 255), thickness)
def drawContours(image, contours, thickness=1):
i = 0
for contour in contours:
cv2.drawContours(image, [contours[i]], i, (0, 255, 0), thickness)
area = cv2.contourArea(contour)
i += 1
I'm using Python 2.7.13
and OpenCV 2.4.13.3
.
我正在使用Python 2.7.13
和OpenCV 2.4.13.3
。
I've been thinking to extend these lines and get intersection points of lines. Finally, I will get four coordinates of rectangle. But if the image is more complex, I don't know how to deal with.
我一直在考虑延长这些线并获得线的交点。最后,我将得到矩形的四个坐标。但是如果图像更复杂,我不知道如何处理。
回答by zindarod
You need to find the bounding rectangle of the found contours.
您需要找到找到的轮廓的边界矩形。
img = cv2.imread("image.png", -1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
binary = cv2.bitwise_not(gray)
(_,contours,_) = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
for contour in contours:
(x,y,w,h) = cv2.boundingRect(contour)
cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)
回答by Kamil Szelag
You can find bounding rectangle of nonzero points.
您可以找到非零点的边界矩形。
image = cv2.imread("./img/findrect0.png", 1)
gray = util.grayImage(image)
gray_inv = cv2.bitwise_not(gray)
points = cv2.findNonZero(gray)
rect = cv2.boundingRect(points)
回答by alkasm
I've been thinking to extend these lines and get intersection points of lines. Finally, I will get four coordinates of rectangle.
我一直在考虑延长这些线并获得线的交点。最后,我将得到矩形的四个坐标。
More or less, this is a good approach if contours doesn't work out for you. Indeed, as you say,
或多或少,如果轮廓不适合您,这是一个很好的方法。确实如你所说,
But if the image is more complex, I don't know how to deal with.
但是如果图像更复杂,我不知道如何处理。
there are some complications to deal with. The main problem is that typical line detection doesn't give you perfect line segments every time. You may have multiple line segments along the same line, either stacked lengthwise or multiple overlapping. Additionally, you'll need to segment the lines automatically in some way so that you're not trying to find the intersection of parallel lines.
有一些复杂情况需要处理。主要问题是典型的线检测不会每次都给你完美的线段。您可以沿着同一条线有多条线段,可以纵向堆叠或多次重叠。此外,您需要以某种方式自动分割线,这样您就不会试图找到平行线的交点。
However, both of these issues are not too hard to deal with.
I answered a question awhile ago on this siteabout finding intersection points from HoughLinesP
that uses a lot of the below suggestions, though is not as robust (segmenting the lines into two groups for e.g. was done much more naively), but it should give you a good place to start from.
然而,这两个问题都不太难处理。前段时间我在这个网站上回答了一个关于从中找到交点的问题HoughLinesP
,使用了很多以下建议,虽然不是那么健壮(将线分成两组,例如做的更天真),但它应该给你一个开始的好地方。
After you detect the lines, you need to segment the lines into groups or parallel segments. If your rectangle is of a defined orientation, then you can just filter the lines based on that, which would be the easy case. But if the rectangle can be in any orientation, you'll need some other way to segment them. You can use k-means clustering with k=2to find the two main angles, and put the lines corresponding to one angle in a bin and the lines corresponding to the other angle in another bin and find the intersections of the lines in one bin with the lines in the other bin. What's nice about this approach is it would work for any parallelogram. You could also reject lines from each bin if they're not within some threshold (like 10 degrees or something) from being at a right angle with the mean angle from the other bin, or something, if you wanted to stick to rectangles.
检测到线条后,您需要将线条分割成组或平行线段。如果您的矩形具有定义的方向,那么您可以基于该方向过滤线条,这很容易。但是如果矩形可以在任何方向上,您将需要一些其他方式来分割它们。您可以使用k-means 聚类,k=2找到两个主角,并将一个角对应的线放在一个bin中,将另一个角对应的线放在另一个bin中,并找到一个bin中的线与另一个bin中的线的交点。这种方法的好处在于它适用于任何平行四边形。如果您想坚持使用矩形,您还可以拒绝来自每个 bin 的线条,如果它们不在某个阈值(如 10 度或其他)内,与来自另一个 bin 的平均角度成直角,或者其他东西。
Once you have all the lines binned accordingly, you can calculate their intersection points. There's actually a nice formula using determinantsfor calculating the intersection points between two lines given two points on the line, which you already have from the endpoints. So, that's handy! Each line in bin 0 will have an intersection point with the line from bin 1, and that's all you need to do.
将所有线相应地分箱后,您可以计算它们的交点。实际上有一个很好的公式,它使用行列式来计算给定线上两点的两条线之间的交点,您已经从端点获得了这些点。所以,这很方便!bin 0 中的每条线都将与 bin 1 中的线有一个交点,这就是您需要做的全部工作。
So at the end here you'd have 4 clusters of intersection points. One option is to simply group these together, again with k-means with k=4, and you'll have the centroids of those four point clusters, representing the corners of your rectangle. Of course, since you've used a lot of approximation steps along the way, your points won't exactly define a rectangle, so you'll have to fit the closest possible rectangle to those points. Or, instead of k-means, another method would be to try to find a subset of your many intersection points that most accurately represent a rectangle, and thenfit the closest rectangle. Probably some way to use linear regression, least squares, RANSAC, etc to this problem. Or if you want you can just find the bounding rectangle of the four points with boundingRect()
.
所以最后在这里你会有 4 个交叉点集群。一种选择是简单地将它们组合在一起,再次使用k-means 和k=4,您将拥有这四个点簇的质心,代表矩形的角。当然,由于您在此过程中使用了很多近似步骤,因此您的点不会准确定义矩形,因此您必须将最接近的矩形拟合到这些点。或者,代替k均值,另一种方法是尝试找到最准确表示矩形的许多交点的子集,然后拟合最近的矩形。可能是使用线性回归、最小二乘法、RANSAC 等解决此问题的某种方法。或者,如果您愿意,您可以使用 找到四个点的边界矩形boundingRect()
。