Opencv 模拟各向同性线性扩散平滑
我想应用我在标题中命名的去噪过滤器,它基于以下等式: 其中,Opencv 模拟各向同性线性扩散平滑,opencv,filtering,smoothing,Opencv,Filtering,Smoothing,我想应用我在标题中命名的去噪过滤器,它基于以下等式: 其中,d=1是标量常数扩散系数参数,I(x,y)是初始噪声图像,u(x,y,t)是扩散时间t后获得的图像,假设5、10和30。然而,为了在OpenCV中实现这一点,我对使用哪个函数以及如何使用感到非常困惑。我觉得这很简单,但出于某种原因,我感到困惑。有人有主意吗 以下是一个示例图像: 然后,我想将其与高斯滤波方法进行比较,该方法符合以下要求: 其中G√2t(x,y)是高斯核。这证明了对t时间d=1执行各向同性线性扩散与对σ=√(2t)
d=1
是标量常数扩散系数参数,I(x,y)
是初始噪声图像,u(x,y,t)
是扩散时间t
后获得的图像,假设5、10和30
。然而,为了在OpenCV中实现这一点,我对使用哪个函数以及如何使用感到非常困惑。我觉得这很简单,但出于某种原因,我感到困惑。有人有主意吗
以下是一个示例图像:
然后,我想将其与高斯滤波方法进行比较,该方法符合以下要求:
其中G√2t(x,y)
是高斯核。这证明了对t
时间d=1
执行各向同性线性扩散与对σ=√(2t)
我有一个应用高斯滤波的函数:
void gaussian_2D_convolution(const cv::Mat& src, cv::Mat& dst, const float sigma, const int ksize_x = 0, const int ksize_y = 0)
{
int ksize_x_ = ksize_x, ksize_y_ = ksize_y;
// Compute an appropriate kernel size according to the specified sigma
if (sigma > ksize_x || sigma > ksize_y || ksize_x == 0 || ksize_y == 0)
{
ksize_x_ = (int)ceil(2.0f*(1.0f + (sigma - 0.8f) / (0.3f)));
ksize_y_ = ksize_x_;
}
// The kernel size must be and odd number
if ((ksize_x_ % 2) == 0)
{
ksize_x_ += 1;
}
if ((ksize_y_ % 2) == 0)
{
ksize_y_ += 1;
}
// Perform the Gaussian Smoothing
GaussianBlur(src, dst, Size(ksize_x_, ksize_y_), sigma, sigma, BORDER_DEFAULT);
// show result
std::ostringstream out;
out << std::setprecision(1) << std::fixed << sigma;
String title = "sigma: " + out.str();
imshow(title, dst);
imwrite("gaussian/" + title + ".png", dst);
waitKey(260);
}
void gaussian_2D_卷积(常数cv::Mat&src,cv::Mat&dst,常数float sigma,常数int ksize_x=0,常数int ksize_y=0)
{
int ksize_x_uu=ksize_x,ksize_y_uu=ksize_y;
//根据指定的sigma计算适当的内核大小
如果(sigma>ksize|x | sigma>ksize|y | ksize|x==0 | | ksize|y==0)
{
ksize_x_=(int)ceil(2.0f*(1.0f+(sigma-0.8f)/(0.3f));
ksize_y_uu=ksize_x_uu;
}
//内核大小必须为1和奇数
如果((ksize_x_u%2)==0)
{
ksize_x_u+=1;
}
如果((ksize_y_%2)==0)
{
ksize_y_+=1;
}
//执行高斯平滑
GaussianBlur(src、dst、Size(ksize_x_、ksize_y_)、sigma、sigma、BORDER_默认值);
//显示结果
std::ostringstream out;
out这应该按预期工作。这是基于:
- 关于你的问题的评论
代码:
#包括
使用名称空间cv;
空隙ILD(常数Mat1b和src、Mat1b和dst、int iter=10、双扩散系数=1.0、双λ=0.1)
{
Mat1f-img;
src.convertTo(仪表组,CV_32F);
lambda=fmax(0.001,std::fmin(lambda,0.25));//默认情况下[0,0.25]中的某些内容应该是0.25
而(国际热核实验堆--)
{
Mat1f圈;
拉普拉斯(img、lap、CV_32F);
img+=λ*扩散系数*搭接;
}
img.convertTo(dst,CV_8U);
}
int main(){
Mat1b img=imread(“路径到图像”,imread\U灰度);
Mat1b res_ilds;
国际标准(img、res_-ilds);
imshow(“ILDS”,res_ILDS);
waitKey();
返回0;
}
结果:
让我知道它是否适合你Hi@Miki谢谢你的回答和你的时间。我一回到我的工作站就会尝试。但是有一个问题,因为你的方法基于Perona-Malik方法,所以它不是模拟等距线性平滑,而是各向异性非线性,对吗?@theodore它是isotropic!P&M:I+=lambda*(g(dN)。*dN+g(dS)。*dS+g(dE)。*dE+g(dW)。*dW)
,其中dN
是图像在北向的空间导数,依此类推。函数g确定扩散行为。如果g(x)=1
(类似于本例)这是标准的各向同性扩散。好的,我看到运行你的代码可以像你说的那样工作。但是,我想验证一些事情。据我所知,g
函数对应于扩散系数参数d
对吗?如果是,那么你的代码可以更正确地转换为img+=lambda*d*lap;
其中 d
是1。此外,iter
变量表示扩散时间t
参数,对吗?但是,如果我对iter
使用值5,则应对应于σ=√(2t)=3.2
用于高斯平滑,两者应给出相同的结果,但它们没有。此外,在我的初始公式中,没有提到任何lambda
变量,因此如何将其添加到计算中。最后,您使用拉普拉斯滤波器以获得导数,我可以使用sobel或scharr滤波器用于ge吗修正导数,这会改变什么,或者我将使用哪种方法来获得它并不重要。@theodoreimg+=lambda*d*lap
正确。iter
正确。如果我使用……实际上不知道。lambda
在P&M公式中,你可以将其修正为默认值0.25。你需要拉普拉斯算子,你可以合作和索贝尔一起计算,但我看不出有什么好的理由。让我知道
#include <opencv2\opencv.hpp>
using namespace cv;
void ilds(const Mat1b& src, Mat1b& dst, int iter = 10, double diffusivity = 1.0, double lambda = 0.1)
{
Mat1f img;
src.convertTo(img, CV_32F);
lambda = fmax(0.001, std::fmin(lambda, 0.25)); // something in [0, 0.25] by default should be 0.25
while (iter--)
{
Mat1f lap;
Laplacian(img, lap, CV_32F);
img += lambda * diffusivity * lap;
}
img.convertTo(dst, CV_8U);
}
int main() {
Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);
Mat1b res_ilds;
ilds(img, res_ilds);
imshow("ILDS", res_ilds);
waitKey();
return 0;
}