Before introducing Adaptive thresholding, let's look at the concept of Integral Image:
Integral images have been introduced as an efficient way of summing pixels in image regions of interest. They are widely used in applications that involve, for example, computations over sliding windows at multiple scales.
Can be seen, Integral Image avoid a plurality of ROI pixel values and a method for double counting. Next, we achieve the ROI is a simple rectangle, such that each point on the value of the Integral Image: The corner of the image forming point and the pixel values of the rectangular regions and.
The Adaptive thresholding is relative to the fixed thresholding terms. Before we used fixed is fixed threshold, while Adaptive threshold is a fixed threshold and determine a change in the mean, this mean that the average number of pixels around a pixel.
Code
integral.h
In fact, OpenCV has provided a function to calculate the Integral Image of cv::integral, but also to realize his book aside, we here also labeled.
// compute sum over sub-regions of any size from 4 pixel access cv::Vec<T,N> operator()(int xo, int yo, int width, int height) {
// window at (xo,yo) of size width by height return (integralImage.at<cv::Vec<T,N> >(yo+height,xo+width) -integralImage.at<cv::Vec<T,N> >(yo+height,xo) -integralImage.at<cv::Vec<T,N> >(yo,xo+width) +integralImage.at<cv::Vec<T,N> >(yo,xo)); }
// compute sum over sub-regions of any size from 4 pixel access cv::Vec<T,N> operator()(int x, int y, int radius) {
// square window centered at (x,y) of size 2*radius+1 return (integralImage.at<cv::Vec<T,N> >(y+radius+1,x+radius+1) -integralImage.at<cv::Vec<T,N> >(y+radius+1,x-radius) -integralImage.at<cv::Vec<T,N> >(y-radius,x+radius+1) +integralImage.at<cv::Vec<T,N> >(y-radius,x-radius)); } };
// convert to a multi-channel image made of binary planes // nPlanes must be a power of 2 void(const cv::Mat& input, cv::Mat& output, int nPlanes){
// number of bits to mask out int n= 8-static_cast<int>(log(static_cast<double>(nPlanes))/log(2.0)); // mask used to eliminate least significant bits uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
// create a vector of 16 binary images std::vector<cv::Mat> planes; // reduce to nBins bins by eliminating least significant bits cv::Mat reduced= input&mask;
// compute each binary image plane for (int i=0; i<nPlanes; i++) {
// 1 for each pixel equals to i<<shift planes.push_back((reduced==(i<<n))&0x1); // i<<n --> 16, 32, 48, ... }
cv::Mat binary = image.clone(); time = cv::getTickCount(); int nl = binary.rows; // number of lines int nc = binary.cols; // total number of elements per line
// compute integral image cv::Mat iimage; cv::integral(image, iimage, CV_32S);
//for each row int halfSize = blockSize/2; for(int j=halfSize; j<nl - halfSize -1;j++ ){ // get the address of row j uchar* data = binary.ptr<uchar>(j); int* idata1 = iimage.ptr<int>(j-halfSize); // 滑动窗口上边 int* idata2 = iimage.ptr<int>(j+halfSize+1); // 滑动窗口下边
//for pixel of a line for(int i=halfSize; i<nc-halfSize-1;i++){ //compute pix_mean int pix_mean = (idata2[i+halfSize+1]-idata2[i-halfSize]-idata1[i+halfSize+1] +idata1[i-halfSize])/(blockSize*blockSize);
// adaptive threshold using image operators time = cv::getTickCount(); cv::Mat filtered; cv::Mat binaryFiltered; // box filter compute avg of pixels over a rectangle region cv::boxFilter(image, filtered, CV_8U, cv::Size(blockSize,blockSize)); // check if pixel greater than (mean+shreshold) binaryFiltered = image>=(filtered-threshold); time = cv::getTickCount()-time;