Détéction des blobs(contours) et filtre median-traitement d'image-
marouene2706
Messages postés4Date d'inscriptionlundi 22 février 2010StatutMembreDernière intervention24 mars 2011
-
22 mars 2010 à 09:55
ayanedjamel
Messages postés1Date d'inscriptionlundi 20 février 2006StatutMembreDernière intervention 1 juillet 2010
-
1 juil. 2010 à 15:53
bonjour
comme le titre l'indique, je cherche de l'aide pour la creation d'un filtre median en C d'une part, et d'une autre part , une idée pour la détection des blobs (contours)
si qqu'un a un exemple surtout pour la détection des blobs ca sera sympa, je travaille sur un projet de détection de panneaux routiers a l'aide d'une camera installé sur une vehicule. mais je me suis bloqué surtout sur la detection des blobs( detection des formes dans une images)
ayanedjamel
Messages postés1Date d'inscriptionlundi 20 février 2006StatutMembreDernière intervention 1 juillet 2010 1 juil. 2010 à 15:53
// récupération des infos des blobs
if (m_NbBlobs>0)
{
// ajout des blobs dans la liste
// pour tous les blobs supérieurs au seuil des gros défauts
for(int ii=0; ii<m_NbBlobs; ii++)
{
if(m_pBlobArea[ii] > m_pParams->m_SurfSeuilGrosDefautsPix)
{
// parmis tous les blobs trouvés, certains blobs peuvent
// être des blobs "coupés en morceaux" qui vont être reconstitués par le
// traitement d'"extension", donc pour ne pas enregistrer plusieurs défauts
// à la place d'un seul, on ne traite que le plus gros blob d'un ensemble
// de blobs dont les box englobantes (agrandies) se recouvrent
nbGrosDefauts++;
idBlob = ii;
if(ii+1<m_NbBlobs)
{
do
{
// imagette blob en cours
rectblob1 = CalcRectImagette(m_pBlobCenterY[idBlob],Tx,Ty);
// recherche de l'index du gros défaut suivant
idBlobNext = ii+1;
while(idBlobNext<m_NbBlobs && m_pBlobArea[idBlobNext] <= m_pParams->m_SurfSeuilGrosDefautsPix)
idBlobNext++;
// recherche de recouvrement
bIntersect = false;
if(recti.IntersectRect(&rectblob1,&rectblob2))
{
// si le recouvrement est supérieur à 50%, on ne garde que l'imagette
// du plus gros défaut
if(recti.Height()>=Tx/2)
{
bIntersect = true;
if(m_pBlobArea[idBlob]<m_pBlobArea[idBlobNext])
idBlob = idBlobNext;
ii = idBlobNext;
}
}
}
}
while(bIntersect && idBlobNext<=m_NbBlobs);
}
else
rectblob1 = CalcRectImagette(m_pBlobCenterY[idBlob],Tx,Ty);
// imagette sur l'image d'origine mais en couleur pour pouvoir y dessiner le contour
child = M_NULL;
MbufChild2d(m_ImageSrc, rectblob1.left, rectblob1.top, rectblob1.Width(), rectblob1.Height(),&child);
MbufAllocColor(M_DEFAULT_HOST,3,m_pParams->m_TxBuf,m_pParams->m_TxBuf,8+M_UNSIGNED,M_IMAGE+M_PROC+M_RGB24+M_PLANAR,&(grosDefautsInfo.m_MilImagette));
MbufClear(grosDefautsInfo.m_MilImagette,0);
MbufCopyColor(child,grosDefautsInfo.m_MilImagette,M_ALL_BAND);
MbufFree(child);
// imagette sur l'image des blobs
child = M_NULL;
MbufChild2d(m_ImageTrt, rectblob1.left, rectblob1.top, rectblob1.Width(), rectblob1.Height(),&child);
MbufClear(m_CpyBufImagetteBinaire,0);
MbufCopy(child,m_CpyBufImagetteBinaire);
MbufFree(child);
// extension du blob pour "coller" au mieux au défaut réel
// Rq : l'algo "Extension" détermine d'abord les bords visibles du rail
// pour limiter l'extension au rail
Extension(grosDefautsInfo.m_MilImagette,m_CpyBufImagetteBinaire,xminRail,xmaxRail);
// nouvelle recherche de blob uniquement sur l'imagette pour dessiner son contour réel
// et recalcul de ses caractéristiques avant prise en compte dans le fichiers résultats
TraceBlob(grosDefautsInfo.m_MilImagette,
m_CpyBufImagetteBinaire,
m_pBlobArea[idBlob], m_pBlobRatioXY[idBlob], m_pBlobRatioXlargeurRail[idBlob],
xminRail,xmaxRail);
// recherche du pk interpolé à partir du pk de début d'image et de la position dans l'image
if(pLocalisationInfo->m_bPksCroissants)
PkBlob = pLocalisationInfo->m_Pk + m_pBlobCenterY[idBlob]*resolutionY / 1000000;
else
PkBlob = pLocalisationInfo->m_Pk - m_pBlobCenterY[idBlob]*resolutionY / 1000000;
// recopie de l'image de la file
MbufGet(childFile,(void*)m_pBufImageSrc);
CString msg;
msg.Format("je traite le child n° %d",childFile);
// MessageInfo(msg);
// fast process : recherche de variations locales
SearchForLocalVariations(m_pBufImageSrc,m_pBufImageTrt);
// morpho et blobs
TraiteMorphBlobs(m_ImageTrt,m_MilResults);
// récupération des résultats des blobs pour les mettre à disposition des fonctions
// de création des résultats stats et des imagettes des gros défauts
GetBlobsResults();
void CRailImageProcessing::GetBlobsResults()
{
// lecture des résultats des blobs de la file
m_NbBlobs = 0;
MblobGetNumber(m_MilResults, &m_NbBlobs);
if(m_NbBlobs>0)
{
// surface
m_pBlobArea = new double[m_NbBlobs];
if(m_pBlobArea!=NULL)
MblobGetResult(m_MilResults, M_AREA, m_pBlobArea);
// numéro de ligne dans l'image
m_pBlobCenterY = new double[m_NbBlobs];
if(m_pBlobCenterY!=NULL)
MblobGetResult(m_MilResults, M_CENTER_OF_GRAVITY_Y, m_pBlobCenterY);
// ratios pour les gros défauts
m_pBlobRatioXY = new double[m_NbBlobs];
m_pBlobRatioXlargeurRail = new double[m_NbBlobs];
}
}
//*****************************************************************************
// InitApplication
// Alloc des buffers de traitement
//*****************************************************************************
//affinage du traitement directement sur l'imagette du gros defaut
MblobAllocFeatureList(M_DEFAULT_HOST, &m_FeatureListeImagetteDefaut);
MblobAllocResult(M_DEFAULT_HOST, &m_MilResultsImagettes); // imagettes de blob
MblobSelectFeature(m_FeatureListeImagetteDefaut, M_MEAN_PIXEL);
MblobAllocResult(M_DEFAULT_HOST, &m_MilResultsDefauts); // imagettes de blob
MblobAllocResult(M_DEFAULT_HOST, &m_MilResults);
// buffer pour l'extension de contours
m_ProjTab=(signed long *)malloc(m_pParams->m_TxBuf*4);
}
//*****************************************************************************
// Connex
// Analyse dans un voisinnage V8
// Conditions de sortie de la fonction :
// - aucun des pixels voisins du pixel d'entrée [xx,yy]
// n'est en dehors du blob, donc le pixel d'entrée n'est pas élément
// du contour
//*****************************************************************************
void CRailImageProcessing::Connex(unsigned char *pimagette,
unsigned char *pimagetteBinaire,
long sizeXY,
int xx, int yy,
int xmin, int xmax,
int *pNbConnexions)
{
if(xx>1 && xx<(sizeXY-1) && yy>1 && yy<(sizeXY-1) && xx>xmin && xx<xmax)
{
// on cherche un voisin du pixel d'entrée:
// -> qui est en dehors du blob (imagette binarisée), donc le pixel d'entrée est un pixel de contour
// -> dont le niveau de gris est très faible dans l'imagette source
// (les défauts sont noirs sur la bande de roulement blanche)
// et qui est donc toujours un point du défaut réel
// dans ce cas, on l'affecte à 128 pour indiquer qu'il fait partie du blob
if(pimagette[(xx+1)+(yy)*sizeXY]<SEUIL_NG_CONNEXIONS && pimagetteBinaire[(xx+1)+(yy)*sizeXY]==0)
{
(*pNbConnexions)++;
//TRACE("\n*pNbConnexions = %d",*pNbConnexions);
pimagetteBinaire[(xx+1)+(yy)*sizeXY]=128;
if(*pNbConnexions<NB_CONNEXIONS_MAX)
Connex(pimagette,pimagetteBinaire,sizeXY,(xx+1),(yy),xmin,xmax,pNbConnexions);
}
if(pimagette[(xx-1)+(yy)*sizeXY]<SEUIL_NG_CONNEXIONS && pimagetteBinaire[(xx-1)+(yy)*sizeXY]==0)
{
(*pNbConnexions)++;
//TRACE("\n*pNbConnexions = %d",*pNbConnexions);
pimagetteBinaire[(xx-1)+(yy)*sizeXY]=128;
if(*pNbConnexions<NB_CONNEXIONS_MAX)
Connex(pimagette,pimagetteBinaire,sizeXY,(xx-1),(yy),xmin,xmax,pNbConnexions);
}
if(pimagette[(xx)+(yy+1)*sizeXY]<SEUIL_NG_CONNEXIONS && pimagetteBinaire[(xx)+(yy+1)*sizeXY]==0)
{
(*pNbConnexions)++;
//TRACE("\n*pNbConnexions = %d",*pNbConnexions);
pimagetteBinaire[(xx)+(yy+1)*sizeXY]=128;
if(*pNbConnexions<NB_CONNEXIONS_MAX)
Connex(pimagette,pimagetteBinaire,sizeXY,(xx),(yy+1),xmin,xmax,pNbConnexions);
}
if(pimagette[(xx)+(yy-1)*sizeXY]<SEUIL_NG_CONNEXIONS && pimagetteBinaire[(xx)+(yy-1)*sizeXY]==0)
{
(*pNbConnexions)++;
//TRACE("\n*pNbConnexions = %d",*pNbConnexions);
pimagetteBinaire[(xx)+(yy-1)*sizeXY]=128;
if(*pNbConnexions<NB_CONNEXIONS_MAX)
Connex(pimagette,pimagetteBinaire,sizeXY,(xx),(yy-1),xmin,xmax,pNbConnexions);
}
if(pimagette[(xx+1)+(yy+1)*sizeXY]<SEUIL_NG_CONNEXIONS && pimagetteBinaire[(xx+1)+(yy+1)*sizeXY]==0)
{
(*pNbConnexions)++;
//TRACE("\n*pNbConnexions = %d",*pNbConnexions);
pimagetteBinaire[(xx+1)+(yy+1)*sizeXY]=128;
if(*pNbConnexions<NB_CONNEXIONS_MAX)
Connex(pimagette,pimagetteBinaire,sizeXY,(xx+1),(yy+1),xmin,xmax,pNbConnexions);
}
if(pimagette[(xx+1)+(yy-1)*sizeXY]<SEUIL_NG_CONNEXIONS && pimagetteBinaire[(xx+1)+(yy-1)*sizeXY]==0)
{
(*pNbConnexions)++;
//TRACE("\n*pNbConnexions = %d",*pNbConnexions);
pimagetteBinaire[(xx+1)+(yy-1)*sizeXY]=128;
if(*pNbConnexions<NB_CONNEXIONS_MAX)
Connex(pimagette,pimagetteBinaire,sizeXY,(xx+1),(yy-1),xmin,xmax,pNbConnexions);
}
if(pimagette[(xx-1)+(yy+1)*sizeXY]<SEUIL_NG_CONNEXIONS && pimagetteBinaire[(xx-1)+(yy+1)*sizeXY]==0)
{
(*pNbConnexions)++;
//TRACE("\n*pNbConnexions = %d",*pNbConnexions);
pimagetteBinaire[(xx-1)+(yy+1)*sizeXY]=128;
if(*pNbConnexions<NB_CONNEXIONS_MAX)
Connex(pimagette,pimagetteBinaire,sizeXY,(xx-1),(yy+1),xmin,xmax,pNbConnexions);
}
if(pimagette[(xx-1)+(yy-1)*sizeXY]<SEUIL_NG_CONNEXIONS && pimagetteBinaire[(xx-1)+(yy-1)*sizeXY]==0)
{
(*pNbConnexions)++;
//TRACE("\n*pNbConnexions = %d",*pNbConnexions);
pimagetteBinaire[(xx-1)+(yy-1)*sizeXY]=128;
if(*pNbConnexions<NB_CONNEXIONS_MAX)
Connex(pimagette,pimagetteBinaire,sizeXY,(xx-1),(yy-1),xmin,xmax,pNbConnexions);
}
}
}
//*****************************************************************************
// Extension
// extension du contour des blobs pour "coller au mieux au défaut vrai"
// (visuel uniquement pour les imagettes sauvegardées des gros défauts)
//*****************************************************************************
void CRailImageProcessing::Extension(MIL_ID imagetteCouleur, // buffer source imagette
MIL_ID imagetteBinaire, // buffer binarisé imagette
int &xmin, int &xmax)
{
MIL_ID projbuf = M_NULL;
MIL_ID childMonochrome = M_NULL;
MbufChildColor(imagetteCouleur, M_GREEN, &childMonochrome);
unsigned char* pimagette = (unsigned char*)MbufInquire(childMonochrome,M_HOST_ADDRESS,M_NULL);
unsigned char* pimagetteBinaire = (unsigned char*)MbufInquire(imagetteBinaire,M_HOST_ADDRESS,M_NULL);
int xx,yy;
int Tx = MbufInquire(childMonochrome,M_SIZE_X,M_NULL);
int Ty = MbufInquire(childMonochrome,M_SIZE_Y,M_NULL);
int nbConnexions = 0;
// projection de l'imagette d'origine suivant les colonnes
MimAllocResult(M_DEFAULT_HOST,Tx,M_PROJ_LIST,&projbuf);
MimProject(childMonochrome,projbuf,M_0_DEGREE);
MimGetResult(projbuf,M_VALUE,m_ProjTab);
// recherche des colonnes de début et de fin de rail
for(xx=0; xx<Tx && m_ProjTab[xx]/Ty<SEUIL_NG_CONNEXIONS; xx++);
xmin=xx;
for(xx=(Tx-1); xx>=0 && m_ProjTab[xx]/Ty<SEUIL_NG_CONNEXIONS; xx--);
xmax=xx;
// extension du contour des blobs
for(yy=0; yy<Tx; yy++)
{
for(xx=0; xx<Tx; xx++)
{
// SI pixel elt du blob, ET pixel sur la bande de roulement
// ET pixel non déjà traité (255 non traité, 128 traité)
if(pimagetteBinaire[xx+yy*Tx]==255 && xx>xmin && xx<xmax)
{
nbConnexions=0;
pimagetteBinaire[xx+yy*Tx]=128;
Connex(pimagette,pimagetteBinaire,Tx,xx,yy,xmin,xmax,&nbConnexions);
}
}
}
if(nbblobs>0)
{
pBlobArea = new double[nbblobs];
pBlobCentreY = new double[nbblobs];
pBlobCentreX = new double[nbblobs];
pBlobBoxXMin = new double[nbblobs];
pBlobBoxYMin = new double[nbblobs];
pBlobBoxXMax = new double[nbblobs];
pBlobBoxYMax = new double[nbblobs];
if(!pBlobArea || !pBlobCentreY || !pBlobCentreX || !pBlobBoxXMin || !pBlobBoxYMin || !pBlobBoxXMax || !pBlobBoxYMax)
{
ErrorMessage("TraceBlobs : echec allocation",ICON_STOP,GetApp()->m_bDebugGlobal);
bOK = false;
}
else
{
MblobGetResult(m_MilResultsDefauts, M_CENTER_OF_GRAVITY_Y, pBlobCentreY);
MblobGetResult(m_MilResultsDefauts, M_CENTER_OF_GRAVITY_X, pBlobCentreX);
MblobGetResult(m_MilResultsDefauts, M_AREA, pBlobArea);
MblobGetResult(m_MilResultsDefauts, M_BOX_X_MIN, pBlobBoxXMin);
MblobGetResult(m_MilResultsDefauts, M_BOX_Y_MIN, pBlobBoxYMin);
MblobGetResult(m_MilResultsDefauts, M_BOX_X_MAX, pBlobBoxXMax);
MblobGetResult(m_MilResultsDefauts, M_BOX_Y_MAX, pBlobBoxYMax);
// marquage du contour des blobs
MblobFill(m_MilResultsDefauts, childMonochrome, M_ALL_BLOBS + M_CONTOUR, 255);
// recherche du blob de plus grosse aire
areamax = 0;
for(int ii=0; ii<nbblobs; ii++)
if(pBlobArea[ii]>areamax)
{
areamax = pBlobArea[ii];
indexblob = ii;
}
// recherche des caractéristiques permettant le filtrage des joints
ratioXY = ((double)(pBlobBoxXMax[indexblob]-pBlobBoxXMin[indexblob])*resX)/((double)(pBlobBoxYMax[indexblob]-pBlobBoxYMin[indexblob])*resY);
ratioXlargeurRail = (double)(pBlobBoxXMax[indexblob]-pBlobBoxXMin[indexblob])/(double)(xmaxRail-xminRail);
//test d'elimination des defauts peus contrastés
//le blob concerné
//calcul de la moyenne locale
unsigned char* pDataImagette = (unsigned char*)MbufInquire(childBlue,M_HOST_ADDRESS,M_NULL);
int Ty,Tx;
MbufInquire(childBlue,M_SIZE_Y,&Ty);
MbufInquire(childBlue,M_SIZE_X,&Tx);
int moyenneLocaleRail = 0;
int indexPixelRail = 0;
int DebutX,FinX,DebutY,FinY;
MblobCalculate(imagetteBinaire,childBlue,m_FeatureListeImagetteDefaut,m_MilResultsImagettes);
long NbBlobs = 0;
MblobGetNumber(m_MilResultsImagettes, &NbBlobs);
pBlobMean = new double[NbBlobs];
MblobGetResult(m_MilResultsImagettes,M_MEAN_PIXEL,pBlobMean);
for (int ii=DebutX; ii<FinX;ii++)
for(int jj=DebutY;jj<FinY;jj++)
{
// on est en dehors du defaut
if (
(iipBlobBoxXMax[indexblob]) ||
(jjpBlobBoxYMax[indexblob])
)
{
indexPixelRail++;
moyenneLocaleRail += pDataImagette[ii+jj*FinX];
}
}
moyenneLocaleRail /= indexPixelRail;
float contraste = (float)abs((int)pBlobMean[indexblob] - moyenneLocaleRail)/(float)moyenneLocaleRail;
if ( contraste < m_pParams->m_SeuilContrasteGrosDefauts/100.0f)
bOK = false;
// tracé d'une croix au centre du blob principal
MgraColor(M_DEFAULT,M_RGB888(0, 255, 0));
MgraLine(M_DEFAULT,imagetteCouleur,
(int)pBlobCentreX[indexblob]-5,(int)pBlobCentreY[indexblob],
(int)pBlobCentreX[indexblob]+5,(int)pBlobCentreY[indexblob]);
MgraLine(M_DEFAULT,imagetteCouleur,
(int)pBlobCentreX[indexblob],(int)pBlobCentreY[indexblob]-5,
(int)pBlobCentreX[indexblob],(int)pBlobCentreY[indexblob]+5);
//*******************************************************************************
// AddToResultatsDensites
// Sauvegarde des résultats statistiques par classe
//*******************************************************************************