GBImgPropCal.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. #pragma once
  2. #include "math.h"
  3. #include "stdafx.h"
  4. #include "GBImgPropCal.h"
  5. #include <opencv2/core/core.hpp>
  6. #include <opencv2/highgui/highgui.hpp>
  7. #include <opencv2/opencv.hpp>
  8. #include "OTSImageProcess.h"
  9. // calculate image properties
  10. namespace OTSIMGPROC {
  11. using namespace OTSDATA;
  12. using namespace cv;
  13. using namespace std;
  14. // construct
  15. CGBImgPropCal::CGBImgPropCal()
  16. {
  17. Init();
  18. }
  19. // destruct
  20. CGBImgPropCal::~CGBImgPropCal()
  21. {
  22. Clear();
  23. }
  24. // get particle ferret diameter
  25. BOOL CGBImgPropCal::GetParticleFTD(COTSParticlePtr a_pOTSPart, double a_PixelSize , double &dPartFTD, double &dMinWidth, double &dMaxLength, double &dRatio)
  26. {
  27. // safety check
  28. ASSERT(a_pOTSPart);
  29. // 1. convert particle data to image data
  30. // get the segment list
  31. COTSSegmentsList listSegment = a_pOTSPart->GetFeature()->GetSegmentsList();
  32. // get rectangle of the particle
  33. CRect rect = a_pOTSPart->GetParticleRect();
  34. // calculate image data size, expand 1 pixel at the edge
  35. int nWidth = rect.Width() + 1 + nExpand_Size*2;
  36. int nHeight = rect.Height() + 1 + nExpand_Size*2;
  37. // define the image data
  38. Mat cvImageData = Mat::ones(nHeight, nWidth, CV_8U) * nWhiteColor;
  39. // go through segment list
  40. for (auto pSegment : listSegment)
  41. {
  42. int nStart = pSegment->GetStart() - rect.left + nExpand_Size;
  43. int nEnd = pSegment->GetStart() + pSegment->GetLength() - rect.left - 1 + nExpand_Size;
  44. int nHeight = pSegment->GetHeight() - rect.top + nExpand_Size;
  45. line(cvImageData, Point(nStart, nHeight), Point(nEnd, nHeight), Scalar(nBlackColor), nThickness, nLineType);
  46. }
  47. // 2. draw the contours
  48. Mat cvcopyImg = cvImageData.clone();
  49. //cvImageData.release();
  50. // contours
  51. threshold(cvcopyImg, cvcopyImg, nWhiteColor, 100, CV_THRESH_BINARY_INV);
  52. Canny(cvcopyImg, cvcopyImg, 20, 20 * 2, 3);
  53. // find contours
  54. vector<vector<Point>> contours;
  55. findContours(cvcopyImg, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
  56. //Mat cvcopyImg1 = cvcopyImg.clone();
  57. //drawContours(cvcopyImg1, contours, -1, Scalar(nWhiteColor), 1, 8);
  58. //cvcopyImg = cvcopyImg - cvcopyImg1;
  59. //findContours(cvcopyImg, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
  60. vector<Point> listEdge;
  61. for (auto listcont : contours)
  62. {
  63. for (auto pt : listcont)
  64. {
  65. auto itr = std::find_if(listEdge.begin(), listEdge.end(), [pt](Point p)
  66. {
  67. return (p.x == pt.x)&&(p.y == pt.y);
  68. });
  69. if (itr == listEdge.end())
  70. {
  71. listEdge.push_back(pt);
  72. }
  73. }
  74. }
  75. double nx = 0, ny = 0;
  76. for (auto pt : listEdge)
  77. {
  78. nx = nx + pt.x*pt.x;
  79. ny = ny + pt.y*pt.y;
  80. }
  81. nx = sqrt(nx / (double)listEdge.size());
  82. ny = sqrt(ny / (double)listEdge.size());
  83. // 3. calculate the center point
  84. // find the center point
  85. /*Moments edgeMoments = moments(listEdge, true);
  86. Point2f CenterPoint = Point2f(float(edgeMoments.m10 / edgeMoments.m00), float(edgeMoments.m01 / edgeMoments.m00));
  87. Point ptCenter = (Point)CenterPoint;
  88. */
  89. Point ptCenter = Point((int)nx, (int)ny);
  90. // 4. sort contours into 4 quadrant
  91. vector<CPoint> QuaOnelist;
  92. vector<CPoint> QuaTwolist;
  93. vector<CPoint> QuaThreelist;
  94. vector<CPoint> QuaFourlist;
  95. vector<CPoint> Xaxislist;
  96. vector<CPoint> XaxisUplist;
  97. vector<CPoint> XaxisDownlist;
  98. vector<CPoint> Yaxislist;
  99. vector<CPoint> YaxisRightlist;
  100. vector<CPoint> YaxisLeftlist;
  101. int Xmax = 0;
  102. int Ymax = 0;
  103. // coordinate transformation
  104. Point ptPosition;
  105. for (auto pt : listEdge)
  106. {
  107. // for touch the contour
  108. if (pt.x > Xmax)
  109. Xmax = pt.x;
  110. if (pt.y > Ymax)
  111. Ymax = pt.y;
  112. ptPosition.x = pt.x - ptCenter.x;
  113. ptPosition.y = ptCenter.y - pt.y;
  114. if (ptPosition.x >0 && ptPosition.y>0)
  115. {
  116. QuaOnelist.push_back(CPoint(ptPosition.x,ptPosition.y));
  117. }
  118. else if (ptPosition.x <0 && ptPosition.y>0)
  119. {
  120. QuaTwolist.push_back(CPoint(ptPosition.x, ptPosition.y));
  121. }
  122. else if (ptPosition.x <0 && ptPosition.y<0)
  123. {
  124. QuaThreelist.push_back(CPoint(ptPosition.x, ptPosition.y));
  125. }
  126. else if (ptPosition.x >0 && ptPosition.y<0)
  127. {
  128. QuaFourlist.push_back(CPoint(ptPosition.x, ptPosition.y));
  129. }
  130. else if (pt.x == ptCenter.x)
  131. {
  132. Yaxislist.push_back(CPoint(ptPosition.x, ptPosition.y));
  133. }
  134. else if (pt.y == ptCenter.y)
  135. {
  136. Xaxislist.push_back(CPoint(ptPosition.x, ptPosition.y));
  137. }
  138. if (ptPosition.y == 1)
  139. {
  140. XaxisUplist.push_back(CPoint(ptPosition.x, ptPosition.y));
  141. }
  142. else if (ptPosition.y == -1)
  143. {
  144. XaxisDownlist.push_back(CPoint(ptPosition.x, ptPosition.y));
  145. }
  146. if (ptPosition.x == 1)
  147. {
  148. YaxisRightlist.push_back(CPoint(ptPosition.x, ptPosition.y));
  149. }
  150. else if (ptPosition.x == -1)
  151. {
  152. YaxisLeftlist.push_back(CPoint(ptPosition.x, ptPosition.y));
  153. }
  154. }
  155. // get ferret diameter
  156. vector<double> FltDiameter;
  157. if ((Yaxislist.size() == 2) && Xmax >= ptCenter.x)
  158. {
  159. double d = (double)abs(Yaxislist[0].y - Yaxislist[1].y);
  160. FltDiameter.push_back(d);
  161. }
  162. else if (Yaxislist.size() > 2)
  163. {
  164. double d = GetDisFromRLNeigbor(Yaxislist, YaxisRightlist, YaxisLeftlist);
  165. FltDiameter.push_back(d);
  166. }
  167. if ((Xaxislist.size() == 2) && Ymax >= ptCenter.y)
  168. {
  169. double d = (double)abs(Xaxislist[0].x - Xaxislist[1].x);
  170. FltDiameter.push_back(d);
  171. }
  172. else if (Xaxislist.size() > 2)
  173. {
  174. double d = GetDisFromUDNeigbor(Xaxislist, XaxisUplist, XaxisDownlist);
  175. FltDiameter.push_back(d);
  176. }
  177. if ((int)QuaOnelist.size() <= ANGLE_MAX || (int)QuaThreelist.size() <= ANGLE_MAX)
  178. {
  179. if (!GetDisFrom2list(QuaOnelist, QuaThreelist, FltDiameter))
  180. {
  181. return FALSE;
  182. }
  183. }
  184. else
  185. {
  186. if (!GetDisFrom13list(QuaOnelist, QuaThreelist, FltDiameter))
  187. {
  188. return FALSE;
  189. }
  190. }
  191. if ((int)QuaTwolist.size() <= ANGLE_MAX || (int)QuaFourlist.size() <= ANGLE_MAX)
  192. {
  193. if (!GetDisFrom2list(QuaTwolist, QuaFourlist, FltDiameter))
  194. {
  195. return FALSE;
  196. }
  197. }
  198. else
  199. {
  200. if (!GetDisFrom24list(QuaTwolist,QuaFourlist, FltDiameter))
  201. {
  202. return FALSE;
  203. }
  204. }
  205. double dSum = 0;
  206. double dMax = 0;
  207. double dMin = 0;
  208. double a_dAveDia = 0;
  209. GetSuperParticleSize(a_pOTSPart, dMin, dMax, a_dAveDia);
  210. for (auto d : FltDiameter)
  211. {
  212. dSum = dSum + d;
  213. if (d > dMax)
  214. dMax = d;
  215. if (d < dMin && d >0)
  216. dMin = d;
  217. }
  218. //calculate the distance
  219. dPartFTD = a_PixelSize * dSum / (int)FltDiameter.size();
  220. if ((dSum == 0) || (int)FltDiameter.size() == 0)
  221. {
  222. dPartFTD = a_PixelSize * a_dAveDia;
  223. }
  224. dMaxLength = a_PixelSize * dMax;
  225. dMinWidth = a_PixelSize * dMin;
  226. if (dMin != 0)
  227. {
  228. dRatio = dMax / dMin;
  229. }
  230. //cvcopyImg.release();
  231. return TRUE;
  232. }
  233. // initialization
  234. void CGBImgPropCal::Init()
  235. {
  236. }
  237. // clear
  238. void CGBImgPropCal::Clear()
  239. {
  240. }
  241. double CGBImgPropCal::GetDisFrom3(double a_s1, double a_s2, double a_s3)
  242. {
  243. double d = 0;
  244. if (a_s1*a_s2 > 0)
  245. {
  246. d = (double)abs(a_s2 - a_s1);
  247. }
  248. else if (a_s2*a_s3 > 0)
  249. {
  250. d = (double)abs(a_s2 - a_s3);
  251. }
  252. else if (a_s2*a_s3 > 0)
  253. {
  254. d = (double)abs(a_s3 - a_s1);
  255. }
  256. return d;
  257. }
  258. BOOL CGBImgPropCal::GetDisFrom2list(std::vector<CPoint> a_list1, std::vector<CPoint> a_list2, std::vector<double>& a_listFlt)
  259. {
  260. if ((int)a_list1.size() < (int)a_list2.size())
  261. {
  262. if (a_list1.empty())
  263. {
  264. for (auto pt : a_list2)
  265. {
  266. double d = sqrt(pt.x*pt.x + pt.y *pt.y);
  267. a_listFlt.push_back(d);
  268. }
  269. }
  270. else
  271. {
  272. for (auto pt : a_list1)
  273. {
  274. double r1 = sqrt(pt.x*pt.x + pt.y *pt.y);
  275. double k = (double)pt.y / (double)pt.x;
  276. double kmin = 100;
  277. for (auto pot : a_list2)
  278. {
  279. double kThree = (double)pot.y / (double)pot.x;
  280. if (abs(kThree - k) < kmin)
  281. {
  282. kmin = abs(kThree - k);
  283. }
  284. }
  285. double r2;
  286. for (auto pot : a_list2)
  287. {
  288. double kThree = (double)pot.y / (double)pot.x;
  289. if (abs(kThree - k) == kmin)
  290. {
  291. r2 = sqrt(pot.x * pot.x + pot.y *pot.y);
  292. break;
  293. }
  294. }
  295. a_listFlt.push_back((r1 + r2));
  296. }
  297. }
  298. }
  299. else
  300. {
  301. if (a_list2.empty())
  302. {
  303. for (auto pt : a_list1)
  304. {
  305. double d = sqrt(pt.x*pt.x + pt.y *pt.y);
  306. a_listFlt.push_back(d);
  307. }
  308. }
  309. else
  310. {
  311. for (auto pt : a_list2)
  312. {
  313. double r1 = sqrt(pt.x*pt.x + pt.y *pt.y);
  314. double k = (double)pt.y / (double)pt.x;
  315. double kmin = 100;
  316. for (auto pot : a_list1)
  317. {
  318. double kThree = (double)pot.y / (double)pot.x;
  319. if (abs(kThree - k) < kmin)
  320. {
  321. kmin = abs(kThree - k);
  322. }
  323. }
  324. double r2;
  325. for (auto pot : a_list1)
  326. {
  327. double kThree = (double)pot.y / (double)pot.x;
  328. if (abs(kThree - k) == kmin)
  329. {
  330. r2 = sqrt(pot.x * pot.x + pot.y *pot.y);
  331. break;
  332. }
  333. }
  334. a_listFlt.push_back((r1 + r2));
  335. }
  336. }
  337. }
  338. return TRUE;
  339. }
  340. BOOL CGBImgPropCal::GetDisFrom4list(std::vector<CPoint> a_list1, std::vector<CPoint> a_list2,
  341. std::vector<CPoint> a_list3, std::vector<CPoint> a_list4, std::vector<double>& a_listFlt)
  342. {
  343. if ((int)a_list1.size() < ANGLE_MAX ||
  344. (int)a_list2.size() < ANGLE_MAX ||
  345. (int)a_list3.size() < ANGLE_MAX ||
  346. (int)a_list4.size() < ANGLE_MAX)
  347. {
  348. return FALSE;
  349. }
  350. //there should be enough radius in one and two quadrant
  351. for (int i = 0; i < ANGLE_MAX; i++)
  352. {
  353. // one and three
  354. double k = TAN_VALUES[i];
  355. double r1 = 0;
  356. double r2 = 0;
  357. r1 = GetRadiusAsK(a_list1, k);
  358. r2 = GetRadiusAsK(a_list3, k);
  359. if(r1!=0 && r2!=0)
  360. a_listFlt.push_back((r1 + r2));
  361. // two and four
  362. k = -TAN_VALUES[i];
  363. r1 = GetRadiusAsK(a_list2, k);
  364. r2 = GetRadiusAsK(a_list4, k);
  365. if (r1 != 0 && r2 != 0)
  366. a_listFlt.push_back((r1 + r2));
  367. }
  368. return TRUE;
  369. }
  370. BOOL CGBImgPropCal::GetDisFrom13list(std::vector<CPoint> a_list1,
  371. std::vector<CPoint> a_list3,std::vector<double>& a_listFlt)
  372. {
  373. if ((int)a_list1.size() < ANGLE_MAX ||
  374. (int)a_list3.size() < ANGLE_MAX )
  375. {
  376. return FALSE;
  377. }
  378. //there should be enough radius in one and two quadrant
  379. for (int i = 0; i < ANGLE_MAX; i++)
  380. {
  381. // one and three
  382. double k = TAN_VALUES[i];
  383. double r1 = 0;
  384. double r2 = 0;
  385. r1 = GetRadiusAsK(a_list1, k);
  386. r2 = GetRadiusAsK(a_list3, k);
  387. if (r1 != 0 && r2 != 0)
  388. a_listFlt.push_back((r1 + r2));
  389. }
  390. return TRUE;
  391. }
  392. BOOL CGBImgPropCal::GetDisFrom24list(std::vector<CPoint> a_list2,
  393. std::vector<CPoint> a_list4, std::vector<double>& a_listFlt)
  394. {
  395. if ((int)a_list2.size() < ANGLE_MAX ||
  396. (int)a_list4.size() < ANGLE_MAX)
  397. {
  398. return FALSE;
  399. }
  400. //there should be enough radius in one and two quadrant
  401. for (int i = 0; i < ANGLE_MAX; i++)
  402. {
  403. // two and four
  404. double k = -TAN_VALUES[i];
  405. double r1 = GetRadiusAsK(a_list2, k);
  406. double r2 = GetRadiusAsK(a_list4, k);
  407. if (r1 != 0 && r2 != 0)
  408. a_listFlt.push_back((r1 + r2));
  409. }
  410. return TRUE;
  411. }
  412. BOOL CGBImgPropCal::GetSuperParticleSize(COTSParticlePtr a_pOTSPart, double &a_dMinWidth, double &a_dMaxLength, double &a_dAveDia)
  413. {
  414. // safety check
  415. ASSERT(a_pOTSPart);
  416. // 1. convert particle data to image data
  417. // get the segment list
  418. COTSSegmentsList listSegment = a_pOTSPart->GetFeature()->GetSegmentsList();
  419. // get rectangle of the particle
  420. CRect rect = a_pOTSPart->GetParticleRect();
  421. //get the particle rectangle size
  422. a_dMinWidth = rect.Width();
  423. a_dMaxLength = rect.Height();
  424. a_dAveDia = (a_dMinWidth + a_dMaxLength) / 2;
  425. if (a_dMinWidth > a_dMaxLength)
  426. {
  427. a_dMaxLength = a_dMinWidth;
  428. }
  429. return TRUE;
  430. }
  431. // note: this not include touch
  432. double CGBImgPropCal::GetDisFromRLNeigbor(std::vector<CPoint> a_Yaxislist, std::vector<CPoint> a_YaxisRightlist, std::vector<CPoint> a_YaxisLeftlist)
  433. {
  434. double d = 0;
  435. int nXMax,nXMin;
  436. GetMaxMin(a_Yaxislist, AXIAS_DIRECTION::XAX, nXMax, nXMin);
  437. int nXRMax, nXRMin;
  438. GetMaxMin(a_YaxisRightlist, AXIAS_DIRECTION::XAX, nXRMax, nXRMin);
  439. int nXLMax, nXLMin;
  440. GetMaxMin(a_YaxisLeftlist, AXIAS_DIRECTION::XAX, nXLMax, nXLMin);
  441. if (nXMax*nXMin<0 && (nXLMax*nXLMin < 0 || nXRMax*nXLMin < 0))
  442. {
  443. d = abs(nXMax - nXMin);
  444. }
  445. return d;
  446. }
  447. double CGBImgPropCal::GetDisFromUDNeigbor(std::vector<CPoint> a_Xaxislist, std::vector<CPoint> a_XaxisUplist, std::vector<CPoint> a_XaxisDownlist)
  448. {
  449. double d = 0;
  450. int nYMax, nYMin;
  451. GetMaxMin(a_Xaxislist, AXIAS_DIRECTION::YAX, nYMax, nYMin);
  452. int nYUMax, nYUMin;
  453. GetMaxMin(a_XaxisUplist, AXIAS_DIRECTION::YAX, nYUMax, nYUMin);
  454. int nYDMax, nYDMin;
  455. GetMaxMin(a_XaxisDownlist, AXIAS_DIRECTION::YAX, nYDMax, nYDMin);
  456. if (nYMax*nYMin<0 && (nYUMax*nYUMin < 0 || nYDMax*nYDMin < 0))
  457. {
  458. d = abs(nYMax - nYMin);
  459. }
  460. return d;
  461. }
  462. BOOL CGBImgPropCal::GetMaxMin(std::vector<CPoint> a_Xaxislist, AXIAS_DIRECTION a_nDirection, int& a_nMax, int& a_nMin)
  463. {
  464. int nMax = 0;
  465. int nMin = 100;
  466. if (a_nDirection == AXIAS_DIRECTION::YAX)
  467. {
  468. for (auto pt : a_Xaxislist)
  469. {
  470. if (pt.x > nMax)
  471. nMax = pt.x;
  472. if (pt.x < nMin)
  473. nMin = pt.x;
  474. }
  475. }
  476. else if (a_nDirection == AXIAS_DIRECTION::XAX)
  477. {
  478. for (auto pt : a_Xaxislist)
  479. {
  480. if (pt.y > nMax)
  481. nMax = pt.y;
  482. if (pt.y < nMin)
  483. nMin = pt.y;
  484. }
  485. }
  486. a_nMax = nMax;
  487. a_nMin = nMin;
  488. return TRUE;
  489. }
  490. double CGBImgPropCal::GetRadiusAsK(std::vector<CPoint> a_Ptlist, double a_k)
  491. {
  492. double r1 = 0;
  493. vector<CPoint> ptLengthList;
  494. for (auto pt : a_Ptlist)
  495. {
  496. if (abs(pt.x * a_k - pt.y) < VALUE_MIN)
  497. {
  498. ptLengthList.push_back(pt);
  499. }
  500. }
  501. if (ptLengthList.empty())
  502. return 0;
  503. double rAve = 0;
  504. for (auto len : ptLengthList)
  505. {
  506. double r = sqrt(len.x * len.x + len.y *len.y);
  507. rAve += r;
  508. }
  509. rAve = rAve / (double)ptLengthList.size();
  510. return rAve;
  511. }
  512. }