////////////////////////////////////////////////////////// // imgBase.cpp : basic image processing functions ////////////////////////////////////////////////////////// #include "img.h" #include "math.h" #include int _cdecl blob_ord2(const void *, const void *); // Function : img // Description : Object constructor // Creation date : 08/04 // Author : CJ // Inputs : // Outputs : img::img() { dimh = 256; dimv = 256; nbpix = dimh * dimv; itype = TYPE_UCHAR; init = 0; } // Function : ~img // Description : Object destructor // Creation date : 08/04 // Author : CJ // Inputs : // Outputs : img::~img() { if ((data != 0) && (init == 1)) { delete [] ((unsigned char *)data); } init = 0; } // Function : Del // Description : Free the image data // Creation date : 08/04 // Author : CJ // Inputs : // Outputs : void img::Del() { if ((data != 0) && (init == 1)) { delete [] ((unsigned char *)data); } init = 0; } // Function : Create // Description : Allocate the pixel data for the image // Creation date : 08/04 // Author : CJ // Inputs : // Outputs : Return 1 if OK, 0 if default int img::Create(int it, int dh , int dv) { itype = it; dimh = dh; dimv = dv; nbpix = dimh * dimv; if (init == 0) { // Image 8 bits unsigned if (itype == TYPE_UCHAR) { data = (unsigned char *) new unsigned char[nbpix]; } // Image 8 bits signed else if (itype == TYPE_SCHAR) { data = (char *) new char[nbpix]; } // Image 16 bits unsigned else if (itype == TYPE_USHORT) { data = (unsigned short int *) new unsigned short[nbpix]; } // Image 16 bits signed else if (itype == TYPE_SSHORT) { data = (short int*) new short int[nbpix]; } // Image 32 bits of int else if (itype == TYPE_INT) { data = (int *) new int[nbpix]; } // Image 64 bits unsigned else if (itype == TYPE_ULINT) { data = (unsigned long int *) new unsigned long int[nbpix]; } // Image 32 bits of floats else if (itype == TYPE_FLOAT) { data = (float *) new float [nbpix]; } // Image of doubles else if (itype == TYPE_DOUBLE) { data = (double *) new double[nbpix]; } } // Allocation problem if (data == 0) { init = 0; } else { init = 1; } return init; } // Function : copyto // Description : Copy the current image to the image img2 (Image may have different types) // Creation date : 08/04 // Author : CJ // Inputs : // Outputs : void img::CopyTo(img *img2) { if (itype == TYPE_UCHAR) { unsigned char *cadd; cadd = (unsigned char *) data; if (img2->itype == TYPE_UCHAR) { unsigned char *cadd2, *vcadd; cadd2 = (unsigned char *) img2->data; vcadd = (unsigned char *) memcpy(cadd2, cadd, (size_t) (nbpix * sizeof(unsigned char))); } else if (img2->itype == TYPE_USHORT) { unsigned short *sadd, *smax; sadd = (unsigned short *) img2->data; smax = sadd + img2->nbpix; while (sadd < smax) { *sadd = *cadd; cadd++; sadd++; } } } else if (itype == TYPE_USHORT) { unsigned short *cadd; cadd = (unsigned short *) data; if (img2->itype == TYPE_USHORT) { unsigned short *cadd2, *vcadd; cadd2 = (unsigned short *) img2->data; vcadd = (unsigned short *) memcpy(cadd2, cadd, (size_t) (nbpix * sizeof(unsigned short))); } else if (img2->itype == TYPE_UCHAR) { unsigned short *amax; unsigned char *cadd2; cadd2 = (unsigned char *) img2->data; amax = cadd + nbpix; while (cadd < amax) { *cadd2 = (unsigned char) *cadd; cadd++; cadd2++; } } } else if (itype == TYPE_INT) { int *cadd; cadd = (int *) data; if (img2->itype == TYPE_INT) { int *cadd2, *vcadd; cadd2 = (int *) img2->data; vcadd = (int *) memcpy(cadd2, cadd, (size_t) (nbpix * sizeof(char))); } else if (img2->itype == TYPE_UCHAR) { int *amax; unsigned char *cadd2; cadd2 = (unsigned char *) img2->data; amax = cadd + nbpix; while (cadd < amax) { *cadd2 = (unsigned char) *cadd; cadd++; cadd2++; } } else if (img2->itype == TYPE_USHORT) { int *amax; unsigned short *cadd2; cadd2 = (unsigned short *) img2->data; amax = cadd + nbpix; while (cadd < amax) { *cadd2 = (unsigned short) *cadd; cadd++; cadd2++; } } } } // Function : GetValue // Description : Get the value of a pixel // Creation date : 08/04 // Author : CJ // Inputs : // Outputs : int img::GetValue(int x, int y) { int ng = 0; if ((x > 0) && (y > 0) && (x < dimh) && (y < dimv)) { if ( itype == TYPE_UCHAR ) { unsigned char *dadd; dadd = (unsigned char *) data; dadd += x + y * dimh; ng = *dadd; } else if ( itype == TYPE_USHORT ) { unsigned short *dadd; dadd = (unsigned short *) data; dadd += x + y * dimh; ng = *dadd; } else if ( itype == TYPE_INT ) { int *dadd; dadd = (int *) data; dadd += x + y * dimh; ng = *dadd; } } return(ng); } // Function : SetValue // Description : Set the value of a pixel // Creation date : 08/04 // Author : CJ // Inputs : // Outputs : void img::SetValue(int x, int y, int value) { if ((x > 0) && (y > 0) && (x < dimh) && (y < dimv)) { if ( itype == TYPE_UCHAR ) { unsigned char *dadd; dadd = (unsigned char *) data; dadd += x + y * dimh; *dadd = (unsigned char) value; } else if ( itype == TYPE_USHORT ) { unsigned short *dadd; dadd = (unsigned short *) data; dadd += x + y * dimh; *dadd = (unsigned short) value; } else if ( itype == TYPE_INT ) { int *dadd; dadd = (int *) data; dadd += x + y * dimh; *dadd = value; } } } // Function : Equalize // Description : histogram equalization // Creation date : 08/04 // Author : CJ // Inputs : // Outputs : void img::Equalize(int ngray) { double his[SIZEHISTO]; double hissom = 0.0; int i = 0; int x = 0; int y = 0; int ng1 = 0; int ng2 = 0; for (i = 0; i < SIZEHISTO; i++) his[i] = 0; // fill the histogram for (x = 0; x < dimh; x++) { for (y = 0; y < dimv ;y++) { ng1 = GetValue(x, y); if ( ng1 < SIZEHISTO ) { his[ng1]++; hissom++; } } } // cumulative histogram for (i = 1; i < SIZEHISTO; i++) { his[i] += his[i-1]; } // normalisation for (i = 0; i < SIZEHISTO; i++) { his[i] = his[i] / hissom; } // Equalization for (x = 0; x < dimh; x++) { for (y = 0; y < dimv; y++) { ng1 = GetValue(x, y); if ( ng1 < SIZEHISTO ) { ng2 = (int) ( ( (double) ( ngray - 1.0 ) * his[ng1] ) ); if ( ng2 < SIZEHISTO ) { SetValue(x, y, ng2); } } } } } // Function : Fill // Description : Fill all the image with a given gray level value // Creation date : 08/04 // Author : CJ // Inputs : value of the gry level // Outputs : void img::Fill(int value) { if ( itype == TYPE_UCHAR ) { unsigned char *dadd, *amax; dadd = (unsigned char *) data; amax = dadd + nbpix; while ( dadd < amax ) { *dadd = (unsigned char) value; dadd++; } } else if ( itype == TYPE_USHORT ) { unsigned short *dadd, *amax; dadd = (unsigned short *) data; amax = dadd + nbpix; while ( dadd < amax ) { *dadd = (unsigned short) value; dadd++; } } else if ( itype == TYPE_INT ) { int *dadd, *amax; dadd = (int *) data; amax = dadd + nbpix; while ( dadd < amax ) { *dadd = value; dadd++; } } else if (itype == TYPE_DOUBLE) { double *dadd, *amax; dadd = (double *) data; amax = dadd + nbpix; while ( dadd < amax ) { *dadd = value; dadd++; } } } //------------------------------------------------- // Basic functions of the mathematical morphology //------------------------------------------------- // Function : BinaryErosion // Description : mathematical morphological : binary erosion // Creation date : 08/04 // Author : CJ // Inputs : // Outputs : void img::BinaryErosion(img *res) { unsigned short *dadd0; unsigned short *dadd; unsigned short *amax; unsigned short *dadd2; int i; int x; int y; int offset[8]; int dx[8]; int dy[8]; dx[0] = -1; dy[0] = 1; dx[1] = 0; dy[1] = 1; dx[2] = 1; dy[2] = 1; dx[3] = -1; dy[3] = 0; dx[4] = 1; dy[4] = 0; dx[5] = -1; dy[5] = -1; dx[6] = 0; dy[6] = -1; dx[7] = 1; dy[7] = -1; offset[0] = -dimh - 1; offset[1] = -dimh; offset[2] = -dimh + 1; offset[3] = -1; offset[4] = 1; offset[5] = dimh - 1; offset[6] = dimh; offset[7] = dimh + 1; CopyTo(res); dadd0 = (unsigned short *) data; dadd = dadd0; amax = dadd0 + nbpix; dadd2 = (unsigned short *) res->data; x = 0; y = dimv -1; while ( dadd < amax ) { if ( *dadd == 1 ) { for(i = 0; i < 8; i++) { // Overflow if ( ( ( x + dx[i] ) < 0 ) || ( ( x + dx[i] ) > ( dimh - 1 ) ) || ( ( y + dy[i] ) < 0 ) || ( ( y + dy[i] ) > ( dimv - 1 ) ) ) *dadd2 = 0; else { if ( *( dadd + offset[i] ) == 0 ) { *dadd2 = 0; } } } } x++; if ( x >= dimh ) { x = 0; y--; } dadd++; dadd2++; } } // Function : BinaryDilatation // Description : mathematical morphological : binary dilatation // Creation date : 08/04 // Author : CJ // Inputs : // Outputs : void img::BinaryDilatation(img *res) { unsigned short *dadd0; unsigned short *dadd; unsigned short *amax; unsigned short *dadd2; int x = 0; int y = 0; int i = 0; int offset[9]; int dx[8]; int dy[8]; offset[0] = -dimh - 1; offset[1] = -dimh; offset[2] = -dimh + 1; offset[3] = -1; offset[4] = 1; offset[5] = dimh - 1; offset[6] = dimh; offset[7] = dimh + 1; offset[8] = 0; dx[0] = -1; dy[0] = 1; dx[1] = 0; dy[1] = 1; dx[2] = 1; dy[2] = 1; dx[3] = -1; dy[3] = 0; dx[4] = 1; dy[4] = 0; dx[5] = -1; dy[5] = -1; dx[6] = 0; dy[6] = -1; dx[7] = 1; dy[7] = -1; dx[8] = 0; dy[8] = 0; CopyTo(res); dadd0 = (unsigned short *) data; dadd = dadd0 + 1 + dimh; amax = dadd0 + nbpix - 1 - dimh; dadd2 = (unsigned short *) res->data; dadd2+= 1 + dimh; x = 0; y = dimv - 1; while ( dadd < amax ) { for(i = 0; i < 9; i++) { // Overflow if ( ( ( x + dx[i] ) < 0 ) || ( ( x + dx[i] ) > ( dimh - 1 ) ) || ( ( y + dy[i] ) < 0 ) || ( ( y + dy[i] ) > ( dimv - 1 ) ) ) *dadd2 = 0; else { if ( *( dadd + offset[i] ) == 1 ) { *dadd2 = 1; } } } x++; if ( x > dimh - 1 ) { x = 0; y--; } dadd++; dadd2++; } } // Function : BinaryOpening // Description : mathematical morphological : binary opening // Creation date : 08/04 // Author : CJ // Inputs : // Outputs : void img::BinaryOpening(img *tamp) { img tamp1; BinaryErosion(tamp); tamp1.Create(itype, dimh, dimv); tamp->CopyTo(&tamp1); tamp1.BinaryDilatation(tamp); tamp1.Del(); } // Function : BinaryClosing // Description : mathematical morphological : binary closing // Creation date : 08/04 // Author : CJ // Inputs : // Outputs : void img::BinaryClosing(img *tamp) { img tamp1; BinaryDilatation(tamp); tamp1.Create(itype, dimh, dimv); tamp->CopyTo(&tamp1); tamp1.BinaryErosion(tamp); tamp1.Del(); } void img::RemplaceCouleur(int a, int b) { int *dadd, *amax; dadd = (int *) data; amax = dadd + nbpix; while (dadd < amax) { if (*dadd == a) { *dadd = b; } dadd++; } } // Fonction de comparaison pour la fonction de quick sort qsort int _cdecl blob_ord2(const void *arg1, const void *arg2) { struct blob *bl1, *bl2; bl1 = (struct blob *) arg1; bl2 = (struct blob *) arg2; if (bl1->size == bl2->size) { return 0; } else if (bl1->size < bl2->size) { return 1; } else { return -1; } } // Function : BlobColoring // Description : Algorithme du Blob Coloring // Creation date : 05/01/2010 // Author : CJ // Inputs : // Outputs : Renvoie -1 si on dépasse MAXBLOB int img::BlobColoring(blob tblob[MAXBLOB], img *img1) { int i, j, ic, lastblob, nblob, vsup, vleft; unsigned char *dadd, *amax; unsigned int *badd, *badd0, *apix, *apix2, *aleft, *asup, *bmax; int tlabel[MAXBLOB+1]; // Génére une image binaire 0/1 // seuillage(seuil); dadd = (unsigned char *) (data); badd0 = (unsigned int *) (img1->data); badd = badd0; amax = dadd + nbpix; while (dadd < amax) { *badd = *dadd; dadd++; badd++; } for (i = 0; i < MAXBLOB; i++) { tblob[i].bind = 0; tblob[i].used = 0; tblob[i].size = 0; tblob[i].first = 0; } for (i = 0; i < MAXBLOB+1; i++) { tlabel[i] = 0; } lastblob = 0; nblob = 0; // Point en haut à gauche apix = badd0; if (*apix != 0) { lastblob++; nblob++; *apix = lastblob; if (lastblob > MAXBLOB) { return -1; } tblob[lastblob].bind = lastblob; tblob[lastblob].used = 1; tblob[lastblob].size = 1; tblob[lastblob].first = apix; } // Première colonne for (i=1; i MAXBLOB) { return -1; } tblob[lastblob].bind = lastblob; tblob[lastblob].used = 1; tblob[lastblob].size = 1; tblob[lastblob].first = apix; } else { *apix = *aleft; tblob[*apix].size++; } } } asup = apix - dimh; // Colonne 1 à dimv for (i = 1; i < dimv; i++) { aleft = apix++; asup++; // Première colonne if (*apix != 0) { if (*asup == 0) { lastblob++; nblob++; *apix = lastblob; if (lastblob > MAXBLOB) { return -1; } tblob[lastblob].bind = lastblob; tblob[lastblob].used = 1; tblob[lastblob].size = 1; tblob[lastblob].first = apix; } else { *apix = *asup; tblob[*apix].size++; } } // Colonne 1 à dimh for (ic = 1 ;ic < dimh ; ic++) { aleft = apix++; asup++; if (*apix != 0) { if (*aleft == 0) { // case left == 0 if (*asup == 0) { lastblob++; nblob++; *apix = lastblob; if (lastblob > MAXBLOB) { return -1; } tblob[lastblob].bind = lastblob; tblob[lastblob].used = 1; tblob[lastblob].size = 1; tblob[lastblob].first = apix; } else { *apix = *asup; tblob[*apix].size++; } } else { // case left != 0 *apix = *aleft; tblob[*apix].size++; if ((*asup != 0) && (*asup != *aleft)) { // fusion nblob--; vsup = *asup; vleft = *aleft; if (tblob[vleft].size < tblob[vsup].size) { tblob[vsup].size += tblob[vleft].size; tblob[vleft].used = 0; apix2 = tblob[vleft].first; while (apix2 <= apix) { if (*apix2 == (unsigned int) vleft) *apix2 = (int) vsup; apix2++; } } else { tblob[vleft].size += tblob[vsup].size; tblob[vsup].used = 0; apix2 = tblob[vsup].first; while (apix2 <= apix) { if (*apix2 == (unsigned int) vsup) *apix2 = vleft; apix2++; } } } } } } } // Tri des blobs par taille qsort((char *)tblob, lastblob + 1, sizeof(blob), blob_ord2); if (nblob > MAXBLOB) { return -1; } j = 0; for (i = 0; i <= lastblob; i++) { if (tblob[i].used == 1) { tlabel[tblob[i].bind] = j++; } } // recoloriage (en tenant compte des blobs utilisés) badd = badd0; bmax = badd + nbpix; while (badd < bmax) { if ((*badd != 0) && (*badd < MAXBLOB)) { *badd = 1 + tlabel[*badd]; } badd++; } return (nblob); } // Renvoie la surface du blob d'indice nblob // L'image des blobs est en int long img::GetBlobSize(int nblob) { unsigned int *dadd, *amax; long sblob; sblob = 0; dadd = (unsigned int *) data; amax = dadd + nbpix; while (dadd < amax) { if (*dadd == (unsigned int) nblob) { sblob++; } dadd++; } return (sblob); } void img::SaveImgAsRaw() { std::ofstream ofs( "C:\\Img.raw", std::ios_base::out | std::ios_base::binary ); if ( ofs.good() ) { ofs.write( (char*) data, nbpix ); ofs.close(); } }