本文的主要算法实现思路:找一个最小面积的矩形提供长宽由此推算出其他物体的长度
博主只写了测量物体最左最右的长度,只能测量矩形。
如图
最左边的为参照物,然后测量上下两个物体的最左和最右长度。
1,相关库
opencv-python == 4.7.0.72
numpy == 1.24.2
2,参数设置
if __name__ == '__main__':minArea = 200img = cv2.imread(r'D:\1\tp\7.jpg')img = cv2.resize(img, (0, 0), None, 0.5, 0.5)findDis1(img,W=50,H=50)
minArea为图片中最小的识别面积,小于这个面积将不会给识别
findDis1里面的W,H修改为自己的参照物长,宽
3,提取物体轮廓信息
def getContours(img):imgG = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)imgBlur = cv2.GaussianBlur(imgG, (5, 5), 1)imgCanny = cv2.Canny(imgBlur, 100, 100)img2 = img.copy()# kernel = np.ones((5, 5))contours, hiearchy = cv2.findContours(imgCanny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)finalCountours = []for i in contours:area = cv2.contourArea(i)if area > minArea:# 计算轮廓的周长,true表示轮廓为封闭peri = cv2.arcLength(i, True)appprox = cv2.approxPolyDP(i, 0.02 * peri, True)bbox = cv2.boundingRect(appprox)if filter > 0:# if (len(appprox)) == filter:finalCountours.append([len(appprox), area, appprox, bbox, i])else:finalCountours.append([len(appprox), area, appprox, bbox, i])# 对第二个数值面积进行排序,为升序,找出轮廓的最大值finalCountours = sorted(finalCountours, key=lambda x: x[1], reverse=True)for con in finalCountours:cv2.drawContours(img, con[4], -1, (0, 0, 255), 4)return img, finalCountours, img2
前面先对img进行预处理(对输入的图像进行灰度化、高斯模糊和边缘检测操作)
contours,hiearchy=cv2.findContours(imgCanny,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
这个方法适用于opencv4版本的,如过这里报错的话可能是你的版本跟我不一样,如果是opencv3版本的话需要在前面加个参数
4,找到最小面积的轮廓并定位四个点
def reorder(myPoints):myPointsNew = np.zeros_like(myPoints)myPoints = myPoints.reshape((4, 2))add = myPoints.sum(1)myPointsNew[0] = myPoints[np.argmin(add)]myPointsNew[3] = myPoints[np.argmax(add)]diff = np.diff(myPoints, axis=1)myPointsNew[1] = myPoints[np.argmin(diff)]myPointsNew[2] = myPoints[np.argmax(diff)]return myPointsNew
这段代码是返回四个顶点
5,主要计算长度代码解释
for i in cons3:# print(i[1])List.append(i[1])Min = min(List)Min = int(Min)inde = List.index(Min)nPoints = reorder(cons3[inde][2])xw = nPoints[1][0][0] - nPoints[0][0][0]xh = nPoints[2][0][1] - nPoints[0][0][1]a = xw / Wa1 = xh / Hfor i in cons3:List = []for i1 in i[2]:List.append([i1[0][0], i1[0][1]])Bubbl(List)seat = int(len(List) - 2)cv2.arrowedLine(img2,List[0], List[1],(255, 0, 255), 2, 8, 0, 0.05)cv2.arrowedLine(img2, List[seat], List[seat + 1],(255, 0, 255), 2, 8, 0, 0.05)xscd = findDis(List[0],List[1])CD = xscd / aCD = round(CD,1)x, y, w, h = i[3]cv2.putText(img2, '{}cm'.format(CD), (x + w, y), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1,(255, 0, 255), 1)xscd1 = findDis(List[seat], List[seat+1])CD1 = xscd1 /aCD1 =round(CD1,1)cv2.putText(img2, '{}cm'.format(CD1), (x , y + h // 2), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1,(255, 0, 255), 1)cv2.imshow('img2', img2)cv2.waitKey(0)
第一个for是找出最小矩形对应的长度像素值,与我们给出的实际长度做出一个参数a
第二个for是便利每一个矩形图像,并获得最左,最右两个边的长度以及位置信息,并用opencv打印上去主要信息
6,实际效果如图:
7,完整代码可在github上获取
github:https://github.com/weizhi8/opencv.git
地址失效可邮件私聊:2275716724@qq.com