OTSImageDisHelp.cs 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060
  1. using OpenCvSharp;
  2. using OTSCLRINTERFACE;
  3. using OTSCommon.Model;
  4. using OTSIncAReportApp.DataOperation.DataAccess;
  5. using OTSIncAReportApp.SysMgrTools;
  6. using OTSIncAReportGraph.Class;
  7. using OTSIncAReportGraph.Controls;
  8. using OTSModelSharp.DTLBase;
  9. using OTSModelSharp.ServiceInterface;
  10. using System;
  11. using System.Collections;
  12. using System.Collections.Generic;
  13. using System.Data;
  14. using System.Diagnostics;
  15. using System.Drawing;
  16. using System.Drawing.Drawing2D;
  17. using System.IO;
  18. using System.Linq;
  19. using System.Runtime.Serialization.Formatters.Binary;
  20. using Point = System.Drawing.Point;
  21. namespace OTSIncAReportGraph.OTSIncAReportGraphFuncation
  22. {
  23. public class OTSImageDisHelp
  24. {
  25. #region 枚举定义
  26. /// <summary>
  27. /// 样品台X轴方向
  28. /// </summary>
  29. enum OTS_X_AXIS_DIRECTION
  30. {
  31. LEFT_TOWARD = 0,
  32. RIGHT_TOWARD = 1
  33. }
  34. /// <summary>
  35. /// 样品台Y轴方向
  36. /// </summary>
  37. enum OTS_Y_AXIS_DIRECTION
  38. {
  39. UP_TOWARD = 0,
  40. DOWN_TOWARD = 1
  41. }
  42. #endregion
  43. #region 定义变量
  44. public ResultFile resultFile = null;
  45. public ParticleSegmentation m_ParticleSegmentation;
  46. //记录field列表的原值
  47. public List<DisplayField> m_original_list_dfield = null;
  48. //记录原值,颗粒和线段
  49. public List<BaseObject> m_original_list_baseobject = null;
  50. NLog.Logger log;
  51. //field的数量
  52. public int m_field_count = 0;
  53. //particle的数量
  54. public int m_particle_count = 0;
  55. //加载使用的时间
  56. public string m_time_str = "";
  57. //加载使用时间计算时间段2
  58. public string m_time_str2 = "";
  59. //电镜设置对象
  60. public ServiceInterface.HardwareController m_cfun = null;
  61. //是否已经连接到了电镜
  62. //public bool m_SEMConnectionState = false;
  63. //连接到电镜的ID号
  64. public int m_SEM_ID = 0;
  65. #endregion
  66. #region 构造函数
  67. public OTSImageDisHelp( ResultFile result)
  68. {
  69. m_original_list_dfield = new List<DisplayField>();
  70. m_original_list_baseobject = new List<BaseObject>();
  71. resultFile = result;
  72. m_cfun = ServiceInterface.HardwareController.GetSemController();
  73. log = NLog.LogManager.GetCurrentClassLogger();
  74. }
  75. #endregion
  76. #region 封装自定义方法
  77. public Point GetOTSCoordLeftBottomPoint(List<Point> allFldPos)
  78. {
  79. //the ots coordinate system is always positive on the right and up direction.So the leftbottom point would be the smallest point.
  80. //找出最小的x,y用来做偏移运算
  81. int i_offset_x = 1000000000;
  82. int i_offset_y = 1000000000;
  83. //先取出最小的x,y
  84. for (int i = 0; i < allFldPos.Count; i++)
  85. {
  86. if (i_offset_x > allFldPos[i].X)
  87. {
  88. i_offset_x = allFldPos[i].X;
  89. }
  90. if (i_offset_y > allFldPos[i].Y)
  91. {
  92. i_offset_y = allFldPos[i].Y;
  93. }
  94. }
  95. return new Point(i_offset_x, i_offset_y);
  96. }
  97. public Point ConvertOTSCoordinateToScreenCoord(Point otsleftBottomPoint,double pixelSize, Point currenFldPos,RectangleF wholeImageRec,RectangleF singleImgRec)//
  98. {
  99. var OTSPoint=new Point(currenFldPos.X - otsleftBottomPoint.X, currenFldPos.Y - otsleftBottomPoint.Y);
  100. double screenHeight = wholeImageRec.Height + (0 - (int)(Convert.ToDouble(OTSPoint.Y) / pixelSize));//because the screen coordinate is downward rightward positive,so we need to translate the Y coordinate of the OTS system which is upward rightward positive.
  101. screenHeight = screenHeight - singleImgRec.Height;
  102. var screenPoint = new Point((int)(Convert.ToDouble(OTSPoint.X)/pixelSize), (int)screenHeight);
  103. return screenPoint;
  104. }
  105. public Rectangle ConvertAndGetMaxRect(List<Point> inPoints, int in_width, int in_height)
  106. {
  107. //首先要能确定下来,单个物理坐标的宽和高--------------------------------
  108. int i_wl_width = 0;
  109. int i_wl_height = 0;
  110. RectangleF ls_r = GetPhysicalFieldWidthAndHeight(inPoints,in_width,in_height);
  111. i_wl_width = (int)ls_r.Width;
  112. i_wl_height = (int)ls_r.Height;
  113. //-----------------------------------------------------------------------------
  114. int point_x_min = 10000000;
  115. int point_x_max = -10000000;
  116. int point_y_min = 10000000;
  117. int point_y_max = -10000000;
  118. for (int i = 0; i < inPoints.Count(); i++)
  119. {
  120. Point ls_point = inPoints[i];
  121. //取出正数最大x
  122. if (ls_point.X > point_x_max)
  123. point_x_max = ls_point.X;
  124. if (ls_point.Y > point_y_max)
  125. point_y_max = ls_point.Y;
  126. if (ls_point.X < point_x_min)
  127. point_x_min = ls_point.X;
  128. if (ls_point.Y < point_y_min)
  129. point_y_min = ls_point.Y;
  130. }
  131. //然后分别用最大值+abs(最小值),就是x,和y轴的总长值
  132. point_x_max = point_x_max - point_x_min;
  133. point_y_max = point_y_max - point_y_min;
  134. //该算法有个问题,就是不能直观的得到整个范围的大小,要除以倍数再补1能补充缺少的一个field视域**********
  135. point_x_max = ((point_x_max / i_wl_width) + 1) * i_wl_width;
  136. point_y_max = ((point_y_max / i_wl_height) + 1) * i_wl_height;
  137. //将物理宽高,变换成分辨率宽高
  138. if (i_wl_width != 0) point_x_max = (point_x_max / i_wl_width) * in_width; else point_x_max = 0;
  139. if (i_wl_height != 0) point_y_max = (point_y_max / i_wl_height) * in_height; else point_y_max = 0;
  140. Rectangle ret_rectangle = new Rectangle(0, 0, 0, 0);
  141. //判断一下防止出错,只有在有数据的情况下,进行赋值才行
  142. if (inPoints.Count > 0)
  143. {
  144. ret_rectangle = new Rectangle(0, 0, point_x_max, point_y_max);
  145. }
  146. //这样返回是物理坐标的总大小,应该返回像素坐标大小才对
  147. return ret_rectangle;
  148. }
  149. /// <summary>
  150. /// 计算单个field的物理大小 传入field的list,还有测量结果管理类对象,在无法计算出单field的物理大小的情况下,到这里取再计算得出
  151. /// </summary>
  152. /// <returns></returns>
  153. public RectangleF GetPhysicalFieldWidthAndHeight(List<Point> points,int imageWidth,int imageHeight)
  154. {
  155. int width_max = -10000000;
  156. int height_max = -10000000;
  157. int width_max2 = -10000000;
  158. int height_max2 = -10000000;
  159. //先找出最大的值,
  160. for (int i = 0; i < points.Count(); i++)
  161. {
  162. if (width_max < points[i].X)
  163. width_max = points[i].X;
  164. if (height_max < points[i].Y)
  165. height_max = points[i].Y;
  166. }
  167. //再找出第二大的值
  168. for (int i = 0; i < points.Count(); i++)
  169. {
  170. if (width_max2 < points[i].X && width_max != points[i].X)
  171. width_max2 = points[i].X;
  172. if (height_max2 < points[i].Y && height_max != points[i].Y)
  173. height_max2 = points[i].Y;
  174. }
  175. //需要针对第二大的值,获取时进行判断,感觉这里应该如果并未找到第二大的值的情况下,赋于0值,便于以后进行计算
  176. if (width_max2 == -10000000)
  177. width_max2 = width_max;
  178. if (height_max2 == -10000000)
  179. height_max2 = height_max;
  180. RectangleF ret_rect = new RectangleF(0, 0, width_max - width_max2, height_max - height_max2);
  181. //如果最后计算出的宽高有0则重新到测量数据中获取---------------------------------------
  182. if (ret_rect.Width == 0 || ret_rect.Height == 0)
  183. {
  184. //到参数中去取单个宽
  185. double d_scanFieldSize_width = Convert.ToDouble(((Dictionary<string, object>)resultFile.ResultInfo["SEMStageData"])["scanFieldSize"]);
  186. //然后再用单个宽去计算出高是多少
  187. double d_scanFieldSize_height = 0;
  188. if (d_scanFieldSize_width != 0)
  189. d_scanFieldSize_height = (d_scanFieldSize_width / Convert.ToDouble(imageWidth)) * imageHeight;
  190. ret_rect.Width = (int)d_scanFieldSize_width;
  191. ret_rect.Height = (int)d_scanFieldSize_height;
  192. }
  193. ///-----------because all the fields 's height/width=0.75 so here we make an enforce. gsp add at 2019/10/31
  194. ///sometimes the gbfields are not conform to this for the cuting and merging operation.
  195. //if (ret_rect.Height / ret_rect.Width != 0.75f)
  196. //{
  197. // ret_rect = new Rectangle(ret_rect.X, ret_rect.Y, ret_rect.Width, (int)(ret_rect.Width * 0.75f));
  198. //}
  199. return ret_rect;
  200. }
  201. #endregion
  202. #region 电镜操作相关方法
  203. /// <summary>
  204. /// 连接电镜,分布图使用
  205. /// </summary>
  206. public bool ConnectToIpcSvr()
  207. {
  208. //和电镜建立通讯连接
  209. return m_cfun.Connect();
  210. }
  211. /// <summary>
  212. /// 移动电镜到指定的X,Y坐标上,R坐标使用原先的值进行移动
  213. /// </summary>
  214. /// <param name="PositionX"></param>
  215. /// <param name="PositionY"></param>
  216. public void MoveSemToPointXY(double in_PositionX, double in_PositionY)
  217. {
  218. log.Trace("Begin MoveSemToPointXY:(" +in_PositionX.ToString()+","+in_PositionY.ToString()+")");
  219. //首先获取电镜当前的位置,并记录原R值
  220. double ls_PositionX = 0;
  221. double ls_PositionY = 0;
  222. double ls_PositionR = 0;
  223. if (m_cfun.Connect())
  224. {
  225. m_cfun.GetSemPositionXY(ref ls_PositionX, ref ls_PositionY, ref ls_PositionR);
  226. }
  227. else
  228. {
  229. log.Error("Failed to GetSemPositionXY");
  230. return;
  231. }
  232. if (m_cfun.Connect())
  233. {
  234. m_cfun.MoveSEMToPoint(new Point((int)in_PositionX, (int)in_PositionY), ls_PositionR);
  235. }
  236. }
  237. #endregion
  238. #region //--------------------------------------颗粒分布图相关部份---------------------------------------------------------------------
  239. /// <summary>
  240. /// 传入颗粒的tagid和fieldid,来获取该颗粒下对应的xray数据
  241. /// </summary>
  242. /// <param name="in_clr_tagid"></param>
  243. /// <param name="in_clr_fieldid"></param>
  244. /// <param name="Search_xray"></param>
  245. /// <param name="Analysis_xray"></param>
  246. public void GetXrayByParticleTagIDAndFieldID_ForDrawDistrbutionImageAndBSE(int in_clr_tagid, int in_clr_fieldid, out uint[] Search_xray, out uint[] Analysis_xray, out int xray_id, out List<Element> list_celementchemistryclr)
  247. {
  248. Search_xray = new uint[2000];
  249. Analysis_xray = new uint[2000];
  250. xray_id = 0;
  251. list_celementchemistryclr = new List<Element>();
  252. //防止为空校验判断
  253. if (resultFile.List_OTSField == null)
  254. return;
  255. Particle particle = resultFile.List_OTSField.Find(x => x.FieldID == in_clr_fieldid).ParticleList.Find(x => x.ParticleId == in_clr_tagid);
  256. var tmpPart = new ParticleData(resultFile.FilePath).GetParticleXrayDataByFidAndPid(Convert.ToString(particle.FieldId), Convert.ToString(particle.XrayId));
  257. if (tmpPart != null)
  258. {
  259. particle.XRayData = tmpPart.XRayData;
  260. if (particle.XrayId > -1)
  261. {
  262. for (int i = 0; i < 2000; i++)
  263. {
  264. Analysis_xray[i] = BitConverter.ToUInt32(particle.XRayData, i * 4);
  265. }
  266. Search_xray = Analysis_xray;
  267. xray_id = particle.XrayId;
  268. list_celementchemistryclr = particle.ElementList;
  269. }
  270. }
  271. }
  272. /// <summary>
  273. /// 传入所有的物理field坐标点,和单个物理field的宽高,返回所有field的左上角位置,和整个field组成的rect大小
  274. /// </summary>
  275. /// <param name="in_list_point"></param>
  276. /// <param name="in_width"></param>
  277. /// <param name="in_height"></param>
  278. /// <returns></returns>
  279. public Rectangle GetWlRectTopLeftAndRect(List<Point> in_list_point, int in_width, int in_height)
  280. {
  281. //分别获取整个rect的xy最小值和最大值
  282. int i_rect_x_min = 100000000;
  283. int i_rect_y_min = 100000000;
  284. int i_rect_x_max = -100000000;
  285. int i_rect_y_max = -100000000;
  286. for (int i = 0; i < in_list_point.Count; i++)
  287. {
  288. if (i_rect_x_min > in_list_point[i].X)
  289. i_rect_x_min = in_list_point[i].X;
  290. if (i_rect_y_min > in_list_point[i].Y)
  291. i_rect_y_min = in_list_point[i].Y;
  292. if (i_rect_x_max < in_list_point[i].X)
  293. i_rect_x_max = in_list_point[i].X;
  294. if (i_rect_y_max < in_list_point[i].Y)
  295. i_rect_y_max = in_list_point[i].Y;
  296. }
  297. Rectangle ret_rect = new Rectangle(i_rect_x_min, i_rect_y_min,
  298. i_rect_x_max - i_rect_x_min, i_rect_y_max - i_rect_y_min);
  299. return ret_rect;
  300. }
  301. /// <summary>
  302. /// 根据Field的ID,来获取Field列表中对应FIeld的OTS 坐标
  303. /// </summary>
  304. /// <param name="in_fieldid"></param>
  305. /// <returns></returns>
  306. public Point GetOTSPointByFieldID(List<DisplayField> in_list_dfield, int in_fieldid)
  307. {
  308. Point ret_point = new Point(0, 0);
  309. for (int i = 0; i < in_list_dfield.Count; i++)
  310. {
  311. //这里TagID先代表的是底层返回的ID
  312. if (in_list_dfield[i].FieldID == in_fieldid.ToString())
  313. {
  314. ret_point = new Point(Convert.ToInt32(in_list_dfield[i].OTSCoordinatePos.X), Convert.ToInt32(in_list_dfield[i].OTSCoordinatePos.Y));
  315. }
  316. }
  317. return ret_point;
  318. }
  319. /// <summary>
  320. /// 将OTS坐标转换为Sem 坐标
  321. /// </summary>
  322. /// <param name="POTSCoord"></param>
  323. /// <returns></returns>
  324. public Point ChangeOTSToSemCoord(Point POTSCoord)
  325. {
  326. //first if m_semstagedata is null to get stage inforation
  327. Convert.ToDouble(((Dictionary<string, object>)resultFile.ResultInfo["SEMStageData"])["scanFieldSize"]);
  328. //after obtaining stage info,calc stage point data
  329. Point ret_SEM_point = new Point();
  330. // get center point, um
  331. long xStart = Convert.ToInt64(((Dictionary<string, object>)((Dictionary<string, object>)((Dictionary<string, object>)resultFile.ResultInfo["SEMStageData"])["Members"])["XAxis"])["start"]);
  332. long xEnd = Convert.ToInt64(((Dictionary<string, object>)((Dictionary<string, object>)((Dictionary<string, object>)resultFile.ResultInfo["SEMStageData"])["Members"])["XAxis"])["end"]);
  333. long xCenter = (xStart + xEnd) / 2;
  334. long yStart = Convert.ToInt64(((Dictionary<string, object>)((Dictionary<string, object>)((Dictionary<string, object>)resultFile.ResultInfo["SEMStageData"])["Members"])["YAxis"])["start"]);
  335. long yEnd = Convert.ToInt64(((Dictionary<string, object>)((Dictionary<string, object>)((Dictionary<string, object>)resultFile.ResultInfo["SEMStageData"])["Members"])["YAxis"])["end"]);
  336. long yCenter = (yStart + yEnd) / 2;
  337. // delte = SEM - OTSa
  338. long deltex = xCenter - 0;
  339. long deltey = yCenter - 0;
  340. int xdir = Convert.ToInt32(((Dictionary<string, object>)resultFile.ResultInfo["SEMStageData"])["xAxisDir"]);
  341. int ydir = Convert.ToInt32(((Dictionary<string, object>)resultFile.ResultInfo["SEMStageData"])["yAxisDir"]);
  342. if (xdir == (int)OTS_X_AXIS_DIRECTION.LEFT_TOWARD)
  343. {
  344. ret_SEM_point.X = -1 * (POTSCoord.X - Convert.ToInt32(deltex));
  345. }
  346. else if (xdir == (int)OTS_X_AXIS_DIRECTION.RIGHT_TOWARD)
  347. {
  348. ret_SEM_point.X = POTSCoord.X + Convert.ToInt32(deltex);
  349. }
  350. if (ydir == (int)OTS_Y_AXIS_DIRECTION.UP_TOWARD)
  351. {
  352. ret_SEM_point.Y = POTSCoord.Y + Convert.ToInt32(deltey);
  353. }
  354. else if (ydir == (int)OTS_Y_AXIS_DIRECTION.DOWN_TOWARD)
  355. {
  356. ret_SEM_point.Y = -1 * (POTSCoord.Y - Convert.ToInt32(deltey));
  357. }
  358. return ret_SEM_point;
  359. }
  360. #endregion
  361. /// <summary>
  362. /// 判断该点是否在多边形的范围内
  363. /// </summary>
  364. /// <param name="inPoints"></param>
  365. /// <param name="WhetherPoint"></param>
  366. /// <returns></returns>
  367. public bool WhetherInRange(DisplayParticle Part,/*PointF[] inPoints,*/ Point WhetherPoint)
  368. {
  369. var rect = Part.Rect;
  370. if ((rect.Left < WhetherPoint.X && WhetherPoint.X < rect.Right) && (rect.Top < WhetherPoint.Y && WhetherPoint.Y < rect.Bottom))
  371. {
  372. var itm = (BaseObject)Part;
  373. itm.GPath = Part.GetRegionFromDSegments();
  374. PointF[] inPoints = itm.GPath.PathPoints;
  375. bool b_inrange = false;
  376. GraphicsPath myGraphicsPath = new GraphicsPath();
  377. Region myRegion = new Region();
  378. myGraphicsPath.Reset();
  379. myGraphicsPath.AddPolygon(inPoints);
  380. myRegion.MakeEmpty();
  381. myRegion.Union(myGraphicsPath);
  382. //返回判断点是否在多边形里
  383. b_inrange = myRegion.IsVisible(WhetherPoint);
  384. return b_inrange;
  385. }
  386. else
  387. {
  388. return false;
  389. }
  390. }
  391. public bool WhetherInRange(RectangleF rec,PointF[] inPoints, Point WhetherPoint)
  392. {
  393. var rect = rec;
  394. if ((rect.Left < WhetherPoint.X && WhetherPoint.X < rect.Right) && (rect.Top < WhetherPoint.Y && WhetherPoint.Y < rect.Bottom))
  395. {
  396. //var itm = (BaseObject)Part;
  397. //PointF[] inPoints = itm.GPath.PathPoints;
  398. bool b_inrange = false;
  399. GraphicsPath myGraphicsPath = new GraphicsPath();
  400. Region myRegion = new Region();
  401. myGraphicsPath.Reset();
  402. myGraphicsPath.AddPolygon(inPoints);
  403. myRegion.MakeEmpty();
  404. myRegion.Union(myGraphicsPath);
  405. //返回判断点是否在多边形里
  406. b_inrange = myRegion.IsVisible(WhetherPoint);
  407. return b_inrange;
  408. }
  409. else
  410. {
  411. return false;
  412. }
  413. }
  414. /// <summary>
  415. /// 判断该点是否在多边形的范围内的float版本重载
  416. /// </summary>
  417. /// <param name="inPoints"></param>
  418. /// <param name="WhetherPoint"></param>
  419. /// <returns></returns>
  420. public bool WhetherInRange(DisplayParticle Part,/* PointF[] inPoints, */PointF WhetherPoint)
  421. {
  422. var rect = Part.Rect;
  423. if ((rect.Left < WhetherPoint.X && WhetherPoint.X < rect.Right) && (rect.Top < WhetherPoint.Y && WhetherPoint.Y < rect.Bottom))
  424. {
  425. var itm = (BaseObject)Part;
  426. PointF[] inPoints = itm.GPath.PathPoints;
  427. bool b_inrange = false;
  428. GraphicsPath myGraphicsPath = new GraphicsPath();
  429. Region myRegion = new Region();
  430. myGraphicsPath.Reset();
  431. myGraphicsPath.AddPolygon(inPoints);
  432. myRegion.MakeEmpty();
  433. myRegion.Union(myGraphicsPath);
  434. //返回判断点是否在多边形里
  435. b_inrange = myRegion.IsVisible(WhetherPoint);
  436. return b_inrange;
  437. }
  438. else
  439. {
  440. return false;
  441. }
  442. }
  443. #region 颗粒分割功能方法
  444. /// <summary>
  445. /// 获取线段与矩形的两个交点
  446. /// </summary>
  447. /// <param name="line1S"></param>
  448. /// <param name="line1E"></param>
  449. /// <param name="rectangle"></param>
  450. /// <param name="pointList"></param>
  451. /// <returns></returns>
  452. public bool GetInterBetweenLinesAndRect(Point line1S, Point line1E, RectangleF rectangle, ref List<Point> pointList)
  453. {
  454. try
  455. {
  456. PointF pointF = new PointF(-1, -1);
  457. Rect rect = new Rect();
  458. rect.X = m_ParticleSegmentation.ParticleData.RectLeft;
  459. rect.Y = m_ParticleSegmentation.ParticleData.RectTop;
  460. rect.Width = m_ParticleSegmentation.ParticleData.RectWidth;
  461. rect.Height = m_ParticleSegmentation.ParticleData.RectHeight;
  462. float border = 0;
  463. if (GetInterBetweenTwoLines(line1S, line1E, new PointF(rectangle.Left, rectangle.Top), new PointF(rectangle.Right, rectangle.Top), ref pointF))
  464. {
  465. border = (pointF.X - rectangle.Left) / (rectangle.Right - rectangle.Left);
  466. pointList.Add(new Point((int)(rect.X + rect.Width * border), rect.Y));
  467. }
  468. if (GetInterBetweenTwoLines(line1S, line1E,
  469. new PointF(rectangle.Left, rectangle.Bottom), new PointF(rectangle.Right, rectangle.Bottom), ref pointF))
  470. {
  471. border = (pointF.X - rectangle.Left) / (rectangle.Right - rectangle.Left);
  472. pointList.Add(new Point((int)(rect.X + rect.Width * border), rect.Y + rect.Height));
  473. }
  474. if (GetInterBetweenTwoLines(line1S, line1E,
  475. new PointF(rectangle.Left, rectangle.Top), new PointF(rectangle.Left, rectangle.Bottom), ref pointF))
  476. {
  477. border = (pointF.Y - rectangle.Top) / (rectangle.Bottom - rectangle.Top);
  478. pointList.Add(new Point(rect.X, (int)(rect.Y + rect.Height * border)));
  479. }
  480. if (GetInterBetweenTwoLines(line1S, line1E,
  481. new PointF(rectangle.Right, rectangle.Top), new PointF(rectangle.Right, rectangle.Bottom), ref pointF))
  482. {
  483. border = (pointF.Y - rectangle.Top) / (rectangle.Bottom - rectangle.Top);
  484. pointList.Add(new Point(rect.X + rect.Width, (int)(rect.Y + rect.Height * border)));
  485. }
  486. if (pointList.Count == 2)
  487. {
  488. return true;
  489. }
  490. else
  491. {
  492. return false;
  493. }
  494. }
  495. catch (Exception ex)
  496. {
  497. log.Trace("(GetSplitPartFun)" + ex);
  498. return false;
  499. }
  500. }
  501. /// <summary>
  502. /// 获取分离颗粒方法
  503. /// </summary>
  504. /// <param name="startPoint"></param>
  505. /// <param name="endPoint"></param>
  506. /// <returns></returns>
  507. public bool GetSplitPartFun(Point startPoint, Point endPoint, float m_pixelSize)
  508. {
  509. try
  510. {
  511. CImageHandler m_ImagePro = new CImageHandler();
  512. Particle particle1 = (Particle)CloneObject(m_ParticleSegmentation.ParticleData);
  513. Particle particle2 = (Particle)CloneObject(m_ParticleSegmentation.ParticleData);
  514. Dictionary<string, object> sampleMembers = ((Dictionary<string, object>)((Dictionary<string, object>)resultFile.ResultInfo["Sample"])["Members"]);
  515. Dictionary<string, object> imageScanParam = (Dictionary<string, object>)((Dictionary<string, object>)((Dictionary<string, object>)sampleMembers["MsrParams"])["Members"])["ImageScanParam"];
  516. string ImageResolution = imageScanParam["ImageResolution"].ToString();
  517. int width = int.Parse(ImageResolution.Split('_')[1]);
  518. int height = int.Parse(ImageResolution.Split('_')[2]);
  519. using (Mat mat = new Mat(height, width, MatType.CV_8UC1, Scalar.Black))//黑色底图
  520. using (Mat labelMat = new Mat())
  521. using (Mat stats = new Mat())
  522. using (Mat centroids = new Mat())
  523. using (Mat matBse = new Mat(resultFile.List_OTSField[particle1.FieldId].FieldImage, ImreadModes.Grayscale))
  524. {
  525. foreach (Segment segment in m_ParticleSegmentation.ParticleData.SegmentList)
  526. {
  527. Cv2.Line(mat, new OpenCvSharp.Point(segment.Start, segment.Height), new OpenCvSharp.Point(segment.Start + segment.Length, segment.Height), Scalar.White, 1, LineTypes.AntiAlias);
  528. }
  529. //寻找坐标点
  530. List<Point> points1 = new List<Point>();
  531. List<Point> points2 = new List<Point>();
  532. List<int> aveGray1 = new List<int>();
  533. List<int> aveGray2 = new List<int>();
  534. for (int k = 0; k < mat.Height; k++)
  535. {
  536. for (int j = 0; j < mat.Width; j++)
  537. {
  538. if (mat.Get<int>(k, j) != 0)
  539. {
  540. int side = (startPoint.X - j) * (endPoint.Y - k) - (startPoint.Y - k) * (endPoint.X - j);
  541. if (side >= 0)//区分像素位置
  542. {
  543. points1.Add(new Point(j, k));
  544. aveGray1.Add(matBse.Get<byte>(k, j));
  545. }
  546. else
  547. {
  548. points2.Add(new Point(j, k));
  549. aveGray2.Add(matBse.Get<byte>(k, j));
  550. }
  551. }
  552. }
  553. }
  554. //处理Segment
  555. List<COTSSegmentClr> SegmentClrList1 = new List<COTSSegmentClr>();
  556. List<COTSSegmentClr> SegmentClrList2 = new List<COTSSegmentClr>();
  557. List<Segment> SegmentList1 = new List<Segment>();
  558. List<Segment> SegmentList2 = new List<Segment>();
  559. GetSegment(points1, m_ParticleSegmentation.ParticleData, SegmentClrList1, ref SegmentList1);
  560. GetSegment(points2, m_ParticleSegmentation.ParticleData, SegmentClrList2, ref SegmentList2);
  561. //颗粒一
  562. Cv2.Threshold(mat, mat, 0, 0, ThresholdTypes.Binary);
  563. foreach (Segment segment in SegmentList1)
  564. {
  565. Cv2.Line(mat, new OpenCvSharp.Point(segment.Start, segment.Height), new OpenCvSharp.Point(segment.Start + segment.Length, segment.Height), Scalar.White, 1, LineTypes.AntiAlias);
  566. }
  567. Cv2.ConnectedComponentsWithStats(mat, labelMat, stats, centroids, PixelConnectivity.Connectivity8);
  568. CopyToPart(particle1, SegmentList1, SegmentClrList1, aveGray1, stats, centroids, m_pixelSize);
  569. //颗粒二
  570. Cv2.Threshold(mat, mat, 0, 0, ThresholdTypes.Binary);
  571. foreach (Segment segment in SegmentList2)
  572. {
  573. Cv2.Line(mat, new OpenCvSharp.Point(segment.Start, segment.Height), new OpenCvSharp.Point(segment.Start + segment.Length, segment.Height), Scalar.White, 1, LineTypes.AntiAlias);
  574. }
  575. Cv2.ConnectedComponentsWithStats(mat, labelMat, stats, centroids, PixelConnectivity.Connectivity8);
  576. CopyToPart(particle2, SegmentList2, SegmentClrList2, aveGray2, stats, centroids, m_pixelSize);
  577. if (!SaveToDb(particle1, particle2))
  578. {
  579. log.Trace("(GetSplitPartFun) SaveToDb Faild");
  580. return false;
  581. }
  582. }
  583. return true;
  584. }
  585. catch (Exception ex)
  586. {
  587. log.Trace("(GetSplitPartFun)" + ex);
  588. return false;
  589. }
  590. }
  591. /// <summary>
  592. /// 拷贝颗粒数据
  593. /// </summary>
  594. /// <param name="particle"></param>
  595. /// <param name="segments"></param>
  596. /// <param name="SegmentClrList"></param>
  597. /// <param name="aveGray"></param>
  598. /// <param name="stats"></param>
  599. /// <param name="centroids"></param>
  600. /// <param name="dPixelSize"></param>
  601. private void CopyToPart(Particle particle, List<Segment> segments, List<COTSSegmentClr> SegmentClrList, List<int> aveGray, Mat stats, Mat centroids, double dPixelSize)
  602. {
  603. CImageHandler m_ImagePro = new CImageHandler();
  604. COTSParticleClr part = new COTSParticleClr();
  605. part.SetArea(stats.At<int>(1, 4) * dPixelSize * dPixelSize);
  606. part.SetParticleRect(new Rectangle(stats.At<int>(1, 0), stats.At<int>(1, 1), stats.At<int>(1, 2), stats.At<int>(1, 3)));
  607. part.GetFeature().SetSegmentsList(SegmentClrList, false);
  608. m_ImagePro.CalParticleImageProp(part, dPixelSize);
  609. particle.SegmentList = segments;
  610. particle.SegmentNum = segments.Count;
  611. particle.AveGray = (int)aveGray.Average();
  612. particle.RectLeft = stats.At<int>(1, 0);
  613. particle.RectTop = stats.At<int>(1, 1);
  614. particle.RectWidth = stats.At<int>(1, 2);
  615. particle.RectHeight = stats.At<int>(1, 3);
  616. particle.Area = stats.At<int>(1, 4) * dPixelSize * dPixelSize;
  617. particle.PosX = (int)centroids.At<double>(1, 0);
  618. particle.PosY = (int)centroids.At<double>(1, 1);
  619. particle.DFERET = part.GetFeretDiameter();
  620. particle.DMAX = part.GetDMAX();
  621. particle.DMIN = part.GetDMIN();
  622. particle.DPERP = part.GetDMPERP();
  623. particle.PERIMETER = part.GetDPRIMETER();
  624. particle.ORIENTATION = part.GetORIENTATION();
  625. particle.DINSCR = part.GetDINSCR();
  626. particle.DMEAN = part.GetDMEAN();
  627. particle.DELONG = part.GetDELONG();
  628. }
  629. /// <summary>
  630. /// 保存数据库
  631. /// </summary>
  632. /// <param name="particle1"></param>
  633. /// <param name="particle2"></param>
  634. /// <returns></returns>
  635. public bool SaveToDb(Particle particle1, Particle particle2)
  636. {
  637. //初始化
  638. SQLiteHelper sQLiteHelper = new SQLiteHelper(resultFile.FilePath + "\\FIELD_FILES\\Inclusion.db");
  639. sQLiteHelper.GetDBConnection();
  640. sQLiteHelper.BeginTransaction();
  641. //修改Segment表
  642. if (particle1.SegmentList.Count == 0 || particle2.SegmentList.Count == 0)
  643. {
  644. return false;
  645. }
  646. int SegmentCount = sQLiteHelper.ExecuteNewPartIdForTransaction() + 1;
  647. if (!sQLiteHelper.ExecuteSegmentForTransaction(particle1, particle2, SegmentCount))//修改Segment表
  648. {
  649. return false;
  650. }
  651. if (!sQLiteHelper.ExecuteXrayForTransaction(particle1, particle2, SegmentCount))//修改XRayData和PoxXrayInfo表
  652. {
  653. return false;
  654. }
  655. if (!sQLiteHelper.ExecuteIncAForTransaction(particle1, particle2, SegmentCount))//修改IncAData表
  656. {
  657. return false;
  658. }
  659. sQLiteHelper.CommitTransaction();
  660. return true;
  661. }
  662. /// <summary>
  663. /// 线段与矩形是否相交
  664. /// </summary>
  665. /// <param name="linePointX1"></param>
  666. /// <param name="linePointY1"></param>
  667. /// <param name="linePointX2"></param>
  668. /// <param name="linePointY2"></param>
  669. /// <param name="rectangleLeftTopX"></param>
  670. /// <param name="rectangleLeftTopY"></param>
  671. /// <param name="rectangleRightBottomX"></param>
  672. /// <param name="rectangleRightBottomY"></param>
  673. /// <returns></returns>
  674. public bool isLineIntersectRectangle(float linePointX1,
  675. float linePointY1,
  676. float linePointX2,
  677. float linePointY2,
  678. float rectangleLeftTopX,
  679. float rectangleLeftTopY,
  680. float rectangleRightBottomX,
  681. float rectangleRightBottomY)
  682. {
  683. float lineHeight = linePointY1 - linePointY2;
  684. float lineWidth = linePointX2 - linePointX1; // 计算叉乘
  685. float c = linePointX1 * linePointY2 - linePointX2 * linePointY1;
  686. if ((lineHeight * rectangleLeftTopX + lineWidth * rectangleLeftTopY + c >= 0 && lineHeight * rectangleRightBottomX + lineWidth * rectangleRightBottomY + c <= 0)
  687. || (lineHeight * rectangleLeftTopX + lineWidth * rectangleLeftTopY + c <= 0 && lineHeight * rectangleRightBottomX + lineWidth * rectangleRightBottomY + c >= 0)
  688. || (lineHeight * rectangleLeftTopX + lineWidth * rectangleRightBottomY + c >= 0 && lineHeight * rectangleRightBottomX + lineWidth * rectangleLeftTopY + c <= 0)
  689. || (lineHeight * rectangleLeftTopX + lineWidth * rectangleRightBottomY + c <= 0 && lineHeight * rectangleRightBottomX + lineWidth * rectangleLeftTopY + c >= 0))
  690. {
  691. if (rectangleLeftTopX > rectangleRightBottomX)
  692. {
  693. float temp = rectangleLeftTopX;
  694. rectangleLeftTopX = rectangleRightBottomX;
  695. rectangleRightBottomX = temp;
  696. }
  697. if (rectangleLeftTopY < rectangleRightBottomY)
  698. {
  699. float temp1 = rectangleLeftTopY;
  700. rectangleLeftTopY = rectangleRightBottomY;
  701. rectangleRightBottomY = temp1;
  702. }
  703. if ((linePointX1 < rectangleLeftTopX && linePointX2 < rectangleLeftTopX)
  704. || (linePointX1 > rectangleRightBottomX && linePointX2 > rectangleRightBottomX)
  705. || (linePointY1 > rectangleLeftTopY && linePointY2 > rectangleLeftTopY)
  706. || (linePointY1 < rectangleRightBottomY && linePointY2 < rectangleRightBottomY))
  707. {
  708. return false;
  709. }
  710. else
  711. {
  712. return true;
  713. }
  714. }
  715. else
  716. {
  717. return false;
  718. }
  719. }
  720. /// <summary>
  721. /// 求一个线段与另一个线段的交点
  722. /// </summary>
  723. /// <param name="line1S"></param>
  724. /// <param name="line1E"></param>
  725. /// <param name="line2S"></param>
  726. /// <param name="line2E"></param>
  727. /// <param name="interPoint"></param>
  728. /// <returns>-1:不存在交点;1:存在一个交点;2:存在无穷多个交点(重合或部分重合)</returns>
  729. public bool GetInterBetweenTwoLines(PointF line1S, PointF line1E,
  730. PointF line2S, PointF line2E, ref PointF interPoint)
  731. {
  732. int status = -1;
  733. // 判断两条直线各自的矩形包围盒的X与Y的值范围
  734. float line1Xmin = line1S.X < line1E.X ? line1S.X : line1E.X,
  735. line1Xmax = line1S.X > line1E.X ? line1S.X : line1E.X,
  736. line1Ymin = line1S.Y < line1E.Y ? line1S.Y : line1E.Y,
  737. line1Ymax = line1S.Y > line1E.Y ? line1S.Y : line1E.Y,
  738. line2Xmin = line2S.X < line2E.X ? line2S.X : line2E.X,
  739. line2Xmax = line2S.X > line2E.X ? line2S.X : line2E.X,
  740. line2Ymin = line2S.Y < line2E.Y ? line2S.Y : line2E.Y,
  741. line2Ymax = line2S.Y > line2E.Y ? line2S.Y : line2E.Y;
  742. if (line1S.X - line1E.X == 0)
  743. {
  744. // 两条线都垂直于X轴
  745. if (line2S.X - line2E.X == 0)
  746. {
  747. if (line1S.X != line2S.X) status = -1;
  748. else if ((line1Ymin > line2Ymax) || (line1Ymax < line2Ymin)) status = -1;
  749. else if (line1Ymin == line2Ymax)
  750. {
  751. interPoint = new PointF(line1S.X, line1Ymin); status = 1;
  752. }
  753. else if (line1Ymax == line2Ymin)
  754. {
  755. interPoint = new PointF(line1S.X, line1Ymax); status = 1;
  756. }
  757. else status = 2;
  758. }
  759. // line1垂直于X轴,line2不垂直于X轴
  760. else
  761. {
  762. float slope = (line2S.Y - line2E.Y) / (line2S.X - line2E.X);
  763. float offset = line2S.Y - slope * line2S.X;
  764. float newX = line1S.X, newY = slope * newX + offset;
  765. if (newX >= line2Xmin && newX <= line2Xmax && newY >= line1Ymin && newY <= line1Ymax
  766. && newY >= line2Ymin && newY <= line2Ymax)
  767. {
  768. interPoint = new PointF(newX, newY); status = 1;
  769. }
  770. }
  771. }
  772. else
  773. {
  774. // line1不垂直于X轴,line2垂直于X轴
  775. if (line2S.X - line2E.X == 0)
  776. {
  777. float slope = (line1S.Y - line1E.Y) / (line1S.X - line1E.X);
  778. float offset = line1S.Y - slope * line1S.X;
  779. float newX = line2S.X, newY = slope * newX + offset;
  780. if (newX >= line1Xmin && newX <= line1Xmax && newY >= line1Ymin && newY <= line1Ymax
  781. && newY >= line2Ymin && newY <= line2Ymax)
  782. {
  783. interPoint = new PointF(newX, newY); status = 1;
  784. }
  785. }
  786. // line1和line2都不垂直于X轴
  787. else
  788. {
  789. float slope1 = (line1S.Y - line1E.Y) / (line1S.X - line1E.X);
  790. float offset1 = line1S.Y - slope1 * line1S.X;
  791. float slope2 = (line2S.Y - line2E.Y) / (line2S.X - line2E.X);
  792. float offset2 = line2S.Y - slope2 * line2S.X;
  793. // 如果两条直线平行
  794. if (slope1 == slope2)
  795. {
  796. if (offset1 != offset2) status = -1;
  797. else if (line1Xmax == line2Xmin)
  798. {
  799. interPoint = new PointF(line1Xmax, line1Xmax * slope1 + offset1); status = 1;
  800. }
  801. else if (line1Xmin == line2Xmax)
  802. {
  803. interPoint = new PointF(line1Xmin, line1Xmin * slope1 + offset1); status = 1;
  804. }
  805. else if (line1Xmax < line2Xmin || line1Xmin > line2Xmax) status = -1;
  806. else status = 2;
  807. }
  808. else
  809. {
  810. float newX = (offset2 - offset1) / (slope1 - slope2), newY = newX * slope1 + offset1;
  811. if (newX >= line1Xmin && newX <= line1Xmax && newX >= line2Xmin && newX <= line2Xmax)
  812. {
  813. interPoint = new PointF(newX, newY); status = 1;
  814. }
  815. }
  816. }
  817. }
  818. if (status == 1)
  819. {
  820. return true;
  821. }
  822. else
  823. {
  824. return false;
  825. }
  826. }
  827. /// <summary>
  828. /// 获取Segment信息
  829. /// </summary>
  830. /// <param name="points"></param>
  831. /// <param name="SegmentClrList"></param>
  832. /// <param name="SegmentList"></param>
  833. public void GetSegment(List<Point> points, Particle ParticleData, List<COTSSegmentClr> SegmentClrList, ref List<Segment> SegmentList)
  834. {
  835. List<int> segmentStart = new List<int>();
  836. List<int> segmentHeight = new List<int>();
  837. List<int> segmentLength = new List<int>();
  838. FindSegment(points, ref segmentStart, ref segmentHeight, ref segmentLength);
  839. for (int i = 0; i < segmentLength.Count; i++)
  840. {
  841. COTSSegmentClr seg = new COTSSegmentClr();
  842. seg.SetStart(segmentStart[i]);
  843. seg.SetHeight(segmentHeight[i]);
  844. seg.SetLength(segmentLength[i]);
  845. SegmentClrList.Add(seg);
  846. Segment segment = new Segment();
  847. segment.Start = segmentStart[i];
  848. segment.Height = segmentHeight[i];
  849. segment.Length = segmentLength[i];
  850. segment.SegmentNum = segmentLength.Count;
  851. segment.SegmentId = i;
  852. segment.FieldId = ParticleData.FieldId;
  853. segment.XRayId = ParticleData.XrayId;
  854. segment.ParticleId = ParticleData.ParticleId;
  855. SegmentList.Add(segment);
  856. }
  857. }
  858. /// <summary>
  859. /// 寻找segment方法
  860. /// </summary>
  861. public void FindSegment(List<Point> point_list_final, ref List<int> segmentStart, ref List<int> segmentHeight, ref List<int> segmentLength)
  862. {
  863. int flag = 0;
  864. point_list_final.Sort(my_sort);//排序
  865. for (int k = 0; k < point_list_final.Count(); k++)
  866. {
  867. if (k == 0 && k != point_list_final.Count() - 1)//第一个颗粒
  868. {
  869. flag++;
  870. segmentStart.Add(point_list_final[k].X);
  871. segmentHeight.Add(point_list_final[k].Y);
  872. }
  873. else if (k == 0 && k == point_list_final.Count() - 1)//只有一个颗粒
  874. {
  875. segmentStart.Add(point_list_final[k].X);
  876. segmentHeight.Add(point_list_final[k].Y);
  877. segmentLength.Add(1);
  878. }
  879. else if (k == point_list_final.Count() - 1)//最后一个颗粒
  880. {
  881. flag++;
  882. segmentLength.Add(flag);
  883. }
  884. else if (point_list_final[k].Y == point_list_final[k - 1].Y && point_list_final[k].X == point_list_final[k - 1].X + 1)//同行连续
  885. {
  886. flag++;
  887. }
  888. else if (point_list_final[k].Y == point_list_final[k - 1].Y && point_list_final[k].X != point_list_final[k - 1].X + 1)//同行隔断
  889. {
  890. segmentLength.Add(flag);
  891. flag = 1;
  892. segmentStart.Add(point_list_final[k].X);
  893. segmentHeight.Add(point_list_final[k].Y);
  894. }
  895. else if (point_list_final[k].Y != point_list_final[k - 1].Y)//不同行
  896. {
  897. segmentLength.Add(flag);
  898. flag = 1;
  899. segmentStart.Add(point_list_final[k].X);
  900. segmentHeight.Add(point_list_final[k].Y);
  901. }
  902. }
  903. }
  904. /// <summary>
  905. /// 排序方法
  906. /// </summary>
  907. /// <param name="p1"></param>
  908. /// <param name="p2"></param>
  909. /// <returns></returns>
  910. private int my_sort(Point p1, Point p2)
  911. {
  912. return p1.Y == p2.Y ? p1.X.CompareTo(p2.X) : p1.Y.CompareTo(p2.Y); //升序排序
  913. }
  914. public object CloneObject(object obj)
  915. {
  916. using (MemoryStream stream = new MemoryStream())
  917. {
  918. BinaryFormatter formatter = new BinaryFormatter();
  919. stream.Position = 0;
  920. formatter.Serialize(stream, obj);
  921. stream.Position = 0;
  922. return formatter.Deserialize(stream);
  923. }
  924. }
  925. #endregion
  926. }
  927. }