【Python3

您所在的位置:网站首页 照片物体量尺寸 【Python3

【Python3

2023-10-18 09:41| 来源: 网络整理| 查看: 265

这是我参与更文挑战的第27天,活动详情查看: 更文挑战

OpenCV是一个C++库,目前流行的计算机视觉编程库,用于实时处理计算机视觉方面的问题,它涵盖了很多计算机视觉领域的模块。在Python中常使用OpenCV库实现图像处理。

image.png

本文将介绍如何在Python3中使用OpenCV实现测量图像中物体的大小。

参考资料《Measuring size of objects in an image with OpenCV》

原理介绍

为了确定图片中一个物体的尺寸,我们首先需要使用一个参考对象进行“校准”。

我们的参考对象需要有两个重要的属性:

我们应该以可测量的单位(例如毫米,英寸等)知道此对象的尺寸(以宽度或高度为单位)。 我们应该能够根据对象的位置(例如,始终将对象放置在图像的左上角)或通过外观(例如独特的颜色)轻松地在图像中找到该参考对象,与图片中的所有其他对象唯一且不同)。

无论哪种情况,我们的参考对象都应该以某种方式唯一地标识。

在本案例中,我们将使用一个两角五分的美元硬币作为参考物体,并在所有示例中确保它始终是图像中最左的物体,如下所示:

demo06.png

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

pixels_per_metric = object_width / know_width(物体像素宽 / 物体真实宽)

一个两角五分的美元硬币是 0.955 英寸。现在假设我们的 object_width (以像素为单位)被计算为 150 像素宽(基于它的相关边框)。

因此,pixels_per_metric 为:

pixels_per_metric = 150px / 0.955in = 157px

因此,在我们的图像中,每0.955英寸大约有 157 个像素。

利用这个比率,我们可以计算图像中物体的大小。

实现步骤 1.原图转灰度图,高斯滤波,提取边缘,提取轮廓; 2.将轮廓从左到右排序,最左边的作为参照物; 3.计算参照物轮廓大小,pixelPerMetricX,pixelPerMetricY; 4.计算其他物体轮廓,进行处理。 完整代码 import numpy as np from scipy.spatial import distance as dist import cv2 from imutils import contours from imutils import perspective import imutils def show(name,img): cv2.imshow(name,img) cv2.waitKey(0) cv2.destroyAllWindows() def midpoint(ptA,ptB): return ((ptA[0] + ptB[0]) * 0.5 , (ptA[1] + ptB[1]) * 0.5) img = cv2.imread('E:\\demo\\demo06.png') width = 25 img = imutils.resize(img,height = 500) gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray,(5,5),0) edged = cv2.Canny(gray,70,200) edged = cv2.dilate(edged,None,iterations = 1) edged = cv2.erode(edged,None,iterations = 1) cnts,_ = cv2.findContours(edged,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) (cnts,_) = contours.sort_contours(cnts) pixelPerMetricX = 0 pixelPerMetricY = 0 order = 1 for c in cnts: if cv2.contourArea(c) < 100: continue orig = img.copy() box = cv2.minAreaRect(c) box = cv2.boxPoints(box) box = box.astype('int') box = perspective.order_points(box) cv2.drawContours(orig,[box.astype(int)],0,(0,255,0),2) for x,y in box: cv2.circle(orig,(int(x),int(y)),5,(0,0,255),3) (tl,tr,br,bl) = box (tltrX,tltrY) = midpoint(tl,tr) (tlblX,tlblY) = midpoint(tl,bl) (blbrX,blbrY) = midpoint(bl,br) (trbrX,trbrY) = midpoint(tr,br) cv2.circle(orig,(int(tltrX),int(tltrY)),5,(183,197,57),-1) cv2.circle(orig,(int(tlblX),int(tlblY)),5,(183,197,57),-1) cv2.circle(orig,(int(blbrX),int(blbrY)),5,(183,197,57),-1) cv2.circle(orig,(int(trbrX),int(trbrY)),5,(183,197,57),-1) cv2.line(orig,(int(tltrX),int(tltrY)),(int(blbrX),int(blbrY)),(255,0,0),2) cv2.line(orig,(int(tlblX),int(tlblY)),(int(trbrX),int(trbrY)),(255,0,0),2) #纵向 dA = dist.euclidean((tltrX,tltrY),(blbrX,blbrY)) #横向 dB = dist.euclidean((tlblX,tlblY),(trbrX,trbrY)) if pixelPerMetricX == 0 or pixelPerMetricY == 0: pixelPerMetricX = dB / width pixelPerMetricY = dA / width dimA = dA / pixelPerMetricY dimB = dB / pixelPerMetricX cv2.putText(orig,"{:.1f}mm".format(dimB),(int(tltrX)-10,int(tltrY)),cv2.FONT_HERSHEY_COMPLEX,0.6,(255,255,255),1) cv2.putText(orig,"{:.1f}mm".format(dimA),(int(trbrX)-10,int(trbrY)),cv2.FONT_HERSHEY_COMPLEX,0.6,(255,255,255),1) cv2.imwrite('{}.jpg'.format(order),orig) order += 1

输入图片:

demo06.png

输出结果为:

1.jpg

2.jpg

3.jpg

4.jpg

5.jpg

6.jpg

不完善之处

通过单纯的按比率来算图中物体的大小与长度,肯定会存在一定的误差。例如图像的拍摄角度不同会造成一定的测量上的误差。想要得到更好效果,需要对图像进行进一步的处理。

本月将陆续推出相关系列文章,

篇篇精彩,尽请关注。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3