BaseTools.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  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 PaintDotNet.Adjust.BaseImage
  11. {
  12. /// <summary>
  13. /// 图像处理基本工具
  14. /// </summary>
  15. public static class BaseTools
  16. {
  17. public static int[] table =
  18. //0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1
  19. {0,0,0,0,0,0,1,3,0,0,3,1,1,0,1,3,0,0,0,0,0,0,0,0,0,0,2,0,3,0,3,3,
  20. 0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,3,0,2,2,
  21. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  22. 2,0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,3,0,2,0,
  23. 0,0,3,1,0,0,1,3,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
  24. 3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  25. 2,3,1,3,0,0,1,3,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  26. 2,3,0,1,0,0,0,1,0,0,0,0,0,0,0,0,3,3,0,1,0,0,0,0,2,2,0,0,2,0,0,0};
  27. // 2013/12/02: 16,6 2->0
  28. // 2013/12/02: 24,5 0->2
  29. public static int[] table2 =
  30. //0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1
  31. {0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,0,0,0,0,
  32. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,
  33. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  34. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  35. 0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,
  36. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,
  37. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  38. 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  39. /// <summary>
  40. /// 创建一个高斯滤波核
  41. /// </summary>
  42. /// <param name="radius">半径</param>
  43. /// <returns>kernel</returns>
  44. public static Kernel CreateKernel(float radius)
  45. {
  46. var r = (int)Math.Ceiling(radius);
  47. int rows = r * 2 + 1;
  48. var matrix = new float[rows];
  49. float sigma = radius / 3;
  50. float sigma22 = 2 * sigma * sigma;
  51. var sigmaPi2 = (float)(2 * Math.PI * sigma);
  52. var sqrtSigmaPi2 = (float)Math.Sqrt(sigmaPi2);
  53. float radius2 = radius * radius;
  54. float total = 0;
  55. int index = 0;
  56. for (int row = -r; row <= r; row++)
  57. {
  58. float distance = row * row;
  59. if (distance > radius2)
  60. matrix[index] = 0;
  61. else
  62. matrix[index] = (float)Math.Exp(-(distance) / sigma22) / sqrtSigmaPi2;
  63. total += matrix[index];
  64. index++;
  65. }
  66. for (int i = 0; i < rows; i++)
  67. {
  68. matrix[i] /= total;
  69. }
  70. return new Kernel(rows, 1, matrix);
  71. }
  72. /// <summary>
  73. /// Blur and transpose a block of ARGB pixels.
  74. /// </summary>
  75. /// <param name="kernel"></param>
  76. /// <param name="inPixels"></param>
  77. /// <param name="outPixels"></param>
  78. /// <param name="width"></param>
  79. /// <param name="height"></param>
  80. /// <param name="alpha"></param>
  81. /// <param name="premultiply"></param>
  82. /// <param name="unpremultiply"></param>
  83. /// <param name="edgeAction"></param>
  84. public static void ConvolveAndTranspose(Kernel kernel, int[] inPixels, int[] outPixels, int width, int height, bool alpha, bool premultiply, bool unpremultiply, int edgeAction)
  85. {
  86. float[] matrix = kernel.GetKernel();
  87. int cols = kernel.Width;
  88. int cols2 = cols / 2;
  89. for (int y = 0; y < height; y++)
  90. {
  91. int index = y;
  92. int ioffset = y * width;
  93. for (int x = 0; x < width; x++)
  94. {
  95. float r = 0, g = 0, b = 0, a = 0;
  96. int moffset = cols2;
  97. for (int col = -cols2; col <= cols2; col++)
  98. {
  99. float f = matrix[moffset + col];
  100. if (f != 0)
  101. {
  102. int ix = x + col;
  103. if (ix < 0)
  104. {
  105. if (edgeAction == 1)
  106. ix = 0;
  107. else if (edgeAction == 2)
  108. ix = (x + width) % width;
  109. }
  110. else if (ix >= width)
  111. {
  112. if (edgeAction == 1)
  113. ix = width - 1;
  114. else if (edgeAction == 2)
  115. ix = (x + width) % width;
  116. }
  117. int rgb = inPixels[ioffset + ix];
  118. int pa = (rgb >> 24) & 0xff;
  119. int pr = (rgb >> 16) & 0xff;
  120. int pg = (rgb >> 8) & 0xff;
  121. int pb = rgb & 0xff;
  122. if (premultiply)
  123. {
  124. float a255 = pa * (1.0f / 255.0f);
  125. pr = (int)(pr * a255);
  126. pg = (int)(pg * a255);
  127. pb = (int)(pb * a255);
  128. }
  129. a += f * pa;
  130. r += f * pr;
  131. g += f * pg;
  132. b += f * pb;
  133. }
  134. }
  135. if (unpremultiply && a != 0 && a != 255)
  136. {
  137. float f = 255.0f / a;
  138. r *= f;
  139. g *= f;
  140. b *= f;
  141. }
  142. int ff = (int)(a + 0.5);
  143. if (ff > 255) ff = 255;
  144. if (ff < 0) ff = 0;
  145. int ia = alpha ? ff : 0xff;
  146. int ir = (int)(r + 0.5);
  147. if (ir > 255) ir = 255;
  148. if (ir < 0) ir = 0;
  149. int ig = (int)(g + 0.5);
  150. if (ig > 255) ig = 255;
  151. if (ig < 0) ig = 0;
  152. int ib = (int)(b + 0.5);
  153. if (ib > 255) ib = 255;
  154. if (ib < 0) ib = 0;
  155. outPixels[index] = (ia << 24) | (ir << 16) | (ig << 8) | ib;
  156. index += height;
  157. }
  158. }
  159. }
  160. /// <summary>
  161. /// 参考https://blog.csdn.net/ls9512/article/details/50001753
  162. /// RgbToHsv
  163. /// </summary>
  164. /// <param name="prgb"></param>
  165. /// <param name="H"></param>
  166. /// <param name="S"></param>
  167. /// <param name="V"></param>
  168. public static void RgbToHsv(Vec3b prgb, out double H, out double S, out double V)
  169. {
  170. float min, max, tmp;
  171. float R = prgb[2] * 1.0f / 255, G = prgb[1] * 1.0f / 255, B = prgb[0] * 1.0f / 255;
  172. tmp = Math.Min(R, G);
  173. min = Math.Min(tmp, B);
  174. tmp = Math.Max(R, G);
  175. max = Math.Max(tmp, B);
  176. // H
  177. H = 0;
  178. if (max == min)
  179. {
  180. H = 0;
  181. }
  182. else if (max == R && G > B)
  183. {
  184. H = 60 * (G - B) * 1.0f / (max - min) + 0;
  185. }
  186. else if (max == R && G < B)
  187. {
  188. H = 60 * (G - B) * 1.0f / (max - min) + 360;
  189. }
  190. else if (max == G)
  191. {
  192. H = H = 60 * (B - R) * 1.0f / (max - min) + 120;
  193. }
  194. else if (max == B)
  195. {
  196. H = H = 60 * (R - G) * 1.0f / (max - min) + 240;
  197. }
  198. // S
  199. if (max == 0)
  200. {
  201. S = 0;
  202. }
  203. else
  204. {
  205. S = (max - min) * 1.0f / max;
  206. }
  207. // V
  208. V = max;
  209. //return new ColorHSV((int)H, (int)(S * 255), (int)(V * 255));
  210. }
  211. public static void RGBtoHLS(Vec3b prgb, out double H, out double L, out double S)
  212. {
  213. double n_cmax = Math.Max(prgb[0], Math.Max(prgb[1], prgb[2]));
  214. double n_cmin = Math.Min(prgb[0], Math.Min(prgb[1], prgb[2]));
  215. L = (n_cmax + n_cmin) / 2.0 / 255.0;
  216. if (n_cmax == n_cmin)
  217. {
  218. S = H = 0.0;
  219. return;
  220. }
  221. double r = prgb[2] / 255.0;
  222. double g = prgb[1] / 255.0;
  223. double b = prgb[0] / 255.0;
  224. double cmax = n_cmax / 255.0;
  225. double cmin = n_cmin / 255.0;
  226. double delta = cmax - cmin;
  227. if (L < 0.5)
  228. S = delta / (cmax + cmin);
  229. else
  230. S = delta / (2.0 - cmax - cmin);
  231. if (prgb[2] == n_cmax)
  232. H = (g - b) / delta;
  233. else if (prgb[1] == n_cmax)
  234. H = 2.0 + (b - r) / delta;
  235. else
  236. H = 4.0 + (r - g) / delta;
  237. H /= 6.0;
  238. if (H < 0.0)
  239. H += 1.0;
  240. }
  241. public static Vec3b HLStoRGB(double H, double L, double S)
  242. {
  243. if (S < 1.19209290E-07F)//== 0
  244. {
  245. Vec3b r = new Vec3b();
  246. r[0] = (byte)(L * 255);
  247. r[1] = (byte)(L * 255);
  248. r[2] = (byte)(L * 255);
  249. return r;
  250. }
  251. double m1, m2;
  252. if (L < 0.5)
  253. m2 = L * (1.0 + S);
  254. else
  255. m2 = L + S - L * S;
  256. m1 = 2.0 * L - m2;
  257. Vec3b r1 = new Vec3b();
  258. r1[2] = (byte)(__HLS_Value(m1, m2, H * 6.0 + 2.0) * 255);
  259. if (r1[2] < 0) r1[2] = 0; if (r1[2] > 255) r1[2] = 255;
  260. r1[1] = (byte)(__HLS_Value(m1, m2, H * 6.0) * 255);
  261. if (r1[1] < 0) r1[1] = 0; if (r1[1] > 255) r1[1] = 255;
  262. r1[0] = (byte)(__HLS_Value(m1, m2, H * 6.0 - 2.0) * 255);
  263. if (r1[0] < 0) r1[0] = 0; if (r1[0] > 255) r1[0] = 255;
  264. return r1;
  265. }
  266. public static double __HLS_Value(double m1, double m2, double h)
  267. {
  268. if (h > 6.0)
  269. h -= 6.0;
  270. else if (h < 0.0)
  271. h += 6.0;
  272. if (h < 1.0)
  273. return m1 + (m2 - m1) * h;
  274. else if (h < 3.0)
  275. return m2;
  276. else if (h < 4.0)
  277. return m1 + (m2 - m1) * (4.0 - h);
  278. return m1;
  279. }
  280. /// <summary>
  281. /// Bitmap转int数组
  282. /// </summary>
  283. /// <param name="map"></param>
  284. /// <returns></returns>
  285. public static int[] ByteArray(Bitmap map)
  286. {
  287. var data = map.LockBits(new Rectangle(0, 0, map.Width, map.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
  288. var length = map.Width * map.Height * 4;
  289. byte[] _byteArray = new byte[length];
  290. if (data.Stride == map.Width * 4)
  291. {
  292. Marshal.Copy(data.Scan0, _byteArray, 0, length);
  293. }
  294. else
  295. {
  296. for (int i = 0, l = map.Height; i < l; i++)
  297. {
  298. var p = new IntPtr(data.Scan0.ToInt32() + data.Stride * i);
  299. Marshal.Copy(p, _byteArray, i * map.Width * 4, map.Width * 4);
  300. }
  301. }
  302. map.UnlockBits(data);
  303. var intArray = new int[_byteArray.Length / 4];
  304. for (int i = 0; i < _byteArray.Length; i += 4)
  305. {
  306. intArray[i / 4] = BitConverter.ToInt32(_byteArray, i);
  307. }
  308. return intArray;
  309. }
  310. /// <summary>
  311. /// 【可以优化速度】判断是否是黑/白二值图像
  312. /// </summary>
  313. /// <param name="mat"></param>
  314. /// <returns></returns>
  315. public static bool DetermineBinaryImage(Mat mat)
  316. {
  317. for (int o = 0; o < mat.Height; o++)
  318. {
  319. for (int p = 0; p < mat.Width; p++)
  320. {
  321. byte v = mat.At<byte>(o, p);
  322. if(v!=255 && v != 0)
  323. {
  324. return false;
  325. }
  326. }
  327. }
  328. return true;
  329. }
  330. /// <summary>
  331. /// 根据图像的直方图判断是否是二个颜色的图
  332. /// </summary>
  333. /// <param name="mat"></param>
  334. /// <returns></returns>
  335. public static bool DetermineBinaryImageByHist(Mat mat)
  336. {
  337. //根据灰度图的直方图计算是否是二值图
  338. Mat[] mats0 = new Mat[] { mat };
  339. int[] channels0 = new int[] { 0 };
  340. int[] histsize = new int[] { 256 };//一个通道,初始化为256箱子
  341. Rangef[] range = new Rangef[1];
  342. range[0].Start = 0.0F;//从0开始(含)
  343. range[0].End = 256.0F;//到256结束(不含)
  344. Mat hist = new Mat();
  345. Cv2.CalcHist(mats0, channels0, new Mat(), hist, 1, histsize, range);
  346. int value = 0;
  347. for (int i = 0; i < 256; i++)
  348. {
  349. //取每个bin的数目
  350. int temp = (int)(hist.At<float>(i, 0));
  351. if (temp > 0)
  352. value++;
  353. }
  354. return value == 2;
  355. }
  356. /// <summary>
  357. /// 收缩图像
  358. /// </summary>
  359. /// <param name="ip"></param>
  360. /// <param name="ip2"></param>
  361. /// <param name="hasEdgePixels"></param>
  362. /// <returns></returns>
  363. public static Mat shrink(Mat ip, Mat ip2, bool hasEdgePixels)
  364. {
  365. if (hasEdgePixels)
  366. {
  367. int width = ip.Width;
  368. int height = ip.Height;
  369. for (int y = 0; y < height; y++)
  370. for (int x = 0; x < width; x++)
  371. ip.Set<byte>(y, x, ip2.At<byte>(y + 1, x + 1));
  372. }
  373. return ip;
  374. }
  375. /// <summary>
  376. /// 阴影校正功能里面,用来进行行列处理的方法
  377. /// </summary>
  378. /// <param name="I_OUT"></param>
  379. /// <param name="threshold"></param>
  380. /// <returns></returns>
  381. public static Mat ImageSmoothIIR(Mat I_OUT, double threshold)
  382. {
  383. int M = I_OUT.Height;
  384. int N = I_OUT.Width;
  385. for (int P = 1; P < M; P++)
  386. {
  387. I_OUT.Row[P] = threshold * 1.0f * (I_OUT.Row[P - 1] - I_OUT.Row[P]) + I_OUT.Row[P];
  388. }
  389. for (int P = M - 2; P > -1; P--)
  390. {
  391. I_OUT.Row[P] = threshold * 1.0f * (I_OUT.Row[P + 1] - I_OUT.Row[P]) + I_OUT.Row[P];
  392. }
  393. for (int L = 1; L < N; L++)
  394. {
  395. I_OUT.Col[L] = threshold * 1.0f * (I_OUT.Col[L - 1] - I_OUT.Col[L]) + I_OUT.Col[L];
  396. }
  397. for (int L = N - 2; L > -1; L--)
  398. {
  399. I_OUT.Col[L] = threshold * 1.0f * (I_OUT.Col[L + 1] - I_OUT.Col[L]) + I_OUT.Col[L];
  400. }
  401. return I_OUT;
  402. }
  403. /// <summary>
  404. /// 引射线法判断点是否在多边形内部(以该点为起点沿x轴负方向做一条射线)
  405. /// </summary>
  406. /// <param name="p"></param>
  407. /// <param name="vPoint"></param>
  408. /// <returns></returns>
  409. public static bool isPointInPolygon(System.Drawing.Point p, List<System.Drawing.PointF> vPoint)
  410. {
  411. int i, j = vPoint.Count - 1;
  412. bool inside = false;
  413. double x = p.X;
  414. double y = p.Y;
  415. for (i = 0; i < vPoint.Count; i++)
  416. {
  417. if (((vPoint[i].Y < y && vPoint[j].Y >= y) || (vPoint[i].Y >= y && vPoint[j].Y < y)) && (vPoint[i].X <= x || vPoint[j].X <= x))
  418. {
  419. double dTmp = vPoint[i].X + (y - vPoint[i].Y) / (vPoint[j].Y - vPoint[i].Y) * (vPoint[j].X - vPoint[i].X);
  420. bool bTmp;
  421. if (dTmp == x) //点在多边形的边上,也算在多边形内
  422. {
  423. //count = 1;
  424. return true;
  425. }
  426. else
  427. bTmp = (dTmp < x);
  428. inside ^= bTmp;
  429. //if (bTmp)
  430. //count++;
  431. }
  432. j = i;
  433. }
  434. return inside;
  435. }
  436. /// <summary>
  437. /// 判断点是否在椭圆内
  438. /// </summary>
  439. /// <param name="point"></param>
  440. /// <param name="centerPoint"></param>
  441. /// <returns></returns>
  442. public static bool isPointInOval(System.Drawing.Point point, System.Drawing.PointF centerPoint, float xaxis, float yaxis)
  443. {
  444. double v = Math.Pow(centerPoint.X - point.X, 2) / Math.Pow(xaxis, 2) + Math.Pow(centerPoint.Y - point.Y, 2) / Math.Pow(yaxis, 2);
  445. return v < 1;
  446. }
  447. /// <summary>
  448. /// System.Drawing.Point转OpenCvSharp.Point
  449. /// </summary>
  450. /// <param name="points1"></param>
  451. /// <param name="points2"></param>
  452. /// <returns></returns>
  453. public static List<OpenCvSharp.Point> pointToPoint(List<System.Drawing.PointF> points)
  454. {
  455. List<OpenCvSharp.Point> points1 = new List<OpenCvSharp.Point>();
  456. foreach(System.Drawing.PointF point in points)
  457. {
  458. points1.Add(new OpenCvSharp.Point(point.X, point.Y));
  459. }
  460. return points1;
  461. }
  462. /// <summary>
  463. /// 判断mat是否相同
  464. /// </summary>
  465. /// <param name="a"></param>
  466. /// <param name="b"></param>
  467. /// <returns></returns>
  468. public static bool matEqual(Mat a, Mat b) {
  469.     Mat temp = new Mat();
  470. Cv2.BitwiseXor(a, b, temp);
  471. Mat[] mats = temp.Split();
  472. int a1 = Cv2.CountNonZero(mats[0]);
  473. int a2 = Cv2.CountNonZero(mats[1]);
  474. int a3 = Cv2.CountNonZero(mats[2]);
  475. int a4 = Cv2.CountNonZero(mats[3]);
  476. return (a1+ a2+ a3+ a4) ==0;
  477. }
  478. /// <summary>
  479. /// 图像旋转
  480. /// </summary>
  481. /// <param name="src"></param>
  482. /// <param name="dst"></param>
  483. /// <param name="angle"></param>
  484. /// <param name="flags"></param>
  485. public static void ImageRotate(Mat src, Mat dst, float angle, InterpolationFlags flags)
  486. {
  487. Mat dst1 = new Mat();
  488. Point2f center = new Point2f(src.Cols / 2, src.Rows / 2);
  489. Mat rot = Cv2.GetRotationMatrix2D(center, -angle, 1);
  490. Size2f s2f = new Size2f(src.Size().Width, src.Size().Height);
  491. Rect box = new RotatedRect(new Point2f(0, 0), s2f, -angle).BoundingRect();
  492. double xx = rot.At<double>(0, 2) + box.Width / 2 - src.Cols / 2;
  493. double zz = rot.At<double>(1, 2) + box.Height / 2 - src.Rows / 2;
  494. rot.Set(0, 2, xx);
  495. rot.Set(1, 2, zz);
  496. //对图片进行仿射变换
  497. Cv2.WarpAffine(src, dst1, rot, box.Size, flags);
  498. dst1.CopyTo(dst);
  499. }
  500. /// <summary>
  501. /// 获取不相近的随机颜色
  502. /// </summary>
  503. public static Color GetRandomColor(Color color)
  504. {
  505. double H, L, S;
  506. Vec3b vec3B = new Vec3b();
  507. vec3B.Item0 = color.B;
  508. vec3B.Item1 = color.G;
  509. vec3B.Item1 = color.R;
  510. RGBtoHLS(vec3B, out H, out L, out S);
  511. double H1=0, L1=0, S1=0;
  512. for (var i = 0; i < 1; i++)
  513. {
  514. double[] ret = RandomHsl();
  515. // 颜色相邻颜色差异须大于 0.25
  516. if (i > 0 && Math.Abs(ret[0] - H) < 0.25)
  517. {
  518. i--;
  519. continue; // 重新获取随机色
  520. }
  521. ret[1] = 0.7 + (ret[1] * 0.2); // [0.7 - 0.9] 排除过灰颜色
  522. ret[2] = 0.4 + (ret[2] * 0.4); // [0.4 - 0.8] 排除过亮过暗色
  523. H1 = ret[0];
  524. S1 = ret[1];
  525. L1 = ret[2];
  526. }
  527. Vec3b v = HLStoRGB(H1, L1, S1);
  528. return Color.FromArgb(v.Item2, v.Item1, v.Item0);
  529. }
  530. public static double[] RandomHsl()
  531. {
  532. Random random = new Random();
  533. double[] hsl = new double[3];
  534. var H = random.NextDouble();
  535. var S = random.NextDouble();
  536. var L = random.NextDouble();
  537. hsl[0] = H;
  538. hsl[1] = S;
  539. hsl[2] = L;
  540. return hsl;
  541. }
  542. /// <summary>
  543. /// 将bitmap转透明,需要四个通道的bitmap
  544. /// </summary>
  545. /// <param name="bitmap"></param>
  546. /// <returns></returns>
  547. public static Bitmap BitmapToTransparent(Bitmap bitmap)
  548. {
  549. OpenCvSharp.Mat mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(bitmap);
  550. if(mat.Type() == MatType.CV_8UC4)
  551. {
  552. Mat[] mats = mat.Split();
  553. mats[3].SetTo(new Scalar(0));
  554. Cv2.Merge(mats, mat);
  555. return OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat);
  556. }
  557. return bitmap;
  558. }
  559. /// <summary>
  560. /// 形态学孔洞填充
  561. /// </summary>
  562. /// <param name="srcBw">二值图0/255</param>
  563. /// <returns></returns>
  564. public static Mat FillHole(Mat srcBw, Scalar scalar)
  565. {
  566. OpenCvSharp.Size m_Size = srcBw.Size();
  567. //创建扩展边界的图像
  568. Mat temp = Mat.Zeros(m_Size.Height + 2, m_Size.Width + 2, srcBw.Type());
  569. srcBw.CopyTo(new Mat(temp, new Range(1, m_Size.Height + 1), new Range(1, m_Size.Width + 1)));
  570. //new OpenCvSharp.Point(0, 0)
  571. Cv2.FloodFill(temp, new OpenCvSharp.Point(0, 0), scalar);
  572. //裁剪扩展边界的图像
  573. Mat cutImg = new Mat();
  574. new Mat(temp, new Range(1, m_Size.Height + 1), new Range(1, m_Size.Width + 1)).CopyTo(cutImg);
  575. return srcBw | (~cutImg);
  576. }
  577. /// <summary>
  578. /// 返回合并后的图片
  579. /// 主要适用于四通道合并为三通道
  580. /// </summary>
  581. /// <param name="arr"></param>
  582. /// <returns></returns>
  583. public static Mat MergeMatFromMatArr(Mat[] arr)
  584. {
  585. Mat[] mats = new Mat[3];
  586. mats[0] = arr[0];
  587. mats[1] = arr[1];
  588. mats[2] = arr[2];
  589. Mat dst = new Mat();
  590. Cv2.Merge(mats, dst);
  591. return dst;
  592. }
  593. /// <summary>
  594. /// 形态学提取连通分量
  595. /// </summary>
  596. /// <param name="src">需要0/1的二值图</param>
  597. /// <param name="iseight">true 8连通 / false 4连通</param>
  598. /// <param name="points">各个连通区域的种子点的坐标集合</param>
  599. /// <param name="nums">各个连通区域的像素个数集合</param>
  600. public static void MorphologExConnComponents(Mat src, bool iseight, out List<OpenCvSharp.Point> points, out List<int> nums)
  601. {
  602. points = new List<OpenCvSharp.Point>();
  603. nums = new List<int>();
  604. Mat structelement;
  605. if (iseight)
  606. structelement = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(3, 3));
  607. else
  608. structelement = Cv2.GetStructuringElement(MorphShapes.Cross, new OpenCvSharp.Size(3, 3));
  609. //dst = Mat.Ones(src.Size(), src.Type());
  610. Mat tmp = Mat.Ones(src.Size(), src.Type()); // save last reuslt image
  611. //Mat img = Mat.Ones(src.Size(), src.Type()); //image B
  612. int labelnum = 0; //label of connected component
  613. Mat backupsrc = new Mat();
  614. src.CopyTo(backupsrc);
  615. for (int i = 0; i < backupsrc.Rows; i++)
  616. {
  617. for (int j = 0; j < backupsrc.Cols; j++)
  618. {
  619. if (backupsrc.At<byte>(i, j) == 255)
  620. {
  621. Mat img = Mat.Ones(src.Size(), src.Type());
  622. img.CopyTo(tmp); img.Set<byte>(i, j, 255);
  623. labelnum++;
  624. while (true)
  625. {
  626. Cv2.Dilate(img, img, structelement);
  627. Cv2.BitwiseAnd(img, src, img);
  628. if (Cv2.CountNonZero(img - tmp) == 0)
  629. break;
  630. img.CopyTo(tmp);
  631. }
  632. //Cv2.ImShow("xx" + labelnum, img);
  633. // int xx = Cv2.CountNonZero(img);
  634. //System.Console.WriteLine(labelnum +"、" +i+ "、" + j +":" + xx);
  635. int hh = 0;
  636. //label the connected component
  637. for (int r = 0; r < img.Rows; r++)
  638. {
  639. for (int c = 0; c < img.Cols; c++)
  640. {
  641. if (img.At<byte>(r, c) == 255)
  642. {
  643. hh++;
  644. backupsrc.Set<byte>(r, c, 0);
  645. //dst.Set<int>(r, c, labelnum);
  646. }
  647. }
  648. }
  649. points.Add(new OpenCvSharp.Point(j, i));
  650. nums.Add(hh);
  651. //System.Console.WriteLine(labelnum + ":" + hh);
  652. }
  653. }
  654. }
  655. //return labelnum;
  656. }
  657. public static Mat MergeMatFromMatArr(Mat src, Vec4b vec4B)
  658. {
  659. Mat[] arr = src.Split();
  660. Mat apa = arr[3].Clone();
  661. apa = apa * 1/255;
  662. arr[0] = apa * vec4B.Item0;
  663. arr[1] = apa * vec4B.Item1;
  664. arr[2] = apa * vec4B.Item2;
  665. Cv2.Merge(arr, src);
  666. return src;
  667. }
  668. }
  669. }