GBImgPropCal.cpp 13 KB

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