《光照不均匀图像的灰度波动局部阈值分割》opencv编码实现

来源:互联网 发布:matlab画出网络拓扑图 编辑:程序博客网 时间:2024/04/30 18:38

关于论文

最近遇到了需要处理图像上光照不均匀的问题,参考了论文《光照不均匀图像的灰度波动局部阈值分割》的方法,很感谢作者提供的思路,觉得它的效果很好,对图像的分析也比较到位。

各种算法实验结果对比

实际尝试以后发现这种方法适用于整个范围上的光照不均匀,我们遇到的问题还有阴影遮挡、局部高光等,因此暂时用不上这段编码了,贴在这里供大家参考。关于论文请戳链接。


分析与opencv实现

  • 因为纵向的处理只要将源图像Mat转置输入函数,再转置一次就能得到结果,这里只写了横向实现
  • 对于不同方向、峰和谷的搜索只使用一个函数添加参数组合实现
  • 方法中比较依赖阈值T、和波动阈值系数的取值,使用需要反复对这两个值调节

关于第三点分析,摘取部分原文中的说明:

对于阈值 T 的选取,理论上是依据整幅图像中所有灰度波动曲线的最大灰度值和最小灰度值之间的差值来确定……对阈值 T 的准确选择,还可以借助神经网络的方法对特定类别的图像进行训练,从而获得阈值 T ……

然而,浮动参数的选择是为了更加灵活地控制目标分割宽度的程度……

流程图

代码的设计思路:

Created with Raphaël 2.1.0源图像的某一行查找所有极值点找到首个波峰或波谷查找下一个波谷或波峰对峰和谷之间的区域二值化搜索结束?二值化结果yesno

代码

沿水平方向的阈值化函数:

Mat AutoHThreshold(const Mat& src, const int thresh, const float thr_ratio) {    const int src_width = src.cols;    const int src_height = src.rows;    Mat thr_res = Mat::zeros(src_height, src_width, CV_8U);    for (int j = 0; j < src_height; j++) {        Mat ext_log = Mat::zeros(1, src_width, CV_32S);        int max_val = 0, min_val = 255;        int max_index = -1, min_index = -1;        for (int i = 1; i < src_width - 1; i++) {            int curr_val = src.at<uchar>(j, i);            int last_val = src.at<uchar>(j, i - 1);            int next_val = src.at<uchar>(j, i + 1);            // 寻找极大值            if (curr_val >= last_val && curr_val >= next_val) {                ext_log.at<int>(0, i) = 1;                if (curr_val > max_val) {                    max_val = curr_val;                    max_index = i;                }            }            // 寻找极小值            if (curr_val <= last_val && curr_val <= next_val) {                ext_log.at<int>(0, i) = -1;                if (curr_val < min_val) {                    min_val = curr_val;                    min_index = i;                }            }        }        // 确定首个波峰点或波谷点        int start_index, end_index;        end_index = MIN(max_index, min_index);        start_index = end_index + 1;        while (start_index > end_index) {            // 将上一次的左端点作为本次的右端点            start_index = end_index;            // 找到下一个波峰点或波谷点            end_index = FindNextBottomOrTop(src.row(j), ext_log, thresh,                start_index, -1);            // 根据交替的波峰和波谷二值化            ThresholdByBottomAndTop(src.row(j), ext_log, thr_ratio,                end_index, start_index, &thr_res.row(j));        }        ……    }    return thr_res;}

沿指定方向搜索下一个波峰或波谷的函数:

int FindNextBottomOrTop(const Mat& src, const Mat& ext_log,    const int thresh, const int start_index, const int step) {    int start_sign = ext_log.at<int>(0, start_index);    for (int n = start_index + step; n >= 0 && n < src.cols; n += step) {        // 获取当前位置的极性        int curr_sign = ext_log.at<int>(0, n);        if (curr_sign == 0) continue;        // 找出最小的极小值(极大值)        int curr_val = src.at<uchar>(0, n);        if ((curr_val - ext_val)*start_sign < 0) {            ext_val = curr_val;            ext_index = n;        }        // 找出满足阈值的极大值(极小值)        if (curr_sign * start_sign > 0 && abs(curr_val - ext_val) > thresh)            break;    }    return ext_index;}

阈值化函数很简单,这里就不写了。
可运行代码可以戳这里下载。

原创粉丝点击