本文翻译自pyimagesearch技术博客上的一篇文章,《Measuring size of objects in an image with OpenCV》,原文作者:Adrian Rosebrock 。

https://www.pyimagesearch.com/2016/03/28/measuring-size-of-objects-in-an-image-with-opencv/


  有那么很长一段时间,PyImage Search博客上的小伙伴都在强烈呼吁有关图像目标尺寸检测的博客文档,好了,你们如愿以偿了,我也很高兴能在PyImage Search博客上发布这篇文章并与你分享它。

  关于图像目标检测我写成了三部分,今天介绍的内容选自我所写的第二部分,主要是关于测量图像中物体大小和计算它们之间的距离。

  上周,我们学习了一项重要的技术:如何可靠有效地让旋转的边界框在左上角、右上角、右下角和左下角排列。今天,我们将利用这种技术来帮助我们计算图像中物体的大小。一定要通读整篇文章,看看它是怎么做的!

  图像目标尺寸检测类似于计算从我们的相机到一个物体的距离——在这两种情况下,我们都需要事先定义一个比率来测量每个给定度量单位的像素数(pixels_per_metric)。在这里所说的这个被称为“pixels_per_metric”的比率指标,我在接下来的部分中对其更正式的定义。

pixels_per_metric

  为了确定图像中物体的大小,我们首先需要使用一个参照物作为“校准”点。我们的参照物应该有两个重要的属性:

1、我们应该知道这个物体的真实尺寸(在宽度或高度上的毫米或英寸等值的大小)。

2、我们应该能够轻松地在图片中找到这个参照物,要么基于参照物的位置(如,参照物可以是一副图像中左上角的物体)或基于参照物的外表(例如参照物可以是图片中具有最独特的颜色或独一无二的形状,不同于所有其他的物体)。一句话而言:在任何一种情况下,我们的参照物都应该是以某种方式进行唯一可识别的The One。

  在第1个例子中,我们将使用美分硬币作为我们的参照物,正如你阅读后续其他例子时所看到的,我总是选择图像中最左侧的物体作为参照物。

图1:我们将使用一个美分硬币作为我们的参照物,并确保它总是被放置在图像中最左边,这使得我们可以通过对它们位置的轮廓大小进行排序,进一步来提取信息。

  通过保证这个美分硬币是最左边的物体后,我们可以从左到右对我们的物体等高线区域进行排列,抓住这个硬币(它将始终对应于排序列表中的第一个等高线区域),并使用它来定义我们的pixels_per_metric比率,我们将其定义为:

pixels_per_metric =物体像素宽 / 物体真实宽

  美分硬币的真实宽度是0.955英寸。现在,假设我们图像中硬币的像素宽为150像素(基于它的相关边界框)。那么这种情况下pixels_per_metric这样计算:
pixels_per_metric = 150px / 0.955in = 157px
因此,在我们这幅图像中,每英寸大约有157个像素。有了这个比率,我们可以计算图像中其他物体的大小了。

利用计算机视觉测量物体大小

  既然我们已经理解了pixels_per_metric,我们就可以实现用于测量图像中对象大小的Python程序脚本了。
打开一个新的py文件,插入以下代码:

# import the necessary packages
from scipy.spatial import distance as dist
from imutils import perspective
from imutils import contours
import numpy as np
import argparse
import imutils
import cv2def midpoint(ptA, ptB):return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,help="path to the input image")
ap.add_argument("-w", "--width", type=float, required=True,help="width of the left-most object in the image (in inches)")
args = vars(ap.parse_args())

  第2-8行用来导入我们所需的Python包。在本例中,我们将大量使用imutils包,因此,如果您没有安装它,请确保在使用之前安装它:

$ pip install imutils

  另外如果你已经安装过这个imutils包,也请确保它为最新版本,在我这里所使用最新的版本是0.3.6。

$ pip install --upgrade imutils

  第10行和第11行定义了一个midpoint函数,顾名思义,它用于计算两个(x,y)坐标之间的中点。

  然后我们在第14-19行中解析我们的命令行参数。我们需要两个参数,–image,它是我们输入图像的路径,其中包含我们想要测量的对象,–width,也就是我们的参照物的宽度(英寸),–image路径图像中所认定的那个最左边的物体。

  我们现在可以加载我们的图像并对其进行预处理:

# load the image, convert it to grayscale, and blur it slightly
image = cv2.imread(args["image"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (7, 7), 0)# perform edge detection, then perform a dilation + erosion to
# close gaps in between object edges
edged = cv2.Canny(gray, 50, 100)
edged = cv2.dilate(edged, None, iterations=1)
edged = cv2.erode(edged, None, iterations=1)# find contours in the edge map
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]# sort the contours from left-to-right and initialize the
# 'pixels per metric' calibration variable
(cnts, _) = contours.sort_contours(cnts)
pixelsPerMetric = None

第22-24行从磁盘加载我们的图像,将其转换为灰度,然后使用高斯过滤器平滑它。然后我们执行边缘检测和扩张+磨平,以消除边缘图中边缘之间的任何间隙(第28-30行)。

  第33-35行找到等高线,也就是我们边缘图中物体相对应的轮廓线。

  然后,这些等高线区域从左到右(使得我们可以提取到参照物)在第39行中进行排列。然后我们在第40行时,对pixelsPerMetric值进行初始化。

  下一步是对每一个等高线区域值大小进行检查校验。

# loop over the contours individually
for c in cnts:# if the contour is not sufficiently large, ignore itif cv2.contourArea(c) < 100:continue# compute the rotated bounding box of the contourorig = image.copy()box = cv2.minAreaRect(c)box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box)box = np.array(box, dtype="int")# order the points in the contour such that they appear# in top-left, top-right, bottom-right, and bottom-left# order, then draw the outline of the rotated bounding# boxbox = perspective.order_points(box)cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 2)# loop over the original points and draw themfor (x, y) in box:cv2.circle(orig, (int(x), int(y)), 5, (0, 0, 255), -1)

  在第43行,我们开始对每个单独的轮廓值进行循环。如果等高线区域大小不够大,我们就会丢弃该区域,认为它是边缘检测过程遗留下来的噪音(第45和46行)。

  如果等高线区域足够大,我们就会在第50-52行计算图像的旋转边界框,特别注意:cv2.cv.BoxPoints函数是针对于opencv2.4版本,而cv2.BoxPoints函数是针对于OpenCV 3版本。

  然后我们将旋转的边界框坐标按顺序排列在左上角,右上角,右下角,左下角,正如上周的博客文章(第58行)所讨论的。

  最后,第59-63行用绿色画出物体的轮廓,然后将边界框矩形的顶点画在小的红色圆圈中。现在我们已经有了边界框,接下来就可以计算出一系列的中点:

    # unpack the ordered bounding box, then compute the midpoint# between the top-left and top-right coordinates, followed by# the midpoint between bottom-left and bottom-right coordinates(tl, tr, br, bl) = box(tltrX, tltrY) = midpoint(tl, tr)(blbrX, blbrY) = midpoint(bl, br)# compute the midpoint between the top-left and top-right points,# followed by the midpoint between the top-righ and bottom-right(tlblX, tlblY) = midpoint(tl, bl)(trbrX, trbrY) = midpoint(tr, br)# draw the midpoints on the imagecv2.circle(orig, (int(tltrX), int(tltrY)), 5, (255, 0, 0), -1)cv2.circle(orig, (int(blbrX), int(blbrY)), 5, (255, 0, 0), -1)cv2.circle(orig, (int(tlblX), int(tlblY)), 5, (255, 0, 0), -1)cv2.circle(orig, (int(trbrX), int(trbrY)), 5, (255, 0, 0), -1)# draw lines between the midpointscv2.line(orig, (int(tltrX), int(tltrY)), (int(blbrX), int(blbrY)),(255, 0, 255), 2)cv2.line(orig, (int(tlblX), int(tlblY)), (int(trbrX), int(trbrY)),(255, 0, 255), 2)

  第68-70行将我们前面所得的有序边界框各个值拆分出来,然后计算左上角和右上角之间的中点,然后是计算左下角和右下角之间的中点。

  此外,我们还分别计算左上角与左下角,右上角和右下角的中点(第74和75行)。

  第78-81行在我们的图像上画出蓝色的中点,然后将各中间点用紫色线连接起来。

  接下来,我们需要通过查看我们的参照物来初始化pixelsPerMetric变量:

    # compute the Euclidean distance between the midpointsdA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))# if the pixels per metric has not been initialized, then# compute it as the ratio of pixels to supplied metric# (in this case, inches)if pixelsPerMetric is None:pixelsPerMetric = dB / args["width"]
  • 首先,我们计算中间点集之间的欧几里得距离(第90行和第91行)。
    dA变量将包含高度距离(以像素为单位),而dB将保持我们的宽度距离。

  • 然后,我们在第96行进行检查,看看我们的pixelsPerMetric变量是否已经被初始化了,如果没有,我们将dB除以我们提供的宽度,从而得到每英寸的(近似)像素。
    现在我们已经定义了pixelsPerMetric变量,我们可以测量图像中各物体的大小:

    # compute the size of the objectdimA = dA / pixelsPerMetricdimB = dB / pixelsPerMetric# draw the object sizes on the imagecv2.putText(orig, "{:.1f}in".format(dimA),(int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX,0.65, (255, 255, 255), 2)cv2.putText(orig, "{:.1f}in".format(dimB),(int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX,0.65, (255, 255, 255), 2)# show the output imagecv2.imshow("Image", orig)cv2.waitKey(0)

  第100行和第101行计算物体的尺寸(英寸),方法是通过pixelsper度量值划分各自的欧几里得距离(参见上面的“pixels_per_metric ”一节,以获得关于这个比率如何工作的更多信息)。 第104-109行在我们的图像上画出物体的尺寸,而第112和113行显示输出结果。

物体大小测试结果

  为了测试我们的object_size.py脚本,只需执行以下命令:

 python object_size.py --image images/example_01.png --width 0.955

  您的输出应该如下图所示:


图2:使用OpenCV、Python和计算机视觉+图像处理技术来测量图像中物体的大小

  正如您所看到的,我们已经成功地计算出了我们图像中的每个物体的大小——我们的名片被正确地报告为3.5in x 2in。类似地,我们的镍币被准确地描述为0.8in x 0.8in。 然而,并不是所有的结果都是完美的。 两个游戏男孩的墨盒被报道有稍微不同的尺寸(实际上它们的尺寸是一样的)。两个镍币的尺寸也下降了0.1英寸。 这是为什么?为什么物体的测量不是百分之百准确的?

有两个原因:

  首先,我匆忙用我的iPhone拍了这张照片。这个角度当然不是一个完美的90度角“向下看”(就像鸟的眼睛一样)在物体上。如果没有一个完美的90度视图(或者尽可能接近它),物体的尺寸就会被扭曲。

  其次,我没有使用相机的内在和外在参数来校准我的iPhone。如果不确定这些参数,照片就会倾向于径向和切向镜头失真。执行一个额外的校准步骤来发现这些参数可以“不扭曲”我们的图像,并导致更好的对象大小近似(但是我将把关于失真校正的讨论作为未来博客文章的主题)。

  换句话说,在拍摄对象的照片时,尽量接近90度的视角——这将有助于提高对物体大小估计的准确性。

  让我们看第二个测量物体大小的例子,这次测量的是药片的尺寸:

python object_size.py --image images/example_02.png --width 0.955


  在美国,几乎有一半的处方药物是圆的和/或白色的,因此,如果我们能根据他们的测量结果来过滤药片,我们就有更好的机会准确识别药物。

  最后,我们有一个最后的例子,这次用的是3.5in x 2in 的名片来测量两个黑胶唱片和一个信封的大小:

  同样,结果也不是很完美,但这是由于(1)视角和(2)镜头失真,正如上述分析的两个原因中所提到的。

  在这篇博客文章中,我们学习了如何使用Python和OpenCV来测量图像中物体的大小。 就像我们在测量从相机到物体的距离的教程一样,我们需要确定我们的“”比率,它描述了如何将物体的真实尺寸大小(如英寸、毫米、米等)对应图片中像素的大小(像素)。

  为了计算这个比率,我们需要一个具有两个重要属性的参考对象:

属性1:参照物的宽度或高度对应的(英寸、毫米等单位)

属性2:参照物在图中很容易找到,无论是在对象的位置还是在外观上。

  如果这两个属性都能被满足,您可以利用您的参照物来校准您的pixelspermetric变量,然后从那里计算图像中其他物体的大小。

  翻译能力有限,如有费解之处请多谅解。如需图片、代码,请看原文链接并给原文作者留下邮箱:

https://www.pyimagesearch.com/2016/03/28/measuring-size-of-objects-in-an-image-with-opencv/

更多精彩和项目分享,大家有兴趣也可以关注本人的公众号:gbxiao992

(OpenCV)图像目标尺寸检测相关推荐

  1. 趋高智能机器视觉图像目标尺寸检测尺寸测量的应用方案

    趋高智能机器视觉图像目标尺寸检测尺寸测量的应用方案. 趋高智能机器视觉系统具有测量功能,能够自动测量产品的外观尺寸,比如外形轮廓.孔径.高度.面积等尺寸的测量.尺寸测量无论是在产品的生产过程中,还是产 ...

  2. 计算机科学与探索类别,图像目标类别检测综述-计算机科学与探索.pdf

    图像目标类别检测综述-计算机科学与探索 蔡 强,刘亚奇,曹 健,等.图像目标类别检测综述[J].计算机科学与探索,2015 ,9(3 ):257-265. ISSN 1673-9418 CODEN J ...

  3. OpenCV图像相似度检测,Python实现

    OpenCV图像相似度检测,简单的说是大图中找小图,以图找图. 假设把大图 中的一部分图Android小机器人检测出来 并用红色的线框出来. # OpenCV图像相似度检测matchTemplate, ...

  4. OpenCV图像相似度检测

    # OpenCV图像相似度检测matchTemplate,Python实现 import cv2 as cvif __name__ == "__main__":# 先把图片灰度处理 ...

  5. 【图像检测】基于形态学实现图像目标尺寸测量系统附matlab代码

    1 简介 介绍了一种基于机器视觉技术的目标外观尺寸检测系统.,通过数字图像处理技术获取柚子的纵径,横径,表面积等外观尺寸参数. 2 部分代码 coin_width=1.1000;coin_height ...

  6. streamlit + opencv/YOLOv3 快速构建自己的图像目标检测demo网页(七)

    文章目录 1 案例介绍 2 依赖安装 3 页面使用 4 源码细节解析 4.1 直接读入markdown文件 4.2 加载文件与图片 4.3 opencv + yolov3 检测函数 系列参考: pyt ...

  7. 最全综述 | 图像目标检测

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 前言 图片分类任务我们已经熟悉了,就是算法对其中的对象进行分类.而 ...

  8. 【OpenCV入门教程之十三】OpenCV图像金字塔:高斯金字塔、拉普拉斯金字塔与图片尺寸缩放

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/26157633 作者:毛星云(浅墨) ...

  9. YOLO v2实现图像目标检测

    作者介绍 熊文博,男,西安工程大学电子信息学院,2020级硕士研究生,张宏伟人工智能课题组. 研究方向:机器视觉与人工智能 电子邮件:996270714@qq.com 师兄的CSDN主页: 欢迎关注和 ...

最新文章

  1. ML之LiRSGDR:基于二种算法(LiR、SGDR)对Boston(波士顿房价)数据集(506,13+1)进行价格回归预测并对比各自性能
  2. 【杂谈】从GitHub上星星最多的男人开始发GitHub综述资料
  3. devops 开发_DevOps如何消除开发瓶颈
  4. python中必须使用import引入模块_Python之import方法引入模块详解
  5. GCC编译的几个步骤
  6. Mysql获取当天用户生日
  7. isb 汇编_DSB,ISB,DMB指令
  8. 你TM管这着玩意儿叫H5编辑器?????
  9. ONF与天地互连共同成立开放SDN推广中心(OSPC)
  10. 美化Ubuntu18桌面伪装成MAC桌面
  11. Hinton努力推翻自己积累了30年的学术成果,我才知道什么叫生命力!
  12. 抓包工具在测试中的作用
  13. ZZULI郑州轻工业大学21级新生赛正式赛
  14. 华为硬件工程师手册_漫画解读—华为最强科普:什么是DSP?
  15. cifar-10之matlab初步
  16. sqlserver当前属于哪个季度_sqlserver日期推算(年,季度,月,星期推算)
  17. 关于JS中的一些时间函数
  18. 台式计算机配置清单4500,台式主机配置清单_要一个台式电脑主机清单(价格控制在4500左右最好)...
  19. 1、Melodic驱动笔记本摄像头和USB摄像头
  20. 《Spring Web Flow 实践》

热门文章

  1. 用C++编写一个简易数学计算器
  2. 使用C++模拟动态密码验证
  3. 实时的软件生成 —— Prompt 编程打通低代码的最后一公里?
  4. CentOS-6.5操作系统环境安装优化
  5. age estimation阅读整理(一)
  6. 利用百度地图服务发布自己制作图片的地图
  7. 分数阶傅立叶变换中午matlab,怎么做短时分数阶傅里叶变换
  8. 华胜天成收购中天安泰10%股权 出手网络信息安全
  9. 微信公共号推广技巧、快速涨粉丝的7大技巧总结
  10. dotnet Multi-platform App UI 多平台应用 UI 框架简介