NiblackBinaryImage::NiblackBinaryImage(const GreyLevelImage& anImg, const int aLowThres, const int aHighThres, const int aMaskSize, const float aK, const float aPostThres) : BinaryImage(anImg.width(), anImg.height()) { // Pointer to mean image FloatImage* pMeanImg = 0; // Compute standard deviation and mean StandardDeviationImage stdImg(FloatImage(anImg), pMeanImg, aMaskSize); // Rows to exchange data GreyLevelImage::pointer bRow = new GreyLevelImage::value_type [_width]; GreyLevelImage::pointer gRow = new GreyLevelImage::value_type [_width]; float* mRow = new float [_width]; float* sRow = new float [_width]; // Binarize for (int i = 0 ; i < _height ; ++i) { // Read means pMeanImg->row(i, mRow); // Read deviations stdImg.row(i, sRow); // Read original anImg.row(i, gRow); // Pointers float* m = mRow; float* s = sRow; GreyLevelImage::pointer g = gRow; GreyLevelImage::pointer b = bRow; // Dynamic thresholding for (int j = 0 ; j < _width ; ++j, ++b, ++g) { if (*g < aLowThres) { *b = 1; } else if (*g > aHighThres) { *b = 0; } else if (*g < (GreyLevelImage::value_type) (*m++ + aK * *s++)) { *b = 1; } else { *b = 0; } } // Save line setRow(i, bRow); } // Post-processing if (aPostThres > 0) { // Copy reference image BinaryImage* contours = new BinaryImage(*this); // Extract connected components ConnectedComponents* compConnexes = new ConnectedComponents(*contours); // Prepare tables int labCnt = compConnexes->componentCnt(); // Tables for the sums of the means of the gradient float* gsum = new float [labCnt]; qgFill(gsum, labCnt, 0.f); // Tables for the numbers of points -- for the mean int* psum = new int [labCnt]; qgFill(psum, labCnt, 0); // Table of labels Component::label_type* labRow = new Component::label_type[_width]; // By construction, first and last pixels are always WHITE labRow[1] = 0; labRow[_width - 1] = 0; // Compute the module of Canny gradient CannyGradientImage* gradImg = new CannyGradientImage(anImg); GradientModuleImage gradModImg(*gradImg); delete gradImg; // Construct the image of the contours of the black components // which thus includes the interesting pixels ErodedBinaryImage* eroImg = new ErodedBinaryImage(*contours); (*contours) -= (*eroImg); delete eroImg; // Create a line of floats float* fRow = new float [_width]; // Pointer to the pixel map of the component image Component::label_type* pMapCCImg = (compConnexes->accessComponentImage()).pPixMap() + _width; for (int i = 1 ; i < (_height - 1) ; ++i) { // Get a line of labels from the component image // and set pixels from white components to 0 pMapCCImg += 2; PRIVATEgetBlackLabels(pMapCCImg, labRow); // Read the corresponding line in the contours contours->row(i, bRow); // Read the corresponding line in the module of the gradient gradModImg.row(i, fRow); Component::label_type* p = labRow; GreyLevelImage::pointer q = bRow; float* r = fRow; for (int j = 0 ; j < _width ; ++j, ++p, ++q, ++r) { if (*q != 0) // We are on a contour { gsum[(int)(*p)] += *r; psum[(int)(*p)] += 1; } } // END for j } // END for i delete contours; // Compute the means for (int i = 0 ; i < labCnt ; ++i) { if (psum[i] != 0) { gsum[i] /= psum[i]; } } // END for // Pointer to the pixel map of the component image pMapCCImg = (compConnexes->accessComponentImage()).pPixMap() + _width; // Delete fake black components for (int i = 1 ; i < _height - 1 ; ++i) { // Read the current line of components pMapCCImg += 2; PRIVATEgetBlackLabels(pMapCCImg, labRow); // Read the corresponding line in the binary image row(i, bRow); // Examine components and delete Component::label_type* p = labRow; GreyLevelImage::pointer pb = bRow; for (int j = 0 ; j < _width ; ++j, ++p, ++pb) { if (((*pb) != 0) && (gsum[(int)(*p)] < aPostThres)) { *pb = 0; } } // Save this line setRow(i, bRow); } // END for // Clean up delete [] fRow; delete [] psum; delete [] gsum; delete compConnexes; } // And clean up delete [] bRow; delete [] gRow; delete [] mRow; delete [] sRow; }
// ------------------------------------------------------------------- // C O N S T R U C T O R // ------------------------------------------------------------------- ContrastEnhancedImage::ContrastEnhancedImage(GreyLevelImage& anImg, unsigned int aMaskSize) throw(QgarErrorDomain) : GreyLevelImage(anImg) { int sqsize = (2 * (int)aMaskSize) + 1; // Effective mask size if ((sqsize > _width) || (sqsize > _height)) { std::ostringstream os; os << "Mask [" << sqsize << " X " << sqsize << "] too large for image [" << _width << " X " << _height << "]"; throw QgarErrorDomain(__FILE__, __LINE__, "qgar::ContrastEnhancedImage::ContrastEnhancedImage(qgar::GreyLevelImage&, unsigned int)", os.str()); } // Allocate a table for the maxima and minima per column GreyLevelImage::pointer ltabmax = new GreyLevelImage::value_type[_width]; GreyLevelImage::pointer ltabmin = new GreyLevelImage::value_type[_width]; // Allocate a table for current input row GreyLevelImage::pointer crow = new GreyLevelImage::value_type[_width]; // Allocate a table for current output row GreyLevelImage::pointer orow = new GreyLevelImage::value_type[_width]; GreyLevelImage::pointer p; GreyLevelImage::pointer q; // Now loop on all lines to process // As the image was created from anImg, by default the value of the pixels // is that of anImg, so we do not need to change the first and last rows int i = 0; // current line number in input image for (int l = (int)aMaskSize ; l < _height - (int)aMaskSize ; ++l, ++i) { // Update ltabmax and ltabmin GreyLevelImage::pointer smin = ltabmin; GreyLevelImage::pointer smax = ltabmax; // Set ltabmin to max value (255) qgFill(ltabmin, _width, static_cast<GreyLevelImage::value_type>(255)); // Set ltabmax to min value (0) qgFill(ltabmax, _width, static_cast<GreyLevelImage::value_type>(0)); // ii : current line number while computing ltab for (int ii = i ; ii < i + sqsize ; ++ii) { anImg.row(ii, crow); // get the current row of anImg q = crow; smin = ltabmin; smax = ltabmax; for (int j = 0 ; j < _width ; ++j, ++q, ++smin, ++smax) { if (*smax < *q) { *smax = *q; } if (*smin > *q) { *smin = *q; } } // END for j } // END for ii // And now process the current line row(l, orow); // initialize with old values p = orow + aMaskSize; q = crow + aMaskSize; smin = ltabmin, smax = ltabmax; for (int j = (int)aMaskSize ; j < _width - (int)aMaskSize ; ++j, ++smin, ++smax, ++p, ++q) { // On all columns which can be processed GreyLevelImage::value_type curmax = 0; // current maximum GreyLevelImage::value_type curmin = 255; // current minimum GreyLevelImage::pointer slmax = smax; GreyLevelImage::pointer slmin = smin; for (int k = 0 ; k < sqsize ; ++k, ++slmin, ++slmax) { if (curmax < *slmax) { curmax = *slmax; // new maximum } if (curmin > *slmin) { curmin = *slmin; // new minimum } } // END for k // Compute result if ((curmax - *q) < (*q - curmin)) { *p = curmax; } else { *p = curmin; } } // END for j // Write result setRow(l, orow); } // END for l // Clean up delete [] ltabmin; delete [] ltabmax; delete [] crow; delete [] orow; }