ImageStitchUsingOpenCvSharp.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. namespace OTSMeasureApp.ServiceCenter
  7. {
  8. using OpenCvSharp;
  9. public class ImageStitchUsingOpenCvSharp
  10. {
  11. #region 合并天宇颗粒融合新增函数
  12. public Mat CombinImageX(Mat[] list_mats, int OverlapParam, int type)
  13. {
  14. List<Mat> matStitch = new List<Mat>();//拼接
  15. List<Mat> matCombin = new List<Mat>();//合并
  16. for (int i = 0; i < list_mats.Count(); i++)
  17. {
  18. if (i == 0)//首张
  19. {
  20. matCombin.Add(new Mat(list_mats[i], new OpenCvSharp.Rect(0, 0, list_mats[i].Width - OverlapParam - 100, list_mats[i].Height)));
  21. matStitch.Add(new Mat(list_mats[i], new OpenCvSharp.Rect(list_mats[i].Width - OverlapParam - 100, 0, OverlapParam + 100, list_mats[i].Height)));
  22. }
  23. else if (i == list_mats.Count() - 1)//末张
  24. {
  25. matStitch.Add(new Mat(list_mats[i], new OpenCvSharp.Rect(0, 0, OverlapParam + 100, list_mats[i].Height)));
  26. matCombin.Add(new Mat(list_mats[i], new OpenCvSharp.Rect(OverlapParam + 100, 0, list_mats[i].Width - OverlapParam - 100, list_mats[i].Height)));
  27. }
  28. else
  29. {
  30. matStitch.Add(new Mat(list_mats[i], new OpenCvSharp.Rect(0, 0, OverlapParam + 100, list_mats[i].Height)));
  31. matCombin.Add(new Mat(list_mats[i], new OpenCvSharp.Rect(OverlapParam + 100, 0, list_mats[i].Width - (OverlapParam + 100) * 2, list_mats[i].Height)));
  32. matStitch.Add(new Mat(list_mats[i], new OpenCvSharp.Rect(list_mats[i].Width - OverlapParam - 100, 0, OverlapParam + 100, list_mats[i].Height)));
  33. }
  34. }
  35. for (int i = 0; i < matStitch.Count; i += 2)
  36. {
  37. if (matStitch.Count == 1)
  38. {
  39. matCombin.Insert(i + 1, matStitch[i]);
  40. }
  41. else
  42. {
  43. matCombin.Insert(i + 1, StitchImageX((int)(OverlapParam / 2 * 1.2), type, matStitch[i], matStitch[i + 1]));
  44. }
  45. }
  46. Mat pano = new OpenCvSharp.Mat();
  47. Cv2.HConcat(matCombin.ToArray(), pano);
  48. return pano;
  49. }
  50. public Mat CombinImageY(Mat[] list_mats, int OverlapParam, int type)
  51. {
  52. List<Mat> matStitch = new List<Mat>();//拼接
  53. List<Mat> matCombin = new List<Mat>();//合并
  54. for (int i = 0; i < list_mats.Count(); i++)
  55. {
  56. if (i == 0)//首张
  57. {
  58. matCombin.Add(new Mat(list_mats[i], new OpenCvSharp.Rect(0, 0, list_mats[i].Width, list_mats[i].Height - OverlapParam - 100)));
  59. matStitch.Add(new Mat(list_mats[i], new OpenCvSharp.Rect(0, list_mats[i].Height - OverlapParam - 100, list_mats[i].Width, OverlapParam + 100)));
  60. }
  61. else if (i == list_mats.Count() - 1)//末张
  62. {
  63. matStitch.Add(new Mat(list_mats[i], new OpenCvSharp.Rect(0, 0, list_mats[i].Width, OverlapParam + 100)));
  64. matCombin.Add(new Mat(list_mats[i], new OpenCvSharp.Rect(0, OverlapParam + 100, list_mats[i].Width, list_mats[i].Height - OverlapParam - 100)));
  65. }
  66. else
  67. {
  68. matStitch.Add(new Mat(list_mats[i], new OpenCvSharp.Rect(0, 0, list_mats[i].Width, OverlapParam + 100)));
  69. matCombin.Add(new Mat(list_mats[i], new OpenCvSharp.Rect(0, OverlapParam + 100, list_mats[i].Width, list_mats[i].Height - (OverlapParam + 100) * 2)));
  70. matStitch.Add(new Mat(list_mats[i], new OpenCvSharp.Rect(0, list_mats[i].Height - OverlapParam - 100, list_mats[i].Width, OverlapParam + 100)));
  71. }
  72. }
  73. for (int i = 0; i < matStitch.Count; i += 2)
  74. {
  75. if (matStitch.Count == 1)
  76. {
  77. matCombin.Insert(i + 1, matStitch[i]);
  78. }
  79. else
  80. {
  81. matCombin.Insert(i + 1, StitchImageY(OverlapParam, type, matStitch[i], matStitch[i + 1]));
  82. }
  83. }
  84. Mat pano = new OpenCvSharp.Mat();
  85. Cv2.VConcat(matCombin.ToArray(), pano);
  86. return pano;
  87. }
  88. public struct MStitch
  89. {
  90. public int Pwidth;//单幅图像的宽度
  91. public int Pheight;//单幅图像的高度
  92. public int W_min;//最小的重叠区域宽度
  93. public int W_max;//最大的重叠区域宽度
  94. public int H_min;//最小的重叠区域高度
  95. public double minval;//块过滤阈值
  96. public Mat im;//图像信息
  97. }
  98. public struct ImageParam
  99. {
  100. public int W_box;//宽度信息
  101. public int H_box;//高度信息
  102. public int bdown;//上下信息
  103. public MStitch mStitch; //参数结构
  104. public Mat im;//图像信息
  105. }
  106. /// <summary>
  107. /// 横向拼图
  108. /// </summary>
  109. public Mat StitchImageXGrid(int min_w, int type, Mat newImg1, Mat newImg2)
  110. {
  111. MStitch mStitch = new MStitch();
  112. mStitch.Pwidth = newImg1.Width;
  113. mStitch.Pheight = newImg1.Height;
  114. mStitch.W_min = min_w - 50;
  115. mStitch.W_max = min_w + 50;
  116. mStitch.H_min = newImg1.Height;
  117. mStitch.minval = 255;
  118. mStitch.im = newImg1;
  119. ImageParam imageParam = Fun_Match(newImg2, mStitch);
  120. imageParam.im = newImg2;
  121. if (type == 3)
  122. {
  123. return Fun_Stitch(imageParam);
  124. }
  125. else
  126. {
  127. return Fun_StitchRGB(imageParam);
  128. }
  129. }
  130. /// <summary>
  131. /// 纵向拼图
  132. /// </summary>
  133. public Mat StitchImageYGrid(int min_w, int type, Mat newImg1, Mat newImg2)
  134. {
  135. Cv2.Transpose(newImg1, newImg1);
  136. Cv2.Flip(newImg1, newImg1, FlipMode.X);
  137. Cv2.Transpose(newImg2, newImg2);
  138. Cv2.Flip(newImg2, newImg2, FlipMode.X);
  139. MStitch mStitch = new MStitch();
  140. mStitch.Pwidth = newImg1.Width;
  141. mStitch.Pheight = newImg1.Height;
  142. mStitch.W_min = min_w - 50;
  143. mStitch.W_max = min_w + 50;
  144. mStitch.H_min = newImg1.Height;
  145. mStitch.minval = 255;
  146. mStitch.im = newImg1;
  147. ImageParam imageParam = Fun_Match(newImg2, mStitch);
  148. imageParam.im = newImg2;
  149. Mat result = type == 3 ? Fun_Stitch(imageParam) : Fun_StitchRGB(imageParam);
  150. Cv2.Transpose(result, result);
  151. Cv2.Flip(result, result, FlipMode.Y);
  152. return result;
  153. }
  154. /// <summary>
  155. /// 横向拼图
  156. /// </summary>
  157. public Mat StitchImageX(int min_w, int type, Mat newImg1, Mat newImg2)
  158. {
  159. MStitch mStitch = new MStitch();
  160. mStitch.Pwidth = newImg1.Width;
  161. mStitch.Pheight = newImg1.Height;
  162. mStitch.W_min = min_w;
  163. mStitch.W_max = min_w;
  164. mStitch.H_min = newImg1.Height;
  165. mStitch.minval = 255;
  166. mStitch.im = newImg1;
  167. ImageParam imageParam = Fun_Match(newImg2, mStitch);
  168. imageParam.im = newImg2;
  169. if (type == 3)
  170. {
  171. return Fun_Stitch(imageParam);
  172. }
  173. else
  174. {
  175. return Fun_StitchRGB(imageParam);
  176. }
  177. }
  178. /// <summary>
  179. /// 纵向拼图
  180. /// </summary>
  181. public Mat StitchImageY(int min_w, int type, Mat newImg1, Mat newImg2)
  182. {
  183. Cv2.Transpose(newImg1, newImg1);
  184. Cv2.Flip(newImg1, newImg1, FlipMode.X);
  185. Cv2.Transpose(newImg2, newImg2);
  186. Cv2.Flip(newImg2, newImg2, FlipMode.X);
  187. MStitch mStitch = new MStitch();
  188. mStitch.Pwidth = newImg1.Width;
  189. mStitch.Pheight = newImg1.Height;
  190. mStitch.W_min = min_w - 50;
  191. mStitch.W_max = min_w - 50;
  192. mStitch.H_min = newImg1.Height - 20;
  193. mStitch.minval = 255;
  194. mStitch.im = newImg1;
  195. ImageParam imageParam = Fun_Match(newImg2, mStitch);
  196. imageParam.im = newImg2;
  197. Mat result = type == 2 ? Fun_Stitch(imageParam) : Fun_StitchRGB(imageParam);
  198. Cv2.Transpose(result, result);
  199. Cv2.Flip(result, result, FlipMode.Y);
  200. return result;
  201. }
  202. public static ImageParam Fun_Match(Mat im2, MStitch mStitch)
  203. {
  204. ImageParam imageParam = new ImageParam();
  205. double imsum = 0;
  206. int x1 = 0;
  207. int y1 = 0;
  208. int x2 = 0;
  209. int y2 = 0;
  210. int w_ind = 0;
  211. int h_ind = 0; //
  212. for (int w = mStitch.W_min; w <= mStitch.W_max; w++)
  213. {
  214. for (int h = mStitch.H_min; h <= mStitch.Pheight; h++)
  215. {
  216. imsum = 0;//块差分集初始化
  217. x2 = 1;
  218. for (x1 = mStitch.Pwidth - w; x1 <= mStitch.Pwidth; x1 += 5)
  219. {
  220. y2 = 1;
  221. for (y1 = mStitch.Pheight - h + 1; y1 <= mStitch.Pheight; y1 += 5)
  222. {
  223. //块差分集计算
  224. CheckRC(ref x1, ref y1, mStitch.im);
  225. CheckRC(ref x2, ref y2, im2);
  226. imsum = imsum + Math.Abs(mStitch.im.At<Vec3b>(y1, x1).Item0 - im2.At<Vec3b>(y2, x2).Item0);
  227. y2 = y2 + 5;
  228. }
  229. x2 = x2 + 5;
  230. }
  231. //阈值更新
  232. if (imsum * 5 * 5 <= mStitch.minval * w * h)
  233. {
  234. mStitch.minval = imsum * 5 * 5 / (w * h);
  235. w_ind = w;
  236. h_ind = h;
  237. }
  238. }
  239. }
  240. imageParam.W_box = w_ind;
  241. imageParam.H_box = h_ind;
  242. imageParam.bdown = 1;
  243. //在下窗口所有匹配块内进行搜索
  244. Parallel.For(mStitch.W_min, mStitch.W_max, w =>
  245. {
  246. Parallel.For(mStitch.H_min, mStitch.Pheight, h =>
  247. {
  248. imsum = 0;//块差分集初始化
  249. x2 = 1;
  250. for (x1 = mStitch.Pwidth - w; x1 <= mStitch.Pwidth; x1 += 5)
  251. {
  252. y1 = 1;
  253. for (y2 = mStitch.Pheight - h + 1; y2 <= mStitch.Pheight; y2 += 5)
  254. {
  255. //块差分集计算
  256. CheckRC(ref x1, ref y1, mStitch.im);
  257. CheckRC(ref x2, ref y2, im2);
  258. imsum = imsum + Math.Abs(mStitch.im.At<Vec3b>(y1, x1).Item0 - im2.At<Vec3b>(y2, x2).Item0);
  259. y1 = y1 + 5;
  260. }
  261. x2 = x2 + 5;
  262. }
  263. //阈值更新
  264. if (imsum * 5 * 5 <= mStitch.minval * w * h)
  265. {
  266. mStitch.minval = imsum * 5 * 5 / (w * h);
  267. w_ind = w;
  268. h_ind = h;
  269. imageParam.bdown = 0;
  270. }
  271. });
  272. });
  273. imageParam.mStitch = mStitch;
  274. return imageParam;
  275. }
  276. public static void CheckRC(ref int x, ref int y, Mat im)
  277. {
  278. //图像矩阵访问有效性检测
  279. // 输入参数:
  280. // x——列
  281. // y——行
  282. // im——图像矩阵
  283. // 输出参数:
  284. // x——列
  285. // y——行
  286. y = Math.Max(y, 1);
  287. y = Math.Min(y, im.Height - 1);
  288. x = Math.Max(x, 1);
  289. x = Math.Min(x, im.Width - 1);
  290. }
  291. public Mat Fun_Stitch(ImageParam imageParam)
  292. {
  293. //图像融合
  294. //输入参数:
  295. //im2——待融合图像
  296. //W_box——宽度信息
  297. //H_box——高度信息
  298. //bdown——上下信息
  299. //MStitch——参数结构
  300. //输出参数:
  301. //MStitch——参数结构
  302. //im——融合图像
  303. Mat img = imageParam.im;
  304. int x1 = 0;
  305. int y1 = 0;
  306. int x2 = 0;
  307. int y2 = 0;
  308. double w = 0.5; //融合权值
  309. if (imageParam.bdown == 1)
  310. {
  311. //下区域重叠
  312. x2 = 1;
  313. //融合重叠区域
  314. for (x1 = imageParam.mStitch.Pwidth - imageParam.W_box; x1 < imageParam.mStitch.Pwidth; x1++)
  315. {
  316. y2 = 1;
  317. for (y1 = imageParam.mStitch.Pheight - imageParam.H_box + 1; y1 < imageParam.mStitch.Pheight; y1++)
  318. {
  319. //安全性检测
  320. CheckRC(ref x1, ref y1, imageParam.mStitch.im);
  321. CheckRC(ref x2, ref y2, imageParam.im);
  322. //融合权值
  323. w = (double)x2 / (double)imageParam.W_box;
  324. //加权融合
  325. double ColorRGB = imageParam.mStitch.im.At<Vec3b>(y1, x1).Item0 * (1.0 - w) + imageParam.im.At<Vec3b>(y2, x2).Item0 * w;
  326. imageParam.mStitch.im.Set<Vec3b>(y1, x1, new Vec3b((byte)ColorRGB, (byte)ColorRGB, (byte)ColorRGB));
  327. y2 = y2 + 1;
  328. }
  329. x2 = x2 + 1;
  330. }
  331. }
  332. else
  333. {
  334. //上区域重叠
  335. x2 = 1;
  336. //融合重叠区域
  337. for (x1 = imageParam.mStitch.Pwidth - imageParam.W_box; x1 < imageParam.mStitch.Pwidth; x1++)
  338. {
  339. y2 = 1;
  340. for (y1 = imageParam.mStitch.Pheight - imageParam.H_box + 1; y1 < imageParam.mStitch.Pheight; y1++)
  341. {
  342. //安全性检测
  343. CheckRC(ref x1, ref y1, imageParam.mStitch.im);
  344. CheckRC(ref x2, ref y2, imageParam.im);
  345. //融合权值
  346. w = (double)x2 / (double)imageParam.W_box;
  347. //加权融合
  348. double ColorRGB = imageParam.mStitch.im.At<Vec3b>(y1, x1).Item0 * (1.0 - w) + imageParam.im.At<Vec3b>(y2, x2).Item0 * w;
  349. imageParam.mStitch.im.Set<Vec3b>(y1, x1, new Vec3b((byte)ColorRGB, (byte)ColorRGB, (byte)ColorRGB));
  350. y2 = y2 + 1;
  351. }
  352. x2 = x2 + 1;
  353. }
  354. }
  355. //最终图
  356. img = new Mat(imageParam.mStitch.Pheight, imageParam.mStitch.Pwidth + imageParam.im.Width - x2 + 1, MatType.CV_8UC3);
  357. //分离出重叠区域
  358. OpenCvSharp.Rect m_select = new OpenCvSharp.Rect(x2 - 1, 0, imageParam.im.Width - x2 + 1, imageParam.mStitch.Pheight);
  359. Mat imgSwitch = new Mat(imageParam.im, m_select);
  360. Cv2.HConcat(imageParam.mStitch.im, imgSwitch, img);
  361. return img;
  362. }
  363. public Mat Fun_StitchRGB(ImageParam imageParam)
  364. {
  365. //图像融合
  366. //输入参数:
  367. //im2——待融合图像
  368. //W_box——宽度信息
  369. //H_box——高度信息
  370. //bdown——上下信息
  371. //MStitch——参数结构
  372. //输出参数:
  373. //MStitch——参数结构
  374. //im——融合图像
  375. Mat img = imageParam.im;
  376. int x1 = 0;
  377. int y1 = 0;
  378. int x2 = 0;
  379. int y2 = 0;
  380. double w = 0.5; //融合权值
  381. if (imageParam.bdown == 1)
  382. {
  383. //下区域重叠
  384. x2 = 1;
  385. //融合重叠区域
  386. for (x1 = imageParam.mStitch.Pwidth - imageParam.W_box; x1 < imageParam.mStitch.Pwidth; x1++)
  387. {
  388. y2 = 1;
  389. for (y1 = imageParam.mStitch.Pheight - imageParam.H_box + 1; y1 < imageParam.mStitch.Pheight; y1++)
  390. {
  391. //安全性检测
  392. CheckRC(ref x1, ref y1, imageParam.mStitch.im);
  393. CheckRC(ref x2, ref y2, imageParam.im);
  394. //融合权值
  395. w = (double)x2 / (double)imageParam.W_box;
  396. //加权融合
  397. double ColorR = imageParam.mStitch.im.At<Vec3b>(y1, x1).Item0 * (1.0 - w) + imageParam.im.At<Vec3b>(y2, x2).Item0 * w;
  398. double ColorG = imageParam.mStitch.im.At<Vec3b>(y1, x1).Item1 * (1.0 - w) + imageParam.im.At<Vec3b>(y2, x2).Item1 * w;
  399. double ColorB = imageParam.mStitch.im.At<Vec3b>(y1, x1).Item2 * (1.0 - w) + imageParam.im.At<Vec3b>(y2, x2).Item2 * w;
  400. if (imageParam.mStitch.im.At<Vec3b>(y1, x1).Item0 == imageParam.mStitch.im.At<Vec3b>(y1, x1).Item1 &&
  401. imageParam.mStitch.im.At<Vec3b>(y1, x1).Item1 == imageParam.mStitch.im.At<Vec3b>(y1, x1).Item2 &&
  402. imageParam.im.At<Vec3b>(y2, x2).Item0 == imageParam.im.At<Vec3b>(y2, x2).Item1 &&
  403. imageParam.im.At<Vec3b>(y2, x2).Item1 == imageParam.im.At<Vec3b>(y2, x2).Item2)
  404. {
  405. imageParam.mStitch.im.Set<Vec3b>(y1, x1, new Vec3b((byte)ColorR, (byte)ColorG, (byte)ColorB));
  406. }
  407. else
  408. {
  409. }
  410. y2 = y2 + 1;
  411. }
  412. x2 = x2 + 1;
  413. }
  414. }
  415. else
  416. {
  417. //上区域重叠
  418. x2 = 1;
  419. //融合重叠区域
  420. for (x1 = imageParam.mStitch.Pwidth - imageParam.W_box; x1 < imageParam.mStitch.Pwidth; x1++)
  421. {
  422. y2 = 1;
  423. for (y1 = imageParam.mStitch.Pheight - imageParam.H_box + 1; y1 < imageParam.mStitch.Pheight; y1++)
  424. {
  425. //安全性检测
  426. CheckRC(ref x1, ref y1, imageParam.mStitch.im);
  427. CheckRC(ref x2, ref y2, imageParam.im);
  428. //融合权值
  429. w = (double)x2 / (double)imageParam.W_box;
  430. //加权融合
  431. double ColorR = imageParam.mStitch.im.At<Vec3b>(y1, x1).Item0 * (1.0 - w) + imageParam.im.At<Vec3b>(y2, x2).Item0 * w;
  432. double ColorG = imageParam.mStitch.im.At<Vec3b>(y1, x1).Item1 * (1.0 - w) + imageParam.im.At<Vec3b>(y2, x2).Item1 * w;
  433. double ColorB = imageParam.mStitch.im.At<Vec3b>(y1, x1).Item2 * (1.0 - w) + imageParam.im.At<Vec3b>(y2, x2).Item2 * w;
  434. if (imageParam.mStitch.im.At<Vec3b>(y1, x1).Item0 == imageParam.mStitch.im.At<Vec3b>(y1, x1).Item1 &&
  435. imageParam.mStitch.im.At<Vec3b>(y1, x1).Item1 == imageParam.mStitch.im.At<Vec3b>(y1, x1).Item2 &&
  436. imageParam.im.At<Vec3b>(y2, x2).Item0 == imageParam.im.At<Vec3b>(y2, x2).Item1 &&
  437. imageParam.im.At<Vec3b>(y2, x2).Item1 == imageParam.im.At<Vec3b>(y2, x2).Item2)
  438. {
  439. imageParam.mStitch.im.Set<Vec3b>(y1, x1, new Vec3b((byte)ColorR, (byte)ColorG, (byte)ColorB));
  440. }
  441. else
  442. {
  443. }
  444. y2 = y2 + 1;
  445. }
  446. x2 = x2 + 1;
  447. }
  448. }
  449. //最终图
  450. img = new Mat(imageParam.mStitch.Pheight, imageParam.mStitch.Pwidth + imageParam.im.Width - x2 + 1, MatType.CV_8UC3);
  451. //分离出重叠区域
  452. OpenCvSharp.Rect m_select = new OpenCvSharp.Rect(x2 - 1, 0, imageParam.im.Width - x2 + 1, imageParam.mStitch.Pheight);
  453. Mat imgSwitch = new Mat(imageParam.im, m_select);
  454. Cv2.HConcat(imageParam.mStitch.im, imgSwitch, img);
  455. return img;
  456. }
  457. #endregion
  458. }
  459. }