如何在Python和Opencv中检测八边形 [英] How to detect an octagonal shape in Python and Opencv
问题描述
我正在使用 python 中的 opencv 开发形状检测算法. 我正在使用库中的轮廓,并且已经成功检测到一些形状:圆形,矩形和三角形. 唯一的问题是,我只需要检测圆形的矩形和八边形. 此外,圈子还在运作,但不一致. 所以,这是我的代码:
I am working on a shape detection algorithm with opencv in python. I am using Contours from the library and I have had some shapes being detected successfully: Circle, Rectangle and Triangle. The only problem is that I only need to detect circles rectangles and octagons. Also, the circle was working, but inconsistently. So, this is my code:
import cv2
import numpy as np
def nothing(x):
# any operation
pass
cap = cv2.VideoCapture(1)
cv2.namedWindow("Trackbars")
cv2.createTrackbar("L-H", "Trackbars", 0, 180, nothing)
cv2.createTrackbar("L-S", "Trackbars", 66, 255, nothing)
cv2.createTrackbar("L-V", "Trackbars", 134, 255, nothing)
cv2.createTrackbar("U-H", "Trackbars", 180, 180, nothing)
cv2.createTrackbar("U-S", "Trackbars", 255, 255, nothing)
cv2.createTrackbar("U-V", "Trackbars", 243, 255, nothing)
font = cv2.FONT_HERSHEY_COMPLEX
while True:
_, frame = cap.read()
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
l_h = cv2.getTrackbarPos("L-H", "Trackbars")
l_s = cv2.getTrackbarPos("L-S", "Trackbars")
l_v = cv2.getTrackbarPos("L-V", "Trackbars")
u_h = cv2.getTrackbarPos("U-H", "Trackbars")
u_s = cv2.getTrackbarPos("U-S", "Trackbars")
u_v = cv2.getTrackbarPos("U-V", "Trackbars")
lower_yellow = np.array([l_h,l_s, l_v])
upper_yellow = np.array([u_h, u_s, u_v])
mask = cv2.inRange(hsv, lower_yellow, upper_yellow)
kernel = np.ones((5, 5), np.uint8)
mask = cv2.erode(mask, kernel)
# Contours detection
if int(cv2.__version__[0]) > 3:
# Opencv 4.x.x
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
else:
# Opencv 3.x.x
_, contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
area = cv2.contourArea(cnt)
approx = cv2.approxPolyDP(cnt, 0.02*cv2.arcLength(cnt, True), True)
x = approx.ravel()[0]
y = approx.ravel()[1]
if area > 400:
cv2.drawContours(frame, [approx], 0, (0, 0, 0), 5)
if len(approx) == 3:
cv2.putText(frame, "Triangle", (x, y), font, 1, (0, 0, 0))
elif len(approx) == 4:
cv2.putText(frame, "Rectangle", (x, y), font, 1, (0, 0, 0))
elif 10 < len(approx) < 20:
cv2.putText(frame, "Circle", (x, y), font, 1, (0, 0, 0))
cv2.imshow("Frame", frame)
cv2.imshow("Mask", mask)
key = cv2.waitKey(1)
if key == 27:
break
cap.release()
cv2.destroyAllWindows()
我想拥有的是更精确地检测八边形和圆形.
What I would like to have is to detect octagons and circles more accurately.
推荐答案
要执行形状检测,我们可以使用轮廓逼近.假设对象是简单形状,这是一种使用阈值+轮廓近似的方法.等高线近似是基于这样的假设,即曲线可以由一系列短线段近似,这些短线段可用于确定轮廓的形状.例如,三角形具有三个顶点,正方形/矩形具有四个顶点,五边形具有五个顶点,依此类推.
To perform shape detection, we can use contour approximation. With the assumption that the objects are simple shapes, here's an approach using thresholding + contour approximation. Contour approximation is based on the assumption that a curve can be approximated by a series of short line segments which can be used to determine the shape of a contour. For instance, a triangle has three vertices, a square/rectangle has four vertices, a pentagon has five vertices, and so on.
-
获取二进制图像.我们加载图像,转换为灰度,然后 Otsu的阈值 获取二进制图像.
Obtain binary image. We load the image, convert to grayscale, then Otsu's threshold to obtain a binary image.
检测形状.使用轮廓逼近过滤查找轮廓并标识每个轮廓的形状.可以使用 arcLength
计算轮廓的周长,并
Detect shapes. Find contours and identify the shape of each contour using contour approximation filtering. This can be done using arcLength
to compute the perimeter of the contour and approxPolyDP
to obtain the actual contour approximation.
输入图片
Input image
标签形状
代码
import cv2
def detect_shape(c):
# Compute perimeter of contour and perform contour approximation
shape = ""
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.04 * peri, True)
# Triangle
if len(approx) == 3:
shape = "triangle"
# Square or rectangle
elif len(approx) == 4:
(x, y, w, h) = cv2.boundingRect(approx)
ar = w / float(h)
# A square will have an aspect ratio that is approximately
# equal to one, otherwise, the shape is a rectangle
shape = "square" if ar >= 0.95 and ar <= 1.05 else "rectangle"
# Pentagon
elif len(approx) == 5:
shape = "pentagon"
# Hexagon
elif len(approx) == 6:
shape = "hexagon"
# Octagon
elif len(approx) == 8:
shape = "octagon"
# Star
elif len(approx) == 10:
shape = "star"
# Otherwise assume as circle or oval
else:
shape = "circle"
return shape
# Load image, grayscale, Otsu's threshold
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# Find contours and detect shape
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
# Identify shape
shape = detect_shape(c)
# Find centroid and label shape name
M = cv2.moments(c)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
cv2.putText(image, shape, (cX - 20, cY), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (36,255,12), 2)
cv2.imshow('thresh', thresh)
cv2.imshow('image', image)
cv2.waitKey()
这篇关于如何在Python和Opencv中检测八边形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!