移动平均的阈值处理 opencv实现


本系列文章由@邻居张师傅 出品,转载请注明出处。

文章链接: https://editor.csdn.net/md?articleId=106491750

邮箱: [email protected]

当前使用OpenCV版本: 4.0.1


目录

  • 原理
  • 实现
  • 参考


原理

相比于对整幅图像取一个固定的阈值,由于光照不均匀等原因,跟一般的方法是对一幅图像中的每个像素点计算阈值,即可变局部阈值。
算法表示如下:
m ( k + 1 ) = 1 n ∑ i = k + 2 − n k + 1 z i ( 1.1 ) m(k+1)=\frac{1}{n}\sum^{k+1}_{i=k+2-n}z_{i}(1.1) m(k+1)=n1i=k+2nk+1zi1.1
其中, z k + 1 z_{k+1} zk+1表示在扫描序列中第 k + 1 k+1 k+1步遇到的点的灰度值, m ( k ) m(k) m(k)为输入图像的第 k k k个点的像素值, n n n表示用于计算平均的点的数量。
根据(1.1)有下式:
m ( k ) = 1 n ∑ i = k + 1 − n k z i ( 1.2 ) m(k)=\frac{1}{n}\sum^{k}_{i=k+1-n}z_{i}(1.2) m(k)=n1i=k+1nkzi1.2
根据(1.1)、(1.2)不难得出下式子:
m ( k + 1 ) = 1 n ∑ i = k + 2 − n k + 1 z i = m ( k ) + 1 n ( z k + 1 − z k + 1 − n ) ( 1.3 ) m(k+1)=\frac{1}{n}\sum^{k+1}_{i=k+2-n}z_{i}=m(k)+\frac{1}{n}(z_{k+1}-z_{k+1-n})(1.3) m(k+1)=n1i=k+2nk+1zi=m(k)+n1(zk+1zk+1n)1.3
接下来就根据每个点的阈值进行二值化操作。
注:我们仅仅在扫描的点的数量大于n时应用式(1.3),其他情况则将 z k + 1 − n z_{k+1-n} zk+1n视为0,即相当于在图像的边界填充了n-1个0


实现

以下是实现结果,左边是原图,右边是结果。
移动平均的阈值处理 opencv实现_第1张图片下面是代码:

#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include 
#include 

using namespace std;
using namespace cv;

void movingThreshold(const Mat &src,Mat &dst,int n=20,float b=0.75);

int main(){
    Mat src=imread("1.tif",IMREAD_GRAYSCALE);
    namedWindow("src",WINDOW_NORMAL);
    imshow("src",src);

    Mat dst;
    movingThreshold(src,dst);
        namedWindow("dst",WINDOW_NORMAL);

    imshow("dst",dst);
    waitKey();

}

void movingThreshold(const Mat &src,Mat &dst,int n,float b){

    int arrayNum=src.rows*src.cols;
    uchar *temp = new uchar[arrayNum];
    for(int y=0;y<src.rows;y++){//二维转换为一维Z字扫描
        for(int x=0;x<src.cols;x++){
            if(y%2==0)
                temp[y*src.rows+x]=src.at<uchar>(y,x);
            else
                temp[y*src.rows+x]=src.at<uchar>(y,src.cols-1-x);
        }
    }

    dst.create(src.size(),CV_8U);
    float m_now=0,m_pre=0,dif=0;
    int index=0;
    for(int y=0;y<src.rows;y++)
        for(int x=0;x<src.cols;x++){
            index=y*src.rows+x;
            if(index+1<n)//当前点总数不足时
                dif=temp[index];
            else
                dif=temp[index]-temp[index+1-n];

            dif *= 1 / n;
            m_now=m_pre+dif;//得出阈值
            m_pre=m_now;

            if(src.at<uchar>(y,x)>b*m_now)
                dst.at<uchar>(y,x)=255;
            else
                dst.at<uchar>(y,x)=0;
    }
    delete [] temp;
}

参考

1.冈萨雷斯. 数字图像处理[M]. 北京: 电子工业出版社, 2005.

你可能感兴趣的:(Opencv,数字图像处理,C++)