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

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

  • 2
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
### 回答1: OpenCV是一种开源的计算机视觉库,通过使用OpenCV库可以实现图像处理、目标检测和跟踪等功能。张正是一种摄像机标定技术,它是通过对摄像机进行标定,获取摄像机的内参和外参参数,从而实现对摄像机成像的准确控制和测量。 张正的标定流程主要包括以下几个步骤: 1. 准备标定板:标定板是一张已知尺寸和布局的特殊图片,一般使用棋盘格作为标定板。 2. 采集标定图像:需要将标定板放置在不同的位置和角度,并通过摄像机进行拍摄。 3. 提取角点:通过对标定图像进行处理,提取出标定板上的角点坐标OpenCV提供了一些函数来实现角点的自动提取。 4. 标定参数计算:通过已知的标定尺寸和角点坐标,结合摄像机内外参的数学模型,计算出摄像机的内参和外参参数。 5. 重投影误差评估:将标定参数应用到标定图像上,生成从摄像机成像平面到标定板上对应点的映射关系。通过计算映射点与实际角点的误差,评估标定的准确性。 重投影误差是衡量张正标定结果的一种指标,它表示通过标定参数计算得到的映射点与实际角点之间的差异。通常使用平均重投影误差来评估标定的准确性,即计算所有标定图像上映射点与实际角点之间的欧氏距离平均值。 综上所述,OpenCV中的张正标定流程主要包括准备标定板、采集标定图像、提取角点、标定参数计算和重投影误差评估等步骤,通过这一过程可以获取到摄像机的准确内参和外参参数,从而实现精确的图像测量和相机控制。 ### 回答2: OpenCV中的相机标定,可以通过对相机内外参数进行估计和校准来提高图像处理和计算机视觉算法的准确性。下面我将回答您关于opencv张正有标定流程、误差和重投影的问题。 1. 张正有标定流程:张正有标定是一个基于多个摄像机位置观察到的特定物体上特征点的方法,实现相机的准确定位和定向。标定流程包括以下步骤: - 确定特征点:选择物体上的特征点,并在每个特征点中标记一致的坐标。 - 拍摄多张图片:将摄像机从不同的位置拍摄多张图片,确保特征点能够在每个图像中被观察到。 - 检测特征点:使用特征检测算法,如SIFT或SURF,检测每张图片中的特征点。 - 匹配特征点:对于每个特征点,在所有图像中找到其对应的匹配点。 - 估计相机参数:通过解算几何约束和最小二乘法,估计相机的内外参数,例如相机的焦距、畸变系数和坐标系变换。 - 评估标定结果:通过计算重投影误差和观测点与估计平面之间的距离来评估标定的准确性。 2. 误差:在相机标定中,误差通常分为重投影误差和观测误差。 - 重投影误差:是指通过将标定得到的内外参数应用于标定图像中的特征点,并计算它们在图像平面上的投影点与实际观测到的特征点之间的距离。 - 观测误差:是指标定图像中特征点的观测坐标与其在物体上标记的真实坐标之间的差异。 3. 重投影:重投影是指根据标定的相机内外参数,将物体上的三维坐标投影到图像平面上的过程。通过比较重投影点与实际观测到的特征点之间的距离,可以评估相机标定的准确性。如果重投影误差较小,则表示相机标定较为准确。 总结:在OpenCV中,张正有标定是一个常用的相机校准方法,可以通过检测特征点、拍摄多张图像、估计相机参数来提高图像处理和计算机视觉算法的准确性。标定误差评估和重投影过程可以帮助我们评估标定的准确性,并进一步优化相机的使用效果。 ### 回答3: OpenCV张正有标定流程是用于相机校准的方法,目的是确定相机的内外参数,以消除图像中的畸变。其中,内参数包括焦距、主点坐标等,外参数包括相机的位姿和旋转矩阵。 张正有标定流程包括以下几个步骤: 1. 准备:采集一组已知位置的标定板图像。标定板是一个包含已知物理尺寸的棋盘格,其角点应当在图像中明确可见。 2. 检测角点:使用OpenCV函数在标定板图像中检测棋盘格的角点,即通过像素坐标来定位棋盘格角点的位置。 3. 生成三维-二维对应点集:将已知的物理世界点和相应的图像点建立对应关系。这样的对应关系用于后续的标定计算。 4. 计算相机矩阵:使用已知的标定板图像和对应点集,通过最小二乘法计算相机矩阵。相机矩阵包括内参数和外参数。 5. 评估标定结果:通过重投影误差来评估标定的准确性。重投影误差是指将计算得到的相机矩阵应用到标定板图像上,得到的重投影点与真实图像点之间的距离。越小的重投影误差表示标定结果越准确。 6. 畸变校正:使用计算得到的相机矩阵对图像进行畸变校正,以去除图像中的畸变。 注:重投影是指将物体在三维空间中的坐标投影到二维图像上,再通过逆变换将二维图像坐标映射回三维空间中,与其原始三维坐标对比,产生重投影误差。重投影误差表示了相机矩阵的准确性。通过最小化重投影误差来优化相机矩阵的计算结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

zhy29563

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

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

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

打赏作者

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

抵扣说明:

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

余额充值