时域去噪看上一篇文章,https://blog.csdn.net/myzhouwang/article/details/84708599,为了进一步去噪,考虑从空域进行!
根据hekaiming的GuidedFilter在灰度图上的滤波思想:平坦区域取均值,方差大的地方取自身,于是写了一下空域去噪代码:
void spannarDeNoise(Mat srcMat, Mat &dst, int radius, int maxCov)
{
Mat srcRef;
Mat channel[3];
Mat channelBlur[3];
split(srcMat, channel);
srcMat.convertTo(srcRef, CV_64FC1);
Mat mean_src, mean_src2, mean_Ip, mean_II;
boxFilter(srcRef, mean_src, CV_64FC1, Size(radius, radius));
boxFilter(srcRef.mul(srcRef), mean_src2, CV_64FC1, Size(radius, radius));
Mat var_I = mean_src2 - mean_src.mul(mean_src);
boxFilter(channel[0], channelBlur[0], CV_8UC1, Size(radius, radius));
boxFilter(channel[1], channelBlur[1], CV_8UC1, Size(radius, radius));
boxFilter(channel[2], channelBlur[2], CV_8UC1, Size(radius, radius));
Mat f1 = srcRef.clone();
f1 = var_I / maxCov;
for (int i = 0; i < srcMat.rows; i++)
{
for (int j = 0; j < srcMat.cols; j++)
{
if (f1.at<double>(i, j) > 1)
{
f1.at<double>(i, j) = 1;
}
double c1 = f1.at<double>(i, j);
double c2 = 1 - c1;
dst.at<Vec3b>(i, j)[0] = c1 * srcMat.at<Vec3b>(i, j)[0] + c2 * channelBlur[0].at<uchar>(i, j);
dst.at<Vec3b>(i, j)[1] = c1 * srcMat.at<Vec3b>(i, j)[1] + c2 * channelBlur[1].at<uchar>(i, j);
dst.at<Vec3b>(i, j)[2] = c1 * srcMat.at<Vec3b>(i, j)[2] + c2 * channelBlur[2].at<uchar>(i, j);
}
}
}
调用是这个函数:
void cycTemSpan()
{
Mat deNoiseImg;
temImg.clear();
while (1)
{
Mat iniFrame;
getFrame(iniFrame);
if (deNoise(iniFrame, deNoiseImg))
{
spannarDeNoise(deNoiseImg, deNoiseImg, 5, 5);
showResult(deNoiseImg);
}
else
{
showResult(iniFrame);
}
}
}
该算法是一种保边的滤波器, 实测比中值保得更好!结果如下:
注意点:
该方法效果好,但是计算方差比较耗时,具体时间没有测,但是感官上比时域去噪慢得多,因为时域去噪只计算链各个像素之间的绝对差值和(SAD),该方法的优化选择是利用其他等效方法代替,比如窗口内最大和最小值的差值等,不能完全等效但未必不是一种可以选择的途径;
视频的保边防模糊防拖影去噪的主要思想:
空域:窗口内差值越大, 自身权值越大,领域像素的权值越小;
时域:与前帧(参考帧)的差值越大,自身权值越小,参考帧权值越大(目的:减少与前帧的差值,缩小抖动,当然还有其他约束,具体上时域去噪的注意点);
总之,视频的噪声主要来源与时域的抖动和空域的领域差值,个人见解,非喜勿喷;