BasicCalculationHelper.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.Linq;
  5. namespace SmartCoalApplication.Base.CommTool
  6. {
  7. /// <summary>
  8. /// 基础计算帮助类
  9. /// </summary>
  10. public class BasicCalculationHelper
  11. {
  12. /// <summary>
  13. /// 计算两点之间的距离
  14. /// </summary>
  15. /// <param name="startPoint">起点</param>
  16. /// <param name="endPoint">终点</param>
  17. /// <returns></returns>
  18. public static double GetDistance(Point startPoint, Point endPoint, int digit)
  19. {
  20. try
  21. {
  22. long x = System.Math.Abs(endPoint.X - startPoint.X);
  23. long y = System.Math.Abs(endPoint.Y - startPoint.Y);
  24. return Math.Round(Math.Sqrt(x * x + y * y), digit);
  25. }
  26. catch (Exception)
  27. {
  28. }
  29. return 0.0;
  30. }
  31. /// <summary>
  32. /// 计算两点之间的距离
  33. /// </summary>
  34. /// <param name="startPoint">起点</param>
  35. /// <param name="endPoint">终点</param>
  36. /// <returns></returns>
  37. public static double GetDistance(PointF startPoint, PointF endPoint)
  38. {
  39. try
  40. {
  41. float x = System.Math.Abs(endPoint.X - startPoint.X);
  42. float y = System.Math.Abs(endPoint.Y - startPoint.Y);
  43. return Math.Sqrt(x * x + y * y);
  44. }
  45. catch (Exception)
  46. {
  47. }
  48. return 0.0;
  49. }
  50. public static double GetDistance(PointF startPoint, PointF endPoint, int digit)
  51. {
  52. try
  53. {
  54. long x = System.Math.Abs((int)(endPoint.X - startPoint.X));
  55. long y = System.Math.Abs((int)(endPoint.Y - startPoint.Y));
  56. return Math.Round(Math.Sqrt(x * x + y * y), digit);
  57. }
  58. catch (Exception)
  59. {
  60. }
  61. return 0.0;
  62. }
  63. /// <summary>
  64. /// opencv的仿射变换
  65. /// </summary>
  66. /// <param name="src"></param>
  67. /// <param name="center"></param>
  68. /// <param name="angle"></param>
  69. /// <returns></returns>
  70. public static OpenCvSharp.Point GetPointAffinedPos(OpenCvSharp.Point src, OpenCvSharp.Point center, double angle)
  71. {
  72. OpenCvSharp.Point dst;
  73. int x = src.X - center.X;
  74. int y = src.Y - center.Y;
  75. dst.X = (int)Math.Round(x * Math.Cos(angle) + y * Math.Sin(angle) + center.X);
  76. dst.Y = (int)Math.Round(-x * Math.Sin(angle) + y * Math.Cos(angle) + center.Y);
  77. return dst;
  78. }
  79. /// <summary>
  80. /// 计算轮廓内最左和最右点的距离
  81. /// </summary>
  82. /// <returns></returns>
  83. public static int GetLeftAndRightDistance(OpenCvSharp.Point[] points)
  84. {
  85. OpenCvSharp.Point left = points[0];
  86. OpenCvSharp.Point right = points[0];
  87. foreach (OpenCvSharp.Point p in points)
  88. {
  89. if (left.X > p.X)
  90. {
  91. left = p;
  92. }
  93. if (right.X < p.X)
  94. {
  95. right = p;
  96. }
  97. }
  98. return right.X - left.X;
  99. }
  100. public static List<int> GetCaliperDiameter(OpenCvSharp.Point[] contours, OpenCvSharp.HierarchyIndex hierarchyIndex)
  101. {
  102. //计算结果
  103. List<int> vs = new List<int>();
  104. //每次旋转的角度
  105. double angle = 360 / 64;
  106. //计算中心点
  107. OpenCvSharp.Moments m = OpenCvSharp.Cv2.Moments(contours);
  108. double cx = m.M10 / m.M00;
  109. double cy = m.M01 / m.M00;
  110. for (int i = 0; i < 64; i++)
  111. {
  112. if (i == 0)
  113. {
  114. vs.Add(GetLeftAndRightDistance(contours));
  115. }
  116. else
  117. {
  118. if (contours.Length >= 5 && hierarchyIndex.Parent == -1 && !Double.IsNaN(cx))
  119. {
  120. try
  121. {
  122. OpenCvSharp.Point[] temps = new OpenCvSharp.Point[contours.Count()];
  123. for (int j = 0; j < contours.Count(); j++)
  124. {
  125. temps[j] = BasicCalculationHelper.GetPointAffinedPos(contours[j], new OpenCvSharp.Point(cx, cy), angle * i);
  126. }
  127. vs.Add(GetLeftAndRightDistance(temps));
  128. }
  129. catch (Exception)
  130. {
  131. }
  132. }
  133. /*else
  134. {
  135. vs.Add(0);
  136. }*/
  137. }
  138. }
  139. return vs;
  140. }
  141. /// <summary>
  142. /// 求第三个点到直线上的垂足的点
  143. /// </summary>
  144. /// <param name="start">构成直线的点1</param>
  145. /// <param name="end">构成直线的点2</param>
  146. /// <param name="three">线外的一点</param>
  147. /// <returns></returns>
  148. public static PointF GetDropFeet(PointF start, PointF end, PointF three)
  149. {
  150. PointF footPoint = new PointF();
  151. // 求直线斜率
  152. double k = (double)(end.Y - start.Y) / (end.X - start.X);
  153. //pointArray[0].X == pointArray[1].X || pointArray[0].Y == pointArray[1].Y
  154. if (double.IsInfinity(k) || Math.Abs(k) < 0.001) //垂线斜率不存在或斜率为0
  155. {
  156. if (k > 0)
  157. {
  158. footPoint.X = start.X;
  159. footPoint.Y = three.Y;
  160. }
  161. else if (k < 0)
  162. {
  163. footPoint.X = start.X;
  164. footPoint.Y = three.Y;
  165. }
  166. else
  167. {
  168. footPoint.Y = start.Y;
  169. footPoint.X = three.X;
  170. }
  171. }
  172. else
  173. {
  174. footPoint.X = (float)((k * start.X + three.X / k + three.Y - start.Y) / (1 / k + k));
  175. footPoint.Y = (float)(-1 / k * (footPoint.X - three.X) + three.Y);
  176. }
  177. return footPoint;
  178. }
  179. /// <summary>
  180. /// 已知直线上一点、斜率、线外一点,求垂足
  181. /// </summary>
  182. /// <param name="start">线上一点</param>
  183. /// <param name="k">斜率</param>
  184. /// <param name="three">线外一点</param>
  185. /// <returns></returns>
  186. public static PointF GetDropFeet(PointF start, double k, PointF three)
  187. {
  188. PointF footPoint = new PointF();
  189. if (double.IsInfinity(k) || Math.Abs(k) < 0.001) //垂线斜率不存在或斜率为0
  190. {
  191. if (k > 0)
  192. {
  193. footPoint.X = start.X;
  194. footPoint.Y = three.Y;
  195. }
  196. else if (k < 0)
  197. {
  198. footPoint.X = start.X;
  199. footPoint.Y = three.Y;
  200. }
  201. else
  202. {
  203. footPoint.Y = start.Y;
  204. footPoint.X = three.X;
  205. }
  206. }
  207. else
  208. {
  209. footPoint.X = (float)((k * start.X + three.X / k + three.Y - start.Y) / (1 / k + k));
  210. footPoint.Y = (float)(-1 / k * (footPoint.X - three.X) + three.Y);
  211. }
  212. return footPoint;
  213. }
  214. /// <summary>
  215. /// 三点计算角度,可能不对
  216. /// </summary>
  217. /// <param name="cen"></param>
  218. /// <param name="first"></param>
  219. /// <param name="second"></param>
  220. /// <returns></returns>
  221. public static double Angle(Point cen, Point first, Point second)
  222. {
  223. //判断象限
  224. int x = first.X - cen.X;
  225. int y = first.Y - cen.Y;
  226. int i = 0;
  227. if (x > 0 && y > 0) //第4象限
  228. {
  229. i = 4;
  230. }
  231. else if (x > 0 && y < 0) //第1象限
  232. {
  233. i = 1;
  234. }
  235. else if (x < 0 && y < 0) //第2象限
  236. {
  237. i = 2;
  238. }
  239. else if (x < 0 && y > 0) //第3象限
  240. {
  241. i = 3;
  242. }
  243. double ma_x = first.X - cen.X;
  244. double ma_y = first.Y - cen.Y;
  245. double mb_x = second.X - cen.X;
  246. double mb_y = second.Y - cen.Y;
  247. double v1 = (ma_x * mb_x) + (ma_y * mb_y);
  248. double ma_val = Math.Sqrt(ma_x * ma_x + ma_y * ma_y);
  249. double mb_val = Math.Sqrt(mb_x * mb_x + mb_y * mb_y);
  250. double cosM = v1 / (ma_val * mb_val);
  251. double angleAMB = Math.Acos(cosM) * 180 / Math.PI;
  252. if (i == 1) angleAMB = angleAMB - 90;
  253. if (i == 4) angleAMB = 90 - angleAMB;
  254. if (i == 3) angleAMB = angleAMB + 90;
  255. if (i == 2) angleAMB = 270 - angleAMB;
  256. return double.IsNaN(angleAMB) ? 0 : angleAMB;
  257. }
  258. public static double Angle(PointF cen, PointF first, PointF second)
  259. {
  260. //判断象限
  261. int x = (int)(first.X - cen.X);
  262. int y = (int)(first.Y - cen.Y);
  263. int i = 0;
  264. if (x > 0 && y > 0) //第4象限
  265. {
  266. i = 4;
  267. }
  268. else if (x > 0 && y < 0) //第1象限
  269. {
  270. i = 1;
  271. }
  272. else if (x < 0 && y < 0) //第2象限
  273. {
  274. i = 2;
  275. }
  276. else if (x < 0 && y > 0) //第3象限
  277. {
  278. i = 3;
  279. }
  280. double ma_x = first.X - cen.X;
  281. double ma_y = first.Y - cen.Y;
  282. double mb_x = second.X - cen.X;
  283. double mb_y = second.Y - cen.Y;
  284. double v1 = (ma_x * mb_x) + (ma_y * mb_y);
  285. double ma_val = Math.Sqrt(ma_x * ma_x + ma_y * ma_y);
  286. double mb_val = Math.Sqrt(mb_x * mb_x + mb_y * mb_y);
  287. double cosM = v1 / (ma_val * mb_val);
  288. double angleAMB = Math.Acos(cosM) * 180 / Math.PI;
  289. if (i == 1) angleAMB = angleAMB - 90;
  290. if (i == 4) angleAMB = 90 - angleAMB;
  291. if (i == 3) angleAMB = angleAMB + 90;
  292. if (i == 2) angleAMB = 270 - angleAMB;
  293. return double.IsNaN(angleAMB) ? 0 : angleAMB;
  294. }
  295. /// <summary>
  296. /// 三点计算角度,第二个写法
  297. /// </summary>
  298. /// <param name="P1X"></param>
  299. /// <param name="P1Y"></param>
  300. /// <param name="P2X"></param>
  301. /// <param name="P2Y"></param>
  302. /// <param name="P3X"></param>
  303. /// <param name="P3Y"></param>
  304. /// <returns></returns>
  305. public static double CalculateAngle(double P1X, double P1Y, double P2X, double P2Y,
  306. double P3X, double P3Y)
  307. {
  308. double numerator = P2Y * (P1X - P3X) + P1Y * (P3X - P2X) + P3Y * (P2X - P1X);
  309. double denominator = (P2X - P1X) * (P1X - P3X) + (P2Y - P1Y) * (P1Y - P3Y);
  310. double ratio = numerator / denominator;
  311. double angleRad = Math.Atan(ratio);
  312. double angleDeg = (angleRad * 180) / Math.PI;
  313. /*if (angleDeg < 0)
  314. {
  315. angleDeg = 180 + angleDeg;
  316. }*/
  317. /*if(angleDeg>360)
  318. {
  319. angleDeg = angleDeg - 360 * (angleDeg / 360);
  320. }*/
  321. //angleDeg = 180 - angleDeg;
  322. return -angleDeg;
  323. }
  324. /// <summary>
  325. /// 根据圆心点旋转另一个点
  326. /// </summary>
  327. /// <param name="point">圆上的点</param>
  328. /// <param name="center">圆心点</param>
  329. /// <param name="angle">旋转角度</param>
  330. /// <returns>返回旋转后的点的坐标</returns>
  331. public static Point GetAnglePoint(Point point, Point center, double angle)
  332. {
  333. Point p = new Point();
  334. angle = angle * Math.PI / 180;
  335. p.X = Convert.ToInt32((point.X - center.X) * Math.Cos(angle) - (point.Y - center.Y) * Math.Sin(angle) + center.X);
  336. p.Y = Convert.ToInt32((point.X - center.X) * Math.Sin(angle) + (point.Y - center.Y) * Math.Cos(angle) + center.Y);
  337. return p;
  338. }
  339. /// <summary>
  340. /// 计算夹角
  341. /// </summary>
  342. /// <param name="first">固定点</param>
  343. /// <param name="cen">圆心点</param>
  344. /// <param name="second">浮点</param>
  345. /// <returns>返回旋转后的点的坐标</returns>
  346. public static double CalculateAngle(PointF cen, PointF first, PointF second)
  347. {
  348. double ma_x = first.X - cen.X;
  349. double ma_y = first.Y - cen.Y;
  350. double mb_x = second.X - cen.X;
  351. double mb_y = second.Y - cen.Y;
  352. double v1 = (ma_x * mb_x) + (ma_y * mb_y);
  353. double ma_val = Math.Sqrt(ma_x * ma_x + ma_y * ma_y);
  354. double mb_val = Math.Sqrt(mb_x * mb_x + mb_y * mb_y);
  355. double cosM = v1 / (ma_val * mb_val);
  356. double angleAMB = Math.Acos(cosM) * 180 / Math.PI;
  357. if (second.Y < first.Y) angleAMB = -angleAMB;
  358. return angleAMB;
  359. }
  360. public static PointF GetAnglePoint(PointF point, PointF center, double angle)
  361. {
  362. PointF p = new PointF();
  363. angle = angle * Math.PI / 180;
  364. p.X = (float)((point.X - center.X) * Math.Cos(angle) - (point.Y - center.Y) * Math.Sin(angle) + center.X);
  365. p.Y = (float)((point.X - center.X) * Math.Sin(angle) + (point.Y - center.Y) * Math.Cos(angle) + center.Y);
  366. return p;
  367. }
  368. /// <summary>
  369. /// 计算宽高比
  370. /// </summary>
  371. /// <param name="points"></param>
  372. /// <returns></returns>
  373. public static double CalcAspectRatio(OpenCvSharp.Point[] points)
  374. {
  375. List<OpenCvSharp.Point> ps = points.ToList<OpenCvSharp.Point>();
  376. //最左侧的点
  377. int left = ps.Min<OpenCvSharp.Point>(a => a.X);
  378. //最右侧的点
  379. int right = ps.Max<OpenCvSharp.Point>(a => a.X);
  380. //最顶部的点
  381. int top = ps.Min<OpenCvSharp.Point>(a => a.Y);
  382. //最底部的点
  383. int bottom = ps.Max<OpenCvSharp.Point>(a => a.Y);
  384. int width = right - left;
  385. int height = bottom - top;
  386. if (width == 0 || height == 0)
  387. return 0;
  388. else
  389. return width * 1d / height;
  390. }
  391. /// <summary>
  392. /// 计算长径,找轮廓的最小外接圆
  393. /// </summary>
  394. /// <param name="points"></param>
  395. /// <returns></returns>
  396. public static double CalcLongTrail(OpenCvSharp.Point[] points)
  397. {
  398. if (points.Length < 5)
  399. return 0;
  400. OpenCvSharp.Point2f center;
  401. float radius = 0f;
  402. OpenCvSharp.Cv2.MinEnclosingCircle(points, out center, out radius);
  403. return radius;
  404. //OpenCvSharp.RotatedRect rect = OpenCvSharp.Cv2.FitEllipse(points);
  405. //return rect.Size.Height > rect.Size.Width ? rect.Size.Height : rect.Size.Width;
  406. }
  407. /// <summary>
  408. /// 保留两位小数进位
  409. /// </summary>
  410. /// <param name="value">double类型的值</param>
  411. /// <returns></returns>
  412. public static double DecimalCeiling(double value)
  413. {
  414. double values = Math.Round(value, 2);
  415. if (values < value)
  416. {
  417. values += Math.Pow(0.1, 2);
  418. }
  419. return values;
  420. }
  421. /// <summary>
  422. /// 保留两位小数不进位
  423. /// </summary>
  424. /// <param name="value">double类型的值</param>
  425. /// <returns></returns>
  426. public static double DecimalFloor(double value)
  427. {
  428. return double.Parse(value.ToString("F2"));
  429. }
  430. /// <summary>
  431. /// 计算长径,找轮廓的外接椭圆,计算椭圆的长径
  432. /// </summary>
  433. /// <param name="points"></param>
  434. /// <returns></returns>
  435. public static double CalcLongTrailEllipse(OpenCvSharp.Point[] points)
  436. {
  437. if (points.Length < 5)
  438. return 0;
  439. OpenCvSharp.RotatedRect rect = OpenCvSharp.Cv2.FitEllipse(points);
  440. return rect.Size.Height > rect.Size.Width ? rect.Size.Height : rect.Size.Width;
  441. }
  442. /// <summary>
  443. /// 计算曲线长度
  444. /// </summary>
  445. /// <param name="cen"></param>
  446. /// <param name="first"></param>
  447. /// <param name="second"></param>
  448. /// <returns></returns>
  449. private static double A = 4f / 14175f;
  450. private static int[] B = { 989, 5888, -928, 10496, -4540, 10496, -928, 5888, 989 };
  451. public static double curveLength(PointF[] mLeafPt)
  452. {
  453. if (mLeafPt == null || mLeafPt.Length == 1)
  454. {
  455. return 0f;
  456. }
  457. int n = mLeafPt.Length;
  458. PointF p0 = mLeafPt[0];
  459. PointF Pn = mLeafPt[n - 1];
  460. PointF[] tempArray = new PointF[n + 2];
  461. tempArray[0] = p0;
  462. tempArray[tempArray.Length - 1] = Pn;
  463. for (int i = 1; i < tempArray.Length - 1; i++)
  464. {
  465. tempArray[i] = mLeafPt[i - 1];
  466. }
  467. double a = 0f, b = 0.5f;
  468. double h = (b - a) / 8f;
  469. double length = 0f;
  470. for (int i = 0; i < n - 1; i++)
  471. {
  472. double integral = 0f;
  473. for (int j = 0; j <= 8; j++)
  474. {
  475. double t = a + j * h;
  476. double px = Px(tempArray[i].X, tempArray[i + 1].X, tempArray[i + 2].X, tempArray[i + 1].X, t);
  477. double py = Px(tempArray[i].Y, tempArray[i + 1].Y, tempArray[i + 2].Y, tempArray[i + 1].Y, t);
  478. double f = (double)Math.Sqrt(px * px + py * py);
  479. integral += B[j] * f;
  480. }
  481. integral *= h * A;
  482. length += integral;
  483. }
  484. return length;
  485. }
  486. private static double Px(float p1, float p2, float p3, float p4, double t)
  487. {
  488. return (-12f * t * t + 8 * t - 1) * p1 + (36 * t * t - 20 * t) * p2 + (-36 * t * t + 16 * t + 1) * p3 + (12 * t * t - 4 * t) * p4;
  489. }
  490. /// <summary>
  491. /// 三点角计算
  492. /// </summary>
  493. /// <param name="cen"></param>
  494. /// <param name="first"></param>
  495. /// <param name="second"></param>
  496. /// <returns></returns>
  497. public static double AngleText(PointF cen, PointF first, PointF second)
  498. {
  499. const double M_PI = 3.1415926535897;
  500. double ma_x = first.X - cen.X;
  501. double ma_y = first.Y - cen.Y;
  502. double mb_x = second.X - cen.X;
  503. double mb_y = second.Y - cen.Y;
  504. double v1 = (ma_x * mb_x) + (ma_y * mb_y);
  505. double ma_val = Math.Sqrt(ma_x * ma_x + ma_y * ma_y);
  506. double mb_val = Math.Sqrt(mb_x * mb_x + mb_y * mb_y);
  507. double cosM = v1 / (ma_val * mb_val);
  508. double angleAMB = Math.Acos(cosM) * 180 / M_PI;
  509. return angleAMB;
  510. }
  511. ///<summary>
  512. ///点到直线距离
  513. /// </summary>
  514. /// <param name="point1">线上的1点</param>
  515. /// <param name="point2">线上的2点</param>
  516. /// <param name="point3">线外的点</param>
  517. public static double pointToLine(Point point1, Point point2, Point point3)
  518. {
  519. double space = 0;
  520. double a, b, c;
  521. a = GetDistance(point1, point2, 7);// 线段的长度
  522. b = GetDistance(point1, point3, 7);// (x1,y1)到点的距离
  523. c = GetDistance(point2, point3, 7);// (x2,y2)到点的距离
  524. if (c <= 0.000001 || b <= 0.000001)
  525. {
  526. space = 0;
  527. return space;
  528. }
  529. if (a <= 0.000001)
  530. {
  531. space = b;
  532. return space;
  533. }
  534. if (c * c >= a * a + b * b)
  535. {
  536. space = b;
  537. return space;
  538. }
  539. if (b * b >= a * a + c * c)
  540. {
  541. space = c;
  542. return space;
  543. }
  544. double p = (a + b + c) / 2;// 半周长
  545. double s = Math.Sqrt(p * (p - a) * (p - b) * (p - c));// 海伦公式求面积
  546. space = 2 * s / a;// 返回点到线的距离(利用三角形面积公式求高)
  547. return space;
  548. }
  549. /// <summary>
  550. /// 计算多边形周长
  551. /// </summary>
  552. /// <param name="Points">多边形顶点</param>
  553. /// <param name="digit">小数位数</param>
  554. /// <returns></returns>
  555. public static double GetPolygonPerimeter(PointF[] Points, int digit)
  556. {
  557. float x;
  558. float y;
  559. int j = 0;
  560. double length = 0.0;
  561. for (int i = 0; i < Points.Length; i++)
  562. {
  563. if (i == Points.Length - 1)
  564. j = -1;
  565. else
  566. j = i;
  567. x = System.Math.Abs(Points[j + 1].X - Points[i].X);
  568. y = System.Math.Abs(Points[j + 1].Y - Points[i].Y);
  569. length = length + Math.Round(Math.Sqrt(x * x + y * y), digit);
  570. }
  571. return length;
  572. }
  573. /// <summary>
  574. /// 计算多边形面积
  575. /// </summary>
  576. /// <param name="Points"></param>
  577. /// <param name="digit"></param>
  578. /// <returns></returns>
  579. public static double GetPolygonArea(List<PointF> points)
  580. {
  581. var count = points.Count;
  582. double area0 = 0;
  583. double area1 = 0;
  584. for (int i = 0; i < count; i++)
  585. {
  586. double x = points[i].X;
  587. double y = i + 1 < count ? points[i + 1].Y : points[0].Y;
  588. area0 += x * y;
  589. double lat = points[i].Y;
  590. double lon = i + 1 < count ? points[i + 1].X : points[0].X;
  591. area1 += lat * lon;
  592. }
  593. return Math.Round(Math.Abs(0.5 * (area0 - area1)), 10);
  594. }
  595. /// <summary>
  596. /// 计算两条直线的交点
  597. /// </summary>
  598. /// <param name="lineFirstStar">L1的点1坐标</param>
  599. /// <param name="lineFirstEnd">L1的点2坐标</param>
  600. /// <param name="lineSecondStar">L2的点1坐标</param>
  601. /// <param name="lineSecondEnd">L2的点2坐标</param>
  602. /// <returns></returns>
  603. public static PointF GetIntersection(PointF lineFirstStar, PointF lineFirstEnd, PointF lineSecondStar, PointF lineSecondEnd)
  604. {
  605. /*
  606. * L1,L2都存在斜率的情况:
  607. * 直线方程L1: ( y - y1 ) / ( y2 - y1 ) = ( x - x1 ) / ( x2 - x1 )
  608. * => y = [ ( y2 - y1 ) / ( x2 - x1 ) ]( x - x1 ) + y1
  609. * 令 a = ( y2 - y1 ) / ( x2 - x1 )
  610. * 有 y = a * x - a * x1 + y1 .........1
  611. * 直线方程L2: ( y - y3 ) / ( y4 - y3 ) = ( x - x3 ) / ( x4 - x3 )
  612. * 令 b = ( y4 - y3 ) / ( x4 - x3 )
  613. * 有 y = b * x - b * x3 + y3 ..........2
  614. *
  615. * 如果 a = b,则两直线平等,否则, 联解方程 1,2,得:
  616. * x = ( a * x1 - b * x3 - y1 + y3 ) / ( a - b )
  617. * y = a * x - a * x1 + y1
  618. *
  619. * L1存在斜率, L2平行Y轴的情况:
  620. * x = x3
  621. * y = a * x3 - a * x1 + y1
  622. *
  623. * L1 平行Y轴,L2存在斜率的情况:
  624. * x = x1
  625. * y = b * x - b * x3 + y3
  626. *
  627. * L1与L2都平行Y轴的情况:
  628. * 如果 x1 = x3,那么L1与L2重合,否则平等
  629. *
  630. */
  631. float a = 0, b = 0;
  632. int state = 0;
  633. if (lineFirstStar.X != lineFirstEnd.X)
  634. {
  635. a = (lineFirstEnd.Y - lineFirstStar.Y) / (lineFirstEnd.X - lineFirstStar.X);
  636. state |= 1;
  637. }
  638. if (lineSecondStar.X != lineSecondEnd.X)
  639. {
  640. b = (lineSecondEnd.Y - lineSecondStar.Y) / (lineSecondEnd.X - lineSecondStar.X);
  641. state |= 2;
  642. }
  643. switch (state)
  644. {
  645. case 0: //L1与L2都平行Y轴
  646. {
  647. if (lineFirstStar.X == lineSecondStar.X)
  648. {
  649. //throw new Exception("两条直线互相重合,且平行于Y轴,无法计算交点。");
  650. return new PointF(0, 0);
  651. }
  652. else
  653. {
  654. //throw new Exception("两条直线互相平行,且平行于Y轴,无法计算交点。");
  655. return new PointF(0, 0);
  656. }
  657. }
  658. case 1: //L1存在斜率, L2平行Y轴
  659. {
  660. float x = lineSecondStar.X;
  661. float y = (lineFirstStar.X - x) * (-a) + lineFirstStar.Y;
  662. return new PointF(x, y);
  663. }
  664. case 2: //L1 平行Y轴,L2存在斜率
  665. {
  666. float x = lineFirstStar.X;
  667. //网上有相似代码的,这一处是错误的。你可以对比case 1 的逻辑 进行分析
  668. //源code:lineSecondStar * x + lineSecondStar * lineSecondStar.X + p3.Y;
  669. float y = (lineSecondStar.X - x) * (-b) + lineSecondStar.Y;
  670. return new PointF(x, y);
  671. }
  672. case 3: //L1,L2都存在斜率
  673. {
  674. if (a == b)
  675. {
  676. // throw new Exception("两条直线平行或重合,无法计算交点。");
  677. return new PointF(0, 0);
  678. }
  679. float x = (a * lineFirstStar.X - b * lineSecondStar.X - lineFirstStar.Y + lineSecondStar.Y) / (a - b);
  680. float y = a * x - a * lineFirstStar.X + lineFirstStar.Y;
  681. return new PointF(x, y);
  682. }
  683. }
  684. // throw new Exception("不可能发生的情况");
  685. return new PointF(0, 0);
  686. }
  687. public static List<List<OpenCvSharp.Point>> GetWholeContoursTree(OpenCvSharp.Point[][] contours, OpenCvSharp.HierarchyIndex[] hierarchyIndex, int k)
  688. {
  689. List<List<OpenCvSharp.Point>> wholeContours = new List<List<OpenCvSharp.Point>>();
  690. wholeContours.Add(contours[k].ToList());
  691. if (hierarchyIndex[k].Child > 0)
  692. {
  693. RecursionGetWholeContoursTree(wholeContours, contours, hierarchyIndex, k);
  694. }
  695. return wholeContours;
  696. }
  697. public static void RecursionGetWholeContoursTree(List<List<OpenCvSharp.Point>> wholeContours, OpenCvSharp.Point[][] contours, OpenCvSharp.HierarchyIndex[] hierarchyIndex, int k)
  698. {
  699. if (hierarchyIndex[k].Child > 0)
  700. {
  701. for (int i = 0; i < hierarchyIndex.Length; i++)
  702. {
  703. if (hierarchyIndex[i].Parent == k)
  704. {
  705. wholeContours.Add(contours[i].ToList());
  706. if (hierarchyIndex[i].Child > 0)
  707. {
  708. RecursionGetWholeContoursTree(wholeContours, contours, hierarchyIndex, i);
  709. }
  710. }
  711. }
  712. }
  713. }
  714. }
  715. }