2.均值滤波图像平滑常用于图像的预处理中,如计算梯度时先对图像进行平滑处理,可以减少噪声对梯度的影响。图像平滑一般是通过模板卷积运算实现。模板可以看做是一个大小为nxn的小图像,例如3x3,5x5等等,模板的每个像素都对应一个系数值。模板卷积运算的过程是首先将模板中心依次与图像每个像素重合,通过模板各个系数与图像对应像素相乘来计算模板对应像素的加权平均值,最后将运算结果赋给图像中模板中心对应的像素。
均值滤波是一种经常用到的平滑方法,其对应的模板各个像素的值为1。在VTK中没有直接实现均值滤波的类,但是我们可以通过图像卷积运算来实现。卷积运算通过vtkImageConvolve类实现。通过vtkImageConvolve类,只需要设置相应的卷积模板,便可以实现多种空域图像滤波。
下面代码说明了怎样使用vtkImageConvolve类来实现图像的均值滤波:
1 #include <vtkAutoInit.h>
2 VTK_MODULE_INIT(vtkRenderingOpenGL);
3
4 #include <vtkSmartPointer.h>
5 #include <vtkJPEGReader.h>
6 #include <vtkImageCast.h> //图像数据类型转换为计算类型
7 #include <vtkImageData.h>
8 #include <vtkImageConvolve.h> //图像卷积运行
9 #include <vtkImageShiftScale.h> //设置像素值范围
10 //#include <vtkImageMandelbrotSource.h>
11 #include <vtkImageActor.h>
12 #include <vtkRenderer.h>
13 #include <vtkImageMandelbrotSource.h>
14 #include <vtkRenderWindow.h>
15 #include <vtkRenderWindowInteractor.h>
16 #include <vtkInteractorStyleImage.h>
17
18 int main()
19 {
20 vtkSmartPointer<vtkJPEGReader> reader =
21 vtkSmartPointer<vtkJPEGReader>::New();
22 reader->SetFileName("lena.jpg");
23 reader->Update();
24
25 vtkSmartPointer<vtkImageCast> originalCastFilter =
26 vtkSmartPointer<vtkImageCast>::New();
27 originalCastFilter->SetInputConnection(reader->GetOutputPort()); //建管线
28 originalCastFilter->SetOutputScalarTypeToFloat(); //设置属性
29 originalCastFilter->Update();
30
31 vtkSmartPointer<vtkImageConvolve> convolveFilter =
32 vtkSmartPointer<vtkImageConvolve>::New();
33 convolveFilter->SetInputConnection(originalCastFilter->GetOutputPort()); //建管线
34
35 double kernel[25] = {
36 0.04, 0.04, 0.04, 0.04, 0.04,
37 0.04, 0.04, 0.04, 0.04, 0.04,
38 0.04, 0.04, 0.04, 0.04, 0.04,
39 0.04, 0.04, 0.04, 0.04, 0.04,
40 0.04, 0.04, 0.04, 0.04, 0.04
41 };
42 convolveFilter->SetKernel5x5(kernel);
43 convolveFilter->Update();
44
45 vtkSmartPointer<vtkImageCast> convCastFilter =
46 vtkSmartPointer<vtkImageCast>::New();
47 convCastFilter->SetInputData(convolveFilter->GetOutput());
48 convCastFilter->SetOutputScalarTypeToUnsignedChar(); //转换为图像数据
49 convCastFilter->Update();
50 ///
51 vtkSmartPointer<vtkImageActor> originalActor =
52 vtkSmartPointer<vtkImageActor>::New();
53 originalActor->SetInputData(reader->GetOutput());
54
55 vtkSmartPointer<vtkImageActor> convolvedActor =
56 vtkSmartPointer<vtkImageActor>::New();
57 convolvedActor->SetInputData(convCastFilter->GetOutput());
58
59 double leftViewport[4] = { 0.0, 0.0, 0.5, 1.0 };
60 double rightViewport[4] = { 0.5, 0.0, 1.0, 1.0 };
61
62 vtkSmartPointer<vtkRenderer> originalRenderer =
63 vtkSmartPointer<vtkRenderer>::New();
64 originalRenderer->SetViewport(leftViewport);
65 originalRenderer->AddActor(originalActor);
66 originalRenderer->SetBackground(1.0, 1.0, 1.0);
67 originalRenderer->ResetCamera();
68
69 vtkSmartPointer<vtkRenderer> convolvedRenderer =
70 vtkSmartPointer<vtkRenderer>::New();
71 convolvedRenderer->SetViewport(rightViewport);
72 convolvedRenderer->AddActor(convolvedActor);
73 convolvedRenderer->SetBackground(1.0, 1.0, 1.0);
74 convolvedRenderer->ResetCamera();
75
76 vtkSmartPointer<vtkRenderWindow> rw =
77 vtkSmartPointer<vtkRenderWindow>::New();;
78 rw->AddRenderer(originalRenderer);
79 rw->AddRenderer(convolvedRenderer);
80 rw->SetSize(640, 320);
81 rw->Render();
82 rw->SetWindowName("Smooth by MeanFilter");
83
84 vtkSmartPointer<vtkRenderWindowInteractor> rwi =
85 vtkSmartPointer<vtkRenderWindowInteractor>::New();
86 vtkSmartPointer<vtkInteractorStyleImage> style =
87 vtkSmartPointer<vtkInteractorStyleImage>::New();
88 rwi->SetInteractorStyle(style);
89 rwi->SetRenderWindow(rw);
90 rwi->Initialize();
91 rwi->Start();
92
93 return 0;
94 }
首先vtkJPEGReader对象读取一幅图像。考虑到进行卷积运算时数据范围的变化和精度要求,需要先将图像像素数据类型由unsigned char转换到float类型,该变换通过vtkImageCast实现,对应的设置函数SetOutputScalarTypeToFloat()。接下来需要定义卷积算子和卷积模板。vtkImageConvolve类实现图像的卷积运算,它需要两个输入。一个是需要进行卷积的图像,这里为vtkJPEGReader读取的图像数据,第二个是卷积模板数组。SetKernel5x5()函数接收一个5x5的卷积模板数组,即本例上定义的kernel数组。执行Update()后即可完成卷积运算。需要注意的是,卷积模板对应的系数之和应该为1,否则需要对计算结果进行归一化处理。另外该类中还定义了3x3和7x7的卷积模板设置函数,使用过程是一样的。卷积完成以后,再次通过vtkImageCast将float数据类型转换为unsigned char进行图像显示。
均值滤波的结果如下: