BinaryTools.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
  1. using OpenCvSharp;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Drawing;
  5. using System.Drawing.Imaging;
  6. using System.Linq;
  7. using System.Runtime.InteropServices;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10. namespace SmartCoalApplication.Base.CommTool
  11. {
  12. public class BinaryTools
  13. {
  14. public static Dictionary<int, int> keyValuePairs = new Dictionary<int, int>();
  15. public static Mat rgb_ap, temp_ap, original;
  16. public static Vec4b vec4B;
  17. /// <summary>
  18. /// 新碎屑删除,使用连通分量找寻碎屑
  19. /// </summary>
  20. /// <param name="src"></param>
  21. /// <returns></returns>
  22. public unsafe static Mat DebrisRemoval_New(Mat src, int v = 20)
  23. {
  24. try
  25. {
  26. Mat[] arr = src.Split();
  27. rgb_ap = Tools.MergeMatFromMatArr(arr);
  28. if(arr.Length>3)
  29. temp_ap = arr[3].Clone();
  30. //寻找连通分量
  31. Mat labelMat = new Mat();
  32. Mat stats = new Mat();
  33. Mat centroids = new Mat();
  34. int nonenum = Cv2.ConnectedComponentsWithStats(src.CvtColor(ColorConversionCodes.BGRA2GRAY), labelMat, stats, centroids, PixelConnectivity.Connectivity8);
  35. //寻找在范围内需要删除的碎屑
  36. keyValuePairs.Clear();
  37. for (int h = 1; h < centroids.Height; h++)
  38. {
  39. int areaField1 = stats.At<int>(h, 4);
  40. if (0 <= areaField1 && areaField1 <= v)
  41. {
  42. keyValuePairs.Add(h, 1);
  43. }
  44. }
  45. labelMat.ForEachAsInt32(CommonForEachForInt32);
  46. //合并rgb和透明度
  47. Mat[] mats = rgb_ap.Split();
  48. arr[0] = mats[0];
  49. arr[1] = mats[1];
  50. arr[2] = mats[2];
  51. if (arr.Length > 3)
  52. arr[3] = temp_ap;
  53. Cv2.Merge(arr, src);
  54. }
  55. catch (Exception)
  56. {
  57. }
  58. finally
  59. {
  60. keyValuePairs.Clear();
  61. if (rgb_ap != null && !rgb_ap.IsDisposed)
  62. {
  63. rgb_ap.Dispose();
  64. rgb_ap = null;
  65. }
  66. if (temp_ap != null && !temp_ap.IsDisposed)
  67. {
  68. temp_ap.Dispose();
  69. temp_ap = null;
  70. }
  71. System.GC.Collect();
  72. }
  73. return src;
  74. }
  75. public unsafe static Mat DebrisRemoval_New_1(Mat src, int v = 20)
  76. {
  77. try
  78. {
  79. temp_ap = src.Clone();
  80. //寻找连通分量
  81. Mat labelMat = new Mat();
  82. Mat stats = new Mat();
  83. Mat centroids = new Mat();
  84. int nonenum = Cv2.ConnectedComponentsWithStats(src, labelMat, stats, centroids, PixelConnectivity.Connectivity8);
  85. //寻找在范围内需要删除的碎屑
  86. keyValuePairs.Clear();
  87. for (int h = 1; h < centroids.Height; h++)
  88. {
  89. int areaField1 = stats.At<int>(h, 4);
  90. if (0 <= areaField1 && areaField1 <= v)
  91. {
  92. keyValuePairs.Add(h, 1);
  93. }
  94. }
  95. labelMat.ForEachAsInt32(CommonForEachForInt32_1);
  96. temp_ap.CopyTo(src);
  97. }
  98. catch (Exception)
  99. {
  100. }
  101. finally
  102. {
  103. keyValuePairs.Clear();
  104. if (rgb_ap != null && !rgb_ap.IsDisposed)
  105. {
  106. rgb_ap.Dispose();
  107. rgb_ap = null;
  108. }
  109. if (temp_ap != null && !temp_ap.IsDisposed)
  110. {
  111. temp_ap.Dispose();
  112. temp_ap = null;
  113. }
  114. System.GC.Collect();
  115. }
  116. return src;
  117. }
  118. private unsafe static void CommonForEachForInt32(int* value, int* position)
  119. {
  120. int y = position[0];
  121. int x = position[1];
  122. int v = *value;
  123. if (v > 0 && keyValuePairs.ContainsKey(v))
  124. {
  125. rgb_ap.Set<Vec3b>(y, x, new Vec3b(0, 0, 0));
  126. if(temp_ap!=null)
  127. temp_ap.Set<int>(y, x, 0);
  128. }
  129. }
  130. private unsafe static void CommonForEachForInt32_1(int* value, int* position)
  131. {
  132. int y = position[0];
  133. int x = position[1];
  134. int v = *value;
  135. if (v > 0 && keyValuePairs.ContainsKey(v))
  136. {
  137. if (temp_ap != null)
  138. temp_ap.Set<int>(y, x, 0);
  139. }
  140. }
  141. public unsafe static Mat HoleFilling_NewWithView(Mat src, Vec4b vec4b)
  142. {
  143. vec4B = vec4b;
  144. Mat[] arr2 = src.Split();
  145. Mat tempc = arr2[3];
  146. //去掉透明层
  147. Mat mat = src.CvtColor(ColorConversionCodes.BGRA2BGR);
  148. //填充孔洞
  149. mat = Tools.FillHole(mat, new Scalar(255 - vec4B.Item0, 255 - vec4B.Item1, 255 - vec4B.Item2));
  150. tempc = Tools.FillHole(tempc, new Scalar(255));
  151. //循环处理
  152. mat.ForEachAsVec3b(RGBForEachAsByteForHoleFillingNewWithView);
  153. Mat[] arr1 = mat.Split();
  154. arr2[0] = arr1[0];
  155. arr2[1] = arr1[1];
  156. arr2[2] = arr1[2];
  157. arr2[3] = tempc;
  158. Cv2.Merge(arr2, src);
  159. if (mat != null && !mat.IsDisposed) mat.Dispose();
  160. if (tempc != null && !tempc.IsDisposed) tempc.Dispose();
  161. System.GC.Collect();
  162. return src;
  163. }
  164. private unsafe static void RGBForEachAsByteForHoleFillingNewWithView(Vec3b* value, int* position)
  165. {
  166. int y = position[0];
  167. int x = position[1];
  168. if (value->Item0 == 255 && value->Item1 == 255 && value->Item2 == 255)
  169. {
  170. value->Item0 = vec4B.Item0;
  171. value->Item1 = vec4B.Item1;
  172. value->Item2 = vec4B.Item2;
  173. }
  174. else
  175. {
  176. value->Item0 = 255;
  177. value->Item1 = 255;
  178. value->Item2 = 255;
  179. }
  180. }
  181. public static double CalcNodularity(OpenCvSharp.Point[] contours)
  182. {
  183. Point2f point;
  184. float radius;
  185. double area = Cv2.ContourArea(contours);
  186. if (contours.Length > 500)
  187. {
  188. Cv2.MinEnclosingCircle(Cv2.ConvexHull(contours, true), out point, out radius);
  189. }
  190. else
  191. {
  192. Cv2.MinEnclosingCircle(contours, out point, out radius);
  193. }
  194. return area / (Math.PI * radius * radius);
  195. }
  196. public static bool WithinContour(List<OpenCvSharp.Point[]> contoursAll, OpenCvSharp.Point[] now)
  197. {
  198. foreach (OpenCvSharp.Point[] ps in contoursAll)
  199. {
  200. double inside = Cv2.PointPolygonTest(now, ps[0], true);
  201. if (inside > 0)
  202. return true;
  203. }
  204. return false;
  205. }
  206. /// <summary>
  207. /// 估算适合的阈值
  208. /// </summary>
  209. /// <param name="edge"></param>
  210. /// <param name="first"></param>
  211. /// <returns></returns>
  212. public static float CalcSuitableValue(Mat edge, bool first = true)
  213. {
  214. //寻找较适合的阈值
  215. float[] hist_float = HistTools.CalcHist(edge);
  216. //直方图平滑
  217. int[] hist_int = HistTools.Smooth(hist_float, 5);//10
  218. //寻找所有的峰
  219. List<int> mountainsList = new List<int>();
  220. List<int[]> mountainsArrList = new List<int[]>();
  221. List<int[]> mountainsArrListBackUp = new List<int[]>();
  222. Tools.FindTopAndBetweenWithOutWT123(hist_int, 0, 255, mountainsList, mountainsArrList, mountainsArrListBackUp, new List<string>(), 15);
  223. mountainsList.Sort();
  224. if (first)
  225. return (mountainsList.Min() - 10) <= 0 ? 70 : (mountainsList.Min() - 10);
  226. else
  227. return mountainsList[mountainsList.IndexOf(mountainsList.Min()) + 1];
  228. }
  229. public static float CalcSuitableValueForUnderCut(Mat edge, bool first = true)
  230. {
  231. //寻找较适合的阈值
  232. float[] hist_float = HistTools.CalcHist(edge);
  233. //直方图平滑
  234. int[] hist_int = HistTools.Smooth(hist_float, 10);
  235. //寻找所有的峰
  236. List<int> mountainsList = new List<int>();
  237. List<int[]> mountainsArrList = new List<int[]>();
  238. List<int[]> mountainsArrListBackUp = new List<int[]>();
  239. Tools.FindTopAndBetweenWithOutWT123(hist_int, 0, 255, mountainsList, mountainsArrList, mountainsArrListBackUp, new List<string>(), 15);
  240. mountainsList.Sort();
  241. if (first)
  242. return (mountainsList.Min() - 10) <= 0 ? 70 : (mountainsList.Min());
  243. else
  244. return mountainsList[mountainsList.IndexOf(mountainsList.Min()) + 1];
  245. }
  246. /// <summary>
  247. /// 最找最大的峰的右侧的谷
  248. /// </summary>
  249. /// <param name="edge"></param>
  250. /// <returns></returns>
  251. public static float CalcSuitableValueForMax(Mat edge)
  252. {
  253. //寻找较适合的阈值
  254. float[] hist_float = HistTools.CalcHist(edge);
  255. //直方图平滑
  256. int[] hist_int = HistTools.Smooth(hist_float, 20);
  257. for (int i = 0; i < hist_int.Length; i++)
  258. if (hist_int[i] < 3000) hist_int[i] = 0;
  259. //寻找所有的峰
  260. List<int> mountainsList = new List<int>();
  261. List<int[]> mountainsArrList = new List<int[]>();
  262. List<int[]> mountainsArrListBackUp = new List<int[]>();
  263. Tools.FindTopAndBetweenWithOutWT123(hist_int, 0, 255, mountainsList, mountainsArrList, mountainsArrListBackUp, new List<string>(), 15);
  264. int returnV = 0;
  265. int temp = 0;
  266. int l = 0;
  267. for(int i=0; i< mountainsList.Count; i++)
  268. {
  269. if(mountainsList[i]<200 && temp < mountainsList[i])
  270. {
  271. temp = mountainsList[i];
  272. returnV = mountainsArrList[i][1];
  273. l = i;
  274. }
  275. }
  276. if(returnV > 200) return mountainsArrList[l-1][1];
  277. return returnV;
  278. }
  279. /// <summary>
  280. /// 新版本删除边界
  281. /// </summary>
  282. /// <param name="src"></param>
  283. /// <returns></returns>
  284. public static Mat DeleteContours_New(Mat src)
  285. {
  286. Rect rect;
  287. Mat[] arr = src.Split();
  288. Mat rgb = Tools.MergeMatFromMatArr(arr);
  289. Mat temp_1 = arr[3].Clone();
  290. for (int h = 0; h < temp_1.Width; h++)
  291. {
  292. byte vec4B_top = temp_1.At<byte>(0, h);
  293. if (vec4B_top > 0)
  294. {
  295. Cv2.FloodFill(rgb, new OpenCvSharp.Point(h, 0), new Scalar(0), out rect, null, null, FloodFillFlags.Link8);
  296. Cv2.FloodFill(temp_1, new OpenCvSharp.Point(h, 0), new Scalar(0), out rect, null, null, FloodFillFlags.Link8);
  297. }
  298. }
  299. for (int h = 0; h < temp_1.Width; h++)
  300. {
  301. byte vec4B_bottom = temp_1.At<byte>(temp_1.Height - 1, h);
  302. if (vec4B_bottom > 0)
  303. {
  304. Cv2.FloodFill(rgb, new OpenCvSharp.Point(h, temp_1.Height - 1), new Scalar(0), out rect, null, null, FloodFillFlags.Link8);
  305. Cv2.FloodFill(temp_1, new OpenCvSharp.Point(h, temp_1.Height - 1), new Scalar(0), out rect, null, null, FloodFillFlags.Link8);
  306. }
  307. }
  308. for (int y = 0; y < temp_1.Height; y++)
  309. {
  310. Vec4b vec4B_top = temp_1.At<Vec4b>(y, 0);
  311. if (vec4B_top.Item3 > 0)
  312. {
  313. Cv2.FloodFill(rgb, new OpenCvSharp.Point(0, y), new Scalar(0), out rect, null, null, FloodFillFlags.Link8);
  314. Cv2.FloodFill(temp_1, new OpenCvSharp.Point(0, y), new Scalar(0), out rect, null, null, FloodFillFlags.Link8);
  315. }
  316. }
  317. for (int y = 0; y < temp_1.Height; y++)
  318. {
  319. byte vec4B_top = temp_1.At<byte>(y, temp_1.Width - 1);
  320. if (vec4B_top > 0)
  321. {
  322. Cv2.FloodFill(rgb, new OpenCvSharp.Point(temp_1.Width - 1, y), new Scalar(0), out rect, null, null, FloodFillFlags.Link8);
  323. Cv2.FloodFill(temp_1, new OpenCvSharp.Point(temp_1.Width - 1, y), new Scalar(0), out rect, null, null, FloodFillFlags.Link8);
  324. }
  325. }
  326. Mat[] mats = rgb.Split();
  327. arr[0] = mats[0];
  328. arr[1] = mats[1];
  329. arr[2] = mats[2];
  330. arr[3] = temp_1;
  331. Cv2.Merge(arr, src);
  332. return src;
  333. }
  334. static Mat phaseTemp1;
  335. static double contrast = 2;
  336. static int brightness = 0;
  337. /// <summary>
  338. /// 亮度/对比度/伽马值
  339. /// </summary>
  340. /// <param name="src"></param>
  341. /// <returns></returns>
  342. public unsafe static Mat BCGTransferFunction(Mat src)
  343. {
  344. if (phaseTemp1 != null) phaseTemp1 = null;
  345. contrast = 1.7;
  346. phaseTemp1 = new Mat(src.Size(), MatType.CV_8UC3, Scalar.All(0)); //创建一个和原图像大小相同,类型相同,像素值为0的图像。
  347. Mat imageGamma = null;
  348. try
  349. {
  350. double gamma = 1;
  351. src = src.CvtColor(ColorConversionCodes.GRAY2BGR);
  352. contrast = (contrast - 1.0) / 2.0 + 1.0;//待确认参数范围
  353. src.ForEachAsVec3b(ForeachFunctionByteForBCGTransferMultiChannel);
  354. imageGamma = new Mat();
  355. //灰度归一化
  356. phaseTemp1.ConvertTo(imageGamma, MatType.CV_64F, 1.0 / 255, 0);
  357. Cv2.Pow(imageGamma, gamma, imageGamma);
  358. imageGamma.ConvertTo(imageGamma, MatType.CV_8U, 255, 0);
  359. imageGamma.CopyTo(phaseTemp1);
  360. phaseTemp1.CopyTo(src);
  361. return src.CvtColor(ColorConversionCodes.BGR2GRAY);
  362. }
  363. catch (Exception ex)
  364. {
  365. throw ex;
  366. }
  367. finally
  368. {
  369. if (imageGamma != null && !imageGamma.IsDisposed)
  370. {
  371. imageGamma.Dispose();
  372. }
  373. if (phaseTemp1 != null && !phaseTemp1.IsDisposed)
  374. {
  375. phaseTemp1.Dispose();
  376. phaseTemp1 = null;
  377. }
  378. GC.Collect();
  379. }
  380. }
  381. private unsafe static void ForeachFunctionByteForBCGTransferMultiChannel(Vec3b* value, int* position)
  382. {
  383. int y = position[0];
  384. int x = position[1];
  385. double v0 = contrast * (value->Item0 - 128.0) + 128.0 + brightness;
  386. double v1 = contrast * (value->Item1 - 128.0) + 128.0 + brightness;
  387. double v2 = contrast * (value->Item2 - 128.0) + 128.0 + brightness;
  388. if (v0 > 255) v0 = 255;
  389. else if (v0 < 0) v0 = 0;
  390. if (v1 > 255) v1 = 255;
  391. else if (v1 < 0) v1 = 0;
  392. if (v2 > 255) v2 = 255;
  393. else if (v2 < 0) v2 = 0;
  394. Vec3b vec = new Vec3b();
  395. vec[0] = (byte)v0;
  396. vec[1] = (byte)v1;
  397. vec[2] = (byte)v2;
  398. phaseTemp1.Set<Vec3b>(y, x, vec);
  399. }
  400. private unsafe static void ForeachFunctionByteForBCGTransferOneChannel(double* value, int* position)
  401. {
  402. int y = position[0];
  403. int x = position[1];
  404. double v = contrast * (*value - 128.0) + 128.0 + 0;
  405. if (v > 255) v = 255;
  406. else if (v < 0) v = 0;
  407. phaseTemp1.Set<double>(y, x, v);
  408. }
  409. /// <summary>
  410. /// unsharp mask
  411. /// </summary>
  412. /// <param name="src"></param>
  413. /// <returns></returns>
  414. public static Mat BlurMaskFunction(Mat src, float radius= 4f * 3.14f, int threshold = 1, float amount = 300f)
  415. {
  416. Bitmap map = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(src);
  417. //像素矩阵
  418. var inPixels = ByteArray(map);
  419. var workPixels = new int[inPixels.Length];
  420. var outPixels = new int[inPixels.Length];
  421. //半径
  422. if (radius > 0)
  423. {
  424. Kernel kernel = CreateKernel(radius);
  425. ConvolveAndTranspose(kernel, inPixels, workPixels, map.Width, map.Height, true, true, false, 1);
  426. ConvolveAndTranspose(kernel, workPixels, outPixels, map.Height, map.Width, true, false, true, 1);
  427. }
  428. for (int index = 0; index < inPixels.Length; index++)
  429. {
  430. int rgb1 = inPixels[index];
  431. int r1 = (rgb1 >> 16) & 0xff;
  432. int g1 = (rgb1 >> 8) & 0xff;
  433. int b1 = rgb1 & 0xff;
  434. int rgb2 = outPixels[index];
  435. int r2 = (rgb2 >> 16) & 0xff;
  436. int g2 = (rgb2 >> 8) & 0xff;
  437. int b2 = rgb2 & 0xff;
  438. if (Math.Abs(r1 - r2) >= threshold)
  439. {
  440. r1 = (int)((amount + 1) * (r1 - r2) + r2);
  441. if (r1 < 0) r1 = 0;
  442. if (r1 > 255) r1 = 255;
  443. }
  444. if (Math.Abs(g1 - g2) >= threshold)
  445. {
  446. g1 = (int)((amount + 1) * (g1 - g2) + g2);
  447. if (g1 < 0) g1 = 0;
  448. if (g1 > 255) g1 = 255;
  449. }
  450. if (Math.Abs(b1 - b2) >= threshold)
  451. {
  452. b1 = (int)((amount + 1) * (b1 - b2) + b2);
  453. if (b1 < 0) b1 = 0;
  454. if (b1 > 255) b1 = 255;
  455. }
  456. inPixels[index] = (int)(rgb1 & 0xff000000) | (r1 << 16) | (g1 << 8) | b1;
  457. }
  458. var byteArray = new byte[inPixels.Length * 4];
  459. for (int i = 0; i < inPixels.Length; i++)
  460. {
  461. Array.Copy(BitConverter.GetBytes(inPixels[i]), 0, byteArray, i * 4, 4);
  462. }
  463. Bitmap Image = new Bitmap(map.Width, map.Height, PixelFormat.Format32bppArgb);
  464. var data = ((Bitmap)Image).LockBits(new Rectangle(0, 0, Image.Width, Image.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
  465. if (data.Stride == Image.Width * 4)
  466. {
  467. Marshal.Copy(byteArray, 0, data.Scan0, byteArray.Length);
  468. }
  469. else
  470. {
  471. for (int i = 0, l = Image.Height; i < l; i++)
  472. {
  473. var p = new IntPtr(data.Scan0.ToInt32() + data.Stride * i);
  474. Marshal.Copy(byteArray, i * Image.Width * 4, p, Image.Width * 4);
  475. }
  476. }
  477. ((Bitmap)Image).UnlockBits(data);
  478. return OpenCvSharp.Extensions.BitmapConverter.ToMat((Bitmap)Image);
  479. }
  480. /// <summary>
  481. /// Blur and transpose a block of ARGB pixels.
  482. /// </summary>
  483. /// <param name="kernel"></param>
  484. /// <param name="inPixels"></param>
  485. /// <param name="outPixels"></param>
  486. /// <param name="width"></param>
  487. /// <param name="height"></param>
  488. /// <param name="alpha"></param>
  489. /// <param name="premultiply"></param>
  490. /// <param name="unpremultiply"></param>
  491. /// <param name="edgeAction"></param>
  492. public static void ConvolveAndTranspose(Kernel kernel, int[] inPixels, int[] outPixels, int width, int height, bool alpha, bool premultiply, bool unpremultiply, int edgeAction)
  493. {
  494. float[] matrix = kernel.GetKernel();
  495. int cols = kernel.Width;
  496. int cols2 = cols / 2;
  497. for (int y = 0; y < height; y++)
  498. {
  499. int index = y;
  500. int ioffset = y * width;
  501. for (int x = 0; x < width; x++)
  502. {
  503. float r = 0, g = 0, b = 0, a = 0;
  504. int moffset = cols2;
  505. for (int col = -cols2; col <= cols2; col++)
  506. {
  507. float f = matrix[moffset + col];
  508. if (f != 0)
  509. {
  510. int ix = x + col;
  511. if (ix < 0)
  512. {
  513. if (edgeAction == 1)
  514. ix = 0;
  515. else if (edgeAction == 2)
  516. ix = (x + width) % width;
  517. }
  518. else if (ix >= width)
  519. {
  520. if (edgeAction == 1)
  521. ix = width - 1;
  522. else if (edgeAction == 2)
  523. ix = (x + width) % width;
  524. }
  525. int rgb = inPixels[ioffset + ix];
  526. int pa = (rgb >> 24) & 0xff;
  527. int pr = (rgb >> 16) & 0xff;
  528. int pg = (rgb >> 8) & 0xff;
  529. int pb = rgb & 0xff;
  530. if (premultiply)
  531. {
  532. float a255 = pa * (1.0f / 255.0f);
  533. pr = (int)(pr * a255);
  534. pg = (int)(pg * a255);
  535. pb = (int)(pb * a255);
  536. }
  537. a += f * pa;
  538. r += f * pr;
  539. g += f * pg;
  540. b += f * pb;
  541. }
  542. }
  543. if (unpremultiply && a != 0 && a != 255)
  544. {
  545. float f = 255.0f / a;
  546. r *= f;
  547. g *= f;
  548. b *= f;
  549. }
  550. int ff = (int)(a + 0.5);
  551. if (ff > 255) ff = 255;
  552. if (ff < 0) ff = 0;
  553. int ia = alpha ? ff : 0xff;
  554. int ir = (int)(r + 0.5);
  555. if (ir > 255) ir = 255;
  556. if (ir < 0) ir = 0;
  557. int ig = (int)(g + 0.5);
  558. if (ig > 255) ig = 255;
  559. if (ig < 0) ig = 0;
  560. int ib = (int)(b + 0.5);
  561. if (ib > 255) ib = 255;
  562. if (ib < 0) ib = 0;
  563. outPixels[index] = (ia << 24) | (ir << 16) | (ig << 8) | ib;
  564. index += height;
  565. }
  566. }
  567. }
  568. public static int[] ByteArray(Bitmap map)
  569. {
  570. var data = map.LockBits(new Rectangle(0, 0, map.Width, map.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
  571. var length = map.Width * map.Height * 4;
  572. byte[] _byteArray = new byte[length];
  573. if (data.Stride == map.Width * 4)
  574. {
  575. Marshal.Copy(data.Scan0, _byteArray, 0, length);
  576. }
  577. else
  578. {
  579. for (int i = 0, l = map.Height; i < l; i++)
  580. {
  581. var p = new IntPtr(data.Scan0.ToInt32() + data.Stride * i);
  582. Marshal.Copy(p, _byteArray, i * map.Width * 4, map.Width * 4);
  583. }
  584. }
  585. map.UnlockBits(data);
  586. var intArray = new int[_byteArray.Length / 4];
  587. for (int i = 0; i < _byteArray.Length; i += 4)
  588. {
  589. intArray[i / 4] = BitConverter.ToInt32(_byteArray, i);
  590. }
  591. return intArray;
  592. }
  593. /// <summary>
  594. /// 创建一个高斯滤波核
  595. /// </summary>
  596. /// <param name="radius">半径</param>
  597. /// <returns>kernel</returns>
  598. public static Kernel CreateKernel(float radius)
  599. {
  600. var r = (int)Math.Ceiling(radius);
  601. int rows = r * 2 + 1;
  602. var matrix = new float[rows];
  603. float sigma = radius / 3;
  604. float sigma22 = 2 * sigma * sigma;
  605. var sigmaPi2 = (float)(2 * Math.PI * sigma);
  606. var sqrtSigmaPi2 = (float)Math.Sqrt(sigmaPi2);
  607. float radius2 = radius * radius;
  608. float total = 0;
  609. int index = 0;
  610. for (int row = -r; row <= r; row++)
  611. {
  612. float distance = row * row;
  613. if (distance > radius2)
  614. matrix[index] = 0;
  615. else
  616. matrix[index] = (float)Math.Exp(-(distance) / sigma22) / sqrtSigmaPi2;
  617. total += matrix[index];
  618. index++;
  619. }
  620. for (int i = 0; i < rows; i++)
  621. {
  622. matrix[i] /= total;
  623. }
  624. return new Kernel(rows, 1, matrix);
  625. }
  626. /// <summary>
  627. /// 单通道碎屑删除
  628. /// </summary>
  629. /// <param name="src"></param>
  630. /// <returns></returns>
  631. public unsafe static Mat SingleChannelDebrisRemoval(Mat src, int v = 20)
  632. {
  633. Mat labelMat = new Mat();
  634. Mat stats = new Mat();
  635. Mat centroids = new Mat();
  636. try
  637. {
  638. original = src;
  639. //寻找连通分量
  640. int nonenum = Cv2.ConnectedComponentsWithStats(original, labelMat, stats, centroids, PixelConnectivity.Connectivity8);
  641. //寻找在范围内需要删除的碎屑
  642. keyValuePairs.Clear();
  643. for (int h = 1; h < centroids.Height; h++)
  644. {
  645. int areaField1 = stats.At<int>(h, 4);
  646. if (0 <= areaField1 && areaField1 <= v)
  647. {
  648. keyValuePairs.Add(h, 1);
  649. }
  650. }
  651. labelMat.ForEachAsInt32(SingleCommonForEachForInt32);
  652. }
  653. catch (Exception ex)
  654. {
  655. }
  656. finally
  657. {
  658. keyValuePairs.Clear();
  659. if (labelMat != null && !labelMat.IsDisposed)
  660. {
  661. labelMat.Dispose();
  662. }
  663. if (stats != null && !stats.IsDisposed)
  664. {
  665. stats.Dispose();
  666. }
  667. if (centroids != null && !centroids.IsDisposed)
  668. {
  669. centroids.Dispose();
  670. }
  671. System.GC.Collect();
  672. }
  673. return src;
  674. }
  675. private unsafe static void SingleCommonForEachForInt32(int* value, int* position)
  676. {
  677. int y = position[0];
  678. int x = position[1];
  679. int v = *value;
  680. if (v > 0 && keyValuePairs.ContainsKey(v))
  681. {
  682. original.Set<int>(y, x, 0);
  683. }
  684. }
  685. /// <summary>
  686. /// 单通道孔洞填充
  687. /// </summary>
  688. /// <param name="src"></param>
  689. /// <param name="vec4b"></param>
  690. /// <returns></returns>
  691. public unsafe static Mat SingleChannelHoleFilling(Mat src, Vec4b vec4b)
  692. {
  693. vec4B = vec4b;
  694. //去掉透明层
  695. Mat mat = src.CvtColor(ColorConversionCodes.BGRA2BGR);
  696. //填充孔洞
  697. mat = Tools.FillHole(mat, new Scalar(255 - vec4B.Item0, 255 - vec4B.Item1, 255 - vec4B.Item2));
  698. src = Tools.FillHole(src, new Scalar(255));
  699. //循环处理
  700. mat.ForEachAsVec3b(RGBForEachAsByteForHoleFillingNewWithView);
  701. if (mat != null && !mat.IsDisposed) mat.Dispose();
  702. System.GC.Collect();
  703. return src;
  704. }
  705. /*private unsafe static void RGBForEachAsByteForHoleFillingNewWithView(Vec3b* value, int* position)
  706. {
  707. int y = position[0];
  708. int x = position[1];
  709. if (value->Item0 == 255 && value->Item1 == 255 && value->Item2 == 255)
  710. {
  711. value->Item0 = vec4B.Item0;
  712. value->Item1 = vec4B.Item1;
  713. value->Item2 = vec4B.Item2;
  714. }
  715. else
  716. {
  717. value->Item0 = 255;
  718. value->Item1 = 255;
  719. value->Item2 = 255;
  720. }
  721. }*/
  722. }
  723. }