CameraImageStitchMethod.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /*
  2. 拼接的方法封装到 MatchPicRealtime(Mat matNew, Mat matBig)函数中。
  3. 函数执行流程:
  4. 1、采用OpenCvSharp.Feature2D.ORB的DetectAndCompute算法,检测和计算特征点。
  5. 2、采用OpenCvSharp.DescriptorMatcher.BFMatcher的KnnMatch算法,对检测出来的特征点进行匹配,得到DMatch对象的集合。
  6. 3、筛选DMatch对象的集合,计算得到横向距离差和纵向距离差。
  7. 4、对匹配的结果做过滤,将拼接好的图像返回。
  8. */
  9. using OpenCvSharp;
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Linq;
  13. namespace PaintDotNet.Adjust
  14. {
  15. /// <summary>
  16. /// 图像处理
  17. /// </summary>
  18. public unsafe class AdjustMethods
  19. {
  20. public static Mat LastMat;
  21. public static double LastX;
  22. public static double LastY;
  23. private static Mat BackupMat;
  24. private static Rect LastRect;
  25. /// <summary>
  26. /// 图像拼接方法,返回拼接好的mat
  27. /// </summary>
  28. /// <param name="matSrc">需要拼接的mat1</param>
  29. /// <param name="matTo">需要拼接的mat2</param>
  30. /// <param name="errorFlag">拼接成功/失败</param>
  31. /// <param name="rect">拼接的矩形边框</param>
  32. /// <returns></returns>
  33. public static Mat MatchPicRealtime(Mat matSrc, Mat matTo, out Boolean errorFlag, out Rect rect)
  34. {
  35. errorFlag = false;
  36. Mat mat = matSrc.Clone();
  37. try
  38. {
  39. BackupMat = LastMat;
  40. mat = MatchPicRealtime(matSrc, matTo);
  41. }
  42. catch (Exception)
  43. {
  44. LastMat = BackupMat;
  45. errorFlag = true;
  46. }
  47. rect = LastRect;
  48. return mat;
  49. }
  50. public static Mat MatchPicRealtime(Mat matNew, Mat matBig)
  51. {
  52. if (LastMat == null)
  53. {
  54. LastMat = matNew;
  55. return matNew.Clone();
  56. }
  57. using (Mat matSrcRet = new Mat())
  58. using (Mat matToRet = new Mat())
  59. {
  60. KeyPoint[] keyPointsSrc, keyPointsTo;
  61. using (var surf = OpenCvSharp.ORB.Create(800))
  62. {
  63. surf.DetectAndCompute(LastMat, null, out keyPointsSrc, matSrcRet);
  64. surf.DetectAndCompute(matNew, null, out keyPointsTo, matToRet);
  65. LastMat = matNew;
  66. }
  67. using (var bfMatcher = new OpenCvSharp.BFMatcher())//FlannBasedMatcher
  68. {
  69. var matches = bfMatcher.KnnMatch(matSrcRet, matToRet, k: 2);
  70. var pointsSrc = new List<Point2f>();
  71. var pointsDst = new List<Point2f>();
  72. var goodMatches = new List<DMatch>();
  73. //数组按照元素个数由多到少排序
  74. var arrXMatches = new List<int>();
  75. var arrYMatches = new List<int>();
  76. float XCompute = 0; float YCompute = 0; int coutPt = 0;
  77. foreach (DMatch[] items in matches.Where(x => x.Length > 1))
  78. {
  79. if (items[0].Distance < 0.5 * items[1].Distance)
  80. {
  81. var X_dis = (keyPointsSrc[items[0].QueryIdx].Pt.X - keyPointsTo[items[0].TrainIdx].Pt.X);
  82. var Y_dis = (keyPointsSrc[items[0].QueryIdx].Pt.Y - keyPointsTo[items[0].TrainIdx].Pt.Y);
  83. arrXMatches.Add((int)X_dis);
  84. arrYMatches.Add((int)Y_dis);
  85. }
  86. }
  87. int[] arrX = arrXMatches.ToArray();
  88. int[] arrY = arrYMatches.ToArray();
  89. Array.Sort(arrX);
  90. Array.Sort(arrY);
  91. int valX1 = arrX[0];//当前
  92. int valX2 = 0;//上一个
  93. int timeX1 = 1;//当前
  94. int timeX2 = 0;//上一个
  95. for (int sortI = 1; sortI < arrX.Length; sortI++)
  96. {
  97. if (arrX[sortI] == valX1)
  98. {
  99. timeX1++;
  100. }
  101. else
  102. {
  103. if (timeX1 > timeX2)
  104. {
  105. valX2 = valX1;
  106. timeX2 = timeX1;
  107. }
  108. valX1 = arrX[sortI];
  109. timeX1 = 1;
  110. }
  111. }
  112. if (timeX1 > timeX2)
  113. {
  114. valX2 = valX1;
  115. timeX2 = timeX1;
  116. }
  117. int valY1 = arrY[0];//当前
  118. int valY2 = 0;//上一个
  119. int timeY1 = 1;//当前
  120. int timeY2 = 0;//上一个
  121. for (int sortI = 1; sortI < arrY.Length; sortI++)
  122. {
  123. if (arrY[sortI] == valY1)
  124. {
  125. timeY1++;
  126. }
  127. else
  128. {
  129. if (timeY1 > timeY2)
  130. {
  131. valY2 = valY1;
  132. timeY2 = timeY1;
  133. }
  134. valY1 = arrY[sortI];
  135. timeY1 = 1;
  136. }
  137. }
  138. if (timeY1 > timeY2)
  139. {
  140. valY2 = valY1;
  141. timeY2 = timeY1;
  142. }
  143. foreach (DMatch[] items in matches.Where(x => x.Length > 1))
  144. {
  145. if (items[0].Distance < 0.5 * items[1].Distance)
  146. {
  147. //pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt);
  148. //pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt);
  149. //goodMatches.Add(items[0]);
  150. var X_dis = (keyPointsSrc[items[0].QueryIdx].Pt.X - keyPointsTo[items[0].TrainIdx].Pt.X);
  151. var Y_dis = (keyPointsSrc[items[0].QueryIdx].Pt.Y - keyPointsTo[items[0].TrainIdx].Pt.Y);
  152. if ((valX2 >= X_dis - 5 && valX2 <= X_dis + 5) && (valY2 >= Y_dis - 5 && valY2 <= Y_dis + 5))
  153. {
  154. Console.WriteLine("横向距离差:{0} 纵向距离差:{1}", X_dis, Y_dis);
  155. pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt);
  156. pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt);
  157. goodMatches.Add(items[0]);
  158. //arrXMatches.Add((int)X_dis);
  159. ////arrYMatches.Add((int)Y_dis);
  160. coutPt++;
  161. XCompute += X_dis; YCompute += Y_dis;
  162. }
  163. else
  164. {
  165. Console.WriteLine("横向距离差:{0} 纵向距离差:{1} 舍弃", X_dis, Y_dis);
  166. }
  167. }
  168. }
  169. LastX += XCompute / coutPt;
  170. LastY += YCompute / coutPt;// 600;//
  171. //Console.WriteLine("平均横向距离差:{0} 平均纵向距离差:{1}", currentX, currentY);//计算原图像相对于新图像的(距离差)、-->变换矩阵
  172. var outMat = new Mat();
  173. // 算法RANSAC对匹配的结果做过滤
  174. var pSrc = pointsSrc.ConvertAll(Point2fToPoint2d);
  175. var pDst = pointsDst.ConvertAll(Point2fToPoint2d);
  176. var outMask = new Mat();
  177. var result = new Mat();
  178. // 如果原始的匹配结果为空, 则跳过过滤步骤
  179. if (pSrc.Count > 0 && pDst.Count > 0)
  180. {
  181. int srcOriX = 0;
  182. int srcOriY = 0;
  183. int newOriX = 0;
  184. int newOriY = 0;
  185. // Cv2.FindHomography(pSrc, pDst, HomographyMethods.Ransac, mask: outMask);
  186. //得到变换矩阵后拼接图像
  187. int viewWidth = matBig.Width;// 2448;
  188. int viewHeight = matBig.Height;// 2040;
  189. if (LastX <= 0)
  190. {
  191. viewWidth = (int)(viewWidth - LastX);
  192. srcOriX = (int)(-LastX);
  193. newOriX = 0;
  194. LastX = 0;
  195. }
  196. else
  197. {
  198. viewWidth = (int)Math.Max(LastX + matNew.Width, matBig.Width);
  199. newOriX = (int)LastX;
  200. //for (int i = 0; i < pDst.Count; i++)
  201. //{
  202. // pDst[i] = new Point2d(pSrc[i].X, pDst[i].Y);
  203. //}
  204. }
  205. if (LastY <= 0)
  206. {
  207. viewHeight = (int)(viewHeight - LastY);
  208. srcOriY = (int)(-LastY);
  209. newOriY = 0;
  210. LastY = 0;
  211. }
  212. else
  213. {
  214. //for (int i = 0; i < pDst.Count; i++)
  215. //{
  216. // pDst[i] = new Point2d(pDst[i].X, pSrc[i].Y);
  217. //}
  218. newOriY = (int)LastY;
  219. viewHeight = (int)Math.Max(matBig.Height, matNew.Height + LastY);
  220. }
  221. result = new Mat(new OpenCvSharp.Size(viewWidth, viewHeight), matNew.Type());
  222. //Rect rectSrc = new Rect(0, 0, matNew.Width, matNew.Height);
  223. //Mat tempMatSrc = matNew.Clone(rectSrc);
  224. Mat tempMatSrc = matNew.Clone();
  225. //复制原有区域part1(<--用户选中的区域)到新图像(<--原图像)
  226. Mat mask = tempMatSrc.CvtColor(ColorConversionCodes.RGBA2GRAY);
  227. Mat posSrc = new Mat(result, new Rect(newOriX, newOriY, matNew.Width, matNew.Height));
  228. tempMatSrc.CopyTo(posSrc, mask);//原图像复制到新图像
  229. //Rect rect = new Rect(0, 0, matBig.Width, matBig.Height);
  230. //Mat tempMat = matBig.Clone(rect);
  231. Mat tempMat = matBig.Clone();
  232. //复制原有区域part2(<--用户选中的区域)到新图像(<--原图像)
  233. mask = tempMat.CvtColor(ColorConversionCodes.RGBA2GRAY);
  234. Mat pos = new Mat(result, new Rect(srcOriX, srcOriY, matBig.Width, matBig.Height));
  235. tempMat.CopyTo(pos, mask);//原图像复制到新图像
  236. LastRect = new Rect(newOriX, newOriY, matNew.Width, matNew.Height);
  237. //Bitmap part2 = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(result);
  238. ////、、R3a
  239. //part2.Save(@"ResSurfA" + indexRes + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
  240. return result;
  241. }
  242. result = matNew.Clone();
  243. return result;
  244. }
  245. }
  246. }
  247. private static Point2d Point2fToPoint2d(Point2f input)
  248. {
  249. Point2d p2 = new Point2d(input.X, input.Y);
  250. return p2;
  251. }
  252. }
  253. }