BaseTools.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765
  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] = new Rangef(0.0F, 256.0F);
  343. Mat hist = new Mat();
  344. Cv2.CalcHist(mats0, channels0, new Mat(), hist, 1, histsize, range);
  345. int value = 0;
  346. for (int i = 0; i < 256; i++)
  347. {
  348. //取每个bin的数目
  349. int temp = (int)(hist.At<float>(i, 0));
  350. if (temp > 0)
  351. value++;
  352. }
  353. return value == 2;
  354. }
  355. /// <summary>
  356. /// 收缩图像
  357. /// </summary>
  358. /// <param name="ip"></param>
  359. /// <param name="ip2"></param>
  360. /// <param name="hasEdgePixels"></param>
  361. /// <returns></returns>
  362. public static Mat shrink(Mat ip, Mat ip2, bool hasEdgePixels)
  363. {
  364. if (hasEdgePixels)
  365. {
  366. int width = ip.Width;
  367. int height = ip.Height;
  368. for (int y = 0; y < height; y++)
  369. for (int x = 0; x < width; x++)
  370. ip.Set<byte>(y, x, ip2.At<byte>(y + 1, x + 1));
  371. }
  372. return ip;
  373. }
  374. /// <summary>
  375. /// 阴影校正功能里面,用来进行行列处理的方法
  376. /// </summary>
  377. /// <param name="I_OUT"></param>
  378. /// <param name="threshold"></param>
  379. /// <returns></returns>
  380. public static Mat ImageSmoothIIR(Mat I_OUT, double threshold)
  381. {
  382. /*int M = I_OUT.Height;
  383. int N = I_OUT.Width;
  384. for (int P = 1; P < M; P++)
  385. {
  386. I_OUT.Row[P] = threshold * 1.0f * (I_OUT.Row[P - 1] - I_OUT.Row[P]) + I_OUT.Row[P];
  387. }
  388. for (int P = M - 2; P > -1; P--)
  389. {
  390. I_OUT.Row[P] = threshold * 1.0f * (I_OUT.Row[P + 1] - I_OUT.Row[P]) + I_OUT.Row[P];
  391. }
  392. for (int L = 1; L < N; L++)
  393. {
  394. I_OUT.Col[L] = threshold * 1.0f * (I_OUT.Col[L - 1] - I_OUT.Col[L]) + I_OUT.Col[L];
  395. }
  396. for (int L = N - 2; L > -1; L--)
  397. {
  398. I_OUT.Col[L] = threshold * 1.0f * (I_OUT.Col[L + 1] - I_OUT.Col[L]) + I_OUT.Col[L];
  399. }
  400. return I_OUT;*/
  401. Mat temp = null;
  402. int M = I_OUT.Height;
  403. int N = I_OUT.Width;
  404. for (int P = 1; P < M; P++)
  405. {
  406. temp = (threshold * 1.0f * (I_OUT.Row(P - 1) - I_OUT.Row(P)) + I_OUT.Row(P));
  407. temp.CopyTo(I_OUT.Row(P));
  408. }
  409. for (int P = M - 2; P > -1; P--)
  410. {
  411. temp = (threshold * 1.0f * (I_OUT.Row(P + 1) - I_OUT.Row(P)) + I_OUT.Row(P));
  412. temp.CopyTo(I_OUT.Row(P));
  413. }
  414. for (int L = 1; L < N - 1; L++)
  415. {
  416. temp = (threshold * 1.0f * (I_OUT.Col(L - 1) - I_OUT.Col(L)) + I_OUT.Col(L));
  417. temp.CopyTo(I_OUT.Col(L));
  418. }
  419. for (int L = N - 2; L > -1; L--)
  420. {
  421. temp = (threshold * 1.0f * (I_OUT.Col(L + 1) - I_OUT.Col(L)) + I_OUT.Col(L));
  422. temp.CopyTo(I_OUT.Col(L));
  423. }
  424. return I_OUT;
  425. }
  426. /// <summary>
  427. /// 引射线法判断点是否在多边形内部(以该点为起点沿x轴负方向做一条射线)
  428. /// </summary>
  429. /// <param name="p"></param>
  430. /// <param name="vPoint"></param>
  431. /// <returns></returns>
  432. public static bool isPointInPolygon(System.Drawing.Point p, List<System.Drawing.PointF> vPoint)
  433. {
  434. int i, j = vPoint.Count - 1;
  435. bool inside = false;
  436. double x = p.X;
  437. double y = p.Y;
  438. for (i = 0; i < vPoint.Count; i++)
  439. {
  440. 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))
  441. {
  442. double dTmp = vPoint[i].X + (y - vPoint[i].Y) / (vPoint[j].Y - vPoint[i].Y) * (vPoint[j].X - vPoint[i].X);
  443. bool bTmp;
  444. if (dTmp == x) //点在多边形的边上,也算在多边形内
  445. {
  446. //count = 1;
  447. return true;
  448. }
  449. else
  450. bTmp = (dTmp < x);
  451. inside ^= bTmp;
  452. //if (bTmp)
  453. //count++;
  454. }
  455. j = i;
  456. }
  457. return inside;
  458. }
  459. /// <summary>
  460. /// 判断点是否在椭圆内
  461. /// </summary>
  462. /// <param name="point"></param>
  463. /// <param name="centerPoint"></param>
  464. /// <returns></returns>
  465. public static bool isPointInOval(System.Drawing.Point point, System.Drawing.PointF centerPoint, float xaxis, float yaxis)
  466. {
  467. double v = Math.Pow(centerPoint.X - point.X, 2) / Math.Pow(xaxis, 2) + Math.Pow(centerPoint.Y - point.Y, 2) / Math.Pow(yaxis, 2);
  468. return v < 1;
  469. }
  470. /// <summary>
  471. /// System.Drawing.Point转OpenCvSharp.Point
  472. /// </summary>
  473. /// <param name="points1"></param>
  474. /// <param name="points2"></param>
  475. /// <returns></returns>
  476. public static List<OpenCvSharp.Point> pointToPoint(List<System.Drawing.PointF> points)
  477. {
  478. List<OpenCvSharp.Point> points1 = new List<OpenCvSharp.Point>();
  479. foreach(System.Drawing.PointF point in points)
  480. {
  481. points1.Add(new OpenCvSharp.Point(point.X, point.Y));
  482. }
  483. return points1;
  484. }
  485. /// <summary>
  486. /// 判断mat是否相同
  487. /// </summary>
  488. /// <param name="a"></param>
  489. /// <param name="b"></param>
  490. /// <returns></returns>
  491. public static bool matEqual(Mat a, Mat b) {
  492.     Mat temp = new Mat();
  493. Cv2.BitwiseXor(a, b, temp);
  494. Mat[] mats = temp.Split();
  495. int a1 = Cv2.CountNonZero(mats[0]);
  496. int a2 = Cv2.CountNonZero(mats[1]);
  497. int a3 = Cv2.CountNonZero(mats[2]);
  498. int a4 = Cv2.CountNonZero(mats[3]);
  499. return (a1+ a2+ a3+ a4) ==0;
  500. }
  501. /// <summary>
  502. /// 图像旋转
  503. /// </summary>
  504. /// <param name="src"></param>
  505. /// <param name="dst"></param>
  506. /// <param name="angle"></param>
  507. /// <param name="flags"></param>
  508. public static void ImageRotate(Mat src, Mat dst, float angle, InterpolationFlags flags)
  509. {
  510. Mat dst1 = new Mat();
  511. Point2f center = new Point2f(src.Cols / 2, src.Rows / 2);
  512. Mat rot = Cv2.GetRotationMatrix2D(center, -angle, 1);
  513. Size2f s2f = new Size2f(src.Size().Width, src.Size().Height);
  514. Rect box = new RotatedRect(new Point2f(0, 0), s2f, -angle).BoundingRect();
  515. double xx = rot.At<double>(0, 2) + box.Width / 2 - src.Cols / 2;
  516. double zz = rot.At<double>(1, 2) + box.Height / 2 - src.Rows / 2;
  517. rot.Set(0, 2, xx);
  518. rot.Set(1, 2, zz);
  519. //对图片进行仿射变换
  520. Cv2.WarpAffine(src, dst1, rot, box.Size, flags);
  521. dst1.CopyTo(dst);
  522. }
  523. /// <summary>
  524. /// 获取不相近的随机颜色
  525. /// </summary>
  526. public static Color GetRandomColor(Color color)
  527. {
  528. double H, L, S;
  529. Vec3b vec3B = new Vec3b();
  530. vec3B.Item0 = color.B;
  531. vec3B.Item1 = color.G;
  532. vec3B.Item1 = color.R;
  533. RGBtoHLS(vec3B, out H, out L, out S);
  534. double H1=0, L1=0, S1=0;
  535. for (var i = 0; i < 1; i++)
  536. {
  537. double[] ret = RandomHsl();
  538. // 颜色相邻颜色差异须大于 0.25
  539. if (i > 0 && Math.Abs(ret[0] - H) < 0.25)
  540. {
  541. i--;
  542. continue; // 重新获取随机色
  543. }
  544. ret[1] = 0.7 + (ret[1] * 0.2); // [0.7 - 0.9] 排除过灰颜色
  545. ret[2] = 0.4 + (ret[2] * 0.4); // [0.4 - 0.8] 排除过亮过暗色
  546. H1 = ret[0];
  547. S1 = ret[1];
  548. L1 = ret[2];
  549. }
  550. Vec3b v = HLStoRGB(H1, L1, S1);
  551. return Color.FromArgb(v.Item2, v.Item1, v.Item0);
  552. }
  553. public static double[] RandomHsl()
  554. {
  555. Random random = new Random();
  556. double[] hsl = new double[3];
  557. var H = random.NextDouble();
  558. var S = random.NextDouble();
  559. var L = random.NextDouble();
  560. hsl[0] = H;
  561. hsl[1] = S;
  562. hsl[2] = L;
  563. return hsl;
  564. }
  565. /// <summary>
  566. /// 将bitmap转透明,需要四个通道的bitmap
  567. /// </summary>
  568. /// <param name="bitmap"></param>
  569. /// <returns></returns>
  570. public static Bitmap BitmapToTransparent(Bitmap bitmap)
  571. {
  572. OpenCvSharp.Mat mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(bitmap);
  573. if(mat.Type() == MatType.CV_8UC4)
  574. {
  575. Mat[] mats = mat.Split();
  576. mats[3].SetTo(new Scalar(0));
  577. Cv2.Merge(mats, mat);
  578. return OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat);
  579. }
  580. return bitmap;
  581. }
  582. /// <summary>
  583. /// 形态学孔洞填充
  584. /// </summary>
  585. /// <param name="srcBw">二值图0/255</param>
  586. /// <returns></returns>
  587. public static Mat FillHole(Mat srcBw, Scalar scalar)
  588. {
  589. OpenCvSharp.Size m_Size = srcBw.Size();
  590. //创建扩展边界的图像
  591. Mat temp = Mat.Zeros(m_Size.Height + 2, m_Size.Width + 2, srcBw.Type());
  592. srcBw.CopyTo(new Mat(temp, new Range(1, m_Size.Height + 1), new Range(1, m_Size.Width + 1)));
  593. //new OpenCvSharp.Point(0, 0)
  594. Cv2.FloodFill(temp, new OpenCvSharp.Point(0, 0), scalar);
  595. //裁剪扩展边界的图像
  596. Mat cutImg = new Mat();
  597. new Mat(temp, new Range(1, m_Size.Height + 1), new Range(1, m_Size.Width + 1)).CopyTo(cutImg);
  598. return srcBw | (~cutImg);
  599. }
  600. /// <summary>
  601. /// 返回合并后的图片
  602. /// 主要适用于四通道合并为三通道
  603. /// </summary>
  604. /// <param name="arr"></param>
  605. /// <returns></returns>
  606. public static Mat MergeMatFromMatArr(Mat[] arr)
  607. {
  608. Mat[] mats = new Mat[3];
  609. mats[0] = arr[0];
  610. mats[1] = arr[1];
  611. mats[2] = arr[2];
  612. Mat dst = new Mat();
  613. Cv2.Merge(mats, dst);
  614. return dst;
  615. }
  616. /// <summary>
  617. /// 形态学提取连通分量
  618. /// </summary>
  619. /// <param name="src">需要0/1的二值图</param>
  620. /// <param name="iseight">true 8连通 / false 4连通</param>
  621. /// <param name="points">各个连通区域的种子点的坐标集合</param>
  622. /// <param name="nums">各个连通区域的像素个数集合</param>
  623. public static void MorphologExConnComponents(Mat src, bool iseight, out List<OpenCvSharp.Point> points, out List<int> nums)
  624. {
  625. points = new List<OpenCvSharp.Point>();
  626. nums = new List<int>();
  627. Mat structelement;
  628. if (iseight)
  629. structelement = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(3, 3));
  630. else
  631. structelement = Cv2.GetStructuringElement(MorphShapes.Cross, new OpenCvSharp.Size(3, 3));
  632. //dst = Mat.Ones(src.Size(), src.Type());
  633. Mat tmp = Mat.Ones(src.Size(), src.Type()); // save last reuslt image
  634. //Mat img = Mat.Ones(src.Size(), src.Type()); //image B
  635. int labelnum = 0; //label of connected component
  636. Mat backupsrc = new Mat();
  637. src.CopyTo(backupsrc);
  638. for (int i = 0; i < backupsrc.Rows; i++)
  639. {
  640. for (int j = 0; j < backupsrc.Cols; j++)
  641. {
  642. if (backupsrc.At<byte>(i, j) == 255)
  643. {
  644. Mat img = Mat.Ones(src.Size(), src.Type());
  645. img.CopyTo(tmp); img.Set<byte>(i, j, 255);
  646. labelnum++;
  647. while (true)
  648. {
  649. Cv2.Dilate(img, img, structelement);
  650. Cv2.BitwiseAnd(img, src, img);
  651. if (Cv2.CountNonZero(img - tmp) == 0)
  652. break;
  653. img.CopyTo(tmp);
  654. }
  655. //Cv2.ImShow("xx" + labelnum, img);
  656. // int xx = Cv2.CountNonZero(img);
  657. //System.Console.WriteLine(labelnum +"、" +i+ "、" + j +":" + xx);
  658. int hh = 0;
  659. //label the connected component
  660. for (int r = 0; r < img.Rows; r++)
  661. {
  662. for (int c = 0; c < img.Cols; c++)
  663. {
  664. if (img.At<byte>(r, c) == 255)
  665. {
  666. hh++;
  667. backupsrc.Set<byte>(r, c, 0);
  668. //dst.Set<int>(r, c, labelnum);
  669. }
  670. }
  671. }
  672. points.Add(new OpenCvSharp.Point(j, i));
  673. nums.Add(hh);
  674. //System.Console.WriteLine(labelnum + ":" + hh);
  675. }
  676. }
  677. }
  678. //return labelnum;
  679. }
  680. public static Mat MergeMatFromMatArr(Mat src, Vec4b vec4B)
  681. {
  682. Mat[] arr = src.Split();
  683. Mat apa = arr[3].Clone();
  684. apa = apa * 1/255;
  685. arr[0] = apa * vec4B.Item0;
  686. arr[1] = apa * vec4B.Item1;
  687. arr[2] = apa * vec4B.Item2;
  688. Cv2.Merge(arr, src);
  689. return src;
  690. }
  691. }
  692. }