获取矩形轮廓坐标

问题描述 投票:0回答:2

我正在尝试获取图像中矩形的 4 个点。我有代码可以获取图像的轮廓并检测它是否有 4 个点。但我不知道如何从轮廓数据中获取这 4 个点。这是我到目前为止所拥有的。它来自我从各种图像处理教程中找到的代码。

import cv2
import numpy as np

green = (0, 255, 0)  # for drawing contours, etc.

# a normal video capture loop
cap = cv2.VideoCapture(1)
if not cap.isOpened():
    print("Cannot open camera")
    exit()

while True:
    ret, frame = cap.read()
    if not ret:
        print("Can't receive frame (stream end?). Exiting ...")
        break

    image = frame.copy()  # can tweak this one
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    blur = cv2.GaussianBlur(gray, (5, 5), 0)
    edged = cv2.Canny(blur, 75, 200)

    contours, _ = cv2.findContours(edged, cv2.RETR_LIST, 
                                   cv2.CHAIN_APPROX_SIMPLE)
    contours = sorted(contours, key=cv2.contourArea, reverse=True)
    cv2.drawContours(image, contours, -1, green, 3)

    # go through each contour looking for the one with 4 points
    # This is a rectangle, and the first one will be the biggest because
    # we sorted the contours from largest to smallest
    doc_cnts = None
    if len(contours) >= 1:
        for contour in contours:
            # we approximate the contour
            peri = cv2.arcLength(contour, True)
            approx = cv2.approxPolyDP(contour, 0.05 * peri, True)
            if len(approx) == 4:
                doc_cnts = approx
                break

    if doc_cnts is not None:
        print(doc_cnts)

    cv2.imshow('original', frame)
    cv2.imshow('changed', edged)

    if cv2.waitKey(1) == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

当我运行这个时,边缘图像看起来像是在图像中找到了矩形的东西。我将相机对准地板上的一个信封。我从地毯图案中看到很多小背景边缘,并且我确实看到信封的较大矩形。

我不明白矩形实际轮廓数据的格式以及如何使用它来获取实际的 x,y 坐标。我不仅仅是想绘制轮廓,我想测试矩形以确保图像是正面拍摄的。

python opencv contour
2个回答
0
投票

我找到了一些有帮助的代码。这样做我可以得到矩形的 4 个点:

    blur = cv2.morphologyEx(frame, cv2.MORPH_CLOSE, blur_kernel, iterations= 3)

    edged = cv2.Canny(blur, 75, 200)  # original is 75, 200

    contours, _ = cv2.findContours(edged, cv2.RETR_LIST,  # was RETR_TREE
                                   cv2.CHAIN_APPROX_SIMPLE)
    contours = sorted(contours, key=cv2.contourArea, reverse=True)

    # go through each contour looking for the one with 4 points
    # This is a rectangle, and the first one will be the biggest because
    # we sorted the contours from largest to smallest
    doc_cnts = None
    if len(contours) >= 1:
        for contour in contours:
            # we approximate the contour
            peri = cv2.arcLength(contour, True)
            approx = cv2.approxPolyDP(contour, 0.05 * peri, True)
            if len(approx) == 4:
                # cv2.drawContours(image, [approx], 0, green, 2)
                all_coordinates = approx.ravel()
                x1 = all_coordinates[0]
                y1 = all_coordinates[1]
                x2 = all_coordinates[2]
                y2 = all_coordinates[3]
                x3 = all_coordinates[4]
                y3 = all_coordinates[5]
                x4 = all_coordinates[6]
                y4 = all_coordinates[7]

                # get the total length of this rectangle

                string = str(x1) + " " + str(y1)
                cv2.putText(frame, string, (x1, y1),
                            cv2.FONT_HERSHEY_COMPLEX, 0.5, green)
                string = str(x2) + " " + str(y2)
                cv2.putText(frame, string, (x2, y2),
                            cv2.FONT_HERSHEY_COMPLEX, 0.5, green)
                string = str(x3) + " " + str(y3)
                cv2.putText(frame, string, (x3, y3),
                            cv2.FONT_HERSHEY_COMPLEX, 0.5, green)
                string = str(x4) + " " + str(y4)
                cv2.putText(frame, string, (x4, y4),
                            cv2.FONT_HERSHEY_COMPLEX, 0.5, green)

                cv2.line(frame, color=green,
                        pt1=(x1, y1),
                        pt2=(x2, y2),
                        thickness=5)
                cv2.line(frame, color=green,
                        pt1=(x2, y2),
                        pt2=(x3, y3),
                        thickness=5)
                cv2.line(frame, color=green,
                        pt1=(x3, y3),
                        pt2=(x4, y4),
                        thickness=5)
                cv2.line(frame, color=green,
                        pt1=(x4, y4),
                        pt2=(x1, y1),
                        thickness=5)


                break

这只是令人讨厌的测试代码,但我想确保我可以获得 4 边形状的坐标。它似乎有效,但有时它会在图像上拾取奇怪的轮廓并给出奇怪的结果。我想我有足够的时间去尝试它并获得更稳定的东西。


0
投票

这里有两种在Python/OpenCV中打印矩形轮廓顶点的简单方法

输入:

import cv2
import numpy as np

# read the image of rectangle as grayscale
img = cv2.imread('rect.png', cv2.IMREAD_GRAYSCALE)

# threshold
thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]

# compute largest contour
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)

# Reduce vertices
peri = cv2.arcLength(big_contour, True)
approx = cv2.approxPolyDP(big_contour, 0.001 * peri, True)

# print approx
print(approx)

print('')

# print coordinates in approx
for p in approx:
    x = p[0][0]
    y = p[0][1]
    pt = str(x) + "," + str(y)
    print(pt)

打印结果(大约):

[[[100 100]]

 [[100 400]]

 [[400 400]]

 [[400 100]]]

x,y 坐标打印列表的结果:

100,100
100,400
400,400
400,100
© www.soinside.com 2019 - 2024. All rights reserved.