1:矩形弧长面积计算
import cv2 as cv
import numpy as np
def canny_demo(image):
t = 80
canny_output = cv.Canny(image, t, t * 2)
cv.imshow("canny_output", canny_output)
return canny_output
src = cv.imread("D:/coin.jpg")
cv.imshow("input", src)
binary = canny_demo(src)
k = np.ones((3, 3), dtype=np.uint8)
binary = cv.morphologyEx(binary, cv.MORPH_DILATE, k)
# 轮廓发现
contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for c in range(len(contours)):
area = cv.contourArea(contours[c])
arclen = cv.arcLength(contours[c], True)
if area < 100 or arclen < 100:
continue
rect = cv.minAreaRect(contours[c])
cx, cy = rect[0]
box = cv.boxPoints(rect)
box = np.int0(box)
cv.drawContours(src,[box],0,(0,0,255),2)
cv.circle(src, (np.int32(cx), np.int32(cy)), 2, (255, 0, 0), 2, 8, 0)
cv.imshow("contours_analysis", src)
cv.waitKey(0)
cv.destroyAllWindows()
建议结合上一篇文章一起看:OpenCV(python)一键入门--十四篇(二值图像分析入门)
cv.findContours,cv.drawContours,cv.morphologyEx,cv.minAreaRect,cv.boxPoints的函数介绍都在上一篇博客中:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1):cv.boundingRect 矩形边框
这里的for循环如果整个换成:
for c in range(len(contours)):
x, y, w, h = cv.boundingRect(contours[c])
cv.drawContours(src, contours, c, (0, 0, 255), 2, 8)
cv.rectangle(src, (x, y), (x+w, y+h), (0, 0, 255), 1, 8, 0)
那么效果如下:
boundingRect的输入是轮廓,在示例代码中我们使用cv.findContours返回的list。
他会返回四个值,一个矩形 左上角的【x,y】坐标,右下角的【x,y】坐标。在绘制矩形的时候,直接用这四个值即可。
绘制图像函数可以参考:OpenCV(python)——一键入门--第4篇
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2):cv.contourArea 计算轮廓面积
该函数使用格林公式计算。不过,对于具有自交点的轮廓,该函数几乎肯定会给出错误的结果。
该函数读取cv.findContours给出的轮廓,返回一个轮廓面积
3):cv.arcLength 计算轮廓弧长
也是输入轮廓,返回弧长(周长)
这个函数的第二参数可以用来指定对象的形状是闭合的(True),还是打开的(一条曲线)。
弧长 = cv2.arcLength(图像,True)
· 其余部分函数还请移步参考上一篇博客:OpenCV(python)一键入门--十四篇(二值图像分析入门)
2:轮廓逼近
import cv2 as cv
import numpy as np
src = cv.imread("D:/cycle.png")
cv.imshow("input", src)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
# 轮廓发现
contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for c in range(len(contours)):
rect = cv.minAreaRect(contours[c])
#print(f"rect:{rect}")
#print(f"result:\n{result}\n")
cx, cy = rect[0]
result = cv.approxPolyDP(contours[c], 4, True)#连续光滑曲线折线化
vertexes = result.shape[0]
#print(f"result.shape:{result.shape}\n")
if vertexes == 3:
cv.putText(src, "triangle", (np.int32(cx), np.int32(cy)),
cv.FONT_HERSHEY_SIMPLEX, .7, (0, 0, 255), 2, 8);
_ = "triangle"
if vertexes == 4:
cv.putText(src, "rectangle", (np.int32(cx), np.int32(cy)),
cv.FONT_HERSHEY_SIMPLEX, .7, (0, 0, 255), 2, 8);
_ = "rectangle"
if vertexes == 6:
cv.putText(src, "poly", (np.int32(cx), np.int32(cy)),
cv.FONT_HERSHEY_SIMPLEX, .7, (0, 0, 255), 2, 8);
_ = "poly"
if vertexes > 10:
cv.putText(src, "circle", (np.int32(cx), np.int32(cy)),
cv.FONT_HERSHEY_SIMPLEX, .7, (0, 0, 255), 2, 8);
_ = "circle"
print(f"vertexes: {vertexes} class: {_}\n")
cv.imshow("contours_analysis", src)
cv.waitKey(0)
cv.destroyAllWindows()
1):cv.approxPolyDP
可以看成是: cv.approxPolyDP(轮廓,参数epsilon,轮廓是否闭合)
将其获取到的 result shape 一下,即可获取其边的个数。通过result.shape[0] 就可以判断。
其效果如下(附上测试原图)
3:使用几何矩阵计算轮廓中心与横纵比过滤
import cv2 as cv
import numpy as np
def canny_demo(image):
t = 80
canny_output = cv.Canny(image, t, t * 2)
cv.imshow("canny_output", canny_output)
return canny_output
src = cv.imread("D:/cycle.png")
cv.imshow("input", src)
binary = canny_demo(src)
k = np.ones((3, 3), dtype=np.uint8)
binary = cv.morphologyEx(binary, cv.MORPH_DILATE, k)
# 轮廓发现
contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for c in range(len(contours)):
rect = cv.minAreaRect(contours[c])
print(f"rect: {rect}")
cx, cy = rect[0]
ww, hh = rect[1]
ratio = np.minimum(ww, hh) / np.maximum(ww, hh)
print(f"ratio: {ratio}")
mm = cv.moments(contours[c])
m00 = mm['m00']
m10 = mm['m10']
m01 = mm['m01']
cx = np.int(m10 / m00)
cy = np.int(m01 / m00)
box = cv.boxPoints(rect)
box = np.int0(box)
if ratio > 0.9:
cv.drawContours(src, [box], 0, (0, 0, 255), 2)
cv.circle(src, (np.int32(cx), np.int32(cy)), 2, (255, 0, 0), 2, 8, 0)
if ratio < 0.5:
cv.drawContours(src, [box], 0, (255, 0, 255), 2)
cv.circle(src, (np.int32(cx), np.int32(cy)), 2, (0, 0, 255), 2, 8, 0)
cv.imshow("contours_analysis", src)
cv.waitKey(0)
cv.destroyAllWindows()
这里我们还使用到rect里的宽和高,用于ratio的计算
1):cv.moments()
参数:
图像的矩可以帮助我们计算图像的质心,面积等
cv.moments(轮廓)
这个函数会给你一个字典,包含所有矩值
根据这些矩的值,我们可以计算出对象的重心
效果如下: