#ifndef IMG_FILTER_H_ #define IMG_FILTER_H_ // functions that operate on pixels // in this file code readability is preferred over speed and memory optimizations #include #include #include namespace img { template inline void normalize(Image &image) { assert(image.isValid()); assert(image.attributes.hasRange(0,255)); if(Safe){ if(!image.isValid()) throw ImageException("Invalid image"); if(!image.attributes.hasRange(0,255)) throw ImageException("Invalid range attribute"); } ScalarType max=maxValue(image); ScalarType min=minValue(image); ScalarType scale=255.0f/(max-min); ScalarType* array = image.dataValues(); int length =image.dataValuesSize(); for(int offset=0;offset inline Image getNormalized(const Image &image) { Image i(image); normalize(i); return i; } template inline void convolution(const Image &source,Image &destination,const DestScalarType *matrix,int matrix_width,int matrix_height) { assert(source.isValid()); assert(matrix != NULL); assert((matrix_width > 0) && ((matrix_width)%2 == 1)); assert((matrix_height > 0) && ((matrix_height)%2 == 1)); if(SrcSafe || DestSafe){ if(!source.isValid()) throw ImageException("Invalid image"); if( matrix == NULL) throw ImageException("NULL convolution matrix"); if( !((matrix_width > 0) && ((matrix_width)%2 == 1)) ) throw ImageException("Matrix width must be a positive odd number"); if( !((matrix_height > 0) && ((matrix_height)%2 == 1)) ) throw ImageException("Matrix height must be a positive odd number"); } destination.setZero(source.width(),source.height()); destination.attributes=source.attributes; int x_radius=(matrix_width-1)/2; int y_radius=(matrix_height-1)/2; // per ogni canale for(int channel=0; channel < Channels ;channel++){ // canali immagine // per ogni riga for (int y = 0; y < source.height(); y++){ // righe immagine // per ogni pixel nella riga for (int x = 0; x < source.width(); x++){ // colonne immagine DestScalarType sum=0.0f; int offset=0; for(int my = y-y_radius; my <= y+y_radius; my++) // righe matrice for(int mx = x-x_radius; mx <= x+x_radius; mx++) //colonne matrice sum += matrix[offset++] * static_cast(source.getValueAsClamped(mx,my,channel)); destination.setValue(x,y,channel,sum); } // colonne immagine } // righe immagine } // canali immagine } template // get[filter]ed() functions constrain return type to be the same of the parameter inline Image getConvolved(const Image &image,const ScalarType *matrix,int matrix_width,int matrix_height) { Image i; convolution(image,i,matrix,matrix_width,matrix_height); return i; } template inline void boxFilter(const Image &source,Image &destination,int radius) { assert(radius > 0); if(SrcSafe || DestSafe){ if(radius <= 0) throw ImageException("Nonpositive radius"); } int matrix_side=2*radius+1; int matrix_size=matrix_side*matrix_side; DestScalarType* matrix=new DestScalarType[matrix_size]; DestScalarType val=1.0f/matrix_size; for(int i=0; i // get[filter]ed() functions constrain return type to be the same of the parameter inline Image getBoxFiltered(const Image &image,int radius) { Image i; boxFilter(image,i,radius); return i; } template inline void _gaussian(const int &radius,const ScalarType &sigma,ScalarType * &matrix,int &matrix_side) { matrix_side=2*radius+1; int matrix_size=matrix_side*matrix_side; matrix=new ScalarType[matrix_size]; // calcolo la matrice int offset=0; const ScalarType c = -0.5f / (sigma*sigma); for(int y = -radius;y <= radius; y++) for(int x = -radius;x <= radius; x++) matrix[offset++] = exp( (x*x+y*y)*c ); // porto la matrice a somma 1 ScalarType sum=0.0f; for(int i=0;i inline void GaussianSmooth(const Image &source,Image &destination,const int radius) { assert(radius > 0.0f); if(SrcSafe || DestSafe){ if(radius <= 0.0f) throw ImageException("Nonpositive radius"); } const DestScalarType sigma = radius/3.0f; DestScalarType *matrix=NULL; int matrix_side=0; _gaussian(radius,sigma,matrix,matrix_side); convolution(source,destination,matrix,matrix_side,matrix_side); delete [] matrix; } template // get[filter]ed() functions constrain return type to be the same of the parameter inline Image getGaussianSmoothed(const Image &image,const int radius) { Image i; GaussianSmooth(image,i,radius); return i; } template inline void LaplacianFilter(const Image &source,Image &destination) { DestScalarType *matrix=new DestScalarType[9]; matrix[0]= 0.0f; matrix[1]= 1.0f; matrix[2]= 0.0f; matrix[3]= 1.0f; matrix[4]=-4.0f; matrix[5]= 1.0f; matrix[6]= 0.0f, matrix[7]= 1.0f; matrix[8]= 0.0f; convolution(source,destination,matrix,3,3); delete [] matrix; } template // get[filter]ed() functions constrain return type to be the same of the parameter inline Image getLaplacianFiltered(const Image &image) { Image i; LaplacianFilter(image,i); return i; } template inline void _laplacian_of_gaussian(const int &radius,const ScalarType &sigma,ScalarType * &matrix,int &matrix_side) { matrix_side=2*radius+1; int matrix_size=matrix_side*matrix_side; matrix=new ScalarType[matrix_size]; // calcolo la matrice int offset=0; const ScalarType c1 = -0.5f/(sigma*sigma); ScalarType c; for(int y = -radius;y <= radius; y++) for(int x = -radius;x <= radius; x++){ c = (x*x+y*y) * c1; matrix[offset++] = (1+c) * exp(c); } // porto la matrice a somma 1 ScalarType sum=0.0f; for(int i=0;i inline void LoGFilter(const Image &source,Image &destination,int radius) { assert(radius > 0.0f); if(SrcSafe || DestSafe){ if(radius <= 0.0f) throw ImageException("Nonpositive radius"); } DestScalarType *matrix=NULL; int matrix_side=0; DestScalarType sigma = radius/3.0f; _laplacian_of_gaussian(radius,sigma,matrix,matrix_side); convolution(source,destination,matrix,matrix_side,matrix_side); delete [] matrix; } template // get[filter]ed() functions constrain return type to be the same of the parameter inline Image getLoGFiltered(const Image &image,int radius) { Image i; LoGFilter(image,i,radius); return i; } template inline void DoGFilter(const Image &source,Image &destination,int radius1,int radius2) { assert(radius1 > 0.0f); assert(radius2 > 0.0f); assert(radius2 > radius1); if(SrcSafe || DestSafe){ if(radius1 <= 0.0f) throw ImageException("Nonpositive radius1"); if(radius2 <= 0.0f) throw ImageException("Nonpositive radius2"); if(radius2 <= radius1) throw ImageException("radius2 is less than radius1"); } int matrix_side=0; DestScalarType *m1=NULL,*m2=NULL; const DestScalarType sigma1=radius1/3.0f; const DestScalarType sigma2=radius2/3.0f; // ottengo la prima gaussiana (col radius della seconda) _gaussian(radius2,sigma1,m1,matrix_side); // ottengo la seconda gaussiana _gaussian(radius2,sigma2,m2,matrix_side); int matrix_size=matrix_side*matrix_side; // sottraggo alla prima gaussiana la seconda for(int i=0;i // get[filter]ed() functions constrain return type to be the same of the parameter inline Image getDoGFiltered(const Image &image,int radius1,int radius2) { Image i; DoGFilter(image,i,radius1,radius2); return i; } template inline void UnsharpMask(const Image &source,Image &destination,int radius,float factor) { assert(radius > 0); assert(factor > 0.0f); if(SrcSafe || DestSafe){ if(radius <= 0.0f) throw ImageException("Nonpositive radius"); if(factor <= 0.0f) throw ImageException("Nonpositive factor"); } // metto l'immagine smoothata in destination GaussianSmooth(source,destination,radius); DestScalarType* source_array = source.dataValues(); DestScalarType* destination_array = destination.dataValues(); int length = source.dataValuesSize(); // unsharpo destination in loco for(int offset=0;offset // get[filter]ed() functions constrain return type to be the same of the parameter inline Image getUnsharpMasked(const Image &image,int radius,float factor) { Image i; UnsharpMask(image,i,radius,factor); return i; } template inline void medianFilter(const Image &source,Image &destination,int radius) { assert(source.isValid()); assert(radius > 0); if(SrcSafe || DestSafe){ if(!source.isValid()) throw ImageException("Invalid image"); if(radius <= 0) throw ImageException("Nonpositive radius"); } destination.setZero(source.width(),source.height()); destination.attributes=source.attributes; // per ogni canale for(int channel=0; channel < Channels;channel++){ // canali immagine // per ogni riga for (int y = 0; y < source.height(); y++){ // righe immagine // per ogni pixel nella riga for (int x = 0; x < source.width(); x++){ // colonne immagine // memorizzo i valori dell'intorno std::vector v; for(int my = y-radius; my <= y+radius; my++) // righe intorno for(int mx = x-radius; mx <= x+radius; mx++) //colonne intorno if (source.isInside(mx,my)) v.push_back(static_cast(source.getValue(mx,my,channel))); // ottengo la mediana int s=v.size(); assert(s>0); nth_element (v.begin(), v.begin()+(s/2), v.end()); DestScalarType median = *(v.begin()+(s/2)); if((s%2)==0) { // even s: mean of the 2 middle elements nth_element (v.begin(), v.begin()+(s/2)+1, v.end()); median = ( *(v.begin()+(s/2)+1) + median ) /2.0f; } // aggiorno il valore alla mediana dell'intorno destination.setValue(x,y,channel,median); } // colonne immagine } // righe immagine } // canali immagine } template // get[filter]ed() functions constrain return type to be the same of the parameter inline Image getMedianFiltered(const Image &image,int radius) { Image i; medianFilter(image,i,radius); return i; } template inline void channels_mean(const img::Image &channels_image, img::Image<1,ScalarType2,Safe2> &mean_image) { assert(channels_image.isValid()); if(Safe1 || Safe2){ if(!channels_image.isValid()) throw img::ImageException("channels_image rgb image"); } mean_image.setZero(channels_image.width(),channels_image.height()); mean_image.attributes=channels_image.attributes; for (int y_coord = 0; y_coord < channels_image.height(); ++y_coord) for (int x_coord = 0; x_coord < channels_image.width(); ++x_coord){ ScalarType2 sum = ScalarType2(0.0); for (int channel=0; channel(channels_image.getValue(x_coord, y_coord, channel)); mean_image.setValue(x_coord, y_coord, 0, sum / ScalarType2(Channels) ); } } } //end namespace img #endif /*IMG_FILTER_H_*/