美文网首页
移动均值二值化

移动均值二值化

作者: 寽虎非虫003 | 来源:发表于2021-06-28 17:43 被阅读0次

    零、前言与参考

    本文主要是针对光照环境有变化的时候的二值化的,来源于冈萨雷斯的书,并在此基础上进行了一些更改。
    更改的主要效果是在有噪声,行列间变化更大的情况下,会更稳定;

    主要来源

    《数字图像处理》(第三版,中文),冈萨雷斯,P491~492:《使用移动平均》


    说明
    效果

    一、原理

    以m_{k}表示像素k处的移动平均值;\\ 以I_k表示k处的像素值\\ 以n个像素值俩计算平均;\\ b表示分割比例;\\ 则\\ \begin{equation} m_{k+1} = \left\{ \begin{aligned} {\frac{1}{n}\sum_{i=k+2-n}^{k+1}, k\geq n-1\\ m_k+\frac{1}{n}(z_{k+1})-z_{k-n}, k\geq n+1} \end{aligned} \right. \end{equation}\\ n取兴趣区域大小的5倍;

    然后再进行二值化。

    \begin{equation} g_{(x,y)} = \left\{ \begin{aligned} {1, f_{(x,y)}\geq bm_{(x,y)}\\ 0, f_{(x,y)}\leq bm_{(x,y)}} \end{aligned} \right. \end{equation}\\ 一般 b 取0.5;\\

    改进的版本和原本的版本在二值化一步完全相同,不同的是,取得m_k的方式,改进版本的取得m_k是由滑窗均值滤波取得,而滤波卷积核的半窗值为感兴趣区域大小的2倍或更多;

    二、基本实现

    此部分代码来源于移动平均的阈值处理 opencv实现,但是这份代码只实现了按行进行移动平均的处理。

    void ThresholdMeanMove(const Mat &src, Mat &dst, int n = 20, float b = 0.5f)
    {
        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.cols + x] = src.at<uchar>(y, x);
                else
                    temp[y*src.cols + 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.cols + x;
                if (index < n)//当前点总数不足时
                    dif = temp[index];
                else
                    dif = temp[index] - temp[index - n];
    
                dif *= (float)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;
    }
    

    三、改进实现

    使用均值滤波来得到均值的,而不是只是用逐行z形求均值。

    void ThresholdMeanMoveWindow(const Mat &src, Mat &dst, int nWindowHalf = 10, float b = 0.5f)
    {
        Mat m;//计算均值
        blur(src, m, Size(2*nWindowHalf+1, 2*nWindowHalf+1), Point(-1, -1), 4);
        dst = src > (b*m);
    }
    

    cuda加速

    void ThresholdMeanMoveWindow_gpu(const Mat &src, Mat &dst, int nWindowHalf, float b)
    {
        Mat m;//计算均值
    
        cv::cuda::GpuMat d_m, d_Src, d_Dst;
        d_Src.upload(src);
        //d_Dst.upload(src);
        //d_m.upload(src);
    
        cv::Ptr<cv::cuda::Filter> median = cv::cuda::createMedianFilter(d_Src.type(), nWindowHalf);
        median->apply(d_Src, d_m);
        cv::cuda::multiply(d_m, b, d_m);//<d_m与比例相乘
        cv::cuda::compare(d_Src, d_m, d_Dst, CMP_GE);//<比较
        d_Dst.download(dst);//<回传
    }
    

    四、结果

    可自行运行对比。

    五、一个点子

    既然可以用均值滤波进行二值化,那么是不是也可以用高斯滤波等其它滤波进行二值化呢?

    相关文章

      网友评论

          本文标题:移动均值二值化

          本文链接:https://www.haomeiwen.com/subject/ziiqultx.html