CHUSEI 3D Webcam双目图像、视差图以及点云显示

环境:Ubuntu系统+opencv+pcl
需要安装uvcdynctrl,执行如下命令

sudo apt-get install uvcdynctrl

安装完成后并把uvcdynctrl命令写成shell脚本来实现四个模式的切换。
下面的脚本将会在cpp程序中调用,不需要自己手动执行。

camera.sh

uvcdynctrl -d /dev/video0 -S 6:8  '(LE)0x50ff'
uvcdynctrl -d /dev/video0 -S 6:15 '(LE)0x00f6'
uvcdynctrl -d /dev/video0 -S 6:8  '(LE)0x2500'
uvcdynctrl -d /dev/video0 -S 6:8  '(LE)0x5ffe'
uvcdynctrl -d /dev/video0 -S 6:15 '(LE)0x0003'
uvcdynctrl -d /dev/video0 -S 6:15 '(LE)0x0002'
uvcdynctrl -d /dev/video0 -S 6:15 '(LE)0x0012'
uvcdynctrl -d /dev/video0 -S 6:15 '(LE)0x0004'
uvcdynctrl -d /dev/video0 -S 6:8  '(LE)0x76c3'
uvcdynctrl -d /dev/video0 -S 6:10 '(LE)0x0400'

camera.cpp

#include <iostream>
#include <opencv2/opencv.hpp>
#include <pcl/io/io.h>  
#include <pcl/visualization/cloud_viewer.h>


int main()
{
	cv::VideoCapture Camera(0);
	if (!Camera.isOpened())
	{
		cout << "Could not open the Camera " << endl;
		return -1;
	}

	cv::Mat Frame, DoubleImage;
	Camera >> Frame;
	cv::namedWindow("DoubleImage");
	cv::namedWindow("Disparity");

	system("./camera.sh");  //脚本存放路径

	char key = 0;
	pcl::visualization::CloudViewer viewer("Cloud Viewer");

	while (key != 32)
	{
		//按ESC退出
		if (viewer.wasStopped())
		{
			cv::destroyWindow("DoubleImage");
			cv::destroyWindow("Disparity");
			break;
		}

		Camera >> Frame;
		if (Frame.empty()) break;

		resize(Frame, DoubleImage, cv::Size(640, 240), (0, 0), (0, 0), cv::INTER_AREA);
		cv::imshow("DoubleImage", DoubleImage);
		cv::Mat	LeftImage = DoubleImage(cv::Rect(0, 0, 320, 240));
		cv::Mat RightImage = DoubleImage(cv::Rect(320, 0, 320, 240));

		cv::Mat intrMatFirst= (cv::Mat_<double>(3, 3) << 2.7647846653266811e+02, 0., 1.3658322295813980e+02, 0.,
			2.7681170126978412e+02, 1.3919490598437602e+02, 0., 0., 1.);
		cv::Mat intrMatSec = (cv::Mat_<double>(3, 3) << 3.2557485062902185e+02, 0., 1.3714262678280906e+02, 0.,
			3.2504070414475200e+02, 1.1438651517732795e+02, 0., 0., 1.);
		cv::Mat distCoeffsFirst = (cv::Mat_<double>(5, 1) << 4.7359935063009624e-02, -2.5971469469815223e-01,
			2.7463835292016435e-04, 2.4313004134302986e-03, 3.4473649080807156e-01);
		cv::Mat distCoffesSec = (cv::Mat_<double>(5, 1) << 1.0651786710439973e-01, -1.9203536317765910e+00,
			-3.3360259626232986e-03, 2.9862284984416717e-04, 8.5437903440274656e+00);
		cv::Mat R = (cv::Mat_<double>(3, 3) << 9.9995813490498642e-01, 1.0678546960460038e-03, 9.0878008169866884e-03,
			-1.1670590644186746e-03, 9.9993971667992876e-01, 1.0917920095149152e-02,
			-9.0755942219366333e-03, -1.0928069015706110e-02, 9.9989910035818452e-01);
		cv::Mat T = (cv::Mat_<double>(3, 1) << -3.9375682530226491e+01, -2.0271483032372781e-02, 4.1437635734962114e-01);
		cv::Mat Q = (cv::Mat_<double>(4, 4) << 1., 0., 0., -1.5396846389770508e+02, 0., 1., 0.,
			-1.2518226909637451e+02, 0., 0., 0., 3.0515958394504935e+02, 0.,
			0., 2.5394975632634070e-02, 0.);
		cv::Mat RFirst = (cv::Mat_<double>(3, 3) << 9.9999753798854729e-01, 1.6975551296879428e-03, -1.4290988158594921e-03,
			-1.6897306595994685e-03, 9.9998367397319954e-01, 5.4586259589697950e-03,
			1.4383418028516221e-03, -5.4561977276854157e-03, 9.9998408041289077e-01);
		cv::Mat RSec = (cv::Mat_<double>(3, 3) << 9.9994449837343669e-01, 5.1479381764392407e-04, -1.0523077497630422e-02,
			-5.7221575119432186e-04, 9.9998496049484742e-01, -5.4544801083754356e-03,
			1.0520111303113922e-02, 5.4601988465525463e-03, 9.9992975427613229e-01);
		cv::Mat PFirst = (cv::Mat_<double>(3, 4) << 3.0515958394504935e+02, 0., 1.5396846389770508e+02, 0., 0.,
			3.0515958394504935e+02, 1.2518226909637451e+02, 0., 0., 0., 1., 0.);
		cv::Mat PSec = (cv::Mat_<double>(3, 4) << 3.0515958394504935e+02, 0., 1.5396846389770508e+02,
			-1.2016533835649794e+04, 0., 3.0515958394504935e+02,
			1.2518226909637451e+02, 0., 0., 0., 1., 0.);

		stereoRectify(intrMatFirst, distCoeffsFirst, intrMatSec, distCoffesSec, cv::Size(320, 240), R, T, RFirst,
			RSec, PFirst, PSec, Q, cv::CALIB_ZERO_DISPARITY, -1, cv::Size(320, 240));

		//stereoRectify
		cv::Mat rmapFirst[2], rmapSec[2], rviewFirst, rviewSec;
		initUndistortRectifyMap(intrMatFirst, distCoeffsFirst, RFirst, PFirst,
			cv::Size(320, 240), CV_16SC2, rmapFirst[0], rmapFirst[1]);		initUndistortRectifyMap(intrMatSec, distCoffesSec, RSec, PSec,
			cv::Size(320, 240), CV_16SC2, rmapSec[0], rmapSec[1]);

		cv::Mat rectifyImageL, rectifyImageR;
		remap(LeftImage, rectifyImageL, rmapFirst[0], rmapFirst[1], cv::INTER_LINEAR);
		remap(RightImage, rectifyImageR, rmapSec[0], rmapSec[1], cv::INTER_LINEAR);

		cv::cvtColor(rectifyImageL, rectifyImageL, cv::COLOR_BGR2GRAY);
		cv::cvtColor(rectifyImageR, rectifyImageR, cv::COLOR_BGR2GRAY);

		cv::Ptr<cv::StereoBM> bm = cv::StereoBM::create(16, 9);
		int blockSize = 1, uniquenessRatio = 0, numDisparities = 5;

		bm->setBlockSize(2 * blockSize + 5);     //SAD窗口大小,5~21之间为宜
		bm->setPreFilterCap(31);
		bm->setMinDisparity(0);  //最小视差,默认值为0, 可以是负值,int型
		bm->setNumDisparities(numDisparities * 16 + 16);//视差窗口,即最大视差值与最小视差值之差,窗口大小必须是16的整数倍,int型
		bm->setTextureThreshold(10);
		bm->setUniquenessRatio(uniquenessRatio);//uniquenessRatio主要可以防止误匹配
		bm->setSpeckleWindowSize(100);
		bm->setSpeckleRange(32);
		bm->setDisp12MaxDiff(-1);
		cv::Mat disp, disp8, xyz;
		bm->compute(rectifyImageL, rectifyImageR, disp);//输入图像必须为灰度图
		disp.convertTo(disp8, CV_8U, 255 / ((numDisparities * 16 + 16)*16.));//计算出的视差是CV_16S格式
		reprojectImageTo3D(disp, xyz, Q, true); //在实际求距离时,ReprojectTo3D出来的X / W, Y / W, Z / W都要乘以16(也就是W除以16),才能得到正确的三维坐标信息。
		xyz *= 16;
		cv::imshow("Disparity", disp8);

		pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);

		int rowNumber = LeftImage.rows;
		int colNumber = LeftImage.cols;

		cloud->height = rowNumber;
		cloud->width = colNumber;
		cloud->points.resize(cloud->width * cloud->height);

		for (unsigned int u = 0; u < rowNumber; ++u)
		{
			for (unsigned int v = 0; v < colNumber; ++v)
			{
				unsigned int num = u * colNumber + v;

				cloud->points[num].b = LeftImage.at<cv::Vec3b>(u, v)[0];
				cloud->points[num].g = LeftImage.at<cv::Vec3b>(u, v)[1];
				cloud->points[num].r = LeftImage.at<cv::Vec3b>(u, v)[2];
				cloud->points[num].x = u; //xyz.at<Vec3f>(u, v)[0];
				cloud->points[num].y = v;//xyz.at<Vec3f>(u, v)[1];
				cloud->points[num].z = xyz.at<cv::Vec3f>(u, v)[2];
			}
		}
		viewer.showCloud(cloud);

		char key = cv::waitKey(100);
	}
	return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(camera)

# 添加opencv库
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS} ${OpenCV2_INCLUDE_DIRS})
link_directories(${OpenCV_LIBRARY_DIRS})

# 添加pcl库
find_package(PCL REQUIRED)
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})

add_executable(camera  camera.cpp)
target_link_libraries(camera  ${OpenCV_LIBRARIES} ${PCL_LIBRARIES})

最后效果图很一般,应该是这个摄像头质量太差了。
在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

给算法爸爸上香

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

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

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

打赏作者

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

抵扣说明:

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

余额充值