赞
踩
简介:实时测量物体尺寸是使用OpenCV进行计算机视觉应用的一个常见案例。下面我来简单实现一下如何在以一张A4纸为背景的前提下进行物体测量。主要功能是从视频或图像中识别出特定的对象(如A4纸),并进行固定的流程:边缘检测、轮廓提取、透视变换和物体尺寸测量。
一、新建My_utils.py文件,编写以下功能:图像预处理、查找A4纸轮廓、进而查找A4纸里的物体轮廓、透视变换、填充、测量物体边长:
- import cv2 as cv
- import numpy as np
-
- def getContours(img,thur = [100,100],showCanny = False,minArea = 1000,filter =0,draw=False): #图像预处理,模糊、边缘检测、腐蚀膨胀等
- img_gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
- img_blur = cv.GaussianBlur(img_gray,(5,5),1)
- img_Canny = cv.Canny(img_blur,thur[0],thur[1])
- kernel = np.ones((5,5))
- img_dail = cv.dilate(img_Canny,kernel,iterations=3)
- img_erode = cv.erode(img_dail,kernel,iterations=2)
- if showCanny:cv.imshow('ShowCanny',img_erode)
-
- contours, hiearchy = cv.findContours(img_erode,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE) #查找轮廓
- finalContors = []
- for i in contours:
- area = cv.contourArea(i) # 计算轮廓面积
- if area > minArea:
- peri = cv.arcLength(i,True)
- approx = cv.approxPolyDP(i,0.02*peri,True)
- bbox = cv.boundingRect(approx) # 获取轮廓的边界框
- if filter>0:
- if len(approx) == filter: # 根据点数过滤轮廓 ,这里我规定查找四边形的物体,可以修改filter满足需求
- finalContors.append((len(approx), area, approx, bbox, i))
- else:
- finalContors.append((len(approx), area, approx, bbox, i))
- # 根据面积大小降序排序轮廓
- finalContors = sorted(finalContors,key=lambda x:x[1],reverse=True)
- # 如果设置绘制,则在图像上绘制轮廓
- if draw:
- for con in finalContors:
- cv.drawContours(img,con[4],-1,(0,0,255),3)
- return img,finalContors
-
- def reorder(myPoints):
- print(myPoints.shape)
- 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
-
- def wrapImg(img,points,w,h,pad=20):
- #透视变换
- # print(points)
- # print(reorder(points))
- points = reorder(points)
- pst1 = np.float32(points)
- pst2 = np.float32([[0,0],[w,0],[0,h],[w,h]])
- # 获取透视变换矩阵
- martrix = cv.getPerspectiveTransform(pst1,pst2)
- imgWrap = cv.warpPerspective(img,martrix,(w,h))
- imgWrap = imgWrap[pad:imgWrap.shape[0]-pad,pad:imgWrap.shape[1]-pad]
-
- return imgWrap
-
- def findDis(pts1,pts2):
- # 计算两点之间的欧氏距离,用于测量边长
- return ((pts2[0]-pts1[0])**2 + (pts2[1]-pts1[1])**2)**0.5

主函数:
- import cv2 as cv
- import my_utils
- # 视频设置
- # 使用mp4v编解码器
- fourcc = cv.VideoWriter_fourcc(*'mp4v')
-
- # 创建VideoWriter对象,保存为.mp4格式
- out = cv.VideoWriter('output.mp4', fourcc, 20.0, (int(380), int(554))) #这里是视频尺寸,要和imgContours2.shape一样
-
- wibcam = True
- img_path = 'test.jpg'
- camera = cv.VideoCapture('test1.mp4')
-
- camera.set(10, 160)
- camera.set(3, 1920)
- camera.set(4, 1080)
- scale = 2
- wP = 210 * scale
- hP = 297 * scale
-
- while True:
- if wibcam:
- success, img = camera.read()
- else:
- img = cv.imread(img_path)
-
- imgContours, conts = my_utils.getContours(img, minArea=50000, filter=4, draw=True)
- if len(conts) != 0:
- biggest = conts[0][2]
- imgWarp = my_utils.wrapImg(img, biggest, wP, hP)
- imgContours2, conts2 = my_utils.getContours(imgWarp, minArea=50, filter=4, thur=[50, 50], draw=False)
-
- if len(conts2) != 0:
- for obj in conts2:
- cv.polylines(imgContours2, [obj[2]], True, (0, 255, 0), 2)
- nPoints = my_utils.reorder(obj[2])
- nW = round((my_utils.findDis(nPoints[0][0]//scale, nPoints[1][0]//scale)/10), 1)
- nH = round((my_utils.findDis(nPoints[0][0]//scale, nPoints[2][0]//scale)/10), 1)
- cv.arrowedLine(imgContours2, (nPoints[0][0][0], nPoints[0][0][1]), (nPoints[1][0][0], nPoints[1][0][1]), (255, 0, 255), 3, 8, 0, 0.05)
- cv.arrowedLine(imgContours2, (nPoints[0][0][0], nPoints[0][0][1]), (nPoints[2][0][0], nPoints[2][0][1]), (255, 0, 255), 3, 8, 0, 0.05)
- x, y, w, h = obj[3]
- cv.putText(imgContours2, '{}cm'.format(nW), (x + 30, y - 10), cv.FONT_HERSHEY_COMPLEX_SMALL, 0.5, (255, 0, 255), 2)
- cv.putText(imgContours2, '{}cm'.format(nH), (x - 70, y + h // 2), cv.FONT_HERSHEY_COMPLEX_SMALL, 0.5, (255, 0, 255), 2)
-
- cv.imshow('A4', imgContours2)
- out.write(imgContours2) # 将图像写入视频文件
- print(imgContours2.shape) #写入尺寸要和这里一样
- img = cv.resize(img, (0, 0), None, 0.3, 0.3)
- cv.imshow('Original', img)
- if cv.waitKey(1) & 0xFF == ord('q'): # 按'q'退出循环
- break
-
- # 释放资源
- camera.release()
- out.release() # 关闭视频文件
- cv.destroyAllWindows()

来看看效果:
output
以上代码实现了一个实时测量物体尺寸的系统。通过摄像头或视频文件输入,检测物体并测量其尺寸,并在画面上显示结果
以上即为全部内容!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。