| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 | /*    拼接的方法封装到 MatchPicRealtime(Mat matNew, Mat matBig)函数中。    函数执行流程:    1、采用OpenCvSharp.Feature2D.ORB的DetectAndCompute算法,检测和计算特征点。    2、采用OpenCvSharp.DescriptorMatcher.BFMatcher的KnnMatch算法,对检测出来的特征点进行匹配,得到DMatch对象的集合。    3、筛选DMatch对象的集合,计算得到横向距离差和纵向距离差。    4、对匹配的结果做过滤,将拼接好的图像返回。  */using OpenCvSharp;using System;using System.Collections.Generic;using System.Linq;namespace PaintDotNet.Adjust{    /// <summary>    /// 图像处理    /// </summary>    public unsafe class AdjustMethods    {        public static Mat LastMat;        public static double LastX;        public static double LastY;        private static Mat BackupMat;        private static Rect LastRect;        /// <summary>        /// 图像拼接方法,返回拼接好的mat        /// </summary>        /// <param name="matSrc">需要拼接的mat1</param>        /// <param name="matTo">需要拼接的mat2</param>        /// <param name="errorFlag">拼接成功/失败</param>        /// <param name="rect">拼接的矩形边框</param>        /// <returns></returns>        public static Mat MatchPicRealtime(Mat matSrc, Mat matTo, out Boolean errorFlag, out Rect rect)        {            errorFlag = false;            Mat mat = matSrc.Clone();            try            {                BackupMat = LastMat;                mat = MatchPicRealtime(matSrc, matTo);            }            catch (Exception)            {                LastMat = BackupMat;                errorFlag = true;            }            rect = LastRect;            return mat;        }        public static Mat MatchPicRealtime(Mat matNew, Mat matBig)        {            if (LastMat == null)            {                LastMat = matNew;                return matNew.Clone();            }            using (Mat matSrcRet = new Mat())            using (Mat matToRet = new Mat())            {                KeyPoint[] keyPointsSrc, keyPointsTo;                using (var surf = OpenCvSharp.ORB.Create(800))                {                    surf.DetectAndCompute(LastMat, null, out keyPointsSrc, matSrcRet);                    surf.DetectAndCompute(matNew, null, out keyPointsTo, matToRet);                    LastMat = matNew;                }                using (var bfMatcher = new OpenCvSharp.BFMatcher())//FlannBasedMatcher                {                    var matches = bfMatcher.KnnMatch(matSrcRet, matToRet, k: 2);                    var pointsSrc = new List<Point2f>();                    var pointsDst = new List<Point2f>();                    var goodMatches = new List<DMatch>();                    //数组按照元素个数由多到少排序                    var arrXMatches = new List<int>();                    var arrYMatches = new List<int>();                    float XCompute = 0; float YCompute = 0; int coutPt = 0;                    foreach (DMatch[] items in matches.Where(x => x.Length > 1))                    {                        if (items[0].Distance < 0.5 * items[1].Distance)                        {                            var X_dis = (keyPointsSrc[items[0].QueryIdx].Pt.X - keyPointsTo[items[0].TrainIdx].Pt.X);                            var Y_dis = (keyPointsSrc[items[0].QueryIdx].Pt.Y - keyPointsTo[items[0].TrainIdx].Pt.Y);                            arrXMatches.Add((int)X_dis);                            arrYMatches.Add((int)Y_dis);                        }                    }                    int[] arrX = arrXMatches.ToArray();                    int[] arrY = arrYMatches.ToArray();                    Array.Sort(arrX);                    Array.Sort(arrY);                    int valX1 = arrX[0];//当前                    int valX2 = 0;//上一个                    int timeX1 = 1;//当前                    int timeX2 = 0;//上一个                    for (int sortI = 1; sortI < arrX.Length; sortI++)                    {                        if (arrX[sortI] == valX1)                        {                            timeX1++;                        }                        else                        {                            if (timeX1 > timeX2)                            {                                valX2 = valX1;                                timeX2 = timeX1;                            }                            valX1 = arrX[sortI];                            timeX1 = 1;                        }                    }                    if (timeX1 > timeX2)                    {                        valX2 = valX1;                        timeX2 = timeX1;                    }                    int valY1 = arrY[0];//当前                    int valY2 = 0;//上一个                    int timeY1 = 1;//当前                    int timeY2 = 0;//上一个                    for (int sortI = 1; sortI < arrY.Length; sortI++)                    {                        if (arrY[sortI] == valY1)                        {                            timeY1++;                        }                        else                        {                            if (timeY1 > timeY2)                            {                                valY2 = valY1;                                timeY2 = timeY1;                            }                            valY1 = arrY[sortI];                            timeY1 = 1;                        }                    }                    if (timeY1 > timeY2)                    {                        valY2 = valY1;                        timeY2 = timeY1;                    }                    foreach (DMatch[] items in matches.Where(x => x.Length > 1))                    {                        if (items[0].Distance < 0.5 * items[1].Distance)                        {                            //pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt);                            //pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt);                            //goodMatches.Add(items[0]);                            var X_dis = (keyPointsSrc[items[0].QueryIdx].Pt.X - keyPointsTo[items[0].TrainIdx].Pt.X);                            var Y_dis = (keyPointsSrc[items[0].QueryIdx].Pt.Y - keyPointsTo[items[0].TrainIdx].Pt.Y);                            if ((valX2 >= X_dis - 5 && valX2 <= X_dis + 5) && (valY2 >= Y_dis - 5 && valY2 <= Y_dis + 5))                            {                                Console.WriteLine("横向距离差:{0} 纵向距离差:{1}", X_dis, Y_dis);                                pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt);                                pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt);                                goodMatches.Add(items[0]);                                //arrXMatches.Add((int)X_dis);                                ////arrYMatches.Add((int)Y_dis);                                coutPt++;                                XCompute += X_dis; YCompute += Y_dis;                            }                            else                            {                                Console.WriteLine("横向距离差:{0} 纵向距离差:{1} 舍弃", X_dis, Y_dis);                            }                        }                    }                    LastX += XCompute / coutPt;                    LastY += YCompute / coutPt;// 600;//                    //Console.WriteLine("平均横向距离差:{0}  平均纵向距离差:{1}", currentX, currentY);//计算原图像相对于新图像的(距离差)、-->变换矩阵                    var outMat = new Mat();                    // 算法RANSAC对匹配的结果做过滤                    var pSrc = pointsSrc.ConvertAll(Point2fToPoint2d);                    var pDst = pointsDst.ConvertAll(Point2fToPoint2d);                    var outMask = new Mat();                    var result = new Mat();                    // 如果原始的匹配结果为空, 则跳过过滤步骤                    if (pSrc.Count > 0 && pDst.Count > 0)                    {                        int srcOriX = 0;                        int srcOriY = 0;                        int newOriX = 0;                        int newOriY = 0;                        // Cv2.FindHomography(pSrc, pDst, HomographyMethods.Ransac, mask: outMask);                        //得到变换矩阵后拼接图像                        int viewWidth = matBig.Width;// 2448;                        int viewHeight = matBig.Height;// 2040;                        if (LastX <= 0)                        {                            viewWidth = (int)(viewWidth - LastX);                            srcOriX = (int)(-LastX);                            newOriX = 0;                            LastX = 0;                        }                        else                        {                            viewWidth = (int)Math.Max(LastX + matNew.Width, matBig.Width);                            newOriX = (int)LastX;                            //for (int i = 0; i < pDst.Count; i++)                            //{                            //    pDst[i] = new Point2d(pSrc[i].X, pDst[i].Y);                            //}                        }                        if (LastY <= 0)                        {                            viewHeight = (int)(viewHeight - LastY);                            srcOriY = (int)(-LastY);                            newOriY = 0;                            LastY = 0;                        }                        else                        {                            //for (int i = 0; i < pDst.Count; i++)                            //{                            //    pDst[i] = new Point2d(pDst[i].X, pSrc[i].Y);                            //}                            newOriY = (int)LastY;                            viewHeight = (int)Math.Max(matBig.Height, matNew.Height + LastY);                        }                        result = new Mat(new OpenCvSharp.Size(viewWidth, viewHeight), matNew.Type());                        //Rect rectSrc = new Rect(0, 0, matNew.Width, matNew.Height);                        //Mat tempMatSrc = matNew.Clone(rectSrc);                        Mat tempMatSrc = matNew.Clone();                        //复制原有区域part1(<--用户选中的区域)到新图像(<--原图像)                        Mat mask = tempMatSrc.CvtColor(ColorConversionCodes.RGBA2GRAY);                        Mat posSrc = new Mat(result, new Rect(newOriX, newOriY, matNew.Width, matNew.Height));                        tempMatSrc.CopyTo(posSrc, mask);//原图像复制到新图像                        //Rect rect = new Rect(0, 0, matBig.Width, matBig.Height);                        //Mat tempMat = matBig.Clone(rect);                        Mat tempMat = matBig.Clone();                        //复制原有区域part2(<--用户选中的区域)到新图像(<--原图像)                        mask = tempMat.CvtColor(ColorConversionCodes.RGBA2GRAY);                        Mat pos = new Mat(result, new Rect(srcOriX, srcOriY, matBig.Width, matBig.Height));                        tempMat.CopyTo(pos, mask);//原图像复制到新图像                        LastRect = new Rect(newOriX, newOriY, matNew.Width, matNew.Height);                        //Bitmap part2 = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(result);                        ////、、R3a                        //part2.Save(@"ResSurfA" + indexRes + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);                        return result;                    }                    result = matNew.Clone();                    return result;                }            }        }        private static Point2d Point2fToPoint2d(Point2f input)        {            Point2d p2 = new Point2d(input.X, input.Y);            return p2;        }    }}
 |