如何使用传统图像处理方法进行圆的检测和测量
Posted 赵卓不凡
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用传统图像处理方法进行圆的检测和测量相关的知识,希望对你有一定的参考价值。
1 引言
上一篇使用传统方法进行石头检测的文章,受到了大家一致的好评.
嗯嗯,应该是一致的好评!
今天我们来研究一个新的方向,如何使用传统方法来进行圆的检测.
如上图所示,存在多个形状各异的物体,这里原型物体只有两个左下角的白色药片,
这里我们需要用图像处理的方法来检测出两个圆形物体,并计算圆形物体相应的面积.
2 解决方案
2.1 二值化
传统图像分割一般采用阈值分割的方法来区分前景和背景,
这里我们采用OTSU的方法来进行二值化操作,方法如下:
image_file = './images/pillsetc.png'
# Step 1: Read image
bgr_image = cv2.imread(image_file,cv2.IMREAD_COLOR)
# Step 2: Threshold the image
gray_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2GRAY)
threshold, thresh_image = cv2.threshold(gray_image, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
print('Graylevel threshold computed with otsu: ', threshold)
运行后结果如下:
上图中,左侧为原图,右侧为二值化后的结果图.
2.2 图像去燥
观察上图二值化后的图像,存在一些零零散散的噪声,这里我们来想办法去除这些噪声.
这里推荐使用remove_small_objects这个函数,该函数可以直接去掉零散的小连通区域,我们代码实现如下:
from skimage import morphology
rmnoise_image = morphology.remove_small_objects(thresh_image.astype(bool), min_size=30)
上述代码,直接将面积小于30的小连通区域和孤点噪声直接剔除,运行结果如下:
上图中,左侧为去燥前的效果图,右侧为去燥后的效果图,可以看出很多零散的噪声和小的连通区域均被滤除.
2.3 消除空洞
观察上述去燥后的图像,注意查看下图绿色接头(红色框内)的二值图像,我们发现存在空洞,这里可以采用先膨胀在腐蚀的操作(闭运算),来消除空洞,代码如下:
fillcap_image = morphology.binary_closing(rmnoise_image, selem=morphology.disk(2))
运行效果如下:
上图中左侧为闭运算操作前的结果图,右侧为使用闭运算后的效果图,可以看出矩形框内的绿色转接头已经消除中间空洞.
2.4 填充
观察下图左侧图像.可以看出黄色框内的椭圆物品中间为空心的,这里需要对其进行填充,填充代码如下:
from scipy.ndimage.morphology import binary_fill_holes
clean_image = binary_fill_holes(fillcap_image)
运行效果如下:
上图中左侧为填充前的结果图,右侧为填充后的效果图,可以看出矩形框内的椭圆物品由空心经填充变为了实心.
2.5 查找轮廓
我们观察上图,可以看出所有物品均被我们处理成一个个独立的封闭区域,这时我们可以采用opencv下的findContours函数来寻找对应区域的外轮廓.代码如下:
contours, _ = cv2.findContours(clean_image.astype(np.uint8), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
h,w = clean_image.shape
obj_image = np.zeros(shape=(h,w,3),dtype=np.uint8)
color_list=[(94,17,43),(128,31,113),(121,54,180),(118,173,253),(190,251,250),(93,96,239)]
for ind, cnt in enumerate(contours):
cv2.drawContours(obj_image, [cnt], 0,color_list[ind], -1)
运行效果如下:
上图中左侧为输入原图,右侧为我们寻找出的外轮廓,并对其进行轮廓填充后的结果图.
2.6 圆的判断
经过上述操作,我们已经可以得到每个物品的外轮廓,接着我们回到我们原来的问题,怎么来判断那个物体是圆形呢?
首先我们来回顾一下圆的性质:
- 圆的面积 A r e a = π R 2 Area= \\pi R^2 Area=πR2
- 圆的周长 P e r i m e t e r = 2 ∗ π ∗ R Perimeter=2*\\pi*R Perimeter=2∗π∗R
接着我们定义 α \\alpha α,由面积和周长组成,计算公式如下:
α = 4 ∗ π ∗ A r e a P e r i m e t e r 2 \\alpha=\\frac{4*\\pi*Area}{Perimeter^2} α=Perimeter24∗π∗Area
对于圆形物体,我们将圆的面积和周长计算公式代入,可以知道
α
=
1
\\alpha=1
α=1.
对于正方形物体来说,我们将正方形的面积和周长计算公式代入,
α
=
4
∗
π
∗
A
r
e
a
P
e
r
i
m
e
t
e
r
2
=
4
∗
π
∗
a
2
(
4
∗
a
)
2
=
π
4
<
1
\\alpha=\\frac{4*\\pi*Area}{Perimeter^2}=\\frac{4*\\pi*a^2}{(4*a)^2}=\\frac{\\pi}{4}<1
α=Perimeter24∗π∗Area=(4∗a)24∗π∗a2=4π<1
总上,我们可以得到以下结论:
如果一个物体的轮廓所计算出的
α
\\alpha
α值越接近于1,那么该轮廓越趋向于圆形物体轮廓.
2.7 计算面积周长
经过2.6节的简单推导,我们已经知道如何判断一个轮廓是否趋向于圆形,基于此我们编写代码如下:
for ind, contour in enumerate(contours):
perimeter = cv2.arcLength(contour, True)
area = cv2.contourArea(contour)
alpha = 4*np.pi*area/(perimeter**2)
print('{0:>6} {1:>9,.0f} {2:>9,.2f} {3:>9,.3f}'.format(ind, area, perimeter, alpha))
# Compute moments in order to find the centroid of objects
moments = cv2.moments(contour)
cx = int(moments['m10'] / moments['m00'])
cy = int(moments['m01'] / moments['m00'])
cv2.putText(obj_image,str(ind),(cx,cy),cv2.FONT_HERSHEY_SIMPLEX,0.5,color=(0,128,0),thickness=2)
# Plot a red circle on the centroid of the round objects
if alpha > round_thresh:
cv2.circle(obj_image,(cx,cy),2,color=(0,0,255),thickness=2)
运行后的结果如下:
Object Area Perimeter Roundness
0 882 110.57 0.907
1 876 110.57 0.900
2 16,928 543.05 0.721
3 3,026 261.12 0.558
4 8,074 338.88 0.884
5 4,908 264.01 0.885
可视化结果如下:
上图中,左侧为输入原图,右侧为我们圆检测后的结果图,图中红色圆点代表我们识别出的圆形物体的质心(也就是圆心).
同时根据定量结果输出我们可以得到以下结论:
- 0号物体和1号物体为检测出的圆形物体,红色小点为对应的圆心
- 0号物体的周长为110.57,面积为882
- 1号物体的周长为110.57,面积为876
3 总结
本文介绍了使用传统图像处理方法进行圆形物体检测的基本方法,并根据圆的性质给出了如何根据轮廓的面积和周长来判断轮廓是否为圆的轮廓的方法.
您学废了吗?
关注公众号《AI算法之道》,获取更多AI算法资讯。
注: 关注公众号,后台回复 圆 , 可获取完整代码
以上是关于如何使用传统图像处理方法进行圆的检测和测量的主要内容,如果未能解决你的问题,请参考以下文章