手把手教你实现条纹结构光三维重建(1)——多频条纹生成

news2024/11/27 1:18:26

关于条纹结构光三维重建的多频相移、格雷码、格雷码+相移、互补格雷码等等编码方法,我们在大多数平台上,包括现在使用语言大模型提问,都可以搜到相关的理论,本人重点是想教会你怎么快速用代码实现。

首先说下硬件要求,条纹最终是要烧录到投影仪里,由投影仪打出来,所以需要根据投影的分辨率设计条纹。比如我接下来代码中写到的基于TI 3010 的分辨率,其为1280*720,如果是4710,则是1920*1080,如果是2010,那么就是854*480了,那当然TI还有一款.45,我们也叫做4500,其分辨率是912*1140,根据自己的投影自行设置就好了。

直接附上代码如下(已经包含大多数注释),理论上配置好opencv就可以使用:

#include <iostream>
#include <vector>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc_c.h"

#define PROJECTOR_WIDTH    1280          //这里定义的是投影仪的分辨率
#define PROJECTOR_HEIGHT   720
#define PI 3.1415926

void generate_freqs(std::vector <float> &freq_array,int length,int min_T)
{
	freq_array[4] = (double)length / min_T;     //我们需要生成五个频率,第五个频率为[投影宽度/周期]
	double x = sqrtf(sqrtf(freq_array[4]));    //第二个频率定义为第五个频率的开四次根号
	freq_array[3] = x * x * x; //第四个频率  
	freq_array[2] = x * x;     //第三个频率
	freq_array[1] = x;         //第二个频率
	freq_array[0] = 1;         //第一个频率
}

void calc_phaseVal(float D, float A, float S, float F, int lens, cv::Mat econde_data)
{
	double W = 2 * PI * F / (double)(lens);
	for (int x = 0; x < lens; x++)
	{
		econde_data.data[x] = (uchar)(D + A * cos((x)*W + S) + 0.5);
	}
}

void generate_pattern()
{
	std::vector<float> h_freq_array, v_freq_array;
	v_freq_array.resize(5);
	generate_freqs(v_freq_array, PROJECTOR_HEIGHT, 10);        //图像垂直方向——横条纹频率
	h_freq_array.resize(5);
	generate_freqs(h_freq_array, PROJECTOR_WIDTH, 10);         //图像水平方向——竖条纹频率

	cv::Mat econde_H(1, PROJECTOR_WIDTH, CV_8UC1, cv::Scalar(255));   //图像水平方向编码,生成一个行,其他行一样
	cv::Mat econde_V(PROJECTOR_HEIGHT,1, CV_8UC1, cv::Scalar(255));    //图像垂直方向编码,生成一个列,其他列一样

	int m_light = 250;        //图像亮度的最大值
	float A = (m_light) / 2;
	float D = (m_light) / 2;
	char fileNameBmp[60];
	float phase_shift[4] = { 0.0, PI / 2, PI, 3 * PI / 2 };

	for (int index = 0; index < 20; index++)   //生成竖条纹(图像水平方向)
	{
		sprintf_s(fileNameBmp, ".//pattern_H//imagecode_H%d.bmp", index + 1);
		int phase = index % 4;
		int freq = index / 4;
		calc_phaseVal(D, A, -phase_shift[phase], h_freq_array[freq],PROJECTOR_WIDTH, econde_H);
		cv::Mat econde_show(PROJECTOR_HEIGHT, PROJECTOR_WIDTH, CV_8UC1, cv::Scalar(255));
		for (int y = 1; y < PROJECTOR_HEIGHT; y++)
		{
			memcpy(&econde_show.data[y * PROJECTOR_WIDTH], econde_H.data, PROJECTOR_WIDTH * sizeof(uchar));
		}
		/*imshow("Econde", Econde_show);
		cvWaitKey(0);*/
		imwrite(fileNameBmp, econde_H);
	}

	for (int index = 0; index < 20; index++)   //生成横条纹(图像垂直方向)
	{
		sprintf_s(fileNameBmp, ".//pattern_V//imagecode_V%d.bmp", index + 1);
		int phase = index % 4;
		int freq = index / 4;
		calc_phaseVal(D, A, -phase_shift[phase], v_freq_array[freq], PROJECTOR_HEIGHT, econde_V);
		cv::Mat econde_show(PROJECTOR_HEIGHT, PROJECTOR_WIDTH, CV_8UC1, cv::Scalar(255));
		for (int y = 0; y < PROJECTOR_WIDTH; y++)
			econde_V.copyTo(econde_show.col(y));
		/*imshow("Econde", econde_show);
		cvWaitKey(0);*/
		imwrite(fileNameBmp, econde_V);
	}

	//最后生成一张白色的图,用于投影纯色光
	cv::Mat econde_white(1, PROJECTOR_WIDTH, CV_8UC1, cv::Scalar(255));
	imwrite(".//pattern_H//white.bmp",econde_white);
}

int main()
{
	generate_pattern();
	return 0;
}

这时候我们可以用imshow显示,看到不同频率不同相位的条纹图

 

对于有的人,可能刚刚接触C++,或者opencv,或者还只是用matlab,在运行代码遇到问题时,可以直接私信我。

在下一章,我将介绍怎么做单目+投影的标定,先看一个三维重建效果

也可以显示伪彩色

我们测量其平面度,某个黑白区域,其平面度为0.088mm,精度还是很不错的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1803113.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【NI国产替代】500 MSPS 采样率,14 bit 分辨率数据采集盒子

• 双高速高精度数据采集通道 • 支持内外精准触发采样模式 • 丰富的总线控制接口 • 抗干扰能力强 高速采集盒子是一款双通道&#xff0c;具有 500 MSPS 采样率&#xff0c;14 bit 分辨率的高速高精度数据采集设备&#xff0c;其模拟输入带宽为 200 MHz&#xff0c;…

【MySQL】常见可执行程序

本文使用的版本是MySQL8&#xff0c;5.7可能会有所不同。 MySQL提供了一些重要的程序用来管理和操作数据库。这里会介绍一些常用的程序及其使用。对于MySQL程序的使用&#xff0c;可以查看官方帮助手册来学习。 MySQL :: MySQL 8.0 Reference Manual :: 6 MySQL Programs 程序…

SM201,SM203主控模块备件

SM201,SM203主控模块备件。MACSV软件安装&#xff1b;二、软件组成及各部分功能&#xff1b;三、组态流程&#xff1b;四、组态详解SM201,SM203主控模块备件&#xff08;组态各部分的操作过程及基本原理&#xff09;。一、MACSV系统软件安装软件安装——计算机角色在每台计算机…

基于STM32智能小车

一、前置准备 前置知识&#xff1a;需要学习stm32&#xff0c;建议去b站看江科大的视频&#xff0c;讲的很详细&#xff0c;学完串口那一块就可以制作了&#xff0c;软件用的是Keil5&#xff0c;开发语言C语言&#xff0c;手机连接蓝牙模块软件是蓝牙调试器。 需要准备的器件…

How To: Localize Bar and Ribbon Skin Items

您可以使用Localizer对象自定义皮肤菜单&#xff0c;而不是迭代每个条形皮肤子菜单项和功能区皮肤库项容器来手动修改这些项。此方法允许您同时自定义所有现有栏子菜单和功能区库中的外观项目。 创建BarLocalizer类的派生类并重写XtraLocalizer.GetLocalizedString方法。 pub…

HTTP-web服务器

web服务器 web服务器实现了http和相关的tcp连接处理&#xff0c;负责管理web服务器提供的资源&#xff0c;以及对服务器的配置&#xff0c;控制以及拓展等方面的管理 web服务器逻辑实现了http协议&#xff0c;并负责提供web服务器的管理功能&#xff0c;web服务器逻辑和操作系…

springboot + Vue前后端项目(第十五记)

项目实战第十五记 写在前面1.后端接口实现1.1 用户表添加角色字段1.2 角色表增加唯一标识字段1.3 UserDTO1.4 UserServiceImpl1.5 MenuServiceImpl 2. 前端实现2.1 User.vue2.2 动态菜单设计2.2.1 Login.vue2.2.2 Aside.vue 2.3 动态路由设计2.3.1 菜单表新增字段page_path2.3.…

开源规则引擎LiteFlow项目应用实践

本文介绍基于开源规则引擎LiteFlow&#xff0c;如何开发规则设计器&#xff0c;在低代码平台中集成规则引擎&#xff0c;并在项目中实现应用的效果。由于低代码平台使用规则引擎实现了逻辑编排的需求&#xff0c;所以本文中的叫法为“逻辑设计”、“逻辑编排”、“逻辑流引擎”…

kafka的leader和follower

leader和follower kafka的leader和follower是相对于分区有意义的&#xff0c;不是相对于broker。 因为每个分区都有leader和follower, leader负责读写数据。 follower负责复制leader的数据保存到自己的日志数据中&#xff0c;并在leader挂掉后重新选举出leader。 kafka会再…

Javascript全解(基础篇)

语法与数据类型 语法 var\let\const var 声明一个变量&#xff0c;可选初始化一个值。 let 声明一个块作用域的局部变量&#xff0c;可选初始化一个值。 const 声明一个块作用域的只读常量。 用 var 或 let 语句声明的变量&#xff0c;如果没有赋初始值&#xff0c;则其值为 …

基于VS2022编译GDAL

下载GDAL源码&#xff1b;下载GDAL编译需要依赖的必须代码&#xff0c;proj&#xff0c;tiff&#xff0c;geotiff三个源码&#xff0c;proj需要依赖sqlite&#xff1b;使用cmake编译proj&#xff0c;tiff&#xff0c;geotiff&#xff1b;proj有版本号要求&#xff1b;使用cmake…

go语言实战--基于Vue3+gin框架的实战Cetide网项目(讲解开发过程中的各种踩坑)

最近被要求学习go语言开发&#xff0c;也就做一个项目实战巩固一下&#xff0c;也分享一下关于gin框架的实战项目 &#xff08;后续应该还是会继续学习Java&#xff0c;这一期还是做一个govue的&#xff09; 经过一段时间的开发过后&#xff0c;感觉现在的开发效率要快不少了&…

Unity2D游戏制作入门 | 12(之人物受伤和死亡的逻辑动画)

上期链接&#xff1a;Unity2D游戏制作入门 | 11(之人物属性及伤害计算)-CSDN博客 上期我们聊到了人物的自身属性和受伤时的计算&#xff0c;我们先给人物和野猪挂上属性和攻击属性的代码&#xff0c;然后通过触发器触发受伤的事件。物体&#xff08;人物也好敌人也行&#xff…

使用 Scapy 库编写 ICMP 不可达攻击脚本

一、介绍 ICMP不可达攻击是一种利用ICMP&#xff08;Internet Control Message Protocol&#xff09;不可达消息来干扰或中断目标系统的网络通信的攻击类型。通过发送伪造的ICMP不可达消息&#xff0c;攻击者可以诱使目标系统认为某些网络路径或主机不可达&#xff0c;从而导致…

vue2中如何使用函数式组件

vue2 中如何使用函数式组件 用 render 定义函数式组件如何处理 props如何在函数式组件中触发自定义事件&#xff1f;injection如何使用 computed 和 methods定义一个函数式组件的 MyButton函数式组件有何优势哪种场景适合使用函数式组件函数式组件的问题参考 函数式组件&#x…

WPS JSA 宏脚本入门和样例

1入门 WPS window版本才支持JSA宏的功能。 可以自动化的操作文档中的一些内容。 参考文档&#xff1a; WPS API 参考文档&#xff1a;https://open.wps.cn/previous/docs/client/wpsLoad 微软的Word API文档&#xff1a;Microsoft.Office.Interop.Word 命名空间 | Microsoft …

测试工具链

缺陷管理 bug管理工具 devops---项目管理--缺陷管理 bug管理地址 https://devsecops.mychery.com:8443/chery/project?filterROLE&statusACTIVE bug管理环境 采用公司的devops平台&#xff0c;对每个项目的bug进行管理。目前在使用 接口测试和服务端性能测试 工具…

基础乐理入门

基础概念 乐音&#xff1a;音高&#xff08;频率&#xff09;固定&#xff0c;振动规则的音。钢琴等乐器发出的是乐音&#xff0c;听起来悦耳、柔和。噪音&#xff1a;振动不规则&#xff0c;音高也不明显的音。风声、雨声、机器轰鸣声是噪音&#xff0c;大多数打击乐器&#…

【CS.SE】使用 docker pull confluentinc/cp-kafka 的全面指南

文章目录 1 引言2 准备工作2.1 安装 Docker2.1.1 在 Linux 上安装 Docker2.1.2 在 macOS 上安装 Docker2.1.3 在 Windows 上安装 Docker 2.2 验证 Docker 安装 3 拉取 confluentinc/cp-kafka Docker 镜像3.1 拉取镜像3.2 验证镜像 4 运行 Kafka 容器4.1 启动 ZooKeeper4.2 启动…

Nextjs学习教程

一.手动创建项目 建议看这个中文网站文档,这个里面的案例配置都是手动的,也可以往下看我这个博客一步步操作 1.在目录下执行下面命令,初始化package.json文件 npm init -y2.安装react相关包以及next包 yarn add next react react-dom // 或者 npm install --save next react…