零、前言与参考
本文主要是针对光照环境有变化的时候的二值化的,来源于冈萨雷斯的书,并在此基础上进行了一些更改。
更改的主要效果是在有噪声,行列间变化更大的情况下,会更稳定;
主要来源
《数字图像处理》(第三版,中文),冈萨雷斯,P491~492:《使用移动平均》
说明
效果
一、原理
然后再进行二值化。
改进的版本和原本的版本在二值化一步完全相同,不同的是,取得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);//<回传
}
四、结果
可自行运行对比。
五、一个点子
既然可以用均值滤波进行二值化,那么是不是也可以用高斯滤波等其它滤波进行二值化呢?
网友评论