对于未经处理的图像,我们无法直接获取点的坐标。特别是对于彩色图像,我们需要将其转换为二值图像,并使用轮廓检测技术来获取轮廓边界的点的坐标。然后,我们才能进行上述寻找凸包点的过程。
1.获取凸包点
2.绘制凸包
# 获取图像
img = cv.imread(r'D:\AI\笔记课件\images\num.png')
# 灰度化
img_gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# 二值化
_,img_binary = cv.threshold(img_gray,127,255,cv.THRESH_OTSU+cv.THRESH_BINARY_INV)
# 获取轮廓
contours,hierarchy = cv.findContours(img_binary,mode=cv.RETR_EXTERNAL,method=cv.CHAIN_APPROX_SIMPLE)
# 获取凸包
points = [cv.convexHull(i) for i in contours]
# 绘制凸包
cv.polylines(img,points,True,(255,0,0),3,cv.LINE_AA)
# 显示图像
cv.imshow('img',img)
cv.waitKey(0)
cv.destroyAllWindows()
img = cv.imread(r"D:\AI\笔记课件\images\flower2.png")
img_copy = img.copy()
# 灰度化
img_gray = cv.cvtColor(img_copy,cv.COLOR_BGR2GRAY)
# 二值化
_,img_binary = cv.threshold(img_gray,127,255,cv.THRESH_OTSU+cv.THRESH_BINARY_INV)
# 查找轮廓
contours,hierarchy = cv.findContours(img_binary,mode=cv.RETR_EXTERNAL,method=cv.CHAIN_APPROX_SIMPLE)
# 绘制轮廓
cv.drawContours(img_copy,contours,-1,(255,0,0),3)
# 获取外接矩阵位置
for i in contours:
x_min,y_min,w,h = cv.boundingRect(i)
# 绘制外接矩形
cv.rectangle(img_copy,(x_min,y_min),(x_min+w,y_min+h),(0,0,255),3,cv.LINE_AA)
# 显示效果
cv.imshow('img',img_copy)
cv.waitKey(0)
cv.destroyAllWindows()
使用旋转卡壳算法
对于多边形P的一个外接矩形存在一条边与原多边形的边共线。
对于每一条边,找到距离边变最远的点的距离作为矩形的高
对于每一条边,找到投影到边最大的距离计算矩形的宽
比较通过每一条边计算得到的矩形面积进行比较,找到最小的矩形面积
w i d t h = ∣ b h ‾ ∣ × cos a + ∣ a d ‾ ∣ × cos θ − ∣ a b ‾ ∣ w i d t h=|\overline{{{b h}}}|\times\cos a+|\overline{{{a d}}}|\times\cos\theta-|\overline{{{a b}}}| width=∣bh∣×cosa+∣ad∣×cosθ−∣ab∣
在OpenCV中,可以直接使用cv2.minAreaRect()来获取最小外接矩形,该函数只需要输入一个参数,就是凸包点的坐标,然后会返回最小外接矩形的中心点坐标、宽高以及旋转角度。
rect = cv2.minAreaRect(cnt)
传入的cnt参数为contours中的轮廓,可以遍历contours中的所有轮廓,然后计算出每个轮廓的小面积外接矩形
rect 是计算轮廓最小面积外接矩形:rect 结构通常包含中心点坐标 (x, y)
、宽度 width
、高度 height
和旋转角度 angle
cv2.boxPoints(rect).astype(int)
cv2.boxPoints(rect)返回 是一个形状为4行2列的数组,每一行代表一个点的坐标(x, y),顺序按照逆时针或顺时针方向排列
将最小外接矩形转换为边界框的四个角点,并转换为整数坐标
img = cv.imread(r"D:\AI\笔记课件\images\num.png")
# 灰度化
img_gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# 二值化
_,img_binary = cv.threshold(img_gray,127,255,cv.THRESH_OTSU+cv.THRESH_BINARY_INV)
# 查找轮廓
contours,hierarchy = cv.findContours(img_binary,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
# 获取最小外接矩形
for i in contours:
rect = cv.minAreaRect(i)
# 获取每个顶点的坐标
box = cv.boxPoints(rect).astype(np.int32)
# 绘制图像
cv.drawContours(img,[box],-1,(255,0,0),2,cv.LINE_AA)
# 显示效果
cv.imshow('img',img)
cv.waitKey(0)
cv.destroyAllWindows()
参数说明:
points
:输入参数图片轮廓数据返回值:
center
:一个包含圆心坐标的二元组 (x, y)
。radius
:浮点数类型,表示计算得到的最小覆盖圆的半径。cv2.circle(img, center, radius, color, thickness)
img
:输入图像,通常是一个numpy数组,代表要绘制圆形的图像。center
:一个二元组 (x, y)
,表示圆心的坐标位置。radius
:整型或浮点型数值,表示圆的半径长度。color
:颜色标识,可以是BGR格式的三元组 (B, G, R)
,例如 (255, 0, 0)
表示红色。thickness
:整数,表示圆边框的宽度。如果设置为 -1
,则会填充整个圆。img = cv.imread(r"D:\AI\笔记课件\images\num.png")
# 灰度化
img_gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# 二值化
_,img_binary = cv.threshold(img_gray,127,255,cv.THRESH_OTSU+cv.THRESH_BINARY_INV)
# 查找轮廓
contours,_ = cv.findContours(img_binary,mode=cv.RETR_EXTERNAL,method=cv.CHAIN_APPROX_SIMPLE)
# 获取最小外接圆
for i in contours:
# 获取每个点的位置信息
(x,y),radius = cv.minEnclosingCircle(i)
# 数据类型转换,元组不能直接使用astype进行类型转换
x,y,radius = np.int_(x),np.int_(y),np.int_(radius)
# 绘制图像
cv.circle(img,(x,y),radius,(255,0,0),3,cv.LINE_AA)
# 显示效果
cv.imshow('img',img)
cv.waitKey(0)
cv.destroyAllWindows()
THE END