[英]How to detect an octagonal shape in Python and Opencv
我正在使用python 中的opencv研究形狀檢測算法。 我正在使用庫中的輪廓,並且成功檢測到一些形狀:圓形、矩形和三角形。 唯一的問題是我只需要檢測圓形矩形和八邊形。 此外,該圈子正在工作,但不一致。 所以,這是我的代碼:
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()
我想要的是更准確地檢測八邊形和圓形。
為了執行形狀檢測,我們可以使用輪廓近似。 假設對象是簡單的形狀,這里有一種使用閾值 + 輪廓近似的方法。 輪廓近似是基於這樣一個假設,即曲線可以由一系列短線段來近似,這些短線段可用於確定輪廓的形狀。 例如,三角形有三個頂點,正方形/矩形有四個頂點,五邊形有五個頂點,依此類推。
獲取二值圖像。 我們加載圖像,轉換為灰度,然后是大津閾值以獲得二值圖像。
檢測形狀。 使用輪廓近似濾波查找輪廓並識別每個輪廓的形狀。 這可以使用arcLength
來計算輪廓的周長和approxPolyDP
來獲得實際的輪廓近似值。
輸入圖像
帶標簽的形狀
代碼
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()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.