admin 管理员组

文章数量: 887006

多张截图拼接成长图

 

背景:工作中我们经常需要将一张张的截图拼接成一整张图。但是因为图片顶部和底部tabBar的存在,我们没有办法直接拼接。下面我们利用opencv的方法实现图片的完美拼接。

素材图片:

基本算法:

1、需要拼接的图片需要有1/3重合的部分,否则无法拼接。所以在截图的时候需要尽量保证图片重合部分超过1/3,否则会拼接失败。
2、重点是需要找到从哪里开始拼接。人眼很容易找到拼接的地方,但是机器需要一个明确的坐标才能进行拼接,所以需要下面的算法来实现拼接。
3、从第一张图片的2/3处截取1/6的图片作为模版,这里最后留下1/6是因为部分截图有底部tabBar,需要排除。
4、用截取到的模版,在第二张图片中查找是否有这块,如果没有则两个图片无法拼接。找到之后返回坐标。
5、根据第四步返回的坐标,截取图片,然后两个图片拼接即可。

相关依赖:

      <dependency><groupId>org.bytedeco</groupId><artifactId>javacv</artifactId><version>1.5.7</version></dependency><dependency><groupId>org.bytedeco</groupId><artifactId>javacv-platform</artifactId><version>1.5.7</version></dependency>

这里是老的依赖版本,但是我这边都进行了验证是可以正常运行的。如果你需要升级新的版本,需要自己验证依赖是否冲突。

实现代码:

package com.test.image;import org.apachemons.collections.CollectionUtils;
import org.bytedeco.javacpp.DoublePointer;
import org.bytedeco.opencv.opencv_core.Mat;
import org.bytedeco.opencv.opencv_core.Point;
import org.bytedeco.opencv.opencv_core.Rect;import java.util.ArrayList;
import java.util.List;import static org.bytedeco.opencv.global.opencv_core.*;
import static org.bytedeco.opencv.global.opencv_imgcodecs.imread;
import static org.bytedeco.opencv.global.opencv_imgcodecs.imwrite;
import static org.bytedeco.opencv.global.opencv_imgproc.*;public class ImageMergeService {/*** 基础算法:*    1、需要拼接的图片需要有1/3重合的部分,否则无法拼接。*    2、重点是需要找到从哪里开始拼接。*    3、从第一张图片的2/3处截取1/6的图片作为模版,这里最后留下1/6是因为部分截图有底部tabBar,需要排除。*    4、用截取到的模版,在第二张图片中查找是否有这块,如果没有则两个图片无法拼接。找到之后返回坐标。*    5、根据第四步返回的坐标,截取图片,然后两个图片拼接即可。** @param picMats*/public static Mat mergePic(List<Mat> picMats ){if(CollectionUtils.isEmpty(picMats)){return null;}Mat resultMat = picMats.get(0);for( int i=1; i< picMats.size(); i++   ){resultMat = mergePic(resultMat,picMats.get(i));}return resultMat;}public static Mat mergePic( Mat baseMat, Mat targetMat ){if(baseMat.size().height()<targetMat.size().height()){return null;}if(baseMat.size().width()!=targetMat.size().width()){return null;}int height = targetMat.size().height();int startHeight = (int)(height*0.7);int templateHeight = height/6;Mat template  = new Mat(baseMat, new Rect(0, baseMat.size().height()+startHeight-targetMat.size().height(), baseMat.size().width(), templateHeight));imwrite( "template.png",template);Mat sameMat = targetMat.clone();matchTemplate(targetMat,template,sameMat,TM_CCOEFF_NORMED );DoublePointer minVal = new DoublePointer();DoublePointer maxVal = new DoublePointer();Point minLoc = new Point();Point maxLoc = new Point();minMaxLoc(sameMat,minVal,maxVal,minLoc,maxLoc,null);System.out.println(sameMat.ptr(maxLoc.x(),maxLoc.y()));System.out.println(maxVal);System.out.println(maxLoc.y());if(maxLoc.y()>targetMat.size().height()-templateHeight){System.out.println("没有找到重合的部分!");return baseMat;}Mat findTemplate  = new Mat(targetMat, new Rect(0,maxLoc.y(), targetMat.size().width(), templateHeight));double diff = compareImage(template,findTemplate);System.out.println(diff);if(diff<0.999){System.out.println("没有找到重合的部分!");return baseMat;}Mat topMat = new Mat(baseMat,new Rect(0,         0, baseMat.size().width(),baseMat.size().height()+startHeight-targetMat.size().height() ));Mat tailMat  = new Mat(targetMat, new Rect(0,         maxLoc.y(), targetMat.size().width(), targetMat.size().height()-maxLoc.y()));Mat resultMat = baseMat.clone();vconcat(topMat, tailMat, resultMat);imwrite( "resultMat.png",resultMat);return resultMat;}public static double compareImage( Mat targetImage, Mat baseImage ){Mat targetImageClone = targetImage.clone();Mat baseImageColne = baseImage.clone();Mat imgDiff1 = targetImage.clone();Mat imgDiff = targetImage.clone();/*** 首先将图片转成灰度图,*/cvtColor(targetImage, targetImageClone, COLOR_BGR2GRAY);cvtColor(baseImage, baseImageColne, COLOR_BGR2GRAY);/*** 两个矩阵相减,获得差异图。*/subtract(targetImageClone, baseImageColne, imgDiff1);subtract(baseImageColne, targetImageClone, imgDiff);/*** 按比重进行叠加。*/addWeighted(imgDiff, 1, imgDiff1, 1, 0, imgDiff);/*** 图片二值化,大于24的为1,小于24的为0*/threshold(imgDiff, imgDiff, 24, 255, THRESH_BINARY);erode(imgDiff, imgDiff, new Mat());dilate(imgDiff, imgDiff, new Mat());return 1-((double) countNonZero(imgDiff) / (imgDiff.size().height() * imgDiff.size().width()));}public static void main( String[] args ){String pic1="picture0.jpg";String pic2="picture1.jpg";String pic3="picture2.jpg";List<Mat> picMatList = new ArrayList<Mat>();picMatList.add(imread(pic1));picMatList.add(imread(pic2));picMatList.add(imread(pic3));mergePic(picMatList);}
}

 拼接结果:

对比上面的素材图片,这里实现了无缝拼接。

本文标签: 多张截图拼接成长图