拼接有多个意思,有的只是简单的两个图片怼成一张图,比如这样:
怼成这样:
OpenCVSharp 有这样的函数,简单说一下,就不上完整代码了:
//上下拼接 两图像宽度必须一样
Cv2.VConcat(srcImg1, srcImg2, ret);
//左右拼接 两图像高度必须一样
Cv2.HConcat(srcImg1, srcImg2, ret);
但多数时候,我们要拼接的图像们之间是有重合的部分,比如这样:
对于这种场景,OpenCVSharp 提供了一个用于 图像拼接的 拼接器 Stitcher:
//智能拼接,图像们有共同的重叠部分
Mat srcImg2 = new Mat(strImg2);
Mat srcImg3 = new Mat(strImg3);
Mat[] images = new Mat[] { srcImg2, srcImg3 }; //数量两个以上
Stitcher stitcher = Stitcher.Create(Stitcher.Mode.Scans);
Mat pano = new Mat();
var status = stitcher.Stitch(images, pano);
if (status != Stitcher.Status.OK)
{
Console.WriteLine("失败:" + status.ToString());
return;
}
Stitcher 对于没有透视变形的图片们拼接效果较好,如果有透视变形,就不适用了,因为它会发生这样的事情:
虽然是拼到一起了,但因为两个照片是从不同的视角拍的,拼接后的图像是扭曲的,我们可能更想要这样的效果:
这时我们就要用到 基于特征的图像拼接:
int w = img2.Width;
int h = img2.Height;
Mat img0 = new Mat(new Size(w * 2, h * 2), img2.Type());
img0[0, h, w, w + w] = img2;
ORB orb = ORB.Create(10000);
Mat dscrip1 = new Mat();
Mat dscrip2 = new Mat();
orb.DetectAndCompute(img1, null, out KeyPoint[] keyPoint1, dscrip1);
orb.DetectAndCompute(img0, null, out KeyPoint[] keyPoint2, dscrip2);
// 暴力匹配
BFMatcher matcher = new BFMatcher(NormTypes.Hamming, true);
DMatch[] match = matcher.Match(dscrip1, dscrip2);
match = match.OrderBy(x => x.Distance).ToArray();
var goodmatch = match.Take(1600);
if (goodmatch.Count() < 4) return;
//画出匹配关系
Mat outImg = new Mat();
Cv2.DrawMatches(img1, keyPoint1, img0, keyPoint2, goodmatch, outImg, flags: DrawMatchesFlags.DrawRichKeypoints | DrawMatchesFlags.NotDrawSinglePoints);
Cv2.ImShow("ORB", outImg);
// 提取匹配的位置
var pointsSrc = new List();
var pointsDst = new List();
foreach (var m in goodmatch)
{
pointsSrc.Add(keyPoint1[m.QueryIdx].Pt);
pointsDst.Add(keyPoint2[m.TrainIdx].Pt);
}
var pSrc = pointsSrc.ConvertAll(Point2fToPoint2d);
var pDst = pointsDst.ConvertAll(Point2fToPoint2d);
//获得变换矩阵
var M = Cv2.FindHomography(pSrc, pDst, HomographyMethods.Ransac);
Console.WriteLine(M);
Console.WriteLine(Cv2.Format(M));
// 对 img1 透视变换
var result = new Mat();
Cv2.WarpPerspective(img1, result, M, new Size(w * 2, h * 2));
// 将img2拼接到结果
result[0, h, w, w + w] = img2;