基础概念
在OpenCV联合C++中给一张图片添加泊松噪声(Poisson Noise)可以通过生成随机数并在图像的每个像素上加上这些随机数来实现。泊松噪声是一种统计分布服从泊松分布的噪声,通常用于模拟光子计数等场景。
使用泊松噪声的场景
泊松噪声通常用于模拟光子计数过程中的噪声,例如在低光条件下拍摄的照片中,由于光子计数的统计特性,会产生这种类型的噪声。因此,在进行图像增强、图像去噪等处理时,添加泊松噪声可以帮助评估算法在实际应用中的鲁棒性。
示例代码1
以下是一个使用OpenCV和C++给一张图片添加泊松噪声的示例代码:
#include <opencv2/opencv.hpp>
#include <iostream>
#include <random>
// 添加泊松噪声的函数
void addPoissonNoise(cv::Mat &image, double scale = 1.0)
{
// 创建随机数生成器
std::random_device rd;
std::default_random_engine gen(rd());
std::poisson_distribution<int> dist(1.0); // 泊松分布
// 获取图像的行数和列数
int rows = image.rows;
int cols = image.cols;
// 遍历图像中的每一个像素
for (int i = 0; i < rows; ++i)
{
for (int j = 0; j < cols; ++j)
{
// 生成一个泊松分布的随机数
int noise = dist(gen);
// 加上噪声
//image.at<uchar>(i, j) = std::min(std::max(image.at<uchar>(i, j) + noise * scale, 0), 255);
image.at<uchar>(i, j) = std::min(std::max((int)(image.at<uchar>(i, j) + noise * scale), 0), 255);
}
}
}
int main()
{
// 读取图像
cv::Mat img = cv::imread("02.png", cv::IMREAD_GRAYSCALE);
if (img.empty())
{
std::cerr << "Error loading image." << std::endl;
return -1;
}
// 添加泊松噪声
addPoissonNoise(img, 1.0); // scale 为 1.0
// 显示原始图像
cv::namedWindow("Original Image", cv::WINDOW_NORMAL);
cv::imshow("Original Image", img);
// 显示添加噪声后的图像
cv::namedWindow("Noisy Image", cv::WINDOW_NORMAL);
cv::imshow("Noisy Image", img);
cv::waitKey(0);
return 0;
}
代码解释
1. 读取图像:使用 cv::imread 函数读取原始图像,并将其转换为灰度图像。
2. 添加泊松噪声:定义一个 addPoissonNoise 函数,该函数接受一个图像矩阵 image 和一个缩放因子 scale。缩放因子 scale 控制噪声的强度。
3. 随机数生成器:使用 <random> 头文件中的 std::random_device 和 std::default_random_engine 生成随机数,std::poisson_distribution 生成符合泊松分布的随机数。
4. 遍历图像:遍历图像的每一个像素点,根据生成的泊松分布随机数给像素值加上噪声。
5. 限制像素值范围:确保像素值在0到255之间,避免超出8位灰度图像的范围。
6. 显示图像:使用 cv::imshow 函数显示原始图像和添加噪声后的图像。
参数调整
•缩放因子 scale:控制噪声的强度,可以根据需要调整该参数。较大的 scale 值会导致更强的噪声。注意事项
•噪声强度:通过调整 scale 参数可以控制噪声的强度。
•数据类型:在加噪声时,需要注意像素值的数据类型。在上面的示例中,我们使用了 uchar 类型,因此需要确保像素值在0到255之间。
•性能优化:如果图像较大,遍历每一个像素可能会比较耗时,可以考虑使用OpenCV提供的并行处理方法,如 cv::parallel_for_ 等。
通过上述方法,你可以很容易地在OpenCV和C++中给一张图片添加泊松噪声。这对于模拟真实世界中的噪声情况非常有用,尤其是在图像处理和计算机视觉的研究和应用中。
运行结果1
除噪方法
在OpenCV联合C++中去除一张图片上的泊松噪声(Poisson Noise),可以采用多种滤波方法。泊松噪声通常表现为与图像亮度相关的噪声,因此需要选择一种能够适应这种特性的滤波方法。以下是一些常用的滤波方法及其适用性:
1. 非局部均值去噪(Non-Local Means Denoising)
非局部均值去噪(NL-means)是一种高级去噪方法,它通过查找图像中的相似区域来进行去噪。这种方法可以在保持图像细节的同时去除噪声,尤其适用于泊松噪声。
示例代码
#include <opencv2/opencv.hpp>
#include <iostream>
int main()
{
// 读取图像
cv::Mat img = cv::imread("path/to/noisy_image.jpg", cv::IMREAD_GRAYSCALE);
if (img.empty())
{
std::cerr << "Error loading image." << std::endl;
return -1;
}
// 显示原始噪声图像
cv::namedWindow("Noisy Image", cv::WINDOW_NORMAL);
cv::imshow("Noisy Image", img);
// 应用非局部均值去噪
cv::Mat denoisedImg;
cv::fastNlMeansDenoising(img, denoisedImg, 10, 7, 21); // h=10, templateWindowSize=7, searchWindowSize=21
// 显示去噪后的图像
cv::namedWindow("Denoised Image", cv::WINDOW_NORMAL);
cv::imshow("Denoised Image", denoisedImg);
cv::waitKey(0);
return 0;
}
运行结果
2. 双边滤波(Bilateral Filtering)
双边滤波是一种非局部均值滤波方法,它在平滑图像的同时能够较好地保留边缘。双边滤波不仅考虑空间邻域,还考虑像素值的相似性,因此在去除泊松噪声的同时,可以较好地保留图像细节。
示例代码
#include <opencv2/opencv.hpp>
#include <iostream>
int main()
{
// 读取图像
cv::Mat img = cv::imread("path/to/noisy_image.jpg", cv::IMREAD_GRAYSCALE);
if (img.empty())
{
std::cerr << "Error loading image." << std::endl;
return -1;
}
// 显示原始噪声图像
cv::namedWindow("Noisy Image", cv::WINDOW_NORMAL);
cv::imshow("Noisy Image", img);
// 应用双边滤波
cv::Mat denoisedImg;
cv::bilateralFilter(img, denoisedImg, 9, 75, 75); // d=9, sigmaColor=75, sigmaSpace=75
// 显示去噪后的图像
cv::namedWindow("Denoised Image", cv::WINDOW_NORMAL);
cv::imshow("Denoised Image", denoisedImg);
cv::waitKey(0);
return 0;
}
运行结果
3. 高斯滤波(Gaussian Filtering)
高斯滤波是一种经典的平滑方法,可以用于去除高斯噪声。尽管泊松噪声与高斯噪声有所不同,但在某些情况下,高斯滤波仍然可以作为一种简单的去噪方法。
示例代码
#include <opencv2/opencv.hpp>
#include <iostream>
int main()
{
// 读取图像
cv::Mat img = cv::imread("path/to/noisy_image.jpg", cv::IMREAD_GRAYSCALE);
if (img.empty())
{
std::cerr << "Error loading image." << std::endl;
return -1;
}
// 显示原始噪声图像
cv::namedWindow("Noisy Image", cv::WINDOW_NORMAL);
cv::imshow("Noisy Image", img);
// 应用高斯滤波
cv::Mat denoisedImg;
cv::GaussianBlur(img, denoisedImg, cv::Size(3, 3), 0); // ksize 为 3x3 的高斯滤波
// 显示去噪后的图像
cv::namedWindow("Denoised Image", cv::WINDOW_NORMAL);
cv::imshow("Denoised Image", denoisedImg);
cv::waitKey(0);
return 0;
}
运行结果
4. 维纳滤波(Wiener Filtering)
维纳滤波是一种基于最小均方误差估计的滤波方法,可以用于去除各种类型的噪声,包括泊松噪声。维纳滤波需要估计噪声的功率谱密度和信号的功率谱密度。示例代码维纳滤波在OpenCV中没有直接的支持,但可以通过自定义实现。
这里提供一个简化的伪代码示例:
示例代码
#include <opencv2/opencv.hpp>
#include <iostream>
void applyWienerFilter(const cv::Mat &input, cv::Mat &output, double noiseVariance)
{
// 假设输入图像为灰度图像
cv::Mat fftInput, fftOutput, psf, noisePower, signalPower, wienerKernel;
// 计算输入图像的傅里叶变换
cv::dft(input, fftInput);
// PSF(点扩散函数)可以是高斯核或其他核
cv::GaussianBlur(cv::Mat::ones(input.size(), CV_32F), psf, cv::Size(3, 3),0);
// 计算PSF的傅里叶变换
cv::dft(psf, psf);
// 计算噪声功率谱密度
noisePower = cv::Mat::ones(fftInput.size(), CV_32F) * noiseVariance;
// 估计信号功率谱密度
signalPower = cv::abs(psf) * cv::abs(psf);
// Wiener 滤波器
wienerKernel = signalPower / (signalPower + noisePower);
// 应用Wiener滤波器
cv::mulSpectrums(fftInput, wienerKernel, fftOutput, 0);
// 反傅里叶变换
cv::dft(fftOutput, fftOutput, cv::DFT_INVERSE | cv::DFT_SCALE);
// 逆变换回空间域
cv::idft(fftOutput, output);
}
int main()
{
// 读取图像
cv::Mat img = cv::imread("path/to/noisy_image.jpg", cv::IMREAD_GRAYSCALE);
if (img.empty())
{
std::cerr << "Error loading image." << std::endl;
return -1;
}
// 显示原始噪声图像
cv::namedWindow("Noisy Image", cv::WINDOW_NORMAL);
cv::imshow("Noisy Image", img);
// 应用维纳滤波
cv::Mat denoisedImg;
applyWienerFilter(img, denoisedImg, 10.0); // 假设噪声方差为 10.0
// 显示去噪后的图像
cv::namedWindow("Denoised Image", cv::WINDOW_NORMAL);
cv::imshow("Denoised Image", denoisedImg);
cv::waitKey(0);
return 0;
}
运行结果
总结
•非局部均值去噪(Non-Local Means Denoising):适用于需要保留图像细节的情况,能够较好地去除泊松噪声。
•双边滤波(Bilateral Filtering):在平滑图像的同时能够较好地保留边缘,适用于需要保持图像细节的情况。
•高斯滤波(Gaussian Filtering):简单易用,但在处理泊松噪声时效果可能不如非局部均值去噪和双边滤波。
•维纳滤波(Wiener Filtering):适用于需要精确去噪的情况,但实现较为复杂。
根据具体的应用需求和图像特点,可以选择最适合的方法。如果需要去除泊松噪声同时尽量保留图像细节,可以优先考虑非局部均值去噪和双边滤波。如果需要更高级的去噪效果,可以考虑维纳滤波。