/*******************************************************************\ Fichier : Stenose.cpp Date : 20/04/98 Version : 1.001 Description : fonctions de mesures de sténose |*******************************************************************| Bugs: Notes: L'ellipse donnée peut être entièrement contenue dans le vaisseau, c'est pour cela que l'on utilise les régions plutôt que le rectangle englobant qui peut contenir des points de couleur. Un rapport entre la surface de l'ellipse et du rectangle est donc erroné, si des points de couleur sont entre le rectangle et l'ellipse |*******************************************************************| Historique : 20/04/98 1.001 : L'ellipse n'était pas affichée si aucun point n'était détecté 24/07/97 1.000 : Première version \*******************************************************************/ #include #include "StenoseBase.h" #include "Ressource.h" //#include "../IMT/MeanEstimate.h" #include "CStenoseResult.h" #include "StenoseResult.h" #include "../Object/regionEllipse.h" #include "../Object/point.h" #include "../NR/ToolsMath.h" #include "../Container/extendedimage.h" CStenoseBase::CStenoseBase (void) { m_pPoints = NULL; Release (); } CStenoseBase::~CStenoseBase() { Release (); } double CStenoseBase::SurfaceEllipse () { return m_dblEllipse; } double CStenoseBase::SurfaceStenose () { return m_dblStenose; } double CStenoseBase::Ratio () { return m_dblRatio; } bool CStenoseBase::Measure(ExtendedImage *h_image, Rect &rcEllipse) { m_image = h_image; assert(g_pCurrentScale); long dwEllipse, dwX, dwY, dwEnd, dwColor; RegionEllipse rgnEllipse; bool fColor; // on libère les ressources allouées pour la précédente mesure Release(); // définition de la zone de mesure m_rcDraw = rcEllipse; m_rcDraw.right++; m_rcDraw.bottom++; rgnEllipse.CreateEllipticRgn(m_rcDraw); dwColor = 0; // nombre de points de couleur dans l'ellipse dwEllipse = 0; // nombre de points dans l'ellipse // nombre maximal de points qui pourraient être affichés m_pPoints = new Point [rcEllipse.Width() * rcEllipse.Height() / 2]; // Balayage horizontal! for (dwY = rcEllipse.top; ((long) dwY) < rcEllipse.bottom; dwY++) { // afin d'accélérer les mesures, on ne travaille que sur les points du segment de droite // horizontale à l'interieur de l'ellipse // Point d'abscisse maximal dwEnd = rcEllipse.right; while ((!rgnEllipse.PtInRegion0(dwEnd, dwY)) && ((int) dwEnd >= rcEllipse.left)) // un des points appartient nécessairement à l'ellipse dwEnd--; // Point d'abscisse minimal dwX = rcEllipse.left + rcEllipse.right - dwEnd; // Premier point de couleur ou non? fColor = IsColor(dwX, dwY); if (fColor) { m_pPoints [m_dwPoints].x = dwX; m_pPoints [m_dwPoints].y = dwY; m_dwPoints++; // a été réinitialisé par Release } // On parcours le segment de droite... while (dwX <= dwEnd) { dwEllipse++; // Nombre de point intérieur à l'ellipse incrémenté! assert (PointInBuffer (dwX, dwY)); if (IsColor(dwX, dwY)) { dwColor++; if (!fColor) { // On passe d'une zone NB à une zone RGB fColor = true; m_pPoints [m_dwPoints].x = dwX; m_pPoints [m_dwPoints].y = dwY; m_dwPoints++; } } else if (fColor) { // On passe d'une zone RGB à une zone NB fColor = false; m_pPoints[m_dwPoints].x = dwX; m_pPoints[m_dwPoints].y = dwY; m_dwPoints++; } dwX++; } } // Fin du balayage horizontal! // Balayage vertical! for (dwX = rcEllipse.left; ((long) dwX) < rcEllipse.right; dwX++) { // afin d'accélérer les mesures, on ne travaille que sur les points du segment de droite // verticale à l'interieur de l'ellipse // Point d'ordonnée maximal dwEnd = rcEllipse.bottom; while ((!rgnEllipse.PtInRegion0(dwX, dwEnd)) && ((int) dwEnd >= rcEllipse.top)) // un des points appartient nécessairement à l'ellipse dwEnd--; // Point d'ordonnée minimal dwY = rcEllipse.top + rcEllipse.bottom - dwEnd; // Premier point de couleur ou non? fColor = IsColor(dwX, dwY); if (fColor) { m_pPoints[m_dwPoints].x = dwX; m_pPoints[m_dwPoints].y = dwY; m_dwPoints++; // a été réinitialisé par Release } // On parcours le segment de droite... while (dwY <= dwEnd) { assert(PointInBuffer(dwX, dwY)); if (IsColor(dwX, dwY)) { if (!fColor) { // On passe d'une zone NB à une zone RGB fColor = true; m_pPoints[m_dwPoints].x = dwX; m_pPoints[m_dwPoints].y = dwY; m_dwPoints++; } } else if (fColor) { // On passe d'une zone RGB à une zone NB fColor = false; m_pPoints[m_dwPoints].x = dwX; m_pPoints[m_dwPoints].y = dwY; m_dwPoints++; } dwY++; } } // Fin du balayage vertical! m_dblRatio = 100 * (1. - double (dwColor) / dwEllipse); m_dblEllipse = g_pCurrentScale->Surface (rcEllipse.Width(), rcEllipse.Height()) * M_PI / 4; m_dblStenose = m_dblEllipse * m_dblRatio / 100.0; m_rcDraw = rcEllipse; m_rcDraw.bottom--; m_rcDraw.right--; return(true); // on retourne toujours un résultat } // fin de Measure void CStenoseBase::Release() { m_rcDraw.SetRectEmpty (); if (m_pPoints) { delete [] m_pPoints; m_pPoints = NULL; } m_dwPoints = 0; // requis par la routine de mesure } bool CStenoseBase::PointInBuffer(const int& x, const int& y) { Point pt; pt.x = x; pt.y = y; return PointInBuffer(pt); } bool CStenoseBase::PointInBuffer(const Point& pt) { assert( m_image ); int dx = m_image->GetWidth(); int dy = m_image->GetHeight(); return ( pt.x >= 0 && pt.y >= 0 && pt.x < dx && pt.y < dy ); } /* unsigned long CStenoseBase::GetPixel(const int& x, const int& y) { Point pt; pt.x = x; pt.y = y; return GetPixel(pt); } unsigned long CStenoseBase::GetPixel(const Point& pt) { assert( m_image ); //#if defined( WIN32 ) && !defined( IMT_DLL ) // return m_image->GetPixel( pt.x, pt.y ); //#else return *m_image->GetPixel( pt.x, pt.y ); //#endif } */ bool CStenoseBase::IsColor(int x, int y) { unsigned char bRed; unsigned char bGreen; unsigned char bBlue; int iRed; int iGreen; int iBlue; // AffectLeadResult(); bRed = m_image->GetPixelRGB( x, y, 0); bGreen = m_image->GetPixelRGB( x, y, 1); bBlue = m_image->GetPixelRGB( x, y, 2); iRed = (int) bRed; iGreen = (int) bGreen; iBlue = (int) bBlue; // un niveau de gris implique bRed = bGreen = bBlue // étant donné que l'image a été numérisé on autorise un delta de 10 entre chaque couleur // ex : 190 197 185 est gris, 190 201 190 est en couleur return ( (abs (iRed - iGreen) > 30) || (abs (iRed - iBlue ) > 30) || (abs (iGreen - iBlue ) > 30) ); } void CStenoseBase::PutPixEllipse(float xc,float yc,float x,float y) { WritePixel( (int) (xc + x), (int) (yc + y)); WritePixel( (int) (xc - x), (int) (yc - y)); WritePixel( (int) (xc + x), (int) (yc - y)); WritePixel( (int) (xc - x), (int) (yc + y)); } void CStenoseBase::WritePixel(int x, int y) { x = 0; y = 0; } // Algorithme MidPoint de dessin d'une Ellipse void CStenoseBase::myDrawEllipse() { float x = 0, y = 0; double p1, p2, t1, t2; int k; float rx, ry, xc, yc; rx = (float) (m_rcDraw.right - m_rcDraw.left) / 2; ry = (float) (m_rcDraw.bottom - m_rcDraw.top) / 2; xc = m_rcDraw.left + rx; yc = m_rcDraw.top + ry; y = ry; p1 = ry * ry - rx * rx * ry + 0.25 * rx * rx; PutPixEllipse(xc, yc, x, y); for (k = 0; (2 * ry * ry * x) <= (2 * rx * rx * y); k++) { t1 = 2 * ry * ry * x + 2 * ry * ry; t2 = 2 * rx * rx * y - 2 * rx * rx; if (p1 < 0) { p1 = p1 + t1 + ry * ry; } else { p1 = p1 + t1 - t2 + ry * ry; y--; } x++; PutPixEllipse(xc, yc, x, y); } p2 = ry * ry * ( x + 0.5 ) * ( x + 0.5 ) + rx * rx * (y - 1) * (y - 1) - rx * rx * ry * ry; PutPixEllipse(xc, yc, x, y); for (k = 0 ; y >= 0 ; k++) { t1 = 2 * ry * ry * x + 2 * ry * ry; t2 = 2 * rx * rx * y - 2 * rx * rx; if (p2 > 0) { p2 = p2 - t2 + rx * rx; } else { p2 = p2 + t1 - t2 + rx * rx; x++; } y--; PutPixEllipse(xc, yc, x, y); } }