OpenCV系列笔记十七:Adaptive thresholding

五迷三道 提交于 2019-12-02 01:56:11

Overview

在介绍Adaptive thresholding之前,让我们来看看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.

可以看到,Integral Image是避免重复计算多个ROI像素值和的一种方法。接下来,我们实现的就是简单的矩形ROI,使得Integral Image上的每一个点的值为:该点和图像左上角形成的矩形区域像素值之和。

而Adaptive thresholding 是相对于fixed thresholding而言的。fixed就是我们之前常用的固定阀值,而Adaptive的阀值是由一个固定阀值和一个变化的均值决定的,这个均值,就是某像素点周围一些像素点的均值。

Code

integral.h

实际上,OpenCV已经提供了计算Integral Image的函数cv::integral,但是书上也自己实现了一边,我们这里也贴上。

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
#define IINTEGRAL#include <opencv2/core.hpp>#include <opencv2/highgui.hpp>#include <opencv2/imgproc.hpp>#include <vector>template <typename T, int N>class IntegralImage {      cv::Mat integralImage;  public:      IntegralImage(cv::Mat image) {                cv::integral(image,integralImage,cv::DataType<T>::type);      }      // 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 2void (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, ...        }        // create multi-channel image        cv::merge(planes,output);}#endif
main.cpp

这里介绍了,OpenCV自带的fixed thresholding, Adaptive thresholding, boxFilter的用法,同时运用Integral Image重新实现了一遍Adaptive thresholding.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
#include <cv.h>#include <highgui.h>#include <opencv2/imgcodecs.hpp>#include <opencv/cv.hpp>#include <iostream>#include "integral.h"int main(){    cv::Mat image = cv::imread("/home/shensir/Documents/MyPrograming/Cpp/Clions/data/book.png",0);    // display original image    cv::namedWindow("Original Image");    cv::imshow("Original Image", image);    // using a fixed threshold    cv::Mat binaryFixed;    cv::Mat binaryAdaptive;    cv::threshold(image, binaryFixed,70,255,cv::THRESH_BINARY);    //using as adaptive threshold    int blockSize=21;  //size of the neighborhood    int threshold=10;  // pixel will be compare to (mean-threshold)    int64 time;    time = cv::getTickCount();    cv::adaptiveThreshold(            image,  //input image            binaryAdaptive, // output binary image            255,  //max value for output            cv::ADAPTIVE_THRESH_GAUSSIAN_C, // adaptive method            cv::THRESH_BINARY, //threshold type            blockSize,            threshold    );    time = cv::getTickCount() - time;    std::cout<<"time (adaptiveThreshold) =  "<<time<<endl;    // compute integral image    IntegralImage<int, 1>integral(image);    // test integral image//    cout<<"sum = "<<integral(18, 45,30, 50)<<endl;//    cv::Mat test(image, cv::Rect(18,45,30,50));//    cv::Scalar t = cv::sum(test);//    cout<<"sum test = "<<t[0]<<endl;    cv::namedWindow("Fixed Threshold");    cv::imshow("Fixed Threshold", binaryFixed);    cv::namedWindow("Adaptive Threshold");    cv::imshow("Adaptive Threshold", binaryAdaptive);    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);            //apply adaptive threshold            if(data[i]<(pix_mean-threshold))                data[i] = 0;            else                data[i]  =255;        }    }    // add white border    for(int j=0;j<halfSize;j++){        uchar *data = binary.ptr<uchar>(j);        for(int i=0; i<binary.cols;i++)            data[i] = 255;    }    for(int j=binary.rows-halfSize-1;j<binary.rows;j++){        uchar * data = binary.ptr<uchar>(j);        for(int i=0; i<binary.cols;i++){            data[i] = 255;        }    }    for(int j=halfSize;j<nl-halfSize-1;j++){        uchar* data = binary.ptr<uchar>(j);        for(int i=0; i<halfSize;i++)            data[i] = 255;        for(int i=binary.cols-halfSize-1;i<binary.cols;i++)            data[i] = 255;    }    time = cv::getTickCount()-time;    cout<<"time integral= "<<time<<endl;    cv::namedWindow("Adaptive Threshold (integral)");    cv::imshow("Adaptive Threshold (integral)", binary);    // 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;    cout<<"time filtered= "<<time<<endl;    cv::namedWindow("Adaptive filtered");    cv::imshow("Adaptive filtered", binaryFiltered);    cv::waitKey();    return 0;}

输出:

time (adaptiveThreshold) = 2305893
time integral= 7118664
time filtered= 1179760

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!