BasicCalculationHelper.cs 31 KB

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