OpenCV3.4.13+OpenCV_contrib 双摄像头实时拼接 环境配置

2023-11-14

如题,基于OpenCV3.4.13+VS2015做了个双摄像头实时拼接的代码,是一个大项目的一个baseline的一部分。下面先说配环境再给代码。
在这里插入图片描述

环境配置

关于OpenCV+VS的环境配置网上已经有很多了,因为这份代码用到了OpenCV_Contrib里面的一些东西,所以这里赘述一下,更详细的过程可以参考这篇博客
使用OpenCV_Contrib就得编译,编译就很麻烦,比配置还麻烦,因此我做了个资源集合,有需要的兄弟可以自取。

链接(2020.12.15更新):https://pan.baidu.com/s/14_EKEYvEQVmS5Bls8lcnxw
提取码:bj29

假设你把我这个名为opencv的资源集合放在了$dir$下,$dir$的具体位置根据你的选择而定。则配置过程为:

1. 系统环境变量

此电脑->右键属性->高级系统设置->环境变量->系统变量->Path->新建,写入:

$dir$\opencv\build\x64\vc14\bin

然后一路确定。

2. VS配置

VS2015,菜单栏->视图->其他窗口->属性管理器,对Debug|X64进行配置,右键Microsoft.Cpp.x64.user,点击属性,然后

VC++->包含目录,加入:

$dir$\opencv\build\include
$dir$\opencv\build\include\opencv
$dir$\opencv\build\include\opencv2

VC++->库目录,加入:

$dir$\opencv\build\x64\vc14\lib

注意这里的vc14是跟我的vs2015对应的,如果你不是vs2015就别选vc14目录,找你的vs对应的vc目录。

连接器->输入->附加依赖项,加入:

opencv_aruco341d.lib
opencv_bgsegm341d.lib
opencv_bioinspired341d.lib
opencv_calib3d341d.lib
opencv_ccalib341d.lib
opencv_core341d.lib
opencv_datasets341d.lib
opencv_dnn341d.lib
opencv_dnn_objdetect341d.lib
opencv_dpm341d.lib
opencv_face341d.lib
opencv_features2d341d.lib
opencv_flann341d.lib
opencv_fuzzy341d.lib
opencv_hdf341d.lib
opencv_hfs341d.lib
opencv_highgui341d.lib
opencv_imgcodecs341d.lib
opencv_imgproc341d.lib
opencv_img_hash341d.lib
opencv_line_descriptor341d.lib
opencv_ml341d.lib
opencv_objdetect341d.lib
opencv_optflow341d.lib
opencv_phase_unwrapping341d.lib
opencv_photo341d.lib
opencv_plot341d.lib
opencv_reg341d.lib
opencv_rgbd341d.lib
opencv_saliency341d.lib
opencv_shape341d.lib
opencv_stereo341d.lib
opencv_stitching341d.lib
opencv_structured_light341d.lib
opencv_superres341d.lib
opencv_surface_matching341d.lib
opencv_text341d.lib
opencv_tracking341d.lib
opencv_video341d.lib
opencv_videoio341d.lib
opencv_videostab341d.lib
opencv_viz341d.lib
opencv_xfeatures2d341d.lib
opencv_ximgproc341d.lib
opencv_xobjdetect341d.lib
opencv_xphoto341d.lib

这里一共有46个.lib文件,有的是OpenCV3.4.13带的,有的是我用cmake和opencv_contrib编译出来的,而且都是对应于3.4.13版本的,如果你不是3.4.13版本你就写你对应的版本和.lib名称。而且我当时没有编译world集合lib,所以这里有46个。

调试->选项->常规 勾选启动源服务器支持。

注意你调试的时候也要选Debug,x64.

3. 库文件添加到系统目录下

将上述46个名称对应的 .dll 文件全都放到C:\Windows\System32下。注意是.dll文件,位置在:

$dir$\opencv\build\x64\vc14\bin

同样的,vc14是对应我的vs2015的,如果你不是vs2015就别选这个目录。

4. 简单的测试一下环境

这里给出一个简单用Stitcher类做拼接的代码测试一下opencv+contrib的环境:

#include <stdio.h>  
#include "myhead.h"
#include <opencv2\opencv.hpp>  
#include <opencv2\stitching.hpp> 

using namespace std;
using namespace cv;

int main()
{
	vector< Mat > vImg;
	Mat rImg;

	vImg.push_back(imread("10.jpg"));
	vImg.push_back(imread("11.jpg"));

	Stitcher stitcher = Stitcher::createDefault();

	unsigned long AAtime = 0, BBtime = 0; //check processing time
	AAtime = getTickCount(); //check processing time

	Stitcher::Status status = stitcher.stitch(vImg, rImg);

	BBtime = getTickCount(); //check processing time 
	printf("Time consuming: %.2lf sec \n", (BBtime - AAtime) / getTickFrequency()); //check processing time

	if (Stitcher::OK == status)
		imshow("Stitching Result", rImg);
	else
		printf("Stitching fail.");
	imwrite("test.jpg", rImg);

	waitKey(0);
}

10.jpg和11.jpg分别如下
10.jpg
11.jpg
如果得到以下显示,那么恭喜你,环境配好了。
test.jpg

双摄像头实时拼接

直接上代码。

#include <iostream>
#include <fstream>
#include <string>
#include <time.h>
#include "opencv2/opencv_modules.hpp"
#include <opencv2/core/utility.hpp>
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/stitching/detail/autocalib.hpp"
#include "opencv2/stitching/detail/blenders.hpp"
#include "opencv2/stitching/detail/timelapsers.hpp"
#include "opencv2/stitching/detail/camera.hpp"
#include "opencv2/stitching/detail/exposure_compensate.hpp"
#include "opencv2/stitching/detail/matchers.hpp"
#include "opencv2/stitching/detail/motion_estimators.hpp"
#include "opencv2/stitching/detail/seam_finders.hpp"
#include "opencv2/stitching/detail/warpers.hpp"
#include "opencv2/stitching/warpers.hpp"

#define ENABLE_LOG 1
#define LOG(msg) std::cout << msg
#define LOGLN(msg) std::cout << msg << std::endl

using namespace std;
using namespace cv;
using namespace cv::detail;

// Default command line args
vector<int> img_names;
bool preview = false;
bool try_cuda = false;
double work_megapix = 0.6;
double seam_megapix = 0.1;
double compose_megapix = -1;
float conf_thresh = 1.f;
string features_type = "surf";
string matcher_type = "homography";
string estimator_type = "homography";
string ba_cost_func = "ray";
string ba_refine_mask = "xxxxx";
bool do_wave_correct = true;
WaveCorrectKind wave_correct = detail::WAVE_CORRECT_HORIZ;
bool save_graph = false;
std::string save_graph_to;

string warp_type = "spherical"; //plane spherical
int expos_comp_type = ExposureCompensator::GAIN_BLOCKS;
float match_conf = 0.3f;
string seam_find_type = "gc_color";
int blend_type = Blender::MULTI_BAND;
int timelapse_type = Timelapser::AS_IS;
float blend_strength = 5;
string result_name = "result.jpg";
bool timelapse = false;
int range_width = -1;

int main(int argc, char* argv[])
{
#if ENABLE_LOG
	int64 app_start_time = getTickCount();
#endif

#if 0
	cv::setBreakOnError(true);
#endif
	VideoCapture cap0(0), cap1(1);
	Mat framecap[10];
	if (cap0.isOpened() && cap1.isOpened())
	{
		cout << "*** ***" << endl;
		cout << "摄像头已启动!" << endl;
	}
	cap0.set(CV_CAP_PROP_FOCUS, 0);
	cap1.set(CV_CAP_PROP_FOCUS, 0);

	int k = 50;
	while (k--)
	{
		if (cap0.read(framecap[0]) && cap1.read(framecap[1]))
		{
			imwrite("frame0.bmp", framecap[0]);
			imwrite("frame1.bmp", framecap[1]);
		}
	}
	img_names.push_back(0);
	img_names.push_back(1);

	// Check if have enough images
	int num_images = static_cast<int>(img_names.size());
	if (num_images < 2)
	{
		LOGLN("Need more images 1");
		getchar();
		return -1;
	}

	double work_scale = 1, seam_scale = 1, compose_scale = 1;
	bool is_work_scale_set = false, is_seam_scale_set = false, is_compose_scale_set = false;

	LOGLN("Finding features...");
#if ENABLE_LOG
	int64 t = getTickCount();
#endif

	Ptr<FeaturesFinder> finder;
	if (features_type == "surf")
	{
#ifdef HAVE_OPENCV_XFEATURES2D
		if (try_cuda && cuda::getCudaEnabledDeviceCount() > 0)
			finder = makePtr<SurfFeaturesFinderGpu>();
		else
#endif
			finder = makePtr<SurfFeaturesFinder>();
	}
	else
	{
		cout << "Unknown 2D features type: '" << features_type << "'.\n";
		getchar();
		return -1;
	}

	Mat full_img, img;
	vector<ImageFeatures> features(num_images);
	vector<Mat> images(num_images);
	vector<Size> full_img_sizes(num_images);
	double seam_work_aspect = 1;

	for (int i = 0; i < num_images; ++i)
	{
		full_img = framecap[i];
		full_img_sizes[i] = full_img.size();

		if (full_img.empty())
		{
			LOGLN("Can't open image " << img_names[i]);
			getchar();
			return -1;
		}
		if (work_megapix < 0)
		{
			img = full_img;
			work_scale = 1;
			is_work_scale_set = true;
		}
		else
		{
			if (!is_work_scale_set)
			{
				work_scale = min(1.0, sqrt(work_megapix * 1e6 / full_img.size().area()));
				is_work_scale_set = true;
			}
			resize(full_img, img, Size(), work_scale, work_scale, INTER_LINEAR_EXACT);
		}
		if (!is_seam_scale_set)
		{
			seam_scale = min(1.0, sqrt(seam_megapix * 1e6 / full_img.size().area()));
			seam_work_aspect = seam_scale / work_scale;
			is_seam_scale_set = true;
		}

		(*finder)(img, features[i]);
		features[i].img_idx = i;
		LOGLN("Features in image #" << i + 1 << ": " << features[i].keypoints.size());

		resize(full_img, img, Size(), seam_scale, seam_scale, INTER_LINEAR_EXACT);
		images[i] = img.clone();
	}

	finder->collectGarbage();
	full_img.release();
	img.release();

	LOGLN("Finding features, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");

	LOG("Pairwise matching");
#if ENABLE_LOG
	t = getTickCount();
#endif
	vector<MatchesInfo> pairwise_matches;
	Ptr<FeaturesMatcher> matcher;
	if (matcher_type == "affine")
		matcher = makePtr<AffineBestOf2NearestMatcher>(false, try_cuda, match_conf);
	else if (range_width == -1)
		matcher = makePtr<BestOf2NearestMatcher>(try_cuda, match_conf);
	else
		matcher = makePtr<BestOf2NearestRangeMatcher>(range_width, try_cuda, match_conf);

	(*matcher)(features, pairwise_matches);
	matcher->collectGarbage();

	LOGLN("Pairwise matching, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");

	// Leave only images we are sure are from the same panorama
	vector<int> indices = leaveBiggestComponent(features, pairwise_matches, conf_thresh);
	vector<Mat> img_subset;
	vector<int> img_names_subset;
	vector<Size> full_img_sizes_subset;
	for (size_t i = 0; i < indices.size(); ++i)
	{
		img_names_subset.push_back(img_names[indices[i]]);
		img_subset.push_back(images[indices[i]]);
		full_img_sizes_subset.push_back(full_img_sizes[indices[i]]);
	}

	images = img_subset;
	img_names = img_names_subset;
	full_img_sizes = full_img_sizes_subset;

	// Check if we still have enough images
	num_images = static_cast<int>(img_names.size());
	if (num_images < 2)
	{
		LOGLN("Need more images 2");
		getchar();
		return -1;
	}

	Ptr<Estimator> estimator = makePtr<HomographyBasedEstimator>();
	vector<CameraParams> cameras;
	if (!(*estimator)(features, pairwise_matches, cameras))
	{
		cout << "Homography estimation failed.\n";
		getchar();
		return -1;
	}

	for (size_t i = 0; i < cameras.size(); ++i)
	{
		Mat R;
		cameras[i].R.convertTo(R, CV_32F);
		cameras[i].R = R;
		LOGLN("Initial camera intrinsics #" << indices[i] + 1 << ":\nK:\n" << cameras[i].K() << "\nR:\n" << cameras[i].R);
	}

	Ptr<detail::BundleAdjusterBase> adjuster = makePtr<detail::BundleAdjusterRay>();
	adjuster->setConfThresh(conf_thresh);
	Mat_<uchar> refine_mask = Mat::zeros(3, 3, CV_8U);
	if (ba_refine_mask[0] == 'x') refine_mask(0, 0) = 1;
	if (ba_refine_mask[1] == 'x') refine_mask(0, 1) = 1;
	if (ba_refine_mask[2] == 'x') refine_mask(0, 2) = 1;
	if (ba_refine_mask[3] == 'x') refine_mask(1, 1) = 1;
	if (ba_refine_mask[4] == 'x') refine_mask(1, 2) = 1;
	adjuster->setRefinementMask(refine_mask);
	if (!(*adjuster)(features, pairwise_matches, cameras))
	{
		cout << "Camera parameters adjusting failed.\n";
		getchar();
		return -1;
	}

	// Find median focal length

	vector<double> focals;
	for (size_t i = 0; i < cameras.size(); ++i)
	{
		LOGLN("Camera #" << indices[i] + 1 << ":\nK:\n" << cameras[i].K() << "\nR:\n" << cameras[i].R);
		focals.push_back(cameras[i].focal);
	}

	sort(focals.begin(), focals.end());
	float warped_image_scale;
	if (focals.size() % 2 == 1)
		warped_image_scale = static_cast<float>(focals[focals.size() / 2]);
	else
		warped_image_scale = static_cast<float>(focals[focals.size() / 2 - 1] + focals[focals.size() / 2]) * 0.5f;

	if (do_wave_correct)
	{
		vector<Mat> rmats;
		for (size_t i = 0; i < cameras.size(); ++i)
			rmats.push_back(cameras[i].R.clone());
		waveCorrect(rmats, wave_correct);
		for (size_t i = 0; i < cameras.size(); ++i)
			cameras[i].R = rmats[i];
	}

	LOGLN("Warping images (auxiliary)... ");
#if ENABLE_LOG
	t = getTickCount();
#endif

	vector<Point> corners(num_images);
	vector<UMat> masks_warped(num_images);
	vector<UMat> images_warped(num_images);
	vector<Size> sizes(num_images);
	vector<UMat> masks(num_images);

	// Preapre images masks
	for (int i = 0; i < num_images; ++i)
	{
		masks[i].create(images[i].size(), CV_8U);
		masks[i].setTo(Scalar::all(255));
	}

	// Warp images and their masks

	Ptr<WarperCreator> warper_creator;
#ifdef HAVE_OPENCV_CUDAWARPING
	if (try_cuda && cuda::getCudaEnabledDeviceCount() > 0)
	{
		warper_creator = makePtr<cv::PlaneWarperGpu>();
	}
	else
#endif
	{
		warper_creator = makePtr<cv::PlaneWarper>();
	}

	if (!warper_creator)
	{
		cout << "Can't create the following warper '" << warp_type << "'\n";
		return 1;
	}

	Ptr<RotationWarper> warper = warper_creator->create(static_cast<float>(warped_image_scale * seam_work_aspect));
	for (int i = 0; i < num_images; ++i)
	{
		Mat_<float> K;
		cameras[i].K().convertTo(K, CV_32F);
		float swa = (float)seam_work_aspect;
		K(0, 0) *= swa; K(0, 2) *= swa;
		K(1, 1) *= swa; K(1, 2) *= swa;

		corners[i] = warper->warp(images[i], K, cameras[i].R, INTER_LINEAR, BORDER_REFLECT, images_warped[i]);
		sizes[i] = images_warped[i].size();

		warper->warp(masks[i], K, cameras[i].R, INTER_NEAREST, BORDER_CONSTANT, masks_warped[i]);
	}

	vector<UMat> images_warped_f(num_images);
	for (int i = 0; i < num_images; ++i)
		images_warped[i].convertTo(images_warped_f[i], CV_32F);

	LOGLN("Warping images, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");

	Ptr<ExposureCompensator> compensator = ExposureCompensator::createDefault(expos_comp_type);
	compensator->feed(corners, images_warped, masks_warped);

	Ptr<SeamFinder> seam_finder;
	if (seam_find_type == "gc_color")
	{
#ifdef HAVE_OPENCV_CUDALEGACY
		if (try_cuda && cuda::getCudaEnabledDeviceCount() > 0)
			seam_finder = makePtr<detail::GraphCutSeamFinderGpu>(GraphCutSeamFinderBase::COST_COLOR);
		else
#endif
			seam_finder = makePtr<detail::GraphCutSeamFinder>(GraphCutSeamFinderBase::COST_COLOR);
	}
	if (!seam_finder)
	{
		cout << "Can't create the following seam finder '" << seam_find_type << "'\n";
		return 1;
	}

	seam_finder->find(images_warped_f, corners, masks_warped);

	// Release unused memory
	images.clear();
	images_warped.clear();
	images_warped_f.clear();
	masks.clear();

	LOGLN("Compositing...");
#if ENABLE_LOG
	t = getTickCount();
#endif

	Mat img_warped, img_warped_s;
	Mat dilated_mask, seam_mask, mask, mask_warped;
	Ptr<Blender> blender;
	Ptr<Timelapser> timelapser;
	//double compose_seam_aspect = 1;
	double compose_work_aspect = 1;

	for (int img_idx = 0; img_idx < num_images; ++img_idx)
	{
		LOGLN("Compositing image #" << indices[img_idx] + 1);

		// Read image and resize it if necessary
		full_img = framecap[img_names[img_idx]];
		if (!is_compose_scale_set)
		{
			if (compose_megapix > 0)
				compose_scale = min(1.0, sqrt(compose_megapix * 1e6 / full_img.size().area()));
			is_compose_scale_set = true;

			// Compute relative scales
			//compose_seam_aspect = compose_scale / seam_scale;
			compose_work_aspect = compose_scale / work_scale;

			// Update warped image scale
			warped_image_scale *= static_cast<float>(compose_work_aspect);
			warper = warper_creator->create(warped_image_scale);

			// Update corners and sizes
			for (int i = 0; i < num_images; ++i)
			{
				// Update intrinsics
				cameras[i].focal *= compose_work_aspect;
				cameras[i].ppx *= compose_work_aspect;
				cameras[i].ppy *= compose_work_aspect;

				// Update corner and size
				Size sz = full_img_sizes[i];
				if (std::abs(compose_scale - 1) > 1e-1)
				{
					sz.width = cvRound(full_img_sizes[i].width * compose_scale);
					sz.height = cvRound(full_img_sizes[i].height * compose_scale);
				}

				Mat K;
				cameras[i].K().convertTo(K, CV_32F);
				Rect roi = warper->warpRoi(sz, K, cameras[i].R);
				corners[i] = roi.tl();
				sizes[i] = roi.size();
			}
		}
		if (abs(compose_scale - 1) > 1e-1)
			resize(full_img, img, Size(), compose_scale, compose_scale, INTER_LINEAR_EXACT);
		else
			img = full_img;
		full_img.release();
		Size img_size = img.size();

		Mat K;
		cameras[img_idx].K().convertTo(K, CV_32F);

		// Warp the current image
		warper->warp(img, K, cameras[img_idx].R, INTER_LINEAR, BORDER_REFLECT, img_warped);

		// Warp the current image mask
		mask.create(img_size, CV_8U);
		mask.setTo(Scalar::all(255));
		warper->warp(mask, K, cameras[img_idx].R, INTER_NEAREST, BORDER_CONSTANT, mask_warped);

		// Compensate exposure
		compensator->apply(img_idx, corners[img_idx], img_warped, mask_warped);

		img_warped.convertTo(img_warped_s, CV_16S);
		img_warped.release();
		img.release();
		mask.release();

		dilate(masks_warped[img_idx], dilated_mask, Mat());
		resize(dilated_mask, seam_mask, mask_warped.size(), 0, 0, INTER_LINEAR_EXACT);
		mask_warped = seam_mask & mask_warped;

		if (!blender && !timelapse)
		{
			blender = Blender::createDefault(blend_type, try_cuda);
			Size dst_sz = resultRoi(corners, sizes).size();
			float blend_width = sqrt(static_cast<float>(dst_sz.area())) * blend_strength / 100.f;
			if (blend_width < 1.f)
				blender = Blender::createDefault(Blender::NO, try_cuda);
			else if (blend_type == Blender::MULTI_BAND)
			{
				MultiBandBlender* mb = dynamic_cast<MultiBandBlender*>(blender.get());
				mb->setNumBands(static_cast<int>(ceil(log(blend_width) / log(2.)) - 1.));
				LOGLN("Multi-band blender, number of bands: " << mb->numBands());
			}
			blender->prepare(corners, sizes);
		}
		else if (!timelapser && timelapse)
		{
			timelapser = Timelapser::createDefault(timelapse_type);
			timelapser->initialize(corners, sizes);
		}
		blender->feed(img_warped_s, mask_warped, corners[img_idx]);
	}

	if (!timelapse)
	{
		Mat result, result_mask;
		blender->blend(result, result_mask);

		LOGLN("Compositing, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");
	}

	LOGLN("Finished preparing, total time: " << ((getTickCount() - app_start_time) / getTickFrequency()) << " sec");
	images.clear();
	images_warped.clear();
	images_warped_f.clear();
	masks.clear();

	int numberofframe = 0;
	time_t beforerun = time(0);
	while (cap0.read(framecap[0]) && cap1.read(framecap[1]))
	{
		//imshow("cap0", framecap[0]);
		//imshow("cap1", framecap[1]);
		//Mat img_warped, img_warped_s;
		//Mat dilated_mask, seam_mask, mask, mask_warped;
		Ptr<Blender> blender;

		for (int img_idx = 0; img_idx < num_images; ++img_idx)
		{
			full_img = framecap[img_idx];
			if (abs(compose_scale - 1) > 1e-1)
				resize(full_img, img, Size(), compose_scale, compose_scale, INTER_LINEAR_EXACT);
			else
				img = full_img;
			full_img.release();
			Size img_size = img.size();

			Mat K;
			cameras[img_idx].K().convertTo(K, CV_32F);

			// Warp the current image
			warper->warp(img, K, cameras[img_idx].R, INTER_LINEAR, BORDER_REFLECT, img_warped);

			// Warp the current image mask
			mask.create(img_size, CV_8U);
			mask.setTo(Scalar::all(255));
			warper->warp(mask, K, cameras[img_idx].R, INTER_NEAREST, BORDER_CONSTANT, mask_warped);

			// Compensate exposure
			compensator->apply(img_idx, corners[img_idx], img_warped, mask_warped);

			img_warped.convertTo(img_warped_s, CV_16S);
			img_warped.release();
			img.release();
			mask.release();

			dilate(masks_warped[img_idx], dilated_mask, Mat());
			resize(dilated_mask, seam_mask, mask_warped.size(), 0, 0, INTER_LINEAR_EXACT);
			mask_warped = seam_mask & mask_warped;

			if (!blender && !timelapse)
			{
				blender = Blender::createDefault(blend_type, try_cuda);
				Size dst_sz = resultRoi(corners, sizes).size();
				float blend_width = sqrt(static_cast<float>(dst_sz.area())) * blend_strength / 100.f;
				if (blend_width < 1.f)
					blender = Blender::createDefault(Blender::NO, try_cuda);
				blender->prepare(corners, sizes);
			}
			blender->feed(img_warped_s, mask_warped, corners[img_idx]);
		}

		Mat result, result_mask;
		blender->blend(result, result_mask);

		Mat frame;
		result.convertTo(frame, CV_8UC1);
		imshow("stitch", frame);
		numberofframe++;

		if (cvWaitKey(10) == 27)  break;
	}
	time_t afterrun = time(0);
	cout << "帧率约为" << numberofframe / (afterrun - beforerun) << "帧/s" << endl;
	getchar();
}

这份代码是从opencv examples里面的stitching_detailed.cpp改过来的,在CPU的基础上基本做到极限了,可优化的空间我感觉是不大。基于GPU加速还可以更快一点,这是后续工作了。也可以很容易地改为3摄像头或者更多摄像头的实时拼接。
代码整体应该没有大的bug,如果提示Need more images 2并且卡住的话表面双摄像头采集到的结果无法拼接起来,你需要调整一下两个摄像头的位置重新拼接试试。
如有问题可以随时与我联系!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenCV3.4.13+OpenCV_contrib 双摄像头实时拼接 环境配置 的相关文章

  • 在白色背景上将透明 PNG 保存为 JPEG

    假设我有一张 BGRA 图像numpy数组看起来非常像这样 233 228 230 128 233 228 230 128 233 228 230 0 164 160 159 65 199 197 196 65 255 255 254 12
  • 将图像从 CV_64F 转换为 CV_8U

    我想转换类型的图像CV 64FC1 to CV 8UC1在 Python 中使用 OpenCV 在 C 中 使用convertTo函数 我们可以使用以下代码片段轻松转换图像类型 image convertTo image CV 8UC1 我
  • 使用高斯混合模型进行皮肤检测

    我正在根据以下进行皮肤检测算法本文 http www cc gatech edu rehg Papers SkinDetect IJCV lowres pdf 第 21 页有两个模型 高斯皮肤混合模型和非皮肤颜色模型 第一个皮肤检测模型效果
  • 正方形检测找不到正方形

    我正在使用该程序方块 c在 OpenCV 库的示例中可用 它适用于每个图像 但我真的不明白为什么它不能识别该图像中绘制的正方形 After CANNY After DILATE The RESULT图像 红色 http img267 ima
  • OpenCV 的 findHomography 产生无意义的结果

    我正在制作一个程序 使用 OpenCV 2 43 中的 ORB 跟踪功能 我遵循并使用了建议从这里 https stackoverflow com questions 9919505 how can i extract fast featu
  • 从彩色背景中提取黑色对象

    人眼很容易辨别black来自其他颜色 但是计算机呢 我在普通的A4纸上打印了一些色块 由于组成彩色图像有青色 品红色和黄色三种墨水 所以我设置每个块的颜色C 20 C 30 C 40 C 50 以及其余两种颜色是 0 这是我的源图像的第一列
  • Python opencv排序轮廓[重复]

    这个问题在这里已经有答案了 我正在关注这个问题 如何从左到右 从上到下对轮廓进行排序 https stackoverflow com questions 38654302 how can i sort contours from left
  • ld:找不到 -llibtbb.dylib 的库

    我尝试从 opencv 2 4 8 apps haarfinder 编译一些文件 但出现以下错误 ld library not found for llibtbb dylib 注意双l在文件名中 我尝试按照这里的教程进行操作 http co
  • Matlab 中 interp2 的类似 OpenCV Api

    有没有类似的功能 其工作原理与 interp2 x y frame z xd yd linear 0 在 OpenCV 中 功能cv remap 几乎可以满足您的要求 请参阅文档here http docs opencv org modul
  • 使用 OpenCV 查找重叠/复杂的圆

    我想计算红圈半径 图2 我在使用 OpenCV 的 HoughCircles 找到这些圆圈时遇到了麻烦 如图所示 2 我只能使用 HoughCircles 找到中心以黑色显示的小圆圈 original fig 2 由于我知道红色圆圈的中心
  • 使用 OpenCV 裁剪黑色边缘

    我认为这应该是一个很简单的问题 但我找不到解决方案或有效的关键字进行搜索 我只有这个图像 黑边没有用 所以我想把它们剪掉 只留下 Windows 图标 和蓝色背景 我不想计算Windows图标的坐标和大小 GIMP 和 Photoshop
  • 在 iPad 上使用 OpenCV 避免碰撞

    我正在开展一个项目 需要使用 OpenCV 实现碰撞避免 这是在 iOS 上完成的 iOS 5 及以上版本即可 项目目标 这个想法是将 iPad 安装在汽车仪表板上并启动应用程序 应用程序应该从相机中抓取帧并进行处理 以检测汽车是否会与任何
  • 相机姿态估计(OpenCV PnP)

    我正在尝试使用网络摄像头从具有已知全球位置的四个基准点的图像中获取全局姿态估计 我检查了许多 stackexchange 问题和一些论文 但似乎无法得到正确的解决方案 我得到的位置数字是可重复的 但与相机移动绝不成线性比例 仅供参考 我正在
  • 如何将 OpenCV 等待键与 Chaquopy 一起使用

    我正在尝试使用 Chaquopy 将计算机视觉应用程序移植到 Android 当我尝试运行脚本时 以下行中出现以下错误 cv2 waitKey 100 打印到嵌入式 python 控制台的错误是 java chaquopy CQPEnv c
  • opencv 视频上的颜色阈值

    I am thresholding for a color range in an opencv video The goal is to seperate the B mode black and white information on
  • C++ OpenCV 2.3 中缺少 MoveWindow()

    我正在使用 OpenCV 2 3 的 C 版本 并且正在努力完成一项基本任务 我想做的是创建一个窗口并将其移动到屏幕上的特定位置 例如使用 cv namedWindow My Window 1 cv MoveWindow My Window
  • CvMat 和 Imread 与 IpImage 和 CvLoadImage

    使用 OpenCv 2 4 我有两个选项来加载图像 1 CvMat and Imread 2 IpImage and CvLoadImage 使用哪一个更好 我尝试将两者混合并最终出现段错误 imread返回一个Mat not CvMat
  • 如何使用 OpenCV 检测图像帧中的对象?

    我正在使用 Raspberry Pi 开发一个漫游器 它将清扫房间并捡起掉落在地上的物体 为了检测物体 我使用了在流动站操作开始时拍摄的参考图像 以及每 10 秒单击一次的图像 新图像 为了确定图像帧是否发生变化 我在参考图像和新图像之间进
  • 如何在Python中使用tcp套接字发送和接收网络摄像头流?

    我正在尝试重新创建这个项目 https github com hamuchiwa AutoRCCar 我拥有的是服务器 我的电脑 和客户端 我的树莓派 我所做的与原始项目不同的是我尝试使用一个简单的网络摄像头而不是树莓派摄像头将图像从我的
  • 如何在给定目标大小的情况下在 python 中调整图像大小,同时保留纵横比?

    首先 我觉得这是一个愚蠢的问题 对此感到抱歉 目前 我发现计算最佳缩放因子 目标像素数的最佳宽度和高度 同时保留纵横比 的最准确方法是迭代并选择最佳缩放因子 但是必须有更好的方法来做到这一点 一个例子 import cv2 numpy as

随机推荐

  • shell脚本不能激活环境变量问题完美解决

    今天在Linux系统写shell脚本时发现配置好java环境变量后 明明写了source etc profile 但还是不能激活 也就是java version没有反应 非要自己手动去激活 后来发现我是用 test sh 来启动的脚本 te
  • RPA技术分享--通过解压 OFD 获取发票信息

    了解RPA www i search com cn 学习RPA https support i search com cn 下载RPA https www i search com cn from csdn 实际上 ofd docx xls
  • sql实现截取字段内容

    场景 出现一批数据需要修复 调用方法进行传参 而存储该字段内容是JSONString呈现 所需的仅仅是其中的某一部分数据 因此需要完成截取 并拼接成想要的格式 使用如下格式调用postman实现自动化执行接口调用 例如 taskId xxx
  • 用GCC生成和调用dll【C语言版】

    今天在网上找了好久 才找到这个能成功运行的视频教程 现在分享给大家 Windows下C语言使用GCC编写和调用dll https www bilibili com video BV1E4411z7Ua share source copy w
  • 颜色识别的实例二

    原图 识别结果 代码 color fuses hdev classify fuses by color dev update window off step set up fuse properties and hue ranges Fus
  • iwebsec靶场 SQL注入漏洞通关笔记6- 宽字节注入

    系列文章目录 iwebsec靶场 SQL注入漏洞通关笔记1 数字型注入 mooyuan的博客 CSDN博客 iwebsec靶场 SQL注入漏洞通关笔记2 字符型注入 宽字节注入 mooyuan的博客 CSDN博客 iwebsec靶场 SQL
  • (十七)QT生成PDF文件

    在实际情况中 我们有时候会遇到需要把txt html或者图片变成PDF文件的情况 例如把检测结果生成PDF文档给客户等等 QT4使用QPrinter来实现这个功能 QT5修改为QPdfWriter这个类 一 QT5的修改 如果你想在QT5中
  • 思岚RPLIDAR A2 在ubuntu 16.04上的测试

    1 下载雷达ROS包 首先在github上下载rplidar的ros包 下载指令为 默认安装了git git clone https github com Slamtec rplidar ros git 在ubuntu上创建工作空间 并将该
  • 落地领域大模型应知必会(2): 轻量化微调

    编者按 在实际部署大模型的过程中可能会面临资源限制的问题 通过轻量化大模型微调技术 可以将大型预训练语言模型适配到特定领域 特定任务 并减小其模型尺寸和计算量需求 提高性能和效率 在上一篇文章中 我们分享了大语言模型的主要微调技术总览 接下
  • 实验6-6 使用函数验证哥德巴赫猜想 (20分)

    http pta patest cn pta test 13 exam 3 question 478 include
  • iOS 关于NSNotificationCenter

    通常我们在 iOS 中发生什么事件时该做什么是由 Delegate 实现的 Apple 还为我们提供了另一种通知响应方式 那就是 NSNotification NSNotificationCenter 较之于 Delegate 可以实现更大
  • 计算机视觉OpenCV-图像直方图

    欢迎来到本博客 作者简介 目前计算机研究生在读 主要研究方向是人工智能和群智能算法方向 目前熟悉python网页爬虫 机器学习 计算机视觉 OpenCV 群智能算法 然后正在学习深度学习的相关内容 以后可能会涉及到网络安全相关领域 毕竟这是
  • 100家企业近年面试题整理

    打造最受企业欢迎的iOS开发者 一直都存在的问题 什么样的员工最受企业欢迎 一直也有人在努力提升自己 成为受企业欢迎的员工 然而 我们应该往方向去提升自己呢 100家知名企业今年来iOS面试题合集 你要的这里都有 企业要的这里也有 从基础开
  • Unity Resources资源管理的优点和痛点

    1 1 Resources详解 我觉得 Resources之所以能被广泛的使用 是因为它的使用非常简单 并且是同步加载 一般来说 正式的商业项目 对外发布资源的时候都是使用AssetBundles的方式进行 AssetBundles的方式有
  • re.compile(pattern,flags=0)中flags的用法

    re正则表达式模块还包括一些有用的操作正则表达式的函数 下面主要介绍compile函数 定义 compile pattern flags 根据包含正则表达式的字符串创建模式对象 通过python的help函数查看compile含义 1 he
  • 【数电】如何使用74LS112(或74LS74)构成一个十四分频器(模七计数器)

    IT精英们 大家都学过数字电子技术吧 尽管这东西没用 不过这些基础课程对思维的培养还是很有好处的 我不爱上课 但不代表我不喜欢数电 我们实验课老师为了加强实验难度 把实验题改掉了 用74LS112 或者74LS74 设计一个十四分频器 原来
  • PHP文件包含

    本地文件包含 打开PHPstudy 打开网站根目录 创建文件 文件内容为 在浏览器上查看所包含文件 远程文件包含 文件include php文件内容 print txt文件内容 远程查看print txt 远程包含shell shell t
  • zookeeper入门到精通03——zookeeper集群搭建

    zookeeper集群搭建 3 1 多虚拟机环境搭建 3 2 zookeeper集群搭建 3 1 多虚拟机环境搭建 我们需要搭建zookeeper集群 而由于zookeeper的的服务器数量需要设置为单数 前文介绍了原因 一个zookeep
  • 2023年第47届(第二届)浙江技能大赛网络安全项目 (世赛省选拔赛)A模块解析

    2023年第47届 第二届 浙江技能大赛网络安全项目 世赛省选拔赛 A模块解析 模块A 企业基础设施安全 1 竞项赛目简介 1 1 介绍 1 2 任务描述 1 3 竞赛说明 2 竞赛项目工作任务 2 2 操作系统安全加固 2 2 1 Win
  • OpenCV3.4.13+OpenCV_contrib 双摄像头实时拼接 环境配置

    如题 基于OpenCV3 4 13 VS2015做了个双摄像头实时拼接的代码 是一个大项目的一个baseline的一部分 下面先说配环境再给代码 环境配置 关于OpenCV VS的环境配置网上已经有很多了 因为这份代码用到了OpenCV C