OpenCV实现图像的裁块与拼接

解释一下标题:裁块就是将一张图像裁成N*N张子图,除此之外没有别的操作;

拼接就是对这些子图操作完之后,再拼回原来那张图(不是类似于配准那样的拼接);

 一、图像裁成若干子块

引用:C++ opencv 将图片分为任意N等分,并保存所有子图片于本地_opencv图像等分_Wendy_lz的博客-CSDN博客

#include
#include
#include
#include
#include
#include
 
using namespace cv;
using namespace std;

void cutImage()
{
   string s = "D:/AAAA/BBBB/CCCC/" + name + ".png";//图片所在路径
   Mat src = imread(s);

vector subImages;  //用于存放等分后的各子图
	int subImageNum = 10;//子图数量=10*10
	int srcHeight, srcWidth, subHeight, subWidth;
	srcHeight = src.rows; srcWidth = src.cols;
	subHeight = srcHeight / subImageNum;
	subWidth = srcWidth / subImageNum;
	for (int j = 0; j < subImageNum; j++)
	{
		for (int i = 0; i < subImageNum; i++)
		{
			if (j < subImageNum - 1 && i < subImageNum - 1) {
				cv::Mat temImage(subHeight, subWidth, CV_8UC3, cv::Scalar(0, 0, 0));
				cv::Mat imageROI = src(cv::Rect(i * subWidth, j * subHeight, temImage.cols, temImage.rows));
				cv::addWeighted(temImage, 1.0, imageROI, 1.0, 0., temImage);
				subImages.push_back(temImage);
			}
			else {
				cv::Mat temImage(srcHeight - (subImageNum - 1) * subHeight, srcWidth - (subImageNum - 1) * subWidth, CV_8UC3, cv::Scalar(0, 0, 0));
				cv::Mat imageROI = src(cv::Rect(i * subWidth, j * subHeight, temImage.cols, temImage.rows));
				cv::addWeighted(temImage, 1.0, imageROI, 1.0, 0., temImage);
				subImages.push_back(temImage);
			}
		}
	}

	for (int i = 0; i < subImages.size(); i++)
	{
		string out = "D:/AAAA/BBBB/EEEE/" + name +"_"+std::to_string(i)+ ".png";//输出保存各子图像
		imwrite(out, subImages[i]);
	}

}

int main()
{	
	cutImage();	

	cv::waitKey(0);
	system("pause");
	return 0;
} 

效果如下,一张单独的图被裁剪成100张子图。

OpenCV实现图像的裁块与拼接_第1张图片

OpenCV实现图像的裁块与拼接_第2张图片

上述裁剪方法,可以知道自己得到几张子图像,但是每张子图像的大小并不完全一致。

自己写了一个简单粗暴的方式,可以固定子图像的行列大小,但是需要扩充原图行列,会产生黑边。

#include
#include
#include
#include
#include
#include
 
using namespace cv;
using namespace std;

void testsubimg(string name)//将图片分为n*n大小的若干块
{
	string s = "D:/AA/BB/CC/" + name + ".png";
	Mat src = imread(s);
	int n = 128;//子图像大小为n*n格
	Mat srcadd;
	cv::copyMakeBorder(src, srcadd, 0, (n-(src.rows%n)), 0, (n - (src.cols%n)), CV_8UC1, cv::Scalar::all(0));//向下,向右扩充对应的行列数
	
	vector subbox;
	for (int i = 0; i < srcadd.rows; i+=n)
	{
		for (int j = 0; j < srcadd.cols; j+=n)
		{
			Mat partImage = srcadd(Rect(j, i, n, n));//切出子图像
			subbox.push_back(partImage);		
		}
	}
	
	for (int i = 0; i < subbox.size(); i++)
	{
		string s1 = "D:/AA/BB/CC/ee/" + name + "_" + std::to_string(i) + ".png";
		imwrite(s1, subbox[i]);
	}	
}

int main()
{
	testsubimg("2");
	cv::waitKey(0);
	system("pause");
	return 0;
}

OpenCV实现图像的裁块与拼接_第3张图片

 二、图像横、纵拼接

横向拼接,两张图片的尺寸大小可以不一样。(具体实现使用的下文关键代码)

引用:通过ROI实现图像并排合并_Howardk的博客-CSDN博客

#include
#include
#include
#include
#include
#include
 
using namespace cv;
using namespace std;

Mat comimage(string name1, string name2) //横向拼接
{
	string s1 = "D:/AA/BB/CC/" + name1 + ".png";
	Mat img1 = imread(s1);
	string s2 = "D:/AA/BB/CC/" + name2 + ".png";
	Mat img2 = imread(s2);

	int height = img1.rows;
	int width1 = img1.cols;
	int width2 = img2.cols;
	// 将高图像等比缩放与低图像高度一致
	if (img1.rows > img2.rows)
	{
		height = img2.rows;
		width1 = img1.cols * ((float)img2.rows / (float)img1.rows);
		resize(img1, img1, Size(width1, height));
	}
	else if (img1.rows < img2.rows)
	{
		width2 = img2.cols * ((float)img1.rows / (float)img2.rows);
		resize(img2, img2, Size(width2, height));
	}

	//创建目标Mat
	Mat des;
	des.create(height, width1 + width2, img1.type());
	Mat r1 = des(Rect(0, 0, width1, height));
	img1.copyTo(r1);
	Mat r2 = des(Rect(width1, 0, width2, height));
	img2.copyTo(r2);

	namedWindow("des");
	imshow("des", des);

	return des;
}

int main()
{	
	comimage("1","2");
	
	cv::waitKey(0);
	system("pause");
	return 0;
}

OpenCV实现图像的裁块与拼接_第4张图片

可以看到用于拼接的两张图尺寸是不一致的,图2会更方。代码是让高度向更小的看齐,并且需要改变的那张图同时还要等比例缩小。

 稍微修改一下,实现纵向拼接。两张拼接的图尺寸可以不一致。

#include
#include
#include
#include
#include
#include
 
using namespace cv;
using namespace std;

Mat comimage1(string name1, string name2) //纵向拼接
{
	string s1 = "D:/00-myfiles/车道线提取/testdata0101/NewPaper/temp/" + name1 + ".png";
	Mat img1 = imread(s1);
	string s2 = "D:/00-myfiles/车道线提取/testdata0101/NewPaper/temp/" + name2 + ".png";
	Mat img2 = imread(s2);

	int width = img1.cols;
	int height1 = img1.rows;
	int height2 = img2.rows;
	if (img1.cols > img2.cols)
	{
		width = img2.cols;
		height1 = img1.rows*((float)img2.cols / (float)img1.cols);
		resize(img1, img1, Size(width, height1));
	}
	else if (img1.cols < img2.cols)
	{
		height2 = img2.rows*((float)img1.cols / (float)img2.cols);
		resize(img2, img2, Size(width, height2));
	}

	Mat des;
	des.create(height1 + height2, width, img1.type());
	Mat r1 = des(Rect(0, 0, width, height1));
	img1.copyTo(r1);
	Mat r2 = des(Rect(0, height1, width, height2));
	img2.copyTo(r2);

	namedWindow("des");
	imshow("des", des);

	return des;
}

int main()
{	
	comimage("1","2");
	
	cv::waitKey(0);
	system("pause");
	return 0;
}

下图是纵向拼接效果,图2不完整是因为屏幕太小了,截图只能截到这么多。

纵向拼接还有一个很简单的实现语句,但是要求图像的尺寸必须是一致的,不然就会报错。

Mat merge;
Mat image;
image.push_back(image);//将image图像加到merge图像的最后一行

三、拼回完整的图像

#include
#include
#include
#include
#include
#include
 
using namespace cv;
using namespace std;

void com(string name)
{
	Mat merge;
	for (int k = 0; k < 10; k++)
	{
		vector box;
		for (int i = k * 10; i < (k + 1) * 10; i++)
		{
			string s = "D:/AA/BB/CC/" + name + "_" + std::to_string(i) + ".png";
			Mat src = imread(s);
			box.push_back(src);
		}

		Mat img1 = box[0];
		for (int i = 1; i < box.size(); i++)
		{
			Mat temp = comimage(img1, box[i]);//属于同一行的,横向拼接
			img1 = temp;
		}
		
		if (k==0)
		{
			merge= img1;
		}
		else
		{
			merge=comimage1(merge, img1);//拼出每行之后,再将中间结果纵向拼接
		}
	}
	namedWindow("img_merge");
	imshow("img_merge", merge);
}

int main()
{
	com("001");

	cv::waitKey(0);
	system("pause");
	return 0;
}

OpenCV实现图像的裁块与拼接_第5张图片拼的效果感觉也不是很好,小孩的腿那里明显错位。(个人推测是因为最开始的裁块固定了裁剪数量,每张子图尺寸都不一样,到最后一行的行列数差的最大,经过等比例缩放后就有明显的位移)

你可能感兴趣的:(OpenCV图像处理,opencv,计算机视觉,图像处理,c++)