- 操作系统:ubuntu22.04
- OpenCV版本:OpenCV4.9
- IDE:Visual Studio Code
- 编程语言:C++11
算法描述
原始-对偶算法是用于解决特定类型变分问题(即,寻找一个函数以最小化某个泛函)的算法。特别地,图像去噪可以被视为一种变分问题,因此可以使用原始-对偶算法来进行去噪,这正是这里实现的内容。
需要注意的是,此实现取自2013年7月的一篇博客文章[194],该文章还包含了(稍微更通用的)现成的Python源代码。随后,Vadim Pisarevsky在2013年7月底用C++和OpenCV重写了这段代码,并最终由后续作者对其进行了轻微调整。
尽管可以在[49]中找到对该算法的详细讨论和理论依据,但在这里根据[194]简要概述一下是有意义的。首先,我们将1字节灰度级图像视为从像素矩形域(可以看作是集合{(x,y)∈N×N∣1≤x≤n,1≤y≤m},对于某些m,n∈N)到{0,1,…,255}的函数。我们将噪声图像表示为fi,并且在这种视角下,给定相同大小的图像x,我们可以通过以下公式衡量它的“坏程度”:
∥
∥
∇
x
∥
∥
+
λ
∑
i
∥
∥
x
−
f
i
∥
∥
\left\|\left\|\nabla x\right\|\right\| + \lambda\sum_i\left\|\left\|x-f_i\right\|\right\|
∥∥∇x∥∥+λi∑∥∥x−fi∥∥ 这里的
∥
∥
⋅
∥
∥
\|\|\cdot\|\|
∥∥⋅∥∥
表示L2范数,如你所见,第一个加项表明我们希望我们的图像尽可能平滑(理想情况下,梯度为零,从而保持常数),第二个加项则表明我们希望结果接近我们得到的观测值。如果我们把x视为一个函数,这就是我们寻求最小化的泛函,而此时原始-对偶算法就派上用场了。
cv::denoise_TVL1 是 OpenCV 中用于图像去噪的一个函数,它使用基于总变分(Total Variation, TV)的 L1 正则化方法来处理图像噪声。这种方法特别适合于去除图像中的加性噪声,同时尽可能保留边缘信息。
函数原型
void cv::denoise_TVL1
(
const std::vector< Mat > & observations,
Mat & result,
double lambda = 1.0,
int niters = 30
)
参数
- 参数observations 这个数组应该包含一个或多个需要被恢复的图像的噪声版本。
- 参数result 去噪后的图像将存储在这里。不需要预先分配存储空间,因为如果必要的话会自动分配。
- 参数lambda 对应于上述公式中的λ。随着它的增大,更平滑(模糊)的图像相比细节丰富(但可能有更多的噪声)的图像会被更优地对待。粗略地说,随着它变小,结果会更加模糊,但可以去除更多的严重异常值。
- 参数niters 算法运行的迭代次数。当然,迭代次数越多越好,但是很难从定量的角度来精确说明这一点,因此通常使用默认值并在结果不佳时增加迭代次数。
代码示例
#include <opencv2/opencv.hpp>
#include <vector>
using namespace cv;
using namespace std;
int main()
{
// 加载一组观察图像(例如,多次拍摄的同一场景)
vector< Mat > observations;
observations.push_back( imread( "noisy_image_1.jpg", IMREAD_GRAYSCALE ) );
observations.push_back( imread( "noisy_image_2.jpg", IMREAD_GRAYSCALE ) );
observations.push_back( imread( "noisy_image_3.jpg", IMREAD_GRAYSCALE ) );
if ( observations[ 0 ].empty() || observations[ 1 ].empty() || observations[ 2 ].empty() )
{
cout << "Could not open or find the images!" << endl;
return -1;
}
// 确保所有图像具有相同的大小和类型
for ( size_t i = 1; i < observations.size(); ++i )
{
if ( observations[ i ].size() != observations[ 0 ].size() || observations[ i ].type() != observations[ 0 ].type() )
{
cout << "All images must have the same size and type." << endl;
return -1;
}
}
Mat result;
// 使用默认参数调用 denoise_TVL1 函数
denoise_TVL1( observations, result );
// 显示原始图像和去噪后的结果
imshow( "Noisy Image 1", observations[ 0 ] );
imshow( "Denoised Image", result );
waitKey( 0 );
return 0;
}