/**********************************************************************\ Fichier : Plaque.cpp Date : 18/04/98 Version : 1.100 Description : classe de calcul & affichage d'une épaisseur de plaque |**********************************************************************| Bugs: Notes: |**********************************************************************| Historique : 18/04/98 1.100 : Optimisation (2x plus rapide) Suppression de l'utilisation d'une region pour la mesure, la figure est trop complexe est beaucoup de points sont oubliés (il suffit de l'afficher dans OnDraw pour s'en rendre compte). Suppression de m_nPointsDedans, qui au vu de l'algo était le nombre de points à l'extérieur de la plaque!! Réunion de tous les types de mesure de plaque (NB, RGB, manuel) dans cette classe 07/02/98 1.000 : Première version \*******************************************************************/ /*------------------------------------------------------------------\ Includes \------------------------------------------------------------------*/ #include #include "PlaqueBase.h" #include "Ressource.h" #include "MeanEstimate.h" #include "CPlaqueResult.h" #include "PlaqueResult.h" #include "ToolsMath.h" #include #include #include #define sqr(a) ((a) * (a)) inline int Distance2D (const Point &pt1, const Point &pt2) { return int (sqrt((double) sqr(pt1.x - pt2.x) + (double) sqr(pt1.y - pt2.y))); } CPlaqueBase::CPlaqueBase() { m_etudie = NULL; RAZ(); m_iTache = 0; m_clrVert = 0 | (255 << 16) | (0 << 8); m_clrBleue = 0 | (0 << 16) | (255 << 8); m_debug1 = 1; m_debug2 = 2; m_debug3 = 3; m_debug4 = 4; m_debug5 = 5; } CPlaqueBase::~CPlaqueBase() { delete[] m_etudie; } void CPlaqueBase::RAZ() { m_Etape = etapeRien; m_nVecteursTrouves = 0; m_nPtLongeantPlaque = 0; m_ptInferieur.x = 0; m_ptInferieur.y = 0; m_pointLimite1.x = 0; m_pointLimite1.y = 0; m_pointLimite2.x = 0; m_pointLimite2.y = 0; m_iMax = 0; m_IntervallesIntensite[0] = 0; m_IntervallesIntensite[1] = 0; m_IntervallesIntensite[2] = 0; // m_ptList.clear(); } /*----------------------------------------------------------\ | Mesurer | |-----------------------------------------------------------| | DESCRIPTION : | | On a saisi les segments. Mesurer l'épaisseur de droites | | perpendiculaires, jusqu'au 1° pt vert | | précédemment coloré par Threshold (). | |-----------------------------------------------------------| | PARAMETRES : | \----------------------------------------------------------*/ const short NORTHOMAX = 1000; const short NMAXERREURS = 3; // Erreurs avant de déclarer le segment fini int CPlaqueBase::Mesurer_3 (int iMax) { short iVector; int retour; m_nSommeLongueurs = 0; m_nMesures = 0; m_nLongueurMax = 0; m_nVecteursTrouves = 0; m_nMesuresTotal = 0; // m_ptList.clear(); // Seuillage par propagation retour = Threshold(iMax); // Mesurer les limites de la plaque for (iVector = 0; iVector < (m_nPtLongeantPlaque-1); iVector++) { retour = Mesurer_3_1Segment(m_tPtLongeantPlaque [iVector], m_tPtLongeantPlaque [iVector+1]); } // Et sa surface, son intensité retour = CalculerSurfaceEtIntensitePlaque (false); return retour; } //***** Mesurer 1 des segments définis / utilisateur int CPlaqueBase::Mesurer_3_1Segment (const Point &pt1, const Point &pt2) { CVector vectSegment(pt1.x, pt1.y, pt2.x, pt2.y); CVector vectOrtho; Point ptAVerifier; long iSegment, iLong; bool fFound; // Du segment à mesurer int nLongueurSegment; int retour; retour = 0; GraphMeanInit(); Point pt( pt1.x, pt1.y ); // Parcourir le segment et, tous les NINTERVALLE, calculer l'épaisseur vectOrtho = vectSegment.Orthogonal (pt, m_nSensTrigo); // 0 = sens inverse trigo // la vérification de l'appartenance du point à la région de traitement ralentit certainement // mais je ne trace apparemment pas les droites de la même manière que Windows et certains // points des droites des extrémités n'appartiennent pas à la région for (iSegment = 0; iSegment < vectSegment.Norm (); iSegment++) { vectOrtho.MoveTo(vectSegment [iSegment]); m_nMesuresTotal ++; // on effectue une mesure seulement lorsque la plaque touche la paroi // autrement dit, le premier point du vecteur orthogonal ne doit pas être vert ptAVerifier.x = vectOrtho[1].x; ptAVerifier.y = vectOrtho[1].y; // seules les extrémités des segments devraient poser des problèmes d'appartenance if ( m_rgnATraiter.PtInRegion(&ptAVerifier) && PointInBufferResult(ptAVerifier) && (GetPixelResult(ptAVerifier.x, ptAVerifier.y) != m_clrVert) // [LAU - 13/1/2006] ) { fFound = false; // on cherche la fin de la plaque (<=> premier point vert rencontré) // on s'arrête dès que le point ne fait plus partie de la région de traitement for (iLong = 2;(!fFound )&& (iLong < NORTHOMAX) && m_rgnATraiter.PtInRegion (&ptAVerifier); iLong++) { ptAVerifier.x = vectOrtho [iLong].x; ptAVerifier.y = vectOrtho [iLong].y; if ( PointInBufferResult(ptAVerifier) && (GetPixelResult(ptAVerifier.x, ptAVerifier.y) == m_clrVert) ) { fFound = true; // On a une longueur nLongueurSegment = iLong - 1; m_nSommeLongueurs += nLongueurSegment; m_nMesures ++; if ((unsigned int) nLongueurSegment > (unsigned int) m_nLongueurMax) m_nLongueurMax = nLongueurSegment; if (nLongueurSegment) GraphMeanAddMeasure(true, nLongueurSegment); m_tbPtsTrouvesFin [m_nVecteursTrouves] = vectOrtho [iLong]; // Ajouter le segment à ceux à afficher /* Point pt; pt.x = vectOrtho[iLong].x; pt.y = vectOrtho[iLong].y; m_ptList.push_back( pt ); */ if ((m_nVecteursTrouves + 1) < NBVECTEURSMAX) { m_nVecteursTrouves++; } } } } } return retour; } /*----------------------------------------------------------\ | CalculerSensVecteurs | |-----------------------------------------------------------| | DESCRIPTION : | | Calcule de quel côté est le pt minimum par rapport aux | | segments définis par l'utilisateur -> m_nSensTrigo | |-----------------------------------------------------------| | PARAMETRES : | \----------------------------------------------------------*/ void CPlaqueBase::CalculerSensVecteurs() { CVector vecteur1erSegment (m_tPtLongeantPlaque [0].x, m_tPtLongeantPlaque [0].y, m_tPtLongeantPlaque [m_nPtLongeantPlaque-1].x, m_tPtLongeantPlaque [m_nPtLongeantPlaque-1].y); if (vecteur1erSegment.m_fHorizontal == true) { // Vecteur horizontal : au dessus ou en dessous ? if (m_tPtLongeantPlaque [0].y < m_ptInferieur.y) { // En dessous if (m_tPtLongeantPlaque [0].x > m_tPtLongeantPlaque [m_nPtLongeantPlaque-1].x) { m_nSensTrigo = 1; } else { m_nSensTrigo = 0; } } else { // Au dessus if (m_tPtLongeantPlaque [0].x > m_tPtLongeantPlaque [m_nPtLongeantPlaque-1].x) { m_nSensTrigo = 0; } else { m_nSensTrigo = 1; } } } else { // Vecteur vertical : à gauche ou à droite ? if (m_tPtLongeantPlaque [0].x < m_ptInferieur.x) { // à droite if (m_tPtLongeantPlaque [0].y > m_tPtLongeantPlaque [m_nPtLongeantPlaque-1].y) { m_nSensTrigo = 0; } else { m_nSensTrigo = 1; } } else { // à gauche if (m_tPtLongeantPlaque[0].y > m_tPtLongeantPlaque[m_nPtLongeantPlaque-1].y) { m_nSensTrigo = 1; } else { m_nSensTrigo = 0; } } } } /*----------------------------------------------------------\ | SetRegion | |-----------------------------------------------------------| | DESCRIPTION : | | Crée une région polygonale, composée des segments | | indiqués par l'utilisateur, de 2 segments sur les côtés, | | orthogonaux aux 1° et dernier segments utilisateur, | | et de taille suffisante pour que le m_ptInferieur | | soit dedans. | |-----------------------------------------------------------| | PARAMETRES : | \----------------------------------------------------------*/ bool CPlaqueBase::SetRegion ( const CVector &vFirst, const CVector &vLast, int iLength ) { CVector vOrtho; Point pt( m_tPtLongeantPlaque[m_nPtLongeantPlaque-1].x, m_tPtLongeantPlaque[m_nPtLongeantPlaque-1].y ); vOrtho = vLast.Orthogonal (pt, m_nSensTrigo); // 0 = sens inverse trigo m_pointLimite1.x = vOrtho[iLength].x; m_pointLimite1.x = vOrtho[iLength].x; m_pointLimite1.y = vOrtho[iLength].y; m_tPtLongeantPlaque[m_nPtLongeantPlaque] = m_pointLimite1; pt = Point( m_tPtLongeantPlaque [0].x, m_tPtLongeantPlaque [0].y ); vOrtho = vFirst.Orthogonal (pt, m_nSensTrigo); // 0 = sens inverse trigo m_pointLimite2.x = vOrtho[iLength].x; m_pointLimite2.y = vOrtho[iLength].y; m_tPtLongeantPlaque[m_nPtLongeantPlaque+1] = m_pointLimite2; // Créer le polygone m_rgnATraiter.DeleteObject (); /* m_debug1 = m_nPtLongeantPlaque; m_debug2 = m_pointLimite1.x; m_debug3 = m_pointLimite1.y; m_debug4 = m_pointLimite2.x; m_debug5 = m_pointLimite2.y; */ return (m_rgnATraiter.CreatePolygonRgn (m_tPtLongeantPlaque, m_nPtLongeantPlaque + 2)); } // fin de SetRegion int CPlaqueBase::ParametrerRegionATraiter () { int retour; retour = 0; assert(m_nPtLongeantPlaque >= 2); // Vecteur entre le 1° et le dernier pt utilisateur CVector vGlobal (m_tPtLongeantPlaque [0].x, m_tPtLongeantPlaque [0].y, m_tPtLongeantPlaque [m_nPtLongeantPlaque - 1].x, m_tPtLongeantPlaque [m_nPtLongeantPlaque - 1].y), // Dernier vecteur tracé (peut être égal à vGlobal) vFirst (m_tPtLongeantPlaque[0].x, m_tPtLongeantPlaque[0].y, m_tPtLongeantPlaque[1].x, m_tPtLongeantPlaque[1].y), // Dernier vecteur tracé (peut être égal à vFirst) vLast (m_tPtLongeantPlaque[m_nPtLongeantPlaque - 2].x, m_tPtLongeantPlaque[m_nPtLongeantPlaque - 2].y, m_tPtLongeantPlaque[m_nPtLongeantPlaque - 1].x, m_tPtLongeantPlaque[m_nPtLongeantPlaque - 1].y); Point ptProjected; int nLongueurPlaque, nDistanceAPtInferieur; bool fResult; CalculerSensVecteurs (); // Longueur de la plaque indiquée par l'utilisateur nLongueurPlaque = int(vGlobal.Norm()); // Limiter la longueur des segments de côté Point pti( m_ptInferieur.x, m_ptInferieur.y ); ptProjected.x = vGlobal.Projected (pti).x; ptProjected.y = vGlobal.Projected (pti).y; nDistanceAPtInferieur = int (CVector (ptProjected.x, ptProjected.y, m_ptInferieur.x,m_ptInferieur.y).Norm () + 5); if (nDistanceAPtInferieur > nLongueurPlaque) nLongueurPlaque = nDistanceAPtInferieur; // pour optimiser, on diminue la taille des droites orthogonales d'encadrement // pour que la tache soit à la limite nLongueurPlaque++; do { nLongueurPlaque--; fResult = SetRegion (vFirst, vLast, nLongueurPlaque); } while ((fResult == true) && m_rgnATraiter.PtInRegion (&m_ptInferieur) && (nLongueurPlaque > 1)); if ((fResult == true) && (nLongueurPlaque > 1)) { nLongueurPlaque++; fResult = SetRegion (vFirst, vLast, nLongueurPlaque); } if (fResult == true) { retour = 40; m_debug1 = nLongueurPlaque; m_debug2 = ptProjected.x; m_debug3 = ptProjected.y; m_debug4 = nDistanceAPtInferieur; m_debug5 = 2222; } if ((fResult == false) || (nLongueurPlaque <= 1)) { retour = 41; m_Etape = etapeSegments; m_nPtLongeantPlaque = 0; } else if (m_rgnATraiter.PtInRegion(&m_ptInferieur) == false) { retour = 42; m_Etape = etapeTacheSeuil; // Recommencer cette étape } return retour; } /*----------------------------------------------------------\ | TraiterPoint | |-----------------------------------------------------------| | DESCRIPTION : | | Propagation à partir du pt minimal : colorer en vert les | | points sous le seuil indiqué | | | | modifié pour limiter la profondeur de récursion | |-----------------------------------------------------------| | PARAMETRES : | \----------------------------------------------------------*/ int CPlaqueBase::TraiterPoint (int x, int y) { unsigned char bCheck[9]; int i, xx, yy, xMin, yMin, xMax, yMax; int retour; bool bool0; bool bool1; bool bc0; retour = 0; m_debug1++; // m_wimg.SaveImgAsRaw(); // if (m_debug1 == 40700) if (((m_debug1 % 2500) == 0) && (m_debug1 != 0)) { m_debug1 = m_debug1; } assert(PointInBufferResult(x, y) && (m_type != typeUndefined)); SetPixelResult(x, y); xMin = max(0, x - 1); xMax = min(x + 1, GetWidth() - 1); yMin = max(0, y - 1); yMax = min(y + 1, GetHeight() - 1); i = 0; for (xx = xMin; xx <= xMax; xx++) { for (yy = yMin; yy <= yMax; yy++) { assert (PointInBufferResult(xx, yy)); /* bCheck [i] = ((xx != x) || (yy != y)) && ((m_type == typeRGB) ? IsColor (xx, yy) : (GetIntensityResult(xx, yy) <= m_iMax) ) && (GetPixelResult(xx, yy) != m_clrVert) // [LAU - 13/1/2006] && m_rgnATraiter.PtInRegion0(xx, yy); */ bool0 = ((xx != x) || (yy != y)); if ((bool0) && (m_type == typeRGB)) { bc0 = IsColor (xx, yy); } else { bc0 = (GetIntensityResult(xx, yy) <= m_iMax); } bool1 = (bool0) && (bc0) && (GetPixelResult(xx, yy) != m_clrVert) && m_rgnATraiter.PtInRegion0(xx, yy); bCheck [i] = bool1 ? 1:0; i++; } } i = 0; for (xx = xMin; xx <= xMax; xx++) { for (yy = yMin; yy <= yMax; yy++) { if ((int) bCheck [i++] > 0) { TraiterPoint(xx, yy); } } } return retour; } int CPlaqueBase::Threshold( int iMax ) { int retour; // AffectLeadResult(); // Décompte de la répartition des points m_iMax = iMax; if (!SuiviContour()) { m_debug1 = 0; retour = TraiterPoint(m_ptInferieur.x, m_ptInferieur.y); } // Fermeture et effacement des petites régions. DoClosing(); DoBlobColoring(); return retour; } // fin de Threshold /*----------------------------------------------------------\ | Surface de la plaque | |-----------------------------------------------------------| | DESCRIPTION : | | Crée une région polygonale, composée des segments | | indiqués par l'utilisateur, des extrémités trouvées. | |-----------------------------------------------------------| | PARAMETRES : | \----------------------------------------------------------*/ int CPlaqueBase::CalculerSurfaceEtIntensitePlaque (bool bManuelle) { int nIntensite; Rect rectEnglobant; Point pt; int retour; retour = 0; if (bManuelle) { m_nSensTrigo = 0; assert (m_nVecteursTrouves == 0); // Pour être sûr } // Suppression de l'utilisation d'une region pour la mesure: // la figure est trop complexe et beaucoup de points sont oubliés // (il suffit de l'afficher dans OnDraw pour s'en rendre compte). // seule la région de traitement se monte fiable (peu de points, points éloignés) rectEnglobant = m_rgnATraiter.GetRgnBox(); m_nPointsDansPlaque = 0; m_iSommeIntensitesPlaque = 0; memset (m_IntervallesIntensite, 0, sizeof (m_IntervallesIntensite)); GraphMeanInit(); // Calculer la surface & l'intensité & l'Histogramme. for (pt.y = rectEnglobant.top; pt.y < rectEnglobant.bottom; pt.y++) { for (pt.x = rectEnglobant.left; pt.x < rectEnglobant.right; pt.x++) { if ((GetPixelResult(pt.x, pt.y) != m_clrVert) && (m_rgnATraiter.PtInRegion(&pt))) { nIntensite = GetIntensityResult(pt); // - m_iTache; m_nPointsDansPlaque++; GraphMeanAddMeasure(true, nIntensite); m_iSommeIntensitesPlaque += nIntensite; if (nIntensite < 120) m_IntervallesIntensite [0]++; else if (nIntensite < 200) m_IntervallesIntensite [1]++; else m_IntervallesIntensite [2]++; } } } if (m_iSommeIntensitesPlaque < 0) { retour = 50; } if (bManuelle) { int i1, i2; int nPt1 = -1, nPt2 = -1; int nDistance = 0, nDistanceMax = 0; int iSegment, iOrtho1, iOrtho2; // Calculer la longueur de la plaque (les 2 pts les + éloignés) for (i1 = 0; i1 < m_nPtLongeantPlaque - 1; i1++) for (i2 = i1 + 1; i2 < m_nPtLongeantPlaque; i2++) if ((nDistance = Distance2D (m_tPtLongeantPlaque [i1], m_tPtLongeantPlaque [i2])) > nDistanceMax) { nDistanceMax = nDistance; nPt1 = i1; nPt2 = i2; } if (!bManuelle) GraphMeanInit(); m_nLongueurMax = 0; m_nSommeLongueurs = 0; m_nMesures = 0; // Calculer la largeur if (nDistanceMax) { // Vecteur le long de la plaque CVector vectLong (m_tPtLongeantPlaque [nPt1].x,m_tPtLongeantPlaque [nPt1].y, m_tPtLongeantPlaque [nPt2].x, m_tPtLongeantPlaque [nPt2].y); CVector vectOrtho; // Pour essai if (m_rgnATraiter.PtInRegion0(vectLong [5].x, vectLong [5].y) ) { retour = 52; } if (m_rgnATraiter.PtInRegion0(vectLong [0].x, vectLong [0].y)) { retour = 52; } for (iSegment = 0; iSegment < vectLong.Norm () - 1; iSegment ++) { vectOrtho = vectLong.Orthogonal (vectLong [iSegment], 0); for ( iOrtho1 = 0; iOrtho1 < vectLong.Norm () && (m_rgnATraiter.PtInRegion0(vectOrtho [iOrtho1].x,vectOrtho [iOrtho1].y)); iOrtho1 ++); for ( iOrtho2 = 0; iOrtho2 > -vectLong.Norm () && (m_rgnATraiter.PtInRegion0(vectOrtho [iOrtho2].x,vectOrtho [iOrtho2].y)); iOrtho2 --); if (iOrtho1 - iOrtho2 > ((long) m_nLongueurMax)) m_nLongueurMax = iOrtho1 - iOrtho2; m_nSommeLongueurs += iOrtho1 - iOrtho2; if (!bManuelle) { if (iOrtho1 - iOrtho2) GraphMeanAddMeasure(true, iOrtho1 - iOrtho2); } m_nMesures++; } } } return retour; } int CPlaqueBase::calculPlaque2(QImage *h_image, int nbPts, unsigned char *points) { unsigned char *dadd; unsigned char a, b, c, d; Point point; int npt; int retour; m_result = h_image; if ( !m_etudie ) { m_etudie = new unsigned long[ GetWidth() * GetHeight() ]; } m_wimg.Del(); m_wimg.Create(TYPE_UCHAR, GetWidth(), GetHeight()); m_wimg.Fill(0); m_type = typeManual; retour = 0; npt = 0; dadd = points; do { a = *dadd; dadd++; b = *dadd; dadd++; c = *dadd; dadd++; d = *dadd; dadd++; point.x = d; point.x = point.x | (c << 8); point.x = point.x | (b << 16); point.x = point.x | (a << 24); a = *dadd; dadd++; b = *dadd; dadd++; c = *dadd; dadd++; d = *dadd; dadd++; point.y = d; point.y = point.y | (c << 8); point.y = point.y | (b << 16); point.y = point.y | (a << 24); // if (m_nPtLongeantPlaque < NBPTSLONGEANTMAX) { m_tPtLongeantPlaque [m_nPtLongeantPlaque] = point; m_nPtLongeantPlaque++; } npt++; } while (npt < nbPts); m_tPtLongeantPlaque [m_nPtLongeantPlaque] = m_tPtLongeantPlaque [0]; m_nPtLongeantPlaque++; retour = CalculerPlaqueManuelle(); return retour; } /*----------------------------------------------------------\ | Surface de la plaque | |-----------------------------------------------------------| | DESCRIPTION : | | Crée une région polygonale, composée des segments | | indiqués par l'utilisateur, des extrémités trouvées. | |-----------------------------------------------------------| | PARAMETRES : | \----------------------------------------------------------*/ int CPlaqueBase::CalculerPlaqueManuelle () { int retour; // AffectLeadResult(); // Créer le polygone m_rgnATraiter.DeleteObject(); if (!m_rgnATraiter.CreatePolygonRgn(m_tPtLongeantPlaque, m_nPtLongeantPlaque)) { retour = 31; return retour; } retour = CalculerSurfaceEtIntensitePlaque(true); return retour; } bool CPlaqueBase::IsBorder(int x, int y) { if (!((m_type == typeRGB) ? !IsColor(x, y) : (GetIntensityResult(x, y) > m_iMax))) { // On considère qu'il faut être dans la plaque! return false; } // L'aspect static de ces 7 variables est purement dans un but d'économie de mémoire... static int Xmin, Xmax, xx, Ymin, Ymax, yy, NbPoints; Xmin = max(0, x-1); Xmax = min(x+1, GetWidth() - 1); Ymin = max(0, y-1); Ymax = min(y+1, GetHeight() - 1); // On compte le nombre de points en-plaque autour du point étudié NbPoints = 0; for(xx = Xmin; xx <= Xmax; xx++) { for(yy = Ymin; yy <= Ymax; yy++) { if (((xx != x) || (yy != y)) && ((m_type == typeRGB) ? !IsColor(xx, yy) : (GetIntensityResult(xx, yy) > m_iMax))) { NbPoints++; } } } // Ce point est considéré comme faisant partie de la frontière s'il possède // plus de 3 points en-plaque autour de lui, et s'il n'est pas au milieu de // la plaque (id est tout point autour de lui en-plaque!) if ((NbPoints < 3) || (NbPoints == (Xmax-Xmin+1)*(Ymax-Ymin+1)-1)) { return false; } return true; } bool CPlaqueBase::SuiviContourLocal(int x, int y, double Xd, double Yd, bool Initialise) { static CVector VectBordFin; static int Width; static bool* TabPtParcourus = NULL; // (TabPtParcourus[x+Width*y] == true) s'il le point (x,y) à été parcourus if (Initialise) { Width = GetWidth(); delete [] TabPtParcourus; TabPtParcourus = new bool[Width * GetHeight()]; memset(TabPtParcourus, 0, Width * GetHeight()); VectBordFin = CVector(m_tPtLongeantPlaque[m_nPtLongeantPlaque-1].x,m_tPtLongeantPlaque[m_nPtLongeantPlaque-1].y, m_pointLimite1.x,m_pointLimite1.y); return true; } static int xx, yy; // L'aspect static est purement dans un but d'économie de mémoire... // On marque ce point comme parcourus TabPtParcourus[x+y*Width] = true; // On conserve l'ancienne valeur de la couleur pour pouvoir la restaurer unsigned long OldPixelColor = GetPixelEtudie(x, y); // On dessine en bleu le point étudié (appartenant à priori au contour) SetPixelEtudie(x, y, m_clrBleue); // On a fini avec succes la mesure si le point étudié touche le 2nd bord jaune! Point pt = VectBordFin.Projected(Point(x,y)); if (Distance2D(Point(pt.x,pt.y) , Point(x,y)) < 2) return true; int Xbest, Ybest; Xbest = 0; Ybest = 0; // L'aspect static de ces 6 variables est purement dans un but d'économie de mémoire... static double Vbest; static bool Valide; static int M; static double XdNew; static double YdNew; static double PScal; int dimension = 1; Valide = false; Vbest = 1; while (!Valide) { Vbest = 0.25 * (4 - dimension); // On cherche les coordonnées du point ou la "pertinence" est la plus elevé for(xx = -dimension; xx <= dimension; xx++) { for(yy = -dimension; yy <= dimension; yy++) { // On regarde la pertinence de ce point environnant... if ((xx) || (yy)) { // PScal = (Xd *xx + Yd *yy)/sqrt(xx*xx+yy*yy); PScal = (Xd *xx + Yd *yy) / sqrt((double) xx * xx + (double) yy * yy); // MAJ2005 if ((PScal > Vbest) && (m_rgnATraiter.PtInRegion0(x+xx, y+yy)) && (!TabPtParcourus[(x+xx)+(y+yy)*Width]) && (IsBorder(x+xx, y+yy))) { Vbest = PScal; Xbest = xx; Ybest = yy; } } } } if (Vbest != 0.25*(4 - dimension)) { M = max(abs(Xbest), abs(Ybest)); XdNew = Xbest * M + Xd * 3 * dimension; YdNew = Ybest * M + Yd * 3 * dimension; PScal = sqrt(XdNew * XdNew + YdNew * YdNew); if (SuiviContourLocal(x + Xbest / M, y + Ybest / M, XdNew / PScal, YdNew / PScal)) { Valide = true; break; } else { Valide = false; // On restaure cette variable static au cas où... TabPtParcourus[(x + Xbest) + (y + Ybest) * Width] = true; } } else { // On agrandi la fenetre de recherche... if (dimension < 4) dimension++; else break; } } if (!Valide) { // On remet la couleur initial du point SetPixelEtudie(x, y, OldPixelColor); return false; } return true; } bool CPlaqueBase::SuiviContour() { // On cherche le début de la plaque le long du 1er bord jaune CVector vectSegment(m_pointLimite2.x, m_pointLimite2.y, m_tPtLongeantPlaque[0].x, m_tPtLongeantPlaque[0].y); int i = 0; // On prend le premier point entrant dans la plaque! while(!((m_type == typeRGB) ? !IsColor(vectSegment[i].x, vectSegment[i].y) : (GetIntensityResult(vectSegment[i].x, vectSegment[i].y) > m_iMax))) { i++; if (!PointInBufferResult(vectSegment[i].x, vectSegment[i].y)) return false; } double Xd, Yd, d; // Direction initiale de recherche de contour... Xd = m_tPtLongeantPlaque[1].x - m_tPtLongeantPlaque[0].x; Yd = m_tPtLongeantPlaque[1].y - m_tPtLongeantPlaque[0].y; d = sqrt(Xd * Xd + Yd * Yd); Xd = Xd/d; Yd = Yd/d; int Compteur = 0; bool MesureValide = false; while ((!MesureValide) && (Compteur++ < 5)) // On fait 5 essais maximum... { CopyResultDansEtudie(); // On espère avoir une frontière de la plaque valide en ce point... SuiviContourLocal(0, 0, 0, 0, true); // Initialisation de la fonction! MesureValide = SuiviContourLocal(vectSegment[i].x, vectSegment[i].y, Xd, Yd); if (!MesureValide) { // La première mesure n'est pas valide... // On cherche le premier point sortant de la plaque précedemment détectée! while ((m_type == typeRGB) ? !IsColor(vectSegment[i].x, vectSegment[i].y) : (GetIntensityResult(vectSegment[i].x, vectSegment[i].y) > m_iMax)) { i++; if (!PointInBufferResult(vectSegment[i].x, vectSegment[i].y)) return false; } // On cherche le premier point entrant dans la plaque! while(!((m_type == typeRGB) ? !IsColor(vectSegment[i].x, vectSegment[i].y) : (GetIntensityResult(vectSegment[i].x, vectSegment[i].y) > m_iMax))) { i++; if (!PointInBufferResult(vectSegment[i].x, vectSegment[i].y)) return false; } } } if (!MesureValide) return false; #ifdef _DEBUG // On affiche le résultat de l'algo de repérage du contour plaque. // m_pLeadResult->Copy(m_LeadEtudie); #endif // _DEBUG // Remplissage de la partie hors-plaque en vert SuiviContourRemplis(m_ptInferieur.x, m_ptInferieur.y); return true; } void CPlaqueBase::SuiviContourRemplis(int x, int y) { assert(PointInBufferResult(x, y) && (m_type != typeUndefined)); assert(GetPixelEtudie(x, y) != m_clrBleue); assert(GetPixelResult(x, y) != m_clrVert); int xx, Xmin, Xmax, yy, Ymin, Ymax; // On dessine en vert le point hors-plaque étudié SetPixelResult(x, y); Xmin = max(0, x-2); Xmax = min(x+2, GetWidth() - 1); Ymin = max(0, y-2); Ymax = min(y+2, GetHeight() - 1); // On compte le nombre de points frontière autour du point étudié double NbPoints = 0; for(xx = Xmin; xx <= Xmax; xx++) { for(yy = Ymin; yy <= Ymax; yy++) { if (((xx != x) || (yy != y)) && (GetPixelEtudie(xx, yy) == m_clrBleue)) { NbPoints++; } } } // Ce point est à la fin de l'arbre de parcours si il possède 2 points ou plus // appartenant à la frontières à coté de lui if (NbPoints > 0) return; Xmin = max(0, x-1); Xmax = min(x+1, GetWidth() - 1); Ymin = max(0, y-1); Ymax = min(y+1, GetHeight() - 1); for (xx = Xmin; xx <= Xmax; xx++) { for (yy = Ymin; yy <= Ymax; yy++) { if (((xx != x) || (yy != y)) && (m_rgnATraiter.PtInRegion0(xx, yy)) && (GetPixelEtudie(xx, yy) != m_clrBleue) && (GetPixelResult(xx, yy) != m_clrVert)) { // Le point (xx, yy) est donc hors-plaque et non traité SuiviContourRemplis(xx, yy); } } } } // [LAU - 2/5/2006] Calcule la somme des longeurs entre les points enregistrés longeant la plaque double CPlaqueBase::Get_SommeLongueurs() { double dist = 0; if (m_Etape == etapeRien) { return (int)dist; } for (int i = 0; i < m_nPtLongeantPlaque-1; i++) { dist += CVector (m_tPtLongeantPlaque[i].x, m_tPtLongeantPlaque[i].y, m_tPtLongeantPlaque[i+1].x, m_tPtLongeantPlaque[i+1].y).Norm (g_pCurrentScale); } return (int) dist; } // Algorithme de coloriage de blobs sur l'image d'entrée // Objectif : enlever les petites régions dans l'image seuillée bool CPlaqueBase::DoBlobColoring() { int x, y, i, indblob, nblob, realblob, ng; long taille; img lwimg, lwimg1; int wdimh, wdimv; blob m_tblob[MAXBLOB]; Rect rectEnglobant; rectEnglobant = m_rgnATraiter.GetRgnBox(); wdimh = GetWidth(); wdimv = GetHeight(); lwimg.Create(TYPE_UCHAR, wdimh, wdimv); lwimg1.Create(TYPE_INT, wdimh, wdimv); // On prend des ints lwimg.Fill(0); indblob = 0; nblob = 0; // Générer l'image binaire qui va aller à l'algo. du blob coloring // lwimg for (x = rectEnglobant.left; x < rectEnglobant.right; x++) { for (y = rectEnglobant.top; y < rectEnglobant.bottom; y++) { bool fGreen; fGreen = (GetPixelResult(x, y) == m_clrVert); if (!fGreen) { lwimg.SetValue(x, y, 1); } } } // Résultat : les blobs sont dans wimg1 nblob = lwimg.BlobColoring(m_tblob, &lwimg1); // Elimination des petits blobs. realblob = nblob; for (i = 1; i <= nblob; i++) { taille = lwimg1.GetBlobSize(i); if ((taille < (wdimh * wdimv) - 1) && (taille <= 50)) { lwimg1.RemplaceCouleur(i, MAXBLOB+1); // Sur int } } // Dans lwimg1, les pixels à la valeur MAXBLOB+1, sont ceux des régions à supprimer // Mise à jour de lwimg, puis transfert dans l'image d'origine for (x = rectEnglobant.left; x < rectEnglobant.right; x++) { for (y = rectEnglobant.top; y < rectEnglobant.bottom; y++) { ng = lwimg1.GetValue(x, y); if (ng == (MAXBLOB + 1)) { SetPixelResult(x, y); } } } if (lwimg.init == 1) lwimg.Del(); if (lwimg1.init == 1) lwimg1.Del(); return true; } // Algorithme de fermeture bool CPlaqueBase::DoClosing() { int x, y, ng; img lwimg, lwimg1; int wdimh, wdimv; Rect rectEnglobant; rectEnglobant = m_rgnATraiter.GetRgnBox(); wdimh = GetWidth(); wdimv = GetHeight(); lwimg.Create(TYPE_USHORT, wdimh, wdimv); lwimg1.Create(TYPE_USHORT, wdimh, wdimv); // On prend des ints lwimg.Fill(0); // Générer l'image binaire qui va aller à l'algo. du blob coloring // lwimg for (x = rectEnglobant.left; x < rectEnglobant.right; x++) { for (y = rectEnglobant.top; y < rectEnglobant.bottom; y++) { if (GetPixelResult(x, y) == m_clrVert) { lwimg.SetValue(x, y, 1); } } } lwimg.BinaryClosing(&lwimg1); // Dans lwimg1, les pixels à la valeur MAXBLOB+1, sont ceux des régions à supprimer // Mise à jour de lwimg, puis transfert dans l'image d'origine for (x = rectEnglobant.left; x < rectEnglobant.right; x++) { for (y = rectEnglobant.top; y < rectEnglobant.bottom; y++) { ng = lwimg1.GetValue(x, y); if (ng == 1) { SetPixelResult(x, y); } } } if (lwimg.init == 1) lwimg.Del(); if (lwimg1.init == 1) lwimg1.Del(); return true; } bool CPlaqueBase::PointInBufferResult(const int& x, const int& y) { Point pt(x, y); // pt.x = x; // pt.y = y; return PointInBufferResult(pt); } bool CPlaqueBase::PointInBufferResult(const Point& pt) { assert( m_result ); int dx = GetWidth(); int dy = GetHeight(); return ( (pt.x >= 0) && (pt.y >= 0) && (pt.x < dx) && (pt.y < dy) ); } bool CPlaqueBase::IsColor(int x, int y) { unsigned char bRed; unsigned char bGreen; unsigned char bBlue; int iRed; int iGreen; int iBlue; // AffectLeadResult(); QRgb rgb = m_result->pixel( x, y ); bRed = qRed(rgb); bGreen = qGreen(rgb); bBlue = qBlue(rgb); 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) ); } int CPlaqueBase::GetIntensityResult(const int& x, const int& y) { Point pt; pt.x = x; pt.y = y; return GetIntensityResult(pt); } int CPlaqueBase::GetIntensityResult(const Point& pt) { assert( m_result ); return qGray(m_result->pixel( pt.x, pt.y )); /* value = (char) m_result->GetPixel( pt.x, pt.y ); col = (unsigned char)(value & 0xff); return col; */ /* #if defined( WIN32 ) && !defined( IMT_DLL ) && !defined( PLAQUE_DLL ) return GetRValue( m_result->GetPixel( pt.x, pt.y ) ); #else return *m_result->GetPixel( pt.x, pt.y ); #endif */ } unsigned int CPlaqueBase::GetErrorID(void) { return m_uErrorID; } /*int CPlaqueBase::TestFantome(QImage *h_image, CPlaqueResult *) { int i, x, y, nbPts; unsigned char *points, *dadd; int *input; Point pts[12]; int retour; m_result = h_image; // m_result.Create(768, 576, 24); // m_result.CopyFrom2(h_image); //CopieResultSvg(); nbPts = 6; retour = 0; points = (unsigned char *) malloc( nbPts * sizeof(unsigned char *) ); input = (int *) malloc( 4 * sizeof(int) ); x = 372; y = 177; pts[0].x = 267; pts[0].y = 218; pts[1].x = 300; pts[1].y = 227; pts[2].x = 364; pts[2].y = 232; pts[3].x = 446; pts[3].y = 238; pts[4].x = 509; pts[4].y = 238; pts[5].x = 561; pts[5].y = 234; dadd = points; for (i = 0; i < nbPts; i++) { input[0] = ((pts[i].x & 0xFF000000) >> 24); input[1] = ((pts[i].x & 0x00FF0000) >> 16); input[2] = ((pts[i].x & 0x0000FF00) >> 8); input[3] = ((pts[i].x & 0x000000FF)); *dadd = input[0]; dadd++; *dadd = input[1]; dadd++; *dadd = input[2]; dadd++; *dadd = input[3]; dadd++; input[0] = ((pts[i].y & 0xFF000000) >> 24); input[1] = ((pts[i].y & 0x00FF0000) >> 16); input[2] = ((pts[i].y & 0x0000FF00) >> 8); input[3] = ((pts[i].y & 0x000000FF)); *dadd = input[0]; dadd++; *dadd = input[1]; dadd++; *dadd = input[2]; dadd++; *dadd = input[3]; dadd++; } retour = calculPlaque(h_image, x, y, nbPts, points); //, 60, 120 // m_res->allocate_vectors(m_nPtLongeantPlaque); return retour; }*/ int CPlaqueBase::calculPlaque(QImage *h_image, int x, int y, int nbPts, const QList& pts/*, int seuil1, int seuil2*/) { Point point; int npt; int retour; //unsigned char *dadd; retour = 0; unsigned char a, b, c, d; m_result = h_image; // m_result.Create(768, 576, 24 ); // m_result.CopyFrom2(h_image); m_Etape = etapeRien; // C'est le premier octet qui est pris : le rouge. m_debug1 = (int) GetIntensityResult(100, 125); m_debug2 = (int) GetIntensityResult(200, 170); m_debug3 = (int) GetIntensityResult(300, 460); m_debug4 = (int) m_result->width(); m_debug5 = (int) 1; //retour = 1999; // return retour; // Création de m_etudie if ( m_Etape == etapeRien ) { if ( !m_etudie ) { m_etudie = new unsigned long[ GetWidth() * GetHeight() ]; } /* if ( m_etudie ) { m_etudie->Create( GetWidth(), GetHeight(), 24 ); } */ // 1er Point m_Etape = etapeSegments; m_wimg.Del(); m_wimg.Create(TYPE_UCHAR, GetWidth(), GetHeight()); m_wimg.Fill(0); } retour = 0; //dadd = points; if (m_Etape == etapeSegments) { npt = 0; do { /*a = *dadd; dadd++; b = *dadd; dadd++; c = *dadd; dadd++; d = *dadd; dadd++; point.x = d; point.x = point.x | (c << 8); point.x = point.x | (b << 16); point.x = point.x | (a << 24); a = *dadd; dadd++; b = *dadd; dadd++; c = *dadd; dadd++; d = *dadd; dadd++; point.y = d; point.y = point.y | (c << 8); point.y = point.y | (b << 16); point.y = point.y | (a << 24);*/ point = pts[npt]; if (m_nPtLongeantPlaque < NBPTSLONGEANTMAX) { if ( m_nPtLongeantPlaque && ( (CVector (point.x, point.y, m_tPtLongeantPlaque [m_nPtLongeantPlaque-1].x,m_tPtLongeantPlaque [m_nPtLongeantPlaque-1].y).Norm () <= 5) || ((m_type == typeManual) && (CVector (point.x, point.y, m_tPtLongeantPlaque [0].x, m_tPtLongeantPlaque [0].y).Norm () <= 5)) ) ) { // si la distance entre deux points est inférieure à 5 pixels, on considère que // c'est la fin de la paroi if (m_type == typeManual) { m_tPtLongeantPlaque [m_nPtLongeantPlaque] = m_tPtLongeantPlaque [0]; m_nPtLongeantPlaque++; retour = CalculerPlaqueManuelle(); break; } m_Etape = etapeTacheSeuil; } else { m_tPtLongeantPlaque [m_nPtLongeantPlaque] = point; m_nPtLongeantPlaque++; } } npt++; } while (npt < nbPts); m_Etape = etapeTacheSeuil; // Ajouter voir interface } if (m_Etape == etapeTacheSeuil) { // Pt indiquant la limite inférieure m_ptInferieur.x = x; m_ptInferieur.y = y; // Calculer la région dans laquelle on coloriera retour = ParametrerRegionATraiter (); if (retour == 40) { retour = 20; if ( TestCouleur() ) { m_type = typeRGB; } else { m_type = typeBW; retour = 23; } // Afficher le bitmap LeadResult seulement si la région est OK // est PAS en Release, afin de dissimuler, un peu, la méthode de détection m_Etape = etapeReglage; // s'il y a une phase de réglage (il n'y en a pas pour la plaque couleur) if (m_type == typeRGB) { m_debug1 = 100; retour = Mesurer_3(0); // mesure immédiate // retour = m_nVecteursTrouves; } else { m_debug1 = 200; m_iTache = GetIntensityTache (m_ptInferieur, 7); // Calculer le seuil inferieur Mesurer_3(m_iTache + 10); } // AnalysePlaque(seuil1, seuil2); } } return retour; } int CPlaqueBase::OnLButtonUp(QImage *h_image, int x, int y) { m_result = h_image; // m_result.Create(768, 576, 24 ); // m_result.CopyFrom2(h_image); // Création de m_etudie if (m_Etape == etapeRien) { if ( !m_etudie ) { m_etudie = new unsigned long[ GetWidth() * GetHeight() ]; } /* m_etudie = new ExtendedImage; if ( m_etudie ) { m_etudie->Create( GetWidth(), GetHeight(), 24 ); } */ } return OnLButtonUp(x, y); } int CPlaqueBase::OnLButtonUp(int x, int y) { Point point; point.x = x; point.y = y; return OnLButtonUp(point); } int CPlaqueBase::OnLButtonUp(Point& point) { int retour; int x, y; x = point.x; y = point.y; retour = 0; if (m_Etape == etapeRien) { // 1er Point m_Etape = etapeSegments; m_wimg.Del(); m_wimg.Create(TYPE_UCHAR, GetWidth(), GetHeight()); m_wimg.Fill(0); } if (m_Etape == etapeSegments) { retour = 9; if (m_nPtLongeantPlaque < NBPTSLONGEANTMAX) { if ( m_nPtLongeantPlaque && ( (CVector (point.x, point.y, m_tPtLongeantPlaque [m_nPtLongeantPlaque-1].x,m_tPtLongeantPlaque [m_nPtLongeantPlaque-1].y).Norm () <= 5) || ((m_type == typeManual) && (CVector (point.x, point.y, m_tPtLongeantPlaque [0].x, m_tPtLongeantPlaque [0].y).Norm () <= 5)) ) ) { // si la distance entre deux points est inférieure à 5 pixels, on considère que // c'est la fin de la paroi if (m_type == typeManual) { m_tPtLongeantPlaque [m_nPtLongeantPlaque] = m_tPtLongeantPlaque [0]; m_nPtLongeantPlaque++; retour = CalculerPlaqueManuelle(); // return (retour); } m_Etape = etapeTacheSeuil; // retour = 10; // return (retour); } retour = 11; m_tPtLongeantPlaque [m_nPtLongeantPlaque] = point; m_nPtLongeantPlaque++; } } else if (m_Etape == etapeTacheSeuil) { // Pt indiquant la limite inférieure m_ptInferieur = point; // Calculer la région dans laquelle on coloriera retour = ParametrerRegionATraiter (); if (retour == 40) { retour = 20; if ( TestCouleur() ) { m_type = typeRGB; } else { m_type = typeBW; retour = 23; } //? cursor.Clip (m_pView, NULL); // Cesser le clipping // Afficher le bitmap LeadResult seulement si la région est OK // est PAS en Release, afin de dissimuler, un peu, la méthode de détection m_Etape = etapeReglage; // s'il y a une phase de réglage (il n'y en a pas pour la plaque couleur) if (m_type == typeRGB) { Mesurer_3(0); // mesure immédiate retour = 22; } else { m_iTache = GetIntensityTache (m_ptInferieur, 7); // Calculer le seuil inferieur Mesurer_3(m_iTache + 10); retour = 21; } } } else if (m_Etape == etapeReglage) { retour = 30; } return retour; // Tous les clics ne sont pas faits } unsigned char CPlaqueBase::GetIntensityTache(Point& ptCentre, int nRayonTache) { int nIntensiteTache = 0; // Quelle est l'intensité monochrome de la tache autour de ce pt ? for (int iX = min (GetWidth()-1, max (0, ptCentre.x - nRayonTache)); iX <= min (GetWidth()-1, ptCentre.x + nRayonTache); iX++) { for (int iY = min (GetHeight()-1, max (0, ptCentre.y - nRayonTache)); iY <= min (GetHeight()-1, ptCentre.y + nRayonTache); iY++) { nIntensiteTache += GetIntensityResult(iX, iY); } } return (nIntensiteTache / ((nRayonTache * 2 + 1) * (nRayonTache * 2 + 1))); } double CPlaqueBase::Mean() { return (m_nMesures ? g_pCurrentScale->DistanceX (double (m_nSommeLongueurs) / m_nMesures) : 0.); } double CPlaqueBase::Max() { return (g_pCurrentScale->DistanceX ((long)m_nLongueurMax)); } unsigned char CPlaqueBase::Density() { int res; if (m_nPointsDansPlaque != 0) { res = max(m_iSommeIntensitesPlaque, 0) / m_nPointsDansPlaque; } else { res = 0; } return ((unsigned char) res); } // Surface != DistanceX (m_nPointsDansPlaque) !! double CPlaqueBase::Surface() { double dblSide = sqrt ((double) m_nPointsDansPlaque); return (g_pCurrentScale->Surface (dblSide, dblSide)); } bool CPlaqueBase::TestCouleur() { bool isCouleur = false; Rect rc; int x, y; rc = m_rgnATraiter.GetRgnBox(); m_debug2 = rc.left; m_debug3 = rc.left; m_debug4 = rc.top; m_debug5 = rc.bottom; for (x = rc.left; ((x < rc.right) && (isCouleur == false)); x++) { for (y = rc.top; ((y < rc.bottom) && (isCouleur == false)); y++) { if ( m_rgnATraiter.PtInRegion0( x, y ) ) { isCouleur = IsColor(x, y); if (isCouleur == true) { x = x; y = y; isCouleur = IsColor(x, y); } } } } return isCouleur; } unsigned long CPlaqueBase::GetPixelResult(const int& x, const int& y) { Point pt; pt.x = x; pt.y = y; return GetPixelResult(pt); } unsigned long CPlaqueBase::GetPixelResult(const Point& pt) { unsigned long color; color = 0; if (m_wimg.GetValue(pt.x, pt.y) == 1) { color = m_clrVert; } // m_wimg.SaveImgAsRaw(); return color; /* assert( m_result ); #if defined( WIN32 ) && !defined( PLAQUE_DLL ) return m_result->GetPixel( pt.x, pt.y ); #else return *m_result->GetPixel( pt.x, pt.y ); #endif */ } unsigned long CPlaqueBase::GetPixelEtudie(const int& x, const int& y) { Point pt; pt.x = x; pt.y = y; return GetPixelEtudie(pt); } unsigned long CPlaqueBase::GetPixelEtudie(const Point& pt) { assert( m_etudie ); //#if defined( WIN32 ) && !defined( IMT_DLL ) && !defined( PLAQUE_DLL ) // return m_etudie->GetPixel( pt.x, pt.y ); //#else //return *m_etudie->GetPixel( pt.x, pt.y ); return m_etudie[ pt.x + GetWidth() * pt.y ]; //#endif } void CPlaqueBase::SetPixelResult(int x, int y) { m_wimg.SetValue(x, y, 1); // m_wimg.SaveImgAsRaw(); } void CPlaqueBase::SetPixelEtudie(Point& pt, unsigned long vColor) { int x, y; x = pt.x; y = pt.y; // m_etudie->SetPixel(vColor, x, y); m_etudie[ x + GetWidth() * y ] = vColor; } void CPlaqueBase::SetPixelEtudie(int x, int y, unsigned long vColor) { // m_etudie->SetPixel(vColor, x, y); m_etudie[ x + GetWidth() * y ] = vColor; } int CPlaqueBase::GetWidth() { return m_result->width(); } int CPlaqueBase::GetHeight() { return m_result->height(); } // Copie de m_result dans m_etudie void CPlaqueBase::CopyResultDansEtudie() { // m_etudie->Copy2(GetWidth(), GetHeight(), m_result); if ( !m_etudie ) { m_etudie = new unsigned long[ GetWidth() * GetHeight() ]; } int w, h; int width = GetWidth(); int height = GetHeight(); unsigned long* ptr = m_etudie; for ( h = 0; h < height; h++ ) { for ( w = 0; w < width; w++ ) { *ptr++ = GetPixelResult( w, h ); } } } /*void CPlaqueBase::CopieResultSvg() { int width = m_result->GetWidth(); int height = m_result->GetHeight(); m_result2.Create(width, height, 24 ); m_result2.CopyFrom2(m_result); // m_result.SaveImgAsRaw(); }*/ /*void CPlaqueBase::AffectLeadResult() { m_result->CopyFrom2(&m_result2); }*/ void CPlaqueBase::AnalysePlaque(int seuil1, int seuil2) { int i, x, y; // double dng; // int gray; int ngLumiere, ngAdventitia; // Si la lumière est en Doppler couleur if (IsColor(m_ptInferieur.x, m_ptInferieur.y)) { ngLumiere = 0; } else { ngLumiere = GetIntensityResult(m_ptInferieur.x, m_ptInferieur.y); } ngAdventitia = 0; for (i = 0; i < m_nPtLongeantPlaque; i++) { ngAdventitia += GetIntensityResult(m_tPtLongeantPlaque[i].x, m_tPtLongeantPlaque[i].y); } ngAdventitia = 255; Rect rectEnglobant; rectEnglobant = m_rgnATraiter.GetRgnBox(); for (x = rectEnglobant.left; x < rectEnglobant.right; x++) { for (y = rectEnglobant.top; y < rectEnglobant.bottom; y++) { bool fGreen; fGreen = (GetPixelResult(x, y) == m_clrVert); if ( m_rgnATraiter.PtInRegion0( x, y ) && (!fGreen)) { m_wimg.SetValue(x, y, 2); // On récupére le niveau de gris de l'image originale /* gray = GetIntensityResult(x, y); dng = ((double) (gray - ngLumiere) * 195.0 ) / (double) ngAdventitia; if (dng < 0) dng = 0; if (dng > 195.0) dng = 195.0; if (dng <= seuil1) { m_wimg.SetValue(x, y, 2); } else if ((dng > seuil1) && (dng <= seuil2)) { m_wimg.SetValue(x, y, 3); m_nbPixelsB++; } else if (dng > seuil2) { m_wimg.SetValue(x, y, 4); m_nbPixelsV++; } */ } } } // CalculScoreRepartition(); } /* void CPlaqueBase::CalculScoreRepartition() { int nbConnexesR, nbConnexesB, nbConnexesV; int nbConnections, x, y, i, offset[8]; // Tableau des Offsets // 4 0 5 // 3 1 // 7 2 6 offset[0] = - m_imgPlaque.dimh; offset[1] = 1; offset[2] = m_imgPlaque.dimh; offset[3] = - 1; offset[4] = - 1 - m_imgPlaque.dimh; offset[5] = 1 - m_imgPlaque.dimh; offset[6] = 1 + m_imgPlaque.dimh; offset[7] = - 1 + m_imgPlaque.dimh; m_scoreRepartitionR = 0; m_scoreRepartitionB = 0; m_scoreRepartitionV = 0; m_scoreRepartition = 0; // Scrutation du rectangle englobant de la plaque nbConnexesR = 0; nbConnexesB = 0; nbConnexesV = 0; nbConnections = 0; for (x = rectEnglobant.left; x < rectEnglobant.right; x++) { for (y = rectEnglobant.top; y < rectEnglobant.bottom; y++) { bool fGreen; fGreen = (GetPixelResult(x, y) == m_clrVert); if ( m_rgnATraiter.PtInRegion0( x, y ) && (!fGreen)) { for (i = 0; i < m_connexite; i++) { dadd3 = dadd1 + offset[i]; if (*dadd3 == 1) // L'autre pixel appartient également à la plaque { dadd4 = dadd2 + offset[i]; nbConnections++; // Si les 2 couleurs des pixels sont dans la même zone if ((*dadd2 <= m_SeuilCouleur1) && (*dadd4 <= m_SeuilCouleur1)) { // Les 2 sont dans le seuil du bas nbConnexesR++; } else if ((*dadd2 > m_SeuilCouleur1) && (*dadd4 > m_SeuilCouleur1) && (*dadd2 <= m_SeuilCouleur2) && (*dadd4 <= m_SeuilCouleur2)) { // Les 2 sont dans le seuil du milieu nbConnexesB++; } else if ((*dadd2 > m_SeuilCouleur2) && (*dadd4 > m_SeuilCouleur2)) { // Les 2 sont dans le seuil du haut nbConnexesV++; } } } } } } // Score = 0 : tous les pixels sont de la même couleur // Score = 100% : Aucun pixel connexe if (nbConnections != 0) { m_scoreRepartitionR = 100.0 - (((double) nbConnexesR / (double) nbConnections) * 100.0); m_scoreRepartitionB = 100.0 - (((double) nbConnexesB / (double) nbConnections) * 100.0); m_scoreRepartitionV = 100.0 - (((double) nbConnexesV / (double) nbConnections) * 100.0); } // Score répartition globale m_scoreRepartition = ((m_scoreRepartitionR + m_scoreRepartitionB + m_scoreRepartitionV) / 3.0); } */