04-多阈值检测多边形¶
根据多种阈值进行多边形检测
import matplotlib.pyplot as plt
import numpy as np
import cv2 as cv
%matplotlib inline
初始化图片¶
加载图片,并将图片进行处理(高斯模糊),去掉细节信息方便检测边缘
img = cv.imread("images/pic10.png")
img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
# 高斯模糊
img_dst = cv.GaussianBlur(img, (5, 5), 0)
# img_dst = cv.bilateralFilter(img, 0, 30, 20)
f, (ax1, ax2) = plt.subplots(1,2, figsize=(15, 10))
ax1.set_title("img")
ax1.imshow(img)
ax2.set_title("img_blur")
ax2.imshow(img_dst)
查找边缘¶
- 拆分不同颜色通道
- 使用不同的lower阈值进行二值化,范围0-255,步长26
- 查找并打印边缘
# 边缘列表
squares = []
# 分割图片所有的颜色通道
colors = cv.split(img_dst)
print("共有颜色通道:",len(colors))
def angle_cos(p0, p1, p2):
d1, d2 = (p0-p1).astype('float'), (p2-p1).astype('float')
return abs( np.dot(d1, d2) / np.sqrt( np.dot(d1, d1)*np.dot(d2, d2) ) )
def findCurve(color_channel, squares):
f, axs = plt.subplots(3, 4, figsize=(15, 10))
for i, thrs in enumerate(range(0, 255, 26)):
if thrs == 0:
# 首次循环时,进行Canny边缘查找
bin = cv.Canny(color_channel, 100, 255, apertureSize=5)
# 形态学膨胀
bin = cv.dilate(bin, None)
ax = axs[0][0]
ax.set_title("{}: thrs:{}".format("canny", thrs))
ax.imshow(bin, cmap='gray')
else:
# 二值化
_retval, bin = cv.threshold(color_channel, thrs, 255, cv.THRESH_BINARY)
# 查找二值化后的边缘
_, contours, _hierarchy = cv.findContours(bin, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
img_temp = color_channel.copy()
cv.drawContours(img_temp, contours, -1, (0, 255, 255), 2)
ax = axs[int(i / 4)][i % 4]
ax.set_title("{}: thrs:{}".format(i, thrs))
ax.imshow(img_temp, cmap='gray')
for cnt in contours:
# 计算周长
cnt_len = cv.arcLength(cnt, True)
# 多边形逼近(顶点之间的距离小于或等于指定的精度)
approxCurve = cv.approxPolyDP(cnt, 0.02*cnt_len, True)
# 计算曲线内面积
area = cv.contourArea(approxCurve)
if len(approxCurve) == 4 and 3000 < area < 20000 and cv.isContourConvex(approxCurve):
approxCurve = approxCurve.reshape(-1, 2) # 由Nx1x2 -> Nx2
# 求出最大角的余弦值,如果接近90度,说明是矩形
max_cos = np.max([angle_cos( approxCurve[i], approxCurve[(i+1) % 4], approxCurve[(i+2) % 4] ) for i in range(4)])
if max_cos < 0.2:
print("找到一个轮廓 {}: thrs:{} cnt: {} max_cos: {}".format(i, thrs, repr(approxCurve), max_cos))
squares.append(approxCurve)
output: 共有颜色通道: 3
在不同通道查找轮廓¶
- 通道[0] Red通道
color_channel = colors[0]
findCurve(color_channel, squares)
- 通道[1] Green通道
color_channel = colors[1]
findCurve(color_channel, squares)
- 通道[2] Blue通道
color_channel = colors[2]
findCurve(color_channel, squares)
output:
找到一个轮廓 8: thrs:208 cnt: array([[ 47, 171],
[ 42, 220],
[255, 281],
[266, 234]], dtype=int32) max_cos: 0.1774740150218166
找到一个轮廓 8: thrs:208 cnt: array([[154, 11],
[125, 47],
[286, 203],
[317, 166]], dtype=int32) max_cos: 0.09137963891469728
绘制轮廓逼近后的多边形¶
img_copy = img.copy()
cv.drawContours(img_copy, squares, -1, (0, 255, 0), 3 )
plt.imshow(img_copy)