解释一下标题:裁块就是将一张图像裁成N*N张子图,除此之外没有别的操作;
拼接就是对这些子图操作完之后,再拼回原来那张图(不是类似于配准那样的拼接);
一、图像裁成若干子块
#include<iostream>
#include<fstream>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<vector>
using namespace cv;
using namespace std;
void cutImage()
{
string s = "D:/AAAA/BBBB/CCCC/" + name + ".png";//图片所在路径
Mat src = imread(s);
vector<Mat> 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张子图。
上述裁剪方法,可以知道自己得到几张子图像,但是每张子图像的大小并不完全一致。
自己写了一个简单粗暴的方式,可以固定子图像的行列大小,但是需要扩充原图行列,会产生黑边。
#include<iostream>
#include<fstream>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<vector>
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<Mat> 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;
}
二、图像横、纵拼接
横向拼接,两张图片的尺寸大小可以不一样。(具体实现使用的下文关键代码)
#include<iostream>
#include<fstream>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<vector>
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;
}
可以看到用于拼接的两张图尺寸是不一致的,图2会更方。代码是让高度向更小的看齐,并且需要改变的那张图同时还要等比例缩小。
稍微修改一下,实现纵向拼接。两张拼接的图尺寸可以不一致。
#include<iostream>
#include<fstream>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<vector>
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<iostream>
#include<fstream>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<vector>
using namespace cv;
using namespace std;
void com(string name)
{
Mat merge;
for (int k = 0; k < 10; k++)
{
vector<Mat> 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;
}
拼的效果感觉也不是很好,小孩的腿那里明显错位。(个人推测是因为最开始的裁块固定了裁剪数量,每张子图尺寸都不一样,到最后一行的行列数差的最大,经过等比例缩放后就有明显的位移)