StitchingController.cs 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. using OpenCvSharp.Extensions;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Drawing;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading;
  8. using System.Threading.Tasks;
  9. namespace PaintDotNet.Adjust
  10. {
  11. public class StitchingController
  12. {
  13. public int MathSelect = 3;
  14. /// <summary>
  15. /// 一次:0/连续:1
  16. /// </summary>
  17. public int Mode;
  18. public int State;
  19. /// <summary>
  20. /// 列数
  21. /// </summary>
  22. public readonly int RowN;
  23. /// <summary>
  24. /// 列数
  25. /// </summary>
  26. public readonly int ColumnN;
  27. /// <summary>
  28. /// 拼接率
  29. /// </summary>
  30. public readonly double StitchRate;
  31. Queue<Bitmap> _matBuffer = new Queue<Bitmap>();
  32. public List<Point> _offsetList;
  33. int _counterSum;
  34. int _counterDone;
  35. public Bitmap _img0;
  36. public Bitmap _img1;
  37. public int ImageWidth;
  38. public int ImageHeight;
  39. public OpenCvSharp.Mat _matResult;
  40. public System.Drawing.Bitmap Result
  41. {
  42. get { lock (lockobj) { return _matResult == null ? null : BitmapConverter.ToBitmap(_matResult); } }
  43. }
  44. public OpenCvSharp.Mat ResultMat
  45. {
  46. get { lock (lockobj) { return _matResult == null ? null : _matResult.Clone(); } }
  47. }
  48. public bool IsDone { get; private set; } = false;
  49. public Task StitchingTask;
  50. public StitchingController(int columnN, int rowN, double stitchRate)
  51. {
  52. ColumnN = columnN;
  53. RowN = rowN;
  54. StitchRate = stitchRate;
  55. Mode = 1;
  56. }
  57. public StitchingController(int columnN, double stitichRate, Bitmap[] mats)
  58. {
  59. ColumnN = columnN;
  60. RowN = mats.Length / ColumnN;
  61. foreach (var mat in mats) Add(mat);
  62. Mode = 0;
  63. }
  64. public void Add(Bitmap mat)
  65. {
  66. if (_counterDone == 0)//第一张
  67. {
  68. _img1 = mat;
  69. ImageWidth = mat.Width;
  70. ImageHeight = mat.Height;
  71. _matResult = BitmapConverter.ToMat(mat);
  72. _counterDone++;
  73. }
  74. else
  75. {
  76. _matBuffer.Enqueue(mat);
  77. }
  78. _counterSum++;
  79. }
  80. public void Start()
  81. {
  82. StitchingTask = new Task(Runtime);
  83. StitchingTask.Start();
  84. }
  85. public void Stop()
  86. {
  87. IsDone = true;
  88. }
  89. public void Runtime()
  90. {
  91. while (!IsDone)
  92. {
  93. if (Mode == 1 && _counterDone == ColumnN * RowN)
  94. {
  95. Stop();
  96. return;
  97. }
  98. if (_matBuffer.Count == 0)
  99. {
  100. if (Mode == 0)
  101. {
  102. Stop();
  103. return;
  104. }
  105. Thread.Sleep(50);
  106. }
  107. else
  108. {
  109. _img0 = _matBuffer.Dequeue();
  110. Stitch();
  111. _img1 = _img0;
  112. _counterDone++;
  113. }
  114. }
  115. }
  116. public void SynRun()
  117. {
  118. if (_matBuffer.Count == 0)
  119. {
  120. if (Mode == 0)
  121. {
  122. Stop();
  123. return;
  124. }
  125. }
  126. else
  127. {
  128. _img0 = _matBuffer.Dequeue();
  129. Stitch();
  130. _img1 = _img0;
  131. _counterDone++;
  132. }
  133. if (_counterDone == ColumnN * RowN)
  134. {
  135. Stop();
  136. }
  137. }
  138. public void Stitch()
  139. {
  140. bool error = true;
  141. Point movep = new Point(0, 0);
  142. int dir = Dir();
  143. Bitmap img0;
  144. Bitmap img1;
  145. //切图
  146. {
  147. switch (dir)
  148. {
  149. case 1:
  150. LastX += (int)(ImageWidth * (1 - StitchRate));
  151. img0 = AdjustIntent.Cut(_img0, StitchRate, AdjustIntent.Side.Left);
  152. img1 = AdjustIntent.Cut(_img1, StitchRate, AdjustIntent.Side.Right);
  153. break;
  154. case 2:
  155. LastY += (int)(ImageHeight * (1 - StitchRate));
  156. img0 = AdjustIntent.Cut(_img0, StitchRate, AdjustIntent.Side.Top);
  157. img1 = AdjustIntent.Cut(_img1, StitchRate, AdjustIntent.Side.Buttom);
  158. break;
  159. case 3:
  160. LastX -= (int)(ImageWidth * (1 - StitchRate));
  161. img0 = AdjustIntent.Cut(_img0, StitchRate, AdjustIntent.Side.Right);
  162. img1 = AdjustIntent.Cut(_img1, StitchRate, AdjustIntent.Side.Left);
  163. break;
  164. default:
  165. img0 = _img0;
  166. img1 = _img1;
  167. break;
  168. }
  169. }
  170. //拼接算法 1
  171. if (error && (MathSelect & 1) > 0)
  172. {
  173. int orbCount = img0.Width * img0.Height / 40000;
  174. movep = AdjustIntent.MatchOneBySift(
  175. BitmapConverter.ToMat(img0), BitmapConverter.ToMat(img1), out error, orbCount, 0.1, dir);
  176. }
  177. ////拼接算法 2
  178. if (error && (MathSelect & 2) > 0)
  179. {
  180. movep = VisualMath.Tools.MatchByAccordDotNet(img0, img1, out error);
  181. }
  182. //按位置偏移
  183. if (error)
  184. {
  185. #region 计算偏移
  186. movep = new Point(0, 0);
  187. }
  188. #endregion
  189. #region 拼接图片
  190. lock (lockobj)
  191. _matResult = MatMerge(BitmapConverter.ToMat(_img0), _matResult, movep);
  192. #endregion
  193. }
  194. private int LastX;
  195. private int LastY;
  196. private object lockobj = new object();
  197. /// <summary>
  198. /// 计算拼接方向
  199. /// </summary>
  200. /// <returns>[1]右;[2]下;[3]左</returns>
  201. private int Dir()
  202. {
  203. var rowIndex = _counterDone / ColumnN;
  204. var colIndex = _counterDone % ColumnN;
  205. var directionRect = 1;
  206. if (colIndex == 0)
  207. {
  208. directionRect = 2;
  209. }
  210. else if (rowIndex % 2 == 1)
  211. {
  212. directionRect = 3;
  213. }
  214. return directionRect;
  215. }
  216. private Point DefaultOffset()
  217. {
  218. int x = (int)(ImageWidth * StitchRate);
  219. int y = (int)(ImageHeight * StitchRate);
  220. int dir = Dir();
  221. switch (dir)
  222. {
  223. case 1:
  224. return new Point(x, 0);
  225. case 2:
  226. return new Point(0, y);
  227. case 3:
  228. return new Point(-x, 0);
  229. default:
  230. return new Point(0, 0);
  231. }
  232. }
  233. /// <summary>
  234. /// 等待拼图全部完成
  235. /// </summary>
  236. public void Wait()
  237. {
  238. while (!IsDone)
  239. {
  240. Thread.Sleep(50);
  241. }
  242. }
  243. public void Dispose()
  244. {
  245. IsDone = true;
  246. Wait();
  247. _matResult.Dispose();
  248. GC.Collect();
  249. }
  250. /// <summary>
  251. /// 利用Opencv 将新图贴到大图上
  252. /// </summary>
  253. /// <param name="matNew"></param>
  254. /// <param name="matBig"></param>
  255. /// <param name="point"></param>
  256. /// <returns></returns>
  257. public OpenCvSharp.Mat MatMerge(OpenCvSharp.Mat matNew, OpenCvSharp.Mat matBig, System.Drawing.Point point)
  258. {
  259. //LastX -= point.X;
  260. //LastY -= point.Y;
  261. var result = new OpenCvSharp.Mat();
  262. int srcOriX = 0;
  263. int srcOriY = 0;
  264. int newOriX = 0;
  265. int newOriY = 0;
  266. //得到变换矩阵后拼接图像
  267. int viewWidth = matBig.Width;// 2448;
  268. int viewHeight = matBig.Height;// 2040;
  269. if (LastX <= 0)
  270. {
  271. viewWidth = (int)(viewWidth - LastX);
  272. srcOriX = (int)(-LastX);
  273. newOriX = 0;
  274. LastX = 0;
  275. }
  276. else
  277. {
  278. viewWidth = (int)Math.Max(LastX + matNew.Width, matBig.Width);
  279. newOriX = (int)LastX;
  280. }
  281. if (LastY <= 0)
  282. {
  283. viewHeight = (int)(viewHeight - LastY);
  284. srcOriY = (int)(-LastY);
  285. newOriY = 0;
  286. LastY = 0;
  287. }
  288. else
  289. {
  290. newOriY = (int)LastY;
  291. viewHeight = (int)Math.Max(matBig.Height, matNew.Height + LastY);
  292. }
  293. result = new OpenCvSharp.Mat(new OpenCvSharp.Size(viewWidth, viewHeight), matNew.Type());
  294. OpenCvSharp.Mat tempMatSrc = matNew.Clone();
  295. //复制原有区域part1(<--用户选中的区域)到新图像(<--原图像)
  296. OpenCvSharp.Mat mask = tempMatSrc.CvtColor(OpenCvSharp.ColorConversionCodes.RGBA2GRAY);
  297. OpenCvSharp.Mat posSrc = new OpenCvSharp.Mat(result, new OpenCvSharp.Rect(newOriX, newOriY, matNew.Width, matNew.Height));
  298. tempMatSrc.CopyTo(posSrc, mask);//原图像复制到新图像
  299. OpenCvSharp.Mat tempMat = matBig.Clone();
  300. //复制原有区域part2(<--用户选中的区域)到新图像(<--原图像)
  301. mask = tempMat.CvtColor(OpenCvSharp.ColorConversionCodes.RGBA2GRAY);
  302. OpenCvSharp.Mat pos = new OpenCvSharp.Mat(result, new OpenCvSharp.Rect(srcOriX, srcOriY, matBig.Width, matBig.Height));
  303. tempMat.CopyTo(pos, mask);//原图像复制到新图像
  304. return result;
  305. }
  306. }
  307. }