![8729ac64647b3daa9afabb5721c57e35.png](https://i-blog.csdnimg.cn/blog_migrate/ec44ab8236346a6b842a3b7df8adab4f.jpeg)
在传统的数字图像处理当中,边缘检测与形态学为两门非常重要的技术,在笔者的第一篇文章中已经重点介绍了各种边缘检测算子,因此这次笔者将结合一些较为简单的形态学算法,使用Matlab为大家介绍一个很有意思的测量目标尺寸的小项目,效果如下
![76281a83436ea5ea1497e15cd244cf22.png](https://i-blog.csdnimg.cn/blog_migrate/6d06ff7d9e14ee5494a21d1bcb64e62b.jpeg)
1.测距原理
在数字图像处理当中我们可知,在计算机眼中,每一张图片都实际上表现为一个庞大的矩阵,若在不知道测距物体距离的情况下,是不可能对图像中物体进行大小(size)的测量计算的,因此我们需要引入一个和比例尺类似的概念:pixels per metric ratio
意为给定度量单位的像素比率,在本篇文章中我们将给点度量单位设定为英寸(inch),可以理解为参考物的作用`,给定图像中一参考物大小,便可测得其它目标物体的尺寸大小
其中,参考物需要有两个重要性质:
性质1:参考物尺寸
我们应该知道物体的尺寸(就是宽或高)包括测量的单位(如mm、英寸等)
性质2:易于识别
我们应该能够很容易地在图片中找到参照物体,无论是基于物体的位置(例如,参考物体总是放在图片的左上角)还是通过外观(例如,独特的颜色或形状,不同与图片中的其他物体)。无论是哪种情况,我们的参照物都应该以某种方式具有唯一的可识别性。
在本篇文章中,我们将硬币作为我们的参考物,已知其尺寸大小为1 inch*1 inch,并且为满足性质2,我们确保其始终置于图像最左侧
![47a9a1c72e171b6d0d1e820e624d847d.png](https://i-blog.csdnimg.cn/blog_migrate/c99895e5494e07abd1bd1d7106b1136c.jpeg)
因此我们得到给定度量单位像素比例计算公式:
pixels per metric ratio = 硬币像素数/物体实际尺寸
已知硬币长宽均为1英寸,假设其在图像中像素宽为157px(基于其关联的检测框),得:
pixels per metric ratio = 157px/1.000in = 157px/in
通过使用这一比例,我们便可计算图像中其它物体的尺寸大小信息了
2.利用计算机视觉测量物体的大小
现在我们理解了pixels per metric ratio比率的含义,但我们还需要对目标进行检测进行检测框长宽的提取,这一步我们将用到诸如灰度图变换、边缘检测、形态学等算法
首先我们定义硬币长宽,并且读取原始图像
coin_width
![71833abfeca271f5ae8870c6517dd423.png](https://i-blog.csdnimg.cn/blog_migrate/a7b8ad15da1e9c6fc6709e1e14736a1b.jpeg)
之后我们使用rgb2gray(image)函数进行灰度图转换,并且通过imfilter(f, w,boundary_options)函数对图像进行高斯滤波,其中w为滤波器,由fspecial(type,parameters,sigma)生成,其中将type设为"gaussian",sigma设为1,代码及效果如下
%转换为灰度图像
![c473314556b741d4129e04ba68e212aa.png](https://i-blog.csdnimg.cn/blog_migrate/8a70f023c04af83f541683b8a8bd36ca.jpeg)
对高斯滤波后的图像进行Canny边缘检测,使用edge(I,method,threshold),,其中I为输入图像,method为指定算法,文章中使用"canny"进行边缘检测,而threshold为阈值,通常设为0.1,具体想了解各边缘检测算法详解请看这篇文章
Rustle:数字图像图像处理:边缘检测(Edge detection)zhuanlan.zhihu.com![cccc86d5bfc878461044b19ef078d501.png](https://i-blog.csdnimg.cn/blog_migrate/7dda4f1b0ab380f6b9bd0694ce345dff.jpeg)
边缘检测代码及效果如下所示
I3
![a726b56f8353b1f0c2a81681eb6bb422.png](https://i-blog.csdnimg.cn/blog_migrate/cb8f1498d2bc4042e58ca8097adfa0eb.png)
通过观察边缘图像可以发现各目标内部还具有较细的纹理,对后续八连通区域的检测造成较大干扰,因此我们可以通过孔洞填充操作去除内部纹理,其次提取孔洞填充图像外围边缘,最后使用形态学算法去除较小物体,具体代码如下:
% 孔洞填充
其中bwperim函数与传统的边缘检测概念不同,边缘检测为提取图像边缘特征图像,而bwperim只保留目标最外层边缘,bwareaopen(I4,150)意为去除图像中小于150px的八连通区域(至于为什么选择150,emmmm笔者是把它当成参数直接人为调的哈)
最后效果如下:
![075ccc1f980785afe17bdcb3e0b396d6.png](https://i-blog.csdnimg.cn/blog_migrate/61b902ebb33a8f9b8e25e081906f120d.png)
![4cb7ede9da37584e83ade1e0bd7506f4.png](https://i-blog.csdnimg.cn/blog_migrate/3f419db6ca614c5665f8158edb0d9e91.png)
![78e1b3f7a6f5cbb3f7b08920c50db660.png](https://i-blog.csdnimg.cn/blog_migrate/bbdc329acb387ddc9446900f9131697d.png)
至此,我们便完成了对图像的处理阶段,接下来我们需要对物体进行标记,并且绘制相关的检测框图,其中我们使用 [labelpic,num] = bwlabel(I5,8)来对图像从左至右对目标进行标记,并配合find函数进行特定目标的操作,如接下来我们需要计算pixels per metric ratio,我们需要将最左边硬币目标提取出来,我们可以使用以下代码进行提取
[
其中r,c分别为目标对象(coin)的八连通行列坐标,然后我们使用函数minboundrect(c,r,'p')将得到的r,c进行最小外接矩形的计算,其中参数p表示按边长最小原则进行计算,最后使用minboxing()函数计算最小外接矩形的长宽,具体代码如下:
% 获取标记物体最小外接矩形坐标点
计算pixels per metric ratio:
% 单位英寸像素点比例计算
其中minboundrect与minboxing函数并不是Matlab官方函数,具体代码会在文末给出
我们使用同样的原理进行各目标最小外接矩形的计算,并使用line函数在图像中绘制出矩形框与中点连线
for
最后,我们根据pixels per metric ratio与最小外接矩形长宽计算目标实际尺寸,并通过text函数在图像中进行显示,代码如下:
line
好了现在我们完成了所有工作,最终的效果图便是这样啦
![76281a83436ea5ea1497e15cd244cf22.png](https://i-blog.csdnimg.cn/blog_migrate/6d06ff7d9e14ee5494a21d1bcb64e62b.jpeg)
最后在放两个动图让大家看看效果吧
![103881f659584426b3a19c66eea979b1.gif](https://i-blog.csdnimg.cn/blog_migrate/09c2d0209dbbe788c90a6a9e96defbcf.gif)
![a995182429ed710e7072548e1d4be8d6.gif](https://i-blog.csdnimg.cn/blog_migrate/4b4d7be6ddf6f11d26f5c7edd4dc7a4f.gif)
如上图所示,我们已经成功的计算出图片中每个物体的尺寸
然而,并非所有的结果都是完美的,可能的原因:
- 拍摄的角度并非是一个完美的90°俯视。如果不是90°拍摄,物体的尺寸可能会出现扭曲
- 没有使用相机内在和外在参数来校准。当无法确定这些参数时,照片很容易发生径向和切向的透镜变形。执行额外的校准步骤来找到这些参数可以消除图片中的失真并得到更好的物体大小的近似值
参考
1.Measuring size of objects in an image with OpenCV
代码如下:
coin_width
minboundrect函数
function
minboxing函数
function
码字不易,各位看官点个赞再走呀嘻嘻嘻