当前位置:   article > 正文

OpenCV实现图像的裁块与拼接_opencv图像裁剪及拼接

opencv图像裁剪及拼接

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

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

 一、图像裁成若干子块

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

  1. #include<iostream>
  2. #include<fstream>
  3. #include<opencv2/imgproc/imgproc.hpp>
  4. #include<opencv2/core/core.hpp>
  5. #include<opencv2/highgui/highgui.hpp>
  6. #include<vector>
  7. using namespace cv;
  8. using namespace std;
  9. void cutImage()
  10. {
  11. string s = "D:/AAAA/BBBB/CCCC/" + name + ".png";//图片所在路径
  12. Mat src = imread(s);
  13. vector<Mat> subImages; //用于存放等分后的各子图
  14. int subImageNum = 10;//子图数量=10*10
  15. int srcHeight, srcWidth, subHeight, subWidth;
  16. srcHeight = src.rows; srcWidth = src.cols;
  17. subHeight = srcHeight / subImageNum;
  18. subWidth = srcWidth / subImageNum;
  19. for (int j = 0; j < subImageNum; j++)
  20. {
  21. for (int i = 0; i < subImageNum; i++)
  22. {
  23. if (j < subImageNum - 1 && i < subImageNum - 1) {
  24. cv::Mat temImage(subHeight, subWidth, CV_8UC3, cv::Scalar(0, 0, 0));
  25. cv::Mat imageROI = src(cv::Rect(i * subWidth, j * subHeight, temImage.cols, temImage.rows));
  26. cv::addWeighted(temImage, 1.0, imageROI, 1.0, 0., temImage);
  27. subImages.push_back(temImage);
  28. }
  29. else {
  30. cv::Mat temImage(srcHeight - (subImageNum - 1) * subHeight, srcWidth - (subImageNum - 1) * subWidth, CV_8UC3, cv::Scalar(0, 0, 0));
  31. cv::Mat imageROI = src(cv::Rect(i * subWidth, j * subHeight, temImage.cols, temImage.rows));
  32. cv::addWeighted(temImage, 1.0, imageROI, 1.0, 0., temImage);
  33. subImages.push_back(temImage);
  34. }
  35. }
  36. }
  37. for (int i = 0; i < subImages.size(); i++)
  38. {
  39. string out = "D:/AAAA/BBBB/EEEE/" + name +"_"+std::to_string(i)+ ".png";//输出保存各子图像
  40. imwrite(out, subImages[i]);
  41. }
  42. }
  43. int main()
  44. {
  45. cutImage();
  46. cv::waitKey(0);
  47. system("pause");
  48. return 0;
  49. }

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

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

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

  1. #include<iostream>
  2. #include<fstream>
  3. #include<opencv2/imgproc/imgproc.hpp>
  4. #include<opencv2/core/core.hpp>
  5. #include<opencv2/highgui/highgui.hpp>
  6. #include<vector>
  7. using namespace cv;
  8. using namespace std;
  9. void testsubimg(string name)//将图片分为n*n大小的若干块
  10. {
  11. string s = "D:/AA/BB/CC/" + name + ".png";
  12. Mat src = imread(s);
  13. int n = 128;//子图像大小为n*n格
  14. Mat srcadd;
  15. cv::copyMakeBorder(src, srcadd, 0, (n-(src.rows%n)), 0, (n - (src.cols%n)), CV_8UC1, cv::Scalar::all(0));//向下,向右扩充对应的行列数
  16. vector<Mat> subbox;
  17. for (int i = 0; i < srcadd.rows; i+=n)
  18. {
  19. for (int j = 0; j < srcadd.cols; j+=n)
  20. {
  21. Mat partImage = srcadd(Rect(j, i, n, n));//切出子图像
  22. subbox.push_back(partImage);
  23. }
  24. }
  25. for (int i = 0; i < subbox.size(); i++)
  26. {
  27. string s1 = "D:/AA/BB/CC/ee/" + name + "_" + std::to_string(i) + ".png";
  28. imwrite(s1, subbox[i]);
  29. }
  30. }
  31. int main()
  32. {
  33. testsubimg("2");
  34. cv::waitKey(0);
  35. system("pause");
  36. return 0;
  37. }

 二、图像横、纵拼接

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

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

  1. #include<iostream>
  2. #include<fstream>
  3. #include<opencv2/imgproc/imgproc.hpp>
  4. #include<opencv2/core/core.hpp>
  5. #include<opencv2/highgui/highgui.hpp>
  6. #include<vector>
  7. using namespace cv;
  8. using namespace std;
  9. Mat comimage(string name1, string name2) //横向拼接
  10. {
  11. string s1 = "D:/AA/BB/CC/" + name1 + ".png";
  12. Mat img1 = imread(s1);
  13. string s2 = "D:/AA/BB/CC/" + name2 + ".png";
  14. Mat img2 = imread(s2);
  15. int height = img1.rows;
  16. int width1 = img1.cols;
  17. int width2 = img2.cols;
  18. // 将高图像等比缩放与低图像高度一致
  19. if (img1.rows > img2.rows)
  20. {
  21. height = img2.rows;
  22. width1 = img1.cols * ((float)img2.rows / (float)img1.rows);
  23. resize(img1, img1, Size(width1, height));
  24. }
  25. else if (img1.rows < img2.rows)
  26. {
  27. width2 = img2.cols * ((float)img1.rows / (float)img2.rows);
  28. resize(img2, img2, Size(width2, height));
  29. }
  30. //创建目标Mat
  31. Mat des;
  32. des.create(height, width1 + width2, img1.type());
  33. Mat r1 = des(Rect(0, 0, width1, height));
  34. img1.copyTo(r1);
  35. Mat r2 = des(Rect(width1, 0, width2, height));
  36. img2.copyTo(r2);
  37. namedWindow("des");
  38. imshow("des", des);
  39. return des;
  40. }
  41. int main()
  42. {
  43. comimage("1","2");
  44. cv::waitKey(0);
  45. system("pause");
  46. return 0;
  47. }

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

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

  1. #include<iostream>
  2. #include<fstream>
  3. #include<opencv2/imgproc/imgproc.hpp>
  4. #include<opencv2/core/core.hpp>
  5. #include<opencv2/highgui/highgui.hpp>
  6. #include<vector>
  7. using namespace cv;
  8. using namespace std;
  9. Mat comimage1(string name1, string name2) //纵向拼接
  10. {
  11. string s1 = "D:/00-myfiles/车道线提取/testdata0101/NewPaper/temp/" + name1 + ".png";
  12. Mat img1 = imread(s1);
  13. string s2 = "D:/00-myfiles/车道线提取/testdata0101/NewPaper/temp/" + name2 + ".png";
  14. Mat img2 = imread(s2);
  15. int width = img1.cols;
  16. int height1 = img1.rows;
  17. int height2 = img2.rows;
  18. if (img1.cols > img2.cols)
  19. {
  20. width = img2.cols;
  21. height1 = img1.rows*((float)img2.cols / (float)img1.cols);
  22. resize(img1, img1, Size(width, height1));
  23. }
  24. else if (img1.cols < img2.cols)
  25. {
  26. height2 = img2.rows*((float)img1.cols / (float)img2.cols);
  27. resize(img2, img2, Size(width, height2));
  28. }
  29. Mat des;
  30. des.create(height1 + height2, width, img1.type());
  31. Mat r1 = des(Rect(0, 0, width, height1));
  32. img1.copyTo(r1);
  33. Mat r2 = des(Rect(0, height1, width, height2));
  34. img2.copyTo(r2);
  35. namedWindow("des");
  36. imshow("des", des);
  37. return des;
  38. }
  39. int main()
  40. {
  41. comimage("1","2");
  42. cv::waitKey(0);
  43. system("pause");
  44. return 0;
  45. }

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

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

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

三、拼回完整的图像

  1. #include<iostream>
  2. #include<fstream>
  3. #include<opencv2/imgproc/imgproc.hpp>
  4. #include<opencv2/core/core.hpp>
  5. #include<opencv2/highgui/highgui.hpp>
  6. #include<vector>
  7. using namespace cv;
  8. using namespace std;
  9. void com(string name)
  10. {
  11. Mat merge;
  12. for (int k = 0; k < 10; k++)
  13. {
  14. vector<Mat> box;
  15. for (int i = k * 10; i < (k + 1) * 10; i++)
  16. {
  17. string s = "D:/AA/BB/CC/" + name + "_" + std::to_string(i) + ".png";
  18. Mat src = imread(s);
  19. box.push_back(src);
  20. }
  21. Mat img1 = box[0];
  22. for (int i = 1; i < box.size(); i++)
  23. {
  24. Mat temp = comimage(img1, box[i]);//属于同一行的,横向拼接
  25. img1 = temp;
  26. }
  27. if (k==0)
  28. {
  29. merge= img1;
  30. }
  31. else
  32. {
  33. merge=comimage1(merge, img1);//拼出每行之后,再将中间结果纵向拼接
  34. }
  35. }
  36. namedWindow("img_merge");
  37. imshow("img_merge", merge);
  38. }
  39. int main()
  40. {
  41. com("001");
  42. cv::waitKey(0);
  43. system("pause");
  44. return 0;
  45. }

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/77486
推荐阅读
相关标签
  

闽ICP备14008679号