SLMaster icon indicating copy to clipboard operation
SLMaster copied to clipboard

搭建单目逆相机结构光系统,将相机成像平面下的特征点映射至投影仪成像平面时,发生明显的偏差

Open MechineVID opened this issue 1 year ago • 15 comments

非常感谢您的博文,让我受益良多!搭建单目逆相机结构光系统,使用三频(45、39、34)四步相移获取两个方向的绝对相位值,但将相机成像平面下的特征点映射至投影仪成像平面后,在投影仪成像平面的特征点发生明显的偏差。用的投影仪是DLP3010,分辨率为1280*720。这个误差是因为解相位时(已经使用反向相位补偿)产生的吗?还是其他原因呢?相机和投影仪垂直布置。之后打算使用三角测量模型获取点云

1、在插值方面使用的是以下方法: image

2、相机拍摄到的图像如下: 4

在获取相机平面下的特征点的坐标后将特征点映射到投影仪成像平面后的图像如下: Image_DMD

通过openGL以投影仪成像平面的特征点的坐标为中心绘制的圆的图像如下: 4

MechineVID avatar Apr 23 '24 08:04 MechineVID

您的双方向线性插值看着是没问题的,原理的确如此。

您可以这样排除一下情况:

  1. 先使用相机对标定板进行成像并提取特征点,然后根据内参使用solvePnp()方法获取位姿,最后利用投影矩阵评估本次的特征点提取的RMSE误差。
  2. 评估该误差大小,误差大的话则是特征点提取精度不足导致的,小的话则是有关相位问题上导致的
  3. 在相位问题上,更有可能是因为您采用的反向相位补偿导致的,先试试不采用反向相位补偿看看效果如何

Practice3DVision avatar Apr 24 '24 03:04 Practice3DVision

根据您提供的建议,获取的数据如下: image

该图的RMSE为:0.354727;共拍摄8幅不同角度的图像,平均RMSE为: 0.305761。

这是进行反向相位补偿后的垂直与水平绝对相位图 Image_123 ImageH_123

以下是为未采用反向相位补偿的垂直与水平绝对相位图 Image_123 ImageH_123

未采用反向相位补偿后将相机平面下的特征点的坐标后将特征点映射到投影仪成像平面后的图像如下: Image_DMD

未采用反向相位补偿后通过openGL以投影仪成像平面的特征点的坐标为中心绘制的圆的图像如下: 4

可以看出采用的反向相位补偿效果更好点,那么接下来是要提高特征点提取精度吗?标定板的规格是:7*7; 半径分别为2.5、4、5.5、7;特征点的距离为20。用CAD画并转化为PDF打印的,打印出来后无论半径还是特征点的距离都有所偏差,有的比较正确,有的偏差0-0.5mm

MechineVID avatar Apr 24 '24 07:04 MechineVID

看绝对相位感觉是条纹编码或解码存在问题。

未采用反向相位补偿下也不应该出现这么多周期性相位误差的。

或许您可以把拍摄的三频外差图案上传一下,或者您用我提供的代码解相看看是否一致。

Practice3DVision avatar Apr 24 '24 08:04 Practice3DVision

条纹编码使用的是供应商提供的软件生成的条纹,界面如下: image

这是用python进行解码(未采用反向相位补偿)的代码:

import numpy as np
import cv2 as cv
import math
import os
import csv
import matplotlib.pyplot as plt
from PIL import Image, ImageDraw

# 确保输出文件夹存在,如果不存在则创建(用于保存结果图像)
folder_name = r"C:\0423\1\ru"
if not os.path.exists(folder_name):
    os.makedirs(folder_name)

# 保存DMD“角点”图像
imgDMD_path = r"C:\0423\1\ru\Image_DMD"
image_format = "bmp"   # 图像格式,可以根据需要修改



# 读取CCD图像路径
image_path = r"C:\0423\img\4.bmp"

# 获取DMD角点坐标
csv_DMD = r"C:\0423\1\ru\DMD对应的“角点”坐标_data.csv"

# 保存CCD-DMD图像
image_CCD_DMD = r"C:\0423\1\ru\Image_CCD_DMD"


csv_filename6 = r"C:\0423\1\ru\pha123_data.csv"
csv_filename7 = r"C:\0423\1\ru\phaH123_data.csv"
csv_filename8 = r"C:\0423\1\ru\插值后的绝对相位值(两个方向)_data.csv"
csv_filename9 = r"C:\0423\1\ru\DMD对应的“角点”坐标_data.csv"

class WrappedPhase():
    def __init__(self, n: int = 24):
        self.n = n

    @staticmethod
    def getImageData(m: int = 24):
        '''获取相机拍摄的n幅相移图'''
        I = []
        for i in range(m):
            # filename = ".\\70\\Image_" + str(i) + ".bmp"
            filename = r"C:\0423\1\\Image_" + str(i+1) + ".bmp"
            img_file = np.fromfile(filename, dtype=np.uint8)  # 以dtype形式读取文件
            img = cv.imdecode(img_file, -1)  # 从指定的内存缓存中读取数据,并把数据转换(解码)成图像格式;主要用于从网络传输数据中恢复出图像。
            I.append(img)

        return I

    def computeWrappedphase(self, I, width: int = 1280, hight: int = 720):
        '''计算包裹相位'''

        i = []
        for j in range(24):
            i.append(I[j].astype(np.float32))

        print('初始化垂直条纹所需的数组')
        pha1 = np.zeros((hight, width), np.float32)
        pha2 = np.zeros((hight, width), np.float32)
        pha3 = np.zeros((hight, width), np.float32)

        pha12 = np.zeros((hight, width), np.float32)
        pha23 = np.zeros((hight, width), np.float32)
        pha123 = np.zeros((hight, width), np.float32)

        results = []  # 使用列表存储每8图像得到的结果

        # 初始化水平条纹所需的数值
        print('初始化水平条纹所需的数组')
        phaH1 = np.zeros((hight, width), np.float32)
        phaH2 = np.zeros((hight, width), np.float32)
        phaH3 = np.zeros((hight, width), np.float32)

        phaH12 = np.zeros((hight, width), np.float32)
        phaH23 = np.zeros((hight, width), np.float32)
        phaH123 = np.zeros((hight, width), np.float32)

        resultsH = []  # 使用列表存储每8图像得到的结果

        print('开始计算垂直条纹的三个主值')
        idx = 0
        for a in range(hight):
            for b in range(width):
                if i[0 + idx][a, b] == i[2 + idx][a, b] and i[3 + idx][a, b] < i[1 + idx][a, b]:  # 四个特殊位置
                    pha1[a, b] = 3 * math.pi / 2
                elif i[0 + idx][a, b] == i[2 + idx][a, b] and i[3 + idx][a, b] > i[1 + idx][a, b]:  # 四个特殊位置
                    pha1[a, b] = math.pi / 2
                elif i[3 + idx][a, b] == i[1 + idx][a, b] and i[0 + idx][a, b] < i[2 + idx][a, b]:  # 四个特殊位置
                    pha1[a, b] = math.pi
                elif i[3 + idx][a, b] == i[1 + idx][a, b] and i[0 + idx][a, b] > i[2 + idx][a, b]:  # 四个特殊位置
                    pha1[a, b] = 0
                elif i[0 + idx][a, b] > i[2 + idx][a, b] and i[1 + idx][a, b] < i[3 + idx][a, b]:  # 第一象限
                    pha1[a, b] = math.atan(
                        (i[3 + idx][a, b] - i[1 + idx][a, b]) / (i[0 + idx][a, b] - i[2 + idx][a, b]))
                elif i[0 + idx][a, b] < i[2 + idx][a, b] and i[1 + idx][a, b] < i[3 + idx][a, b]:  # 第二象限
                    pha1[a, b] = math.pi - math.atan(
                        (i[3 + idx][a, b] - i[1 + idx][a, b]) / (i[2 + idx][a, b] - i[0 + idx][a, b]))
                elif i[0 + idx][a, b] < i[2 + idx][a, b] and i[1 + idx][a, b] > i[3 + idx][a, b]:  # 第三象限
                    pha1[a, b] = math.pi + math.atan(
                        (i[3 + idx][a, b] - i[1 + idx][a, b]) / (i[0 + idx][a, b] - i[2 + idx][a, b]))
                elif i[0 + idx][a, b] > i[2 + idx][a, b] and i[1 + idx][a, b] > i[3 + idx][a, b]:  # 第四象限
                    pha1[a, b] = 2 * math.pi - math.atan(
                        (i[1 + idx][a, b] - i[3 + idx][a, b]) / (i[0 + idx][a, b] - i[2 + idx][a, b]))


        # print(f'pha1_1:{pha1_1}')
        # print(f'pha2_1:{pha2_1}')
        print(f'pha1:{pha1}')

        results.append(pha1.copy())

        idx = 4
        for a in range(hight):
            for b in range(width):
                if i[0 + idx][a, b] == i[2 + idx][a, b] and i[3 + idx][a, b] < i[1 + idx][a, b]:  # 四个特殊位置
                    pha2[a, b] = 3 * math.pi / 2
                elif i[0 + idx][a, b] == i[2 + idx][a, b] and i[3 + idx][a, b] > i[1 + idx][a, b]:  # 四个特殊位置
                    pha2[a, b] = math.pi / 2
                elif i[3 + idx][a, b] == i[1 + idx][a, b] and i[0 + idx][a, b] < i[2 + idx][a, b]:  # 四个特殊位置
                    pha2[a, b] = math.pi
                elif i[3 + idx][a, b] == i[1 + idx][a, b] and i[0 + idx][a, b] > i[2 + idx][a, b]:  # 四个特殊位置
                    pha2[a, b] = 0
                elif i[0 + idx][a, b] > i[2 + idx][a, b] and i[1 + idx][a, b] < i[3 + idx][a, b]:  # 第一象限
                    pha2[a, b] = math.atan(
                        (i[3 + idx][a, b] - i[1 + idx][a, b]) / (i[0 + idx][a, b] - i[2 + idx][a, b]))
                elif i[0 + idx][a, b] < i[2 + idx][a, b] and i[1 + idx][a, b] < i[3 + idx][a, b]:  # 第二象限
                    pha2[a, b] = math.pi - math.atan(
                        (i[3 + idx][a, b] - i[1 + idx][a, b]) / (i[2 + idx][a, b] - i[0 + idx][a, b]))
                elif i[0 + idx][a, b] < i[2 + idx][a, b] and i[1 + idx][a, b] > i[3 + idx][a, b]:  # 第三象限
                    pha2[a, b] = math.pi + math.atan(
                        (i[3 + idx][a, b] - i[1 + idx][a, b]) / (i[0 + idx][a, b] - i[2 + idx][a, b]))
                elif i[0 + idx][a, b] > i[2 + idx][a, b] and i[1 + idx][a, b] > i[3 + idx][a, b]:  # 第四象限
                    pha2[a, b] = 2 * math.pi - math.atan(
                        (i[1 + idx][a, b] - i[3 + idx][a, b]) / (i[0 + idx][a, b] - i[2 + idx][a, b]))

        print(f'pha2:{pha2}')
        results.append(pha2.copy())

        idx = 8
        for a in range(hight):
            for b in range(width):
                if i[0 + idx][a, b] == i[2 + idx][a, b] and i[3 + idx][a, b] < i[1 + idx][a, b]:  # 四个特殊位置
                    pha3[a, b] = 3 * math.pi / 2
                elif i[0 + idx][a, b] == i[2 + idx][a, b] and i[3 + idx][a, b] > i[1 + idx][a, b]:  # 四个特殊位置
                    pha3[a, b] = math.pi / 2
                elif i[3 + idx][a, b] == i[1 + idx][a, b] and i[0 + idx][a, b] < i[2 + idx][a, b]:  # 四个特殊位置
                    pha3[a, b] = math.pi
                elif i[3 + idx][a, b] == i[1 + idx][a, b] and i[0 + idx][a, b] > i[2 + idx][a, b]:  # 四个特殊位置
                    pha3[a, b] = 0
                elif i[0 + idx][a, b] > i[2 + idx][a, b] and i[1 + idx][a, b] < i[3 + idx][a, b]:  # 第一象限
                    pha3[a, b] = math.atan(
                        (i[3 + idx][a, b] - i[1 + idx][a, b]) / (i[0 + idx][a, b] - i[2 + idx][a, b]))
                elif i[0 + idx][a, b] < i[2 + idx][a, b] and i[1 + idx][a, b] < i[3 + idx][a, b]:  # 第二象限
                    pha3[a, b] = math.pi - math.atan(
                        (i[3 + idx][a, b] - i[1 + idx][a, b]) / (i[2 + idx][a, b] - i[0 + idx][a, b]))
                elif i[0 + idx][a, b] < i[2 + idx][a, b] and i[1 + idx][a, b] > i[3 + idx][a, b]:  # 第三象限
                    pha3[a, b] = math.pi + math.atan(
                        (i[3 + idx][a, b] - i[1 + idx][a, b]) / (i[0 + idx][a, b] - i[2 + idx][a, b]))
                elif i[0 + idx][a, b] > i[2 + idx][a, b] and i[1 + idx][a, b] > i[3 + idx][a, b]:  # 第四象限
                    pha3[a, b] = 2 * math.pi - math.atan(
                        (i[1 + idx][a, b] - i[3 + idx][a, b]) / (i[0 + idx][a, b] - i[2 + idx][a, b]))


        print(f'pha3:{pha3}')

        results.append(pha3.copy())

        print('结束计算垂直条纹的三个主值\n')

        print('开始计算水平条纹的三个主值')
        idx = 12
        for a in range(hight):
            for b in range(width):
                if i[0 + idx][a, b] == i[2 + idx][a, b] and i[3 + idx][a, b] < i[1 + idx][a, b]:  # 四个特殊位置
                    phaH1[a, b] = 3 * math.pi / 2
                elif i[0 + idx][a, b] == i[2 + idx][a, b] and i[3 + idx][a, b] > i[1 + idx][a, b]:  # 四个特殊位置
                    phaH1[a, b] = math.pi / 2
                elif i[3 + idx][a, b] == i[1 + idx][a, b] and i[0 + idx][a, b] < i[2 + idx][a, b]:  # 四个特殊位置
                    phaH1[a, b] = math.pi
                elif i[3 + idx][a, b] == i[1 + idx][a, b] and i[0 + idx][a, b] > i[2 + idx][a, b]:  # 四个特殊位置
                    phaH1[a, b] = 0
                elif i[0 + idx][a, b] > i[2 + idx][a, b] and i[1 + idx][a, b] < i[3 + idx][a, b]:  # 第一象限
                    phaH1[a, b] = math.atan(
                        (i[3 + idx][a, b] - i[1 + idx][a, b]) / (i[0 + idx][a, b] - i[2 + idx][a, b]))
                elif i[0 + idx][a, b] < i[2 + idx][a, b] and i[1 + idx][a, b] < i[3 + idx][a, b]:  # 第二象限
                    phaH1[a, b] = math.pi - math.atan(
                        (i[3 + idx][a, b] - i[1 + idx][a, b]) / (i[2 + idx][a, b] - i[0 + idx][a, b]))
                elif i[0 + idx][a, b] < i[2 + idx][a, b] and i[1 + idx][a, b] > i[3 + idx][a, b]:  # 第三象限
                    phaH1[a, b] = math.pi + math.atan(
                        (i[3 + idx][a, b] - i[1 + idx][a, b]) / (i[0 + idx][a, b] - i[2 + idx][a, b]))
                elif i[0 + idx][a, b] > i[2 + idx][a, b] and i[1 + idx][a, b] > i[3 + idx][a, b]:  # 第四象限
                    phaH1[a, b] = 2 * math.pi - math.atan(
                        (i[1 + idx][a, b] - i[3 + idx][a, b]) / (i[0 + idx][a, b] - i[2 + idx][a, b]))


        print(f'phaH1:{phaH1}')

        resultsH.append(phaH1.copy())

        idx = 16
        for a in range(hight):
            for b in range(width):
                if i[0 + idx][a, b] == i[2 + idx][a, b] and i[3 + idx][a, b] < i[1 + idx][a, b]:  # 四个特殊位置
                    phaH2[a, b] = 3 * math.pi / 2
                elif i[0 + idx][a, b] == i[2 + idx][a, b] and i[3 + idx][a, b] > i[1 + idx][a, b]:  # 四个特殊位置
                    phaH2[a, b] = math.pi / 2
                elif i[3 + idx][a, b] == i[1 + idx][a, b] and i[0 + idx][a, b] < i[2 + idx][a, b]:  # 四个特殊位置
                    phaH2[a, b] = math.pi
                elif i[3 + idx][a, b] == i[1 + idx][a, b] and i[0 + idx][a, b] > i[2 + idx][a, b]:  # 四个特殊位置
                    phaH2[a, b] = 0
                elif i[0 + idx][a, b] > i[2 + idx][a, b] and i[1 + idx][a, b] < i[3 + idx][a, b]:  # 第一象限
                    phaH2[a, b] = math.atan(
                        (i[3 + idx][a, b] - i[1 + idx][a, b]) / (i[0 + idx][a, b] - i[2 + idx][a, b]))
                elif i[0 + idx][a, b] < i[2 + idx][a, b] and i[1 + idx][a, b] < i[3 + idx][a, b]:  # 第二象限
                    phaH2[a, b] = math.pi - math.atan(
                        (i[3 + idx][a, b] - i[1 + idx][a, b]) / (i[2 + idx][a, b] - i[0 + idx][a, b]))
                elif i[0 + idx][a, b] < i[2 + idx][a, b] and i[1 + idx][a, b] > i[3 + idx][a, b]:  # 第三象限
                    phaH2[a, b] = math.pi + math.atan(
                        (i[3 + idx][a, b] - i[1 + idx][a, b]) / (i[0 + idx][a, b] - i[2 + idx][a, b]))
                elif i[0 + idx][a, b] > i[2 + idx][a, b] and i[1 + idx][a, b] > i[3 + idx][a, b]:  # 第四象限
                    phaH2[a, b] = 2 * math.pi - math.atan(
                        (i[1 + idx][a, b] - i[3 + idx][a, b]) / (i[0 + idx][a, b] - i[2 + idx][a, b]))


        print(f'phaH2:{phaH2}')

        resultsH.append(phaH2.copy())

        idx = 20
        for a in range(hight):
            for b in range(width):
                if i[0 + idx][a, b] == i[2 + idx][a, b] and i[3 + idx][a, b] < i[1 + idx][a, b]:  # 四个特殊位置
                    phaH3[a, b] = 3 * math.pi / 2
                elif i[0 + idx][a, b] == i[2 + idx][a, b] and i[3 + idx][a, b] > i[1 + idx][a, b]:  # 四个特殊位置
                    phaH3[a, b] = math.pi / 2
                elif i[3 + idx][a, b] == i[1 + idx][a, b] and i[0 + idx][a, b] < i[2 + idx][a, b]:  # 四个特殊位置
                    phaH3[a, b] = math.pi
                elif i[3 + idx][a, b] == i[1 + idx][a, b] and i[0 + idx][a, b] > i[2 + idx][a, b]:  # 四个特殊位置
                    phaH3[a, b] = 0
                elif i[0 + idx][a, b] > i[2 + idx][a, b] and i[1 + idx][a, b] < i[3 + idx][a, b]:  # 第一象限
                    phaH3[a, b] = math.atan(
                        (i[3 + idx][a, b] - i[1 + idx][a, b]) / (i[0 + idx][a, b] - i[2 + idx][a, b]))
                elif i[0 + idx][a, b] < i[2 + idx][a, b] and i[1 + idx][a, b] < i[3 + idx][a, b]:  # 第二象限
                    phaH3[a, b] = math.pi - math.atan(
                        (i[3 + idx][a, b] - i[1 + idx][a, b]) / (i[2 + idx][a, b] - i[0 + idx][a, b]))
                elif i[0 + idx][a, b] < i[2 + idx][a, b] and i[1 + idx][a, b] > i[3 + idx][a, b]:  # 第三象限
                    phaH3[a, b] = math.pi + math.atan(
                        (i[3 + idx][a, b] - i[1 + idx][a, b]) / (i[0 + idx][a, b] - i[2 + idx][a, b]))
                elif i[0 + idx][a, b] > i[2 + idx][a, b] and i[1 + idx][a, b] > i[3 + idx][a, b]:  # 第四象限
                    phaH3[a, b] = 2 * math.pi - math.atan(
                        (i[1 + idx][a, b] - i[3 + idx][a, b]) / (i[0 + idx][a, b] - i[2 + idx][a, b]))

        print(f'phaH3:{phaH3}')

        resultsH.append(phaH3.copy())

        """
        结束计算水平条纹的三个主值
        """
        print('结束计算水平条纹的三个主值\n')

        print('显示(垂直条纹)补偿后的包裹相位图\n')
        pha_scaled1 = results[0] * 255 / (2 * math.pi)
        pha_scaled1 = pha_scaled1.astype(np.uint8)

        pha_scaled2 = results[1] * 255 / (2 * math.pi)
        pha_scaled2 = pha_scaled2.astype(np.uint8)

        pha_scaled3 = results[2] * 255 / (2 * math.pi)
        pha_scaled3 = pha_scaled3.astype(np.uint8)


        print('显示(水平条纹)补偿后的包裹相位图\n')
        pha_scaledH1 = resultsH[0] * 255 / (2 * math.pi)
        pha_scaledH1 = pha_scaledH1.astype(np.uint8)

        pha_scaledH2 = resultsH[1] * 255 / (2 * math.pi)
        pha_scaledH2 = pha_scaledH2.astype(np.uint8)

        pha_scaledH3 = resultsH[2] * 255 / (2 * math.pi)
        pha_scaledH3 = pha_scaledH3.astype(np.uint8)


        print('开始计算(垂直条纹)12与23的包裹相位')
        for a in range(hight):
            for b in range(width):
                if results[0][a, b] > results[1][a, b]:  # 四个特殊位置
                    pha12[a, b] = results[0][a, b] - results[1][a, b]
                else:  # 四个特殊位置
                    pha12[a, b] = results[0][a, b] + 2*math.pi - results[1][a, b]

                if results[1][a, b] > results[2][a, b]:  # 四个特殊位置
                    pha23[a, b] = results[1][a, b] - results[2][a, b]
                else:  # 四个特殊位置
                    pha23[a, b] = results[1][a, b] + 2 * math.pi - results[2][a, b]

        print('显示(垂直条纹)12与23的包裹相位图\n')
        pha_scaled12 = pha12 * 255 / (2 * math.pi)
        pha_scaled12 = pha_scaled12.astype(np.uint8)

        pha_scaled23 = pha23 * 255 / (2 * math.pi)
        pha_scaled23 = pha_scaled23.astype(np.uint8)

        print('开始计算(水平条纹)12与23的包裹相位')
        for a in range(hight):
            for b in range(width):
                if resultsH[0][a, b] > resultsH[1][a, b]:  # 四个特殊位置
                    phaH12[a, b] = resultsH[0][a, b] - resultsH[1][a, b]
                else:  # 四个特殊位置
                    phaH12[a, b] = resultsH[0][a, b] + 2*math.pi - resultsH[1][a, b]

                if resultsH[1][a, b] > resultsH[2][a, b]:  # 四个特殊位置
                    phaH23[a, b] = resultsH[1][a, b] - resultsH[2][a, b]
                else:  # 四个特殊位置
                    phaH23[a, b] = resultsH[1][a, b] + 2 * math.pi - resultsH[2][a, b]

        print('显示(水平条纹)12与23的包裹相位图\n')
        pha_scaledH12 = phaH12 * 255 / (2 * math.pi)
        pha_scaledH12 = pha_scaledH12.astype(np.uint8)

        pha_scaledH23 = phaH23 * 255 / (2 * math.pi)
        pha_scaledH23 = pha_scaledH23.astype(np.uint8)


        print('开始计算(垂直条纹)123的绝对相位')
        for a in range(hight):
            for b in range(width):
                if pha12[a, b] > pha23[a, b]:  # 四个特殊位置
                    pha123[a, b] = pha12[a, b] - pha23[a, b]
                else:  # 四个特殊位置
                    pha123[a, b] = pha12[a, b] + 2*math.pi - pha23[a, b]

        print('显示(垂直条纹)123的绝对相位图\n')
        pha_scaled123 = pha123 * 255 / (2 * math.pi)
        pha_scaled123 = pha_scaled123.astype(np.uint8)


        # 为计算插值(垂直条纹)做准备
        pha123 = pha123.T

        print('开始计算(水平条纹)123的绝对相位')
        for a in range(hight):
            for b in range(width):
                if phaH12[a, b] > phaH23[a, b]:  # 四个特殊位置
                    phaH123[a, b] = phaH12[a, b] - phaH23[a, b]
                else:  # 四个特殊位置
                    phaH123[a, b] = phaH12[a, b] + 2*math.pi - phaH23[a, b]

        print('显示(水平条纹)123的绝对相位图\n')
        pha_scaledH123 = phaH123 * 255 / (2 * math.pi)
        pha_scaledH123 = pha_scaledH123.astype(np.uint8)

        # 为计算插值(水平条纹)做准备
        phaH123 = phaH123.T


        # 标定后的“角点”的坐标文件
        file_path = r'C:\0423\img\center_points.csv'

        data = []
        with open(file_path, newline='') as csvfile:
            csv_reader = csv.reader(csvfile)
            for row in csv_reader:
                data.append(row)

        print('开始计算(垂直条纹)对应”角点”的绝对相位值插值后的结果')
        V = []
        for i in range(148, 197):
            col_index = 1  # x/u  列
            row_index = i  # y/v  # 行
            col_index1 = 2  # y/v

            if 0 <= row_index < len(data) and 0 <= col_index < len(data[0]):
                value_u = float(data[row_index][col_index])
                value_v = float(data[row_index][col_index1])

                frac_u, _ = np.modf(value_u)
                frac_v, _ = np.modf(value_v)

                x_1 = pha123[int(np.floor(value_u)), int(np.floor(value_v))]
                y_1 = pha123[int(np.ceil(value_u)), int(np.floor(value_v))]

                x_2 = pha123[int(np.floor(value_u)), int(np.ceil(value_v))]
                y_2 = pha123[int(np.ceil(value_u)), int(np.ceil(value_v))]

                v_1 = (y_1 - x_1) * frac_u + x_1
                v_2 = (y_2 - x_2) * frac_u + x_2

                v_3 = round(((v_2 - v_1) * frac_v + v_1), 4)
                # print(v_3)
                V.append(v_3)

            else:
                print("索引超出数组范围")

        print(len(V))
        print(V)
        print('结束计算(垂直条纹)对应”角点”的绝对相位值插值后的结果\n')


        print('开始计算(水平条纹)对应”角点”的绝对相位值插值后的结果')
        H = []
        # 显示索引为 (1, 2) 处的值
        for i in range(148, 197):
            col_index = 1  # x/u  列
            row_index = i  # y/v  行
            col_index1 = 2

            if 0 <= row_index < len(data) and 0 <= col_index < len(data[0]):
                value_u = float(data[row_index][col_index])
                value_v = float(data[row_index][col_index1])

                frac_u, _ = np.modf(value_u)
                frac_v, _ = np.modf(value_v)

                x_1 = phaH123[int(np.floor(value_u)), int(np.floor(value_v))]
                y_1 = phaH123[int(np.floor(value_u)), int(np.ceil(value_v))]

                x_2 = phaH123[int(np.ceil(value_u)), int(np.floor(value_v))]
                y_2 = phaH123[int(np.ceil(value_u)), int(np.ceil(value_v))]

                h_1 = (y_1 - x_1) * frac_v + x_1
                h_2 = (y_2 - x_2) * frac_v + x_2

                h_3 = round(((h_2 - h_1) * frac_u + h_1), 4)
                # print(h_3)
                H.append(h_3)

            else:
                print("索引超出数组范围")

        print(len(H))
        print(H)
        print('开始计算(水平条纹)对应”角点”的绝对相位值插值后的结果\n')


        print('开始计算(垂直条纹)"角点"x/u的坐标')
        u_x = []
        for j in range(len(V)):
            u = round(((V[j] * width) / (2 * math.pi)), 4)
            print(f"垂直条纹对应“角点x/u的坐标为:{u}")
            u_x.append(u)
        print(f'u_x:{u_x}')
        print('结束计算(垂直条纹)"角点"x/u的坐标\n')


        print('开始计算(水平条纹)"角点"y/v的坐标')
        v_y = []
        for j in range(len(H)):
            v = round(((H[j] * hight) / (2 * math.pi)), 4)
            print(f"水平条纹对应“角点x/u的坐标为:{v}")
            v_y.append(v)
        print(f'v_y:{v_y}')
        print('结束计算(水平条纹)"角点"y/v的坐标\n')


        print('开始生成DMD“角点”图像')
        points = [(u_x[d], v_y[d]) for d in range(len(u_x))]

        # 创建新的图像对象
        image = Image.new('RGB', (width, hight), color=(255, 255, 255))   #  (0, 0, 0)背景颜色
        draw = ImageDraw.Draw(image)

        for point in points:
            x, y = round(point[0]), round(point[1])  # 将坐标四舍五入到最接近的整数值
            draw.point((x, y), fill=(255, 255, 255))   #  (0, 0, 0)背景颜色

            for i in range(x - 15, x + 15):
                if 0 <= i < width:
                    image.putpixel((i, y), (0, 0, 0))  # 上下延伸   (255, 0, 0)十字架的颜色
            for j in range(y - 15, y + 15):
                if 0 <= j < hight:
                    image.putpixel((x, j), (0, 0, 0))  # 左右延伸   (255, 0, 0)十字架的颜色


        image.show()
        image.save(f'{imgDMD_path}.{image_format.lower()}')
        print('结束生成DMD“角点”图像')


        # 将DMD中的“角点”坐标保存到csv文件中
        header = ['x/u', 'y/v']
        with open(csv_filename9, mode='w', newline='') as file:
            writer = csv.writer(file)

            # # 写入标题行
            # writer.writerow(header)

            # 同时迭代两个列表,逐行写入数据到 CSV 文件
            for k in range(len(u_x)):
                writer.writerow([u_x[k], v_y[k]])

        print("CSV 文件写入完成:", csv_filename9)


        print('开始在CCD上绘制DMD图像的角点')
        # 定义十字架的长度
        length = 15

        # 从CSV文件中读取第二、第三列作为点的坐标,跳过标题行
        points = []
        with open(csv_DMD, 'r') as csvfile:
            csvreader = csv.reader(csvfile)
            next(csvreader)  # 跳过标题行
            for row in csvreader:
                # 仅提取第二列和第三列作为坐标
                x, y = map(float, row[0:2])
                points.append((int(x), int(y)))

        # 读取图像
        image = cv.imread(image_path)

        # 在图像上画十字架
        for point in points:
            x, y = point
            cv.line(image, (x, y - length), (x, y + length), (0, 0, 255), 1)  # 垂直线
            cv.line(image, (x - length, y), (x + length, y), (0, 0, 255), 1)  # 水平线

        # 显示结果
        cv.imshow("Cross Image", image)
        cv.waitKey(0)
        cv.destroyAllWindows()
        cv.imwrite(f'{image_CCD_DMD}.{image_format.lower()}', image)

        print('结束在CCD上绘制DMD图像的角点')

        with open(csv_filename6, mode='w', newline='') as file:
            writer = csv.writer(file)

            # 写入数据到 CSV 文件
            for row in pha123:
                writer.writerow(row)

        print("CSV 文件写入完成:", csv_filename6)

        with open(csv_filename7, mode='w', newline='') as file:
            writer = csv.writer(file)

            # 写入数据到 CSV 文件
            for row in phaH123:
                writer.writerow(row)

        print("CSV 文件写入完成:", csv_filename7)


        # 将插值后(两个方向)的绝对相位值保存到csv文件中
        header = ['x/u', 'y/v']
        with open(csv_filename8, mode='w', newline='') as file:
            writer = csv.writer(file)

            # 写入标题行
            writer.writerow(header)

            # 同时迭代两个列表,逐行写入数据到 CSV 文件
            for i in range(len(V)):
                writer.writerow([V[i], H[i]])

        print("CSV 文件写入完成:", csv_filename8)

        if __name__ == "__main__":

            images = [pha_scaled1, pha_scaled2, pha_scaled3, pha_scaled12, pha_scaled23, pha_scaled123,
                      pha_scaledH1, pha_scaledH2, pha_scaledH3, pha_scaledH12, pha_scaledH23, pha_scaledH123]
            tit = ['pha1', 'pha2', 'pha3', 'pha12', 'pha23', 'pha123',
                   'phaH1', 'phaH2', 'phaH3', 'phaH12', 'phaH23', 'phaH123']
            for i in range(len(images)):
                plt.figure(figsize=(15, 9))
                plt.imshow(images[i], cmap='gray')
                plt.title(f"{tit[i]}")
                plt.axis('off')  # 可选择关闭坐标轴
                plt.show()

            file_names = ["Image_1.bmp", "Image_2.bmp", "Image_3.bmp", "Image_12.bmp", "Image_23.bmp", "Image_123.bmp",
                          "ImageH_1.bmp", "ImageH_2.bmp", "ImageH_3.bmp", "ImageH_12.bmp", "ImageH_23.bmp",
                          "ImageH_123.bmp"]
            images = [pha_scaled1, pha_scaled2, pha_scaled3, pha_scaled12, pha_scaled23, pha_scaled123,
                      pha_scaledH1, pha_scaledH2, pha_scaledH3, pha_scaledH12, pha_scaledH23, pha_scaledH123]

            # 保存图像
            for i in range(len(images)):
                file_path = os.path.join(folder_name, file_names[i])
                plt.imsave(file_path, images[i])
                plt.imsave(file_path, images[i], cmap='gray')

            plt.close('all')

        return pha1, pha2, pha12, pha23, pha123, phaH1, phaH2, phaH12, phaH23, phaH123


if __name__ == "__main__":
    w = WrappedPhase()
    w.computeWrappedphase(w.getImageData())


以下是三频外差图案(垂直条纹,四步相移),您说的您提供的解相代码在哪呀? 1 2 3 4 5 6 7 8 9 10 11 12

MechineVID avatar Apr 24 '24 11:04 MechineVID

这是结构光投影仪的参数 image

MechineVID avatar Apr 24 '24 11:04 MechineVID

我尝试使用SLMaster进行解相,得到的绝对相位非常光滑,应该是您的解码部分代码存在问题,请自行调试解决。以下是使用SLMaster得到的绝对相位:

0

SLMaster提供三频外差解相方法,见代码code,使用示例可见google_test测试用例case

Practice3DVision avatar Apr 24 '24 12:04 Practice3DVision

好的,非常感谢!有个问题还想向您请教,麻烦可以更加具体说明我应该调用哪个函数,以至于可以直接用自己的图像进行解相(离线),而不用Qt。麻烦您了

MechineVID avatar Apr 24 '24 13:04 MechineVID

上面回答中:

SLMaster提供三频外差解相方法,见代码code,使用示例可见google_test测试用例case

点击进去,一看就明白了,google_test最后一个测试用例是实际情况的解相函数调用。

Practice3DVision avatar Apr 25 '24 00:04 Practice3DVision

好的,非常感谢!我再研究研究,对C不太熟

MechineVID avatar Apr 25 '24 01:04 MechineVID

感谢您您提供的代码,效果确实好多了,有个疑问向您请教:

params.height = 720;
params.width = 1280;
params.horizontal = false;
params.nbrOfPeriods = 45;  
params.confidenceThreshold = 40.f;

中的confidenceThreshold的值不会对特征点的绝对相位值产生影响吧?

当我用params.confidenceThreshold = 30 时绝对相位图如下: 30

当我用params.confidenceThreshold = 40 时绝对相位图如下: 40

肉眼上看这两幅图有明显的区别

MechineVID avatar Apr 26 '24 01:04 MechineVID

该值仅用于噪声点剔除,不会对绝对相位产生影响。

Practice3DVision avatar Apr 26 '24 02:04 Practice3DVision

好的,请问在使用threeFrequencyHeterodynePattern.cpp中的unwrapPhaseMap函数时,该函数输出的矩阵的值是直接映射到0-255上了吗?如果是的话,我应该怎么修改参数/代码,使其的绝对相位值映射回[0, 2pi]上呢?以便之后操作

MechineVID avatar Apr 26 '24 05:04 MechineVID

自己在获取绝对相位后归一化就可以了,参考cv::normalize()函数

Practice3DVision avatar Apr 26 '24 12:04 Practice3DVision

好的

MechineVID avatar Apr 26 '24 13:04 MechineVID

您提供的recoverDepth.hreverseCamera函数的phase具体含义是啥呀?还有就是minDepthmaxDepth是根据实际情况自己估计吗?

 * @brief 逆相机三角测量模型
 * @param phase         绝对相位
 * @param PL            左相机投影矩阵
 * @param PR            右相机投影矩阵
 * @param minDepth      最小深度
 * @param maxDepth      最大深度
 * @param pitch         节距
 * @param depth         深度图
 * @param isHonrizon    是否为水平条纹
 */
void SLMASTER_API reverseCamera(const cv::Mat &phase, const Eigen::Matrix4f &PL,
                                const Eigen::Matrix4f &PR, const float minDepth,
                                const float maxDepth, const float pitch,
                                cv::Mat &depth, const bool isHonrizon = false);

MechineVID avatar Apr 28 '24 08:04 MechineVID