【OpenCV】标定后完成真实物理尺寸测量

该博客主要介绍了使用OpenCV进行相机标定的过程,包括棋盘格图案的使用、标定参数的计算等。接着,通过找到图像的边缘点,并利用估计的仿射变换将这些点映射到物理坐标系中,计算了两点间的距离。文章还展示了边缘点查找的详细步骤,包括高斯滤波、Sobel边缘检测等技术。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 导包

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
import math
import glob

2. 相机标定

pattern_rows = 10
pattern_cols = 6
pattern_size = (pattern_rows, pattern_cols)
square_size = 10  # mm
object_points = np.zeros((pattern_rows * pattern_cols, 3), np.float32)
object_points[:, :2] = np.mgrid[0:pattern_rows, 0:pattern_cols].T.reshape(-1, 2) * square_size
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001)


objpoints = []
imgpoints = []
images = glob.glob('./images/*.bmp')
for fname in images:
    gray = cv.imread(fname, cv.IMREAD_GRAYSCALE)
    height, width = gray.shape
    
    flags = cv.CALIB_CB_ADAPTIVE_THRESH + cv.CALIB_CB_FILTER_QUADS + cv.CALIB_CB_FAST_CHECK
    ret, corners = cv.findChessboardCorners(image=gray, patternSize=pattern_size, flags=flags)
    if ret == True:
        objpoints.append(object_points)
        corners = cv.cornerSubPix(gray,corners, (11,11), (-1,-1), criteria)
        imgpoints.append(corners)

ret, mtx, dist, rvecs, tvecs = cv.calibrateCamera(objpoints, imgpoints, (width, height), None, None)

3. 参考图像

img_ref = cv.imread('./images./Image_20210907144725602.bmp', cv.IMREAD_GRAYSCALE)
plt.imshow(img_ref, cmap='gray')

在这里插入图片描述

4. 计算图像与参考平面的映射关系

trans, _ = cv.estimateAffine2D(corners, object_points[:,np.newaxis,:2])

5. 边缘点查找

def FindEdgePoint(src, roi, kernel_size = 2, edge_threshold = 30.0, edge_type = 1, edge_polarity = 0):
    # ROI 长宽取整且获取矩形顶点
    new_roi = (roi[0], (math.ceil(roi[1][0]), math.ceil(roi[1][1])), roi[2])
    roi_points = cv.boxPoints(new_roi)
    
    # ROI区域图像转正
    rect_point = np.array([[0, new_roi[1][1] - 1],
                       [0, 0],
                       [new_roi[1][0] - 1, 0],
                       [new_roi[1][0] - 1, new_roi[1][1] - 1]], dtype=np.float32)
    trans_local = cv.getPerspectiveTransform(roi_points, rect_point)
    img_dst = cv.warpPerspective(src, trans_local, new_roi[1])
    
    # 垂直投影
    img_h2 = np.average(img_dst,axis=0)
    img_h = np.expand_dims(img_h2, 0)
    
    # 高斯滤波
    img_h = cv.GaussianBlur(img_h, (kernel_size * 2 + 1, 1), 0)
    
    # 索贝尔边缘提取
    img_s = cv.Sobel(src=img_h, ddepth=-1, dx=1, dy=0, ksize=1, scale = 1, delta = 0, borderType=cv.BORDER_DEFAULT)
    
    # 边缘提取
    img_s_abs = np.abs(img_s)
    indice = []
    values = []
    for index in range(img_s.shape[1]):
        if img_s_abs[0, index] > edge_threshold:
            if edge_type == 0:
                if edge_polarity == 0:
                    values.append(img_s[0, index])
                    indice.append(index)
                elif edge_polarity == 1 and img_s[0, index] > 0:
                    values.append(img_s[0, index])
                    indice.append(index)
                elif edge_polarity == 2 and img_s[0, index] < 0:
                    values.append(img_s[0, index])
                    indice.append(index)
            elif edge_type == 1:
                if edge_polarity == 0:
                    indice.append(index)
                    values.append(img_s[0, index])
                    break
                elif edge_polarity == 1 and img_s[0, index] > 0:
                    indice.append(index)
                    values.append(img_s[0, index])
                    break
                elif edge_polarity == 2 and img_s[0, index] < 0:
                    values.append(img_s[0, index])
                    indice.append(index)
                    break
            elif edge_threshold == 2:
                if edge_polarity == 0:
                    if (len(indice) == 0):
                        indice.append(index)
                        values.append(img_s[0, index])
                    else:
                        indice[0] = index
                        values[1] = img_s[0, index]
                elif edge_polarity == 1 and img_s[0, index] > 0:
                    if (len(indice) == 0):
                        indice.append(index)
                        values.append(img_s[0, index])
                    else:
                        indice[0] = index
                        values[1] = img_s[0, index]
                elif edge_polarity == 2 and img_s[0, index] < 0:
                    if (len(indice) == 0):
                        indice.append(index)
                        values.append(img_s[0, index])
                    else:
                        indice[0] = index
                        values[1] = img_s[0, index]
            else:
                if edge_polarity == 0:
                    if (len(indice) == 0):
                        indice.append(index)
                        values.append(img_s[0, index])
                    else:
                        if math.abs(values[1] < img_s_abs[0, index]):
                            indice[0] = index
                            values[1] = img_s[0, index]
                elif edge_polarity == 1 and img_s[0, index] > 0:
                    if (len(indice) == 0):
                        indice.append(index)
                        values.append(img_s[0, index])
                    else:
                        if math.abs(values[1] < img_s_abs[0, index]):
                            indice[0] = index
                            values[1] = img_s[0, index]
                elif edge_polarity == 2 and img_s[0, index] < 0:
                    if (len(indice) == 0):
                        indice.append(index)
                        values.append(img_s[0, index])
                    else:
                        if math.abs(values[1] < img_s_abs[0, index]):
                            indice[0] = index
                            values[1] = img_s[0, index]
    # 反转坐标
    half_height = new_roi[1][1] * 0.5
    edge_point_h = []
    trans_inv = np.linalg.inv(trans_local)
    color_image = cv.cvtColor(src, cv.COLOR_GRAY2BGR)
    for i in range(len(values)):
        point_h = np.array([indice[0], half_height]).reshape(1,1,2)
        edge_point = cv.transform(point_h, trans_inv)
        cv.circle(color_image, (int(edge_point[0, 0, 0]), int(edge_point[0, 0, 1])), 20, (255, 0, 0), -1)
    plt.figure(figsize=(20,8))
    plt.imshow(color_image[...,::-1])
    
    return edge_point[0, 0, 0],edge_point[0, 0, 1]
x1,y1 = FindEdgePoint(img_ref, ((789.72, 1037.57),(150, 224.288), 0))

在这里插入图片描述

x2,y2 = FindEdgePoint(img_ref, ((3325.32, 1037.57),(150, 224.288), 0))

在这里插入图片描述

6. 将点映射到物理坐标

new_x1 = trans[0, 0] * x1 + trans[0, 1] * y1 + trans[0, 2]
new_y1 = trans[1, 0] * x1 + trans[1, 1] * y1 + trans[1, 2]
new_x2 = trans[0, 0] * x2 + trans[0, 1] * y2 + trans[0, 2]
new_y2 = trans[1, 0] * x2 + trans[1, 1] * y2 + trans[1, 2]

dist = math.sqrt((new_x1 - new_x2) ** 2 + (new_y1 - new_y2) ** 2)
print(dist)

110.0605974101517

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhy29563

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值