StenoseNBBase.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  1. /*******************************************************************\
  2. Fichier : StenoseNBBase.cpp
  3. Date : 4/01/10
  4. Version : 1.000
  5. Description : classe de calcul d'une sténose N&B
  6. |*******************************************************************|
  7. Bugs:
  8. Notes:
  9. |*******************************************************************|
  10. Historique :
  11. 10/02/98 1.000 : Première version
  12. \*******************************************************************/
  13. /*----------------------------------------------------------\
  14. Includes
  15. \----------------------------------------------------------*/
  16. #include <limits>
  17. #include "StenoseNBBase.h"
  18. #include "Ressource.h"
  19. //#include "../IMT/MeanEstimate.h"
  20. #include "../Object/regionEllipse.h"
  21. #include "../Object/point.h"
  22. #include "../NR/ToolsMath.h"
  23. #include "../Container/extendedimage.h"
  24. #include "../TRIM/img.h"
  25. #ifndef max
  26. #define max(a,b) (((a) > (b)) ? (a) : (b))
  27. #endif
  28. #ifndef min
  29. #define min(a,b) (((a) < (b)) ? (a) : (b))
  30. #endif
  31. CStenoseNBBase::CStenoseNBBase (void)
  32. {
  33. // Couleur des points à afficher pour le degré de sténose
  34. m_rcStenose.SetRectEmpty();
  35. m_step = stepNone;
  36. m_clrVert = 0 | (255 << 16) | (0 << 8);
  37. m_clrOrange = 216 | (216 << 16) | (28 << 8);
  38. m_pPoints = NULL;
  39. m_SeuilBlobColoring = 40;
  40. }
  41. CStenoseNBBase::~CStenoseNBBase()
  42. {
  43. Release ();
  44. }
  45. void CStenoseNBBase::Release()
  46. {
  47. if (m_pPoints)
  48. {
  49. delete [] m_pPoints;
  50. m_pPoints = NULL;
  51. }
  52. m_dwPoints = 0; // requis par la routine de mesure
  53. }
  54. double CStenoseNBBase::Ratio()
  55. {
  56. return (100.0 * m_dwOther / (m_dwGreen + m_dwOther));
  57. }
  58. double CStenoseNBBase::Surface()
  59. {
  60. return m_dblSurface;
  61. }
  62. int CStenoseNBBase::Density()
  63. {
  64. return m_dwMean;
  65. }
  66. bool CStenoseNBBase::ParametrerRegionATraiter (Rect &rcStenose, Point ptStenose)
  67. {
  68. // Région à traiter
  69. m_ptStenose = ptStenose;
  70. m_rcStenose = rcStenose;
  71. m_rgnATraiter.DeleteObject();
  72. m_rgnATraiter.CreateEllipticRgn(rcStenose);
  73. return true;
  74. }
  75. /*----------------------------------------------------------\
  76. | Mesurer |
  77. |-----------------------------------------------------------|
  78. | DESCRIPTION : |
  79. | On a saisi un segment. Mesurer l'épaisseur de droites |
  80. | perpendiculaires. |
  81. |-----------------------------------------------------------|
  82. | PARAMETRES : |
  83. | ... |
  84. \----------------------------------------------------------*/
  85. void CStenoseNBBase::TraiterPoint (int x, int y)
  86. {
  87. assert(PointInBufferResult(x, y));
  88. if (PointInBufferResult(x, y))
  89. {
  90. int xx, yy, xMax, yMax;
  91. // Colorer ce point en vert
  92. // SetPixelResult(y, x, m_clrVert);
  93. SetPixelResult(x, y, m_clrOrange);
  94. // Pour optimiser le temps de calcul, on effectue les tests les plus rapides en premier
  95. xMax = min (x + 1, GetWidth() - 1);
  96. yMax = min (y + 1, GetHeight() - 1);
  97. for (xx = max (0, x - 1); xx <= xMax; xx++)
  98. {
  99. for (yy = max (0, y - 1); yy <= yMax; yy++)
  100. {
  101. if ((xx != x) || (yy != y))
  102. {
  103. assert(PointInBufferResult(xx, yy));
  104. // <= sur les intensités sinon à 255 tout n'est pas rempli
  105. if ( (GetIntensityResult(xx, yy) <= m_iMax)
  106. // && (GetPixelResult(xx, yy) != m_clrVert)
  107. && (GetPixelResult(xx, yy) != m_clrOrange)
  108. && m_rgnATraiter.PtInRegion0(xx, yy)
  109. )
  110. {
  111. TraiterPoint (xx, yy); // Pas de max
  112. }
  113. }
  114. }
  115. }
  116. }
  117. }
  118. int CStenoseNBBase::GetIntensityTache(int ptCentrex, int ptCentrey, int nRayonTache)
  119. {
  120. int nIntensiteTache = 0;
  121. // Quelle est l'intensité monochrome de la tache autour de ce pt ?
  122. for (int iX = min (m_result->GetWidth()-1, max (0, ptCentrex - nRayonTache));
  123. iX <= min (m_result->GetWidth()-1, ptCentrex + nRayonTache); iX++)
  124. {
  125. for (int iY = min (m_result->GetHeight()-1, max (0, ptCentrey - nRayonTache));
  126. iY <= min (m_result->GetHeight()-1, ptCentrey + nRayonTache); iY++)
  127. {
  128. nIntensiteTache += m_result->GetPixelRGB( iX, iY, 0);
  129. }
  130. }
  131. return (nIntensiteTache / ((nRayonTache * 2 + 1) * (nRayonTache * 2 + 1)));
  132. }
  133. int CStenoseNBBase::Threshold_2(ExtendedImage *h_image, int iMax, Rect &rcEllipse, int ptx, int pty)
  134. {
  135. int dwColor;
  136. int retour;
  137. iMax = 0; // Unused
  138. m_result = h_image;
  139. m_wimg.Del();
  140. m_wimg.Create(TYPE_UCHAR, GetWidth(), GetHeight());
  141. m_wimg.Fill(0);
  142. Release();
  143. m_ptStenose.x = ptx;
  144. m_ptStenose.y = pty;
  145. m_step = stepSettings;
  146. m_rcStenose = rcEllipse;
  147. m_rcStenose.right++;
  148. m_rcStenose.bottom++;
  149. // nombre maximal de points qui pourraient être affichés
  150. m_pPoints = new Point [m_rcStenose.Width() * m_rcStenose.Height()];
  151. m_rgnATraiter.DeleteObject ();
  152. m_rgnATraiter.CreateEllipticRgn(m_rcStenose);
  153. // GetIntensityTache inclus dans la librairie
  154. m_iMax = GetIntensityTache(ptx, pty, 7) + 10;
  155. TraiterPoint(m_ptStenose.x, m_ptStenose.y);
  156. // Fermeture et Effacement des petites régions
  157. DoClosing();
  158. DoBlobColoring();
  159. //***** Afficher les résultats
  160. GraphMeanInit();
  161. dwColor = 0;
  162. m_dwGreen = 0;
  163. m_dwOther = 0;
  164. m_dwMean = 0;
  165. m_dblVesselArea = g_pCurrentScale->Surface (m_rcStenose.Width(), m_rcStenose.Height()) * M_PI / 4;
  166. for (int x = m_rcStenose.left; x < m_rcStenose.right; x++)
  167. {
  168. for (int y = m_rcStenose.top; y < m_rcStenose.bottom; y++)
  169. {
  170. bool fGreen;
  171. // Même en dehors de la région sinon le bord inférieur droit est exclu
  172. // fGreen = (GetPixelResult(x, y) == m_clrVert);
  173. fGreen = (GetPixelResult(x, y) == m_clrOrange);
  174. if (fGreen)
  175. {
  176. m_dwGreen++;
  177. m_pPoints[m_dwPoints].x = x;
  178. m_pPoints[m_dwPoints].y = y;
  179. m_dwPoints++;
  180. }
  181. if (m_rgnATraiter.PtInRegion0(x, y))
  182. {
  183. if (!fGreen)
  184. {
  185. dwColor += IsColor (x, y) ? 1 : 0;
  186. m_dwOther++;
  187. m_dwMean += GetIntensityResult(x, y);
  188. GraphMeanAddMeasure(true, GetIntensityResult(x, y));
  189. }
  190. }
  191. }
  192. }
  193. if (m_dwOther)
  194. {
  195. m_dwMean /= m_dwOther;
  196. }
  197. assert(m_dwMean <= 255);
  198. m_dblSurface = m_dblVesselArea * Ratio () / 100.0;
  199. if (dwColor > 50)
  200. {
  201. retour = 10;
  202. }
  203. else
  204. {
  205. retour = 11;
  206. }
  207. return retour;
  208. } // fin de Threshold_2
  209. // Algorithme de coloriage de blobs sur l'image d'entrée
  210. // Objectif : enlever les petites régions dans l'image seuillée
  211. bool CStenoseNBBase::DoBlobColoring()
  212. {
  213. int x, y, i, indblob, nblob, realblob, ng;
  214. long taille;
  215. img lwimg, lwimg1;
  216. int wdimh, wdimv;
  217. blob m_tblob[MAXBLOB];
  218. wdimh = GetWidth();
  219. wdimv = GetHeight();
  220. lwimg.Create(TYPE_UCHAR, wdimh, wdimv);
  221. lwimg1.Create(TYPE_INT, wdimh, wdimv); // On prend des ints
  222. lwimg.Fill(0);
  223. indblob = 0;
  224. nblob = 0;
  225. // Générer l'image binaire qui va aller à l'algo. du blob coloring
  226. // Lwimg
  227. for (x = m_rcStenose.left; x < m_rcStenose.right; x++)
  228. {
  229. for (y = m_rcStenose.top; y < m_rcStenose.bottom; y++)
  230. {
  231. if (m_rgnATraiter.PtInRegion0(x, y))
  232. {
  233. bool fGreen;
  234. fGreen = (GetPixelResult(x, y) == m_clrOrange);
  235. if (!fGreen)
  236. {
  237. lwimg.SetValue(x, y, 1);
  238. }
  239. }
  240. }
  241. }
  242. // Résultat : les blobs sont dans wimg1
  243. nblob = lwimg.BlobColoring(m_tblob, &lwimg1);
  244. // Elimination des petits blobs.
  245. realblob = nblob;
  246. for (i = 1; i <= nblob; i++)
  247. {
  248. taille = lwimg1.GetBlobSize(i);
  249. if ((taille < (wdimh * wdimv) - 1) && (taille <= m_SeuilBlobColoring))
  250. {
  251. lwimg1.RemplaceCouleur(i, MAXBLOB+1); // Sur int
  252. }
  253. }
  254. // Dans lwimg1, les pixels à la valeur MAXBLOB+1, sont ceux des régions à supprimer
  255. // Mise à jour de lwimg, puis transfert dans l'image d'origine
  256. for (x = m_rcStenose.left; x < m_rcStenose.right; x++)
  257. {
  258. for (y = m_rcStenose.top; y < m_rcStenose.bottom; y++)
  259. {
  260. if (m_rgnATraiter.PtInRegion0(x, y))
  261. {
  262. ng = lwimg1.GetValue(x, y);
  263. if (ng == (MAXBLOB+1))
  264. {
  265. SetPixelResult(x, y, m_clrOrange);
  266. }
  267. }
  268. }
  269. }
  270. if (lwimg.init == 1) lwimg.Del();
  271. if (lwimg1.init == 1) lwimg1.Del();
  272. return true;
  273. }
  274. // Algorithme de fermeture
  275. bool CStenoseNBBase::DoClosing()
  276. {
  277. int x, y, ng;
  278. img lwimg, lwimg1;
  279. int wdimh, wdimv;
  280. wdimh = GetWidth();
  281. wdimv = GetHeight();
  282. lwimg.Create(TYPE_USHORT, wdimh, wdimv);
  283. lwimg1.Create(TYPE_USHORT, wdimh, wdimv); // On prend des ints
  284. lwimg.Fill(0);
  285. // Générer l'image binaire qui va aller à l'algo. du blob coloring
  286. // lwimg
  287. for (x = m_rcStenose.left; x < m_rcStenose.right; x++)
  288. {
  289. for (y = m_rcStenose.top; y < m_rcStenose.bottom; y++)
  290. {
  291. if (m_rgnATraiter.PtInRegion0(x, y))
  292. {
  293. bool fGreen;
  294. fGreen = (GetPixelResult(x, y) == m_clrOrange);
  295. if (fGreen)
  296. {
  297. lwimg.SetValue(x, y, 1);
  298. }
  299. }
  300. }
  301. }
  302. lwimg.BinaryClosing(&lwimg1);
  303. // Dans lwimg1, les pixels à la valeur MAXBLOB+1, sont ceux des régions à supprimer
  304. // Mise à jour de lwimg, puis transfert dans l'image d'origine
  305. for (x = m_rcStenose.left; x < m_rcStenose.right; x++)
  306. {
  307. for (y = m_rcStenose.top; y < m_rcStenose.bottom; y++)
  308. {
  309. if (m_rgnATraiter.PtInRegion0(x, y))
  310. {
  311. ng = lwimg1.GetValue(x, y);
  312. if (ng == 1)
  313. {
  314. SetPixelResult(x, y, m_clrOrange);
  315. }
  316. }
  317. }
  318. }
  319. if (lwimg.init == 1) lwimg.Del();
  320. if (lwimg1.init == 1) lwimg1.Del();
  321. return true;
  322. }
  323. int CStenoseNBBase::GetWidth()
  324. {
  325. return m_result->GetWidth();
  326. }
  327. int CStenoseNBBase::GetHeight()
  328. {
  329. return m_result->GetHeight();
  330. }
  331. unsigned long CStenoseNBBase::GetPixelResult(const int& x, const int& y)
  332. {
  333. Point pt;
  334. pt.x = x;
  335. pt.y = y;
  336. return GetPixelResult(pt);
  337. }
  338. unsigned long CStenoseNBBase::GetPixelResult(const Point& pt)
  339. {
  340. unsigned long color;
  341. color = 0;
  342. if (m_wimg.GetValue(pt.x, pt.y) == 1)
  343. {
  344. color = m_clrOrange;
  345. }
  346. // m_wimg.SaveImgAsRaw();
  347. return color;
  348. /*
  349. assert( m_result );
  350. #if defined( WIN32 ) && !defined( PLAQUE_DLL )
  351. return m_result->GetPixel( pt.x, pt.y );
  352. #else
  353. return *m_result->GetPixel( pt.x, pt.y );
  354. #endif
  355. */
  356. }
  357. void CStenoseNBBase::SetPixelResult(Point& pt, unsigned long vColor)
  358. {
  359. int x, y;
  360. x = pt.x;
  361. y = pt.y;
  362. SetPixelResult(x, y, vColor);
  363. }
  364. void CStenoseNBBase::SetPixelResult(int x, int y, unsigned long vColor)
  365. {
  366. m_wimg.SetValue(x, y, 1);
  367. // m_wimg.SaveImgAsRaw();
  368. }
  369. bool CStenoseNBBase::IsColor(int x, int y)
  370. {
  371. unsigned char bRed;
  372. unsigned char bGreen;
  373. unsigned char bBlue;
  374. int iRed;
  375. int iGreen;
  376. int iBlue;
  377. // AffectLeadResult();
  378. bRed = m_result->GetPixelRGB( x, y, 0);
  379. bGreen = m_result->GetPixelRGB( x, y, 1);
  380. bBlue = m_result->GetPixelRGB( x, y, 2);
  381. iRed = (int) bRed;
  382. iGreen = (int) bGreen;
  383. iBlue = (int) bBlue;
  384. // un niveau de gris implique bRed = bGreen = bBlue
  385. // étant donné que l'image a été numérisé on autorise un delta de 10 entre chaque couleur
  386. // ex : 190 197 185 est gris, 190 201 190 est en couleur
  387. return ( (abs (iRed - iGreen) > 30)
  388. || (abs (iRed - iBlue ) > 30)
  389. || (abs (iGreen - iBlue ) > 30)
  390. );
  391. }
  392. unsigned char CStenoseNBBase::GetIntensityResult(const int& x, const int& y)
  393. {
  394. Point pt;
  395. pt.x = x;
  396. pt.y = y;
  397. return GetIntensityResult(pt);
  398. }
  399. unsigned char CStenoseNBBase::GetIntensityResult(const Point& pt)
  400. {
  401. assert( m_result );
  402. return m_result->GetPixelGray( pt.x, pt.y );
  403. /*
  404. value = (char) m_result->GetPixel( pt.x, pt.y );
  405. col = (unsigned char)(value & 0xff);
  406. return col;
  407. */
  408. /*
  409. #if defined( WIN32 ) && !defined( IMT_DLL ) && !defined( PLAQUE_DLL )
  410. return GetRValue( m_result->GetPixel( pt.x, pt.y ) );
  411. #else
  412. return *m_result->GetPixel( pt.x, pt.y );
  413. #endif
  414. */
  415. }
  416. bool CStenoseNBBase::PointInBufferResult(const int& x, const int& y)
  417. {
  418. Point pt;
  419. pt.x = x;
  420. pt.y = y;
  421. return PointInBufferResult(pt);
  422. }
  423. bool CStenoseNBBase::PointInBufferResult(const Point& pt)
  424. {
  425. assert( m_result );
  426. int dx = GetWidth();
  427. int dy = GetHeight();
  428. return ( pt.x >= 0 && pt.y >= 0 && pt.x < dx && pt.y < dy );
  429. }
  430. void CStenoseNBBase::PutPixEllipse(float xc,float yc,float x,float y)
  431. {
  432. WritePixel( (int) (xc + x), (int) (yc + y));
  433. WritePixel( (int) (xc - x), (int) (yc - y));
  434. WritePixel( (int) (xc + x), (int) (yc - y));
  435. WritePixel( (int) (xc - x), (int) (yc + y));
  436. }
  437. void CStenoseNBBase::WritePixel(int x, int y)
  438. {
  439. }
  440. // Algorithme MidPoint de dessin d'une Ellipse
  441. void CStenoseNBBase::myDrawEllipse()
  442. {
  443. float x = 0, y = 0;
  444. double p1, p2, t1, t2;
  445. int k;
  446. float rx, ry, xc, yc;
  447. rx = (float) (m_rcStenose.right - m_rcStenose.left) / 2;
  448. ry = (float) (m_rcStenose.bottom - m_rcStenose.top) / 2;
  449. xc = m_rcStenose.left + rx;
  450. yc = m_rcStenose.top + ry;
  451. y = ry;
  452. p1 = ry * ry - rx * rx * ry + 0.25 * rx * rx;
  453. PutPixEllipse(xc, yc, x, y);
  454. for (k = 0; (2 * ry * ry * x) <= (2 * rx * rx * y); k++)
  455. {
  456. t1 = 2 * ry * ry * x + 2 * ry * ry;
  457. t2 = 2 * rx * rx * y - 2 * rx * rx;
  458. if (p1 < 0)
  459. {
  460. p1 = p1 + t1 + ry * ry;
  461. }
  462. else
  463. {
  464. p1 = p1 + t1 - t2 + ry * ry;
  465. y--;
  466. }
  467. x++;
  468. PutPixEllipse(xc, yc, x, y);
  469. }
  470. p2 = ry * ry * ( x + 0.5 ) * ( x + 0.5 ) + rx * rx * (y - 1) * (y - 1) - rx * rx * ry * ry;
  471. PutPixEllipse(xc, yc, x, y);
  472. for (k = 0 ; y >= 0 ; k++)
  473. {
  474. t1 = 2 * ry * ry * x + 2 * ry * ry;
  475. t2 = 2 * rx * rx * y - 2 * rx * rx;
  476. if (p2 > 0)
  477. {
  478. p2 = p2 - t2 + rx * rx;
  479. }
  480. else
  481. {
  482. p2 = p2 + t1 - t2 + rx * rx;
  483. x++;
  484. }
  485. y--;
  486. PutPixEllipse(xc, yc, x, y);
  487. }
  488. }