OpenCV - 如何找到圆角矩形的矩形轮廓?

时间:2017-09-29 09:39:45

标签: python opencv

我正在尝试在图像中找到带圆角的矩形对象的轮廓。我尝试了HoughLinesPfindContours,但未达到预期效果。

results

我想找到这样的矩形: desired result

代码:

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

我正在使用Python 2.7.13OpenCV 2.4.13.3

我一直在考虑扩展这些线并获得线的交点。最后,我将得到四个矩形坐标。 但如果图像更复杂,我不知道如何处理。

3 个答案:

答案 0 :(得分:14)

您需要找到找到的轮廓的边界矩形。

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)

result

答案 1 :(得分:2)

您可以找到非零点的边界矩形。

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)

答案 2 :(得分:1)

  

我一直在考虑扩展这些线并获得线的交点。最后,我将得到四个矩形坐标。

或多或少,如果轮廓不适合你,这是一个很好的方法。的确如你所说,

  

但如果图像更复杂,我不知道如何处理。

有一些并发症需要处理。主要问题是典型的线检测并不能每次都为您提供完美的线段。您可以在同一条线上有多个线段,纵向堆叠或多个重叠。此外,您需要以某种方式自动分割线条,这样您就不会尝试找到平行线的交叉点。

然而,这两个问题都不是很难处理。 我answered a question awhile ago on this site关于从使用以下许多建议的HoughLinesP中找到交叉点,虽然不那么健壮(将线分成两组,例如更天真地做了),但它应该给出你是一个很好的起点。

检测到线条后,您需要将线条划分为组或平行线段。如果你的矩形是一个定义的方向,那么你可以根据它来过滤这些线,这很容易。但是如果矩形可以处于任何方向,则需要一些其他方法来分割它们。您可以使用 k - 使用 k = 2 进行聚类来找到两个主要角度,并将对应于一个角度的线条放在一个箱子中,并将这些线条对应于另一个角度在另一个箱子中的角度,找到一个箱子中的线条与另一个箱子中的线条的交叉点。这种方法有什么好处,它适用于任何平行四边形。你也可以拒绝每个垃圾箱中的线条,如果它们不在某个阈值(如10度或者其他东西)内,与另一个垃圾箱的平均角度成直角,或者某个东西,如果你想要坚持矩形。 / p>

一旦您将所有线条相应分箱,您就可以计算它们的交点。实际上a nice formula using determinants用于计算两条线之间的交点,给出线上的两个点,这些点已经从端点获得。所以,这很方便! bin 0中的每一行都与bin 1中的行有一个交叉点,这就是你需要做的全部。

所以最后这里你有4个交叉点集群。一种选择是简单地将这些组合在一起,再次使用 k -means与 k = 4 ,并且你将拥有这四个点簇的质心,代表角落你的矩形。当然,由于您沿途使用了大量的近似步骤,因此您的点不会精确定义矩形,因此您必须将最接近的矩形拟合到这些点。或者,而不是 k -means,另一种方法是尝试找到最准确表示矩形的多个交叉点的子集,然后拟合最近的矩形。可能是某种方式使用线性回归,最小二乘法,RANSAC等来解决这个问题。或者如果你想要,你可以用boundingRect()找到四个点的边界矩形。