- 操作系統: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;
}