Opencv 测量物体尺寸

简介:实时测量物体尺寸是使用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

以上代码实现了一个实时测量物体尺寸的系统。通过摄像头或视频文件输入,检测物体并测量其尺寸,并在画面上显示结果

以上即为全部内容!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值