VTK图形图像开发进阶-学习笔记 05(03) VTK图像处理

5.4 边缘检测

图像中不连续的灰度值会产生边缘,图像的边缘检测是基于边界的图像分割方法的基础。分水岭算法通常是分割原图的梯度图像,而梯度实际上也反映图像的边缘信息

5.4.1 梯度算子

梯度算子对应于图像的一阶导数。图像的一阶导数一般是通过差分运算来近似的。VTK中可以用vtkImageCradient类计算图像梯度。

///****************************************************/
///*  Examples/Chap05/5.4_ImageGradientExample.cpp     */
///****************************************************/

#include <vtkSmartPointer.h>
#include <vtkJPEGReader.h>
#include <vtkImageGradient.h>
#include <vtkImageMagnitude.h>
#include <vtkImageShiftScale.h>
#include <vtkImageData.h>
#include <vtkImageActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>

int main(int argn, char* argv[]) {

	// 读入灰度图像
	vtkSmartPointer<vtkJPEGReader> reader =
		vtkSmartPointer<vtkJPEGReader>::New();
	reader->SetFileName("D://lena_gray.jpg");
	reader->Update();

	vtkSmartPointer<vtkImageGradient> gradientFilter =
		vtkSmartPointer<vtkImageGradient>::New();
	gradientFilter->SetInputConnection(reader->GetOutputPort());
	gradientFilter->SetDimensionality(2);

	vtkSmartPointer<vtkImageMagnitude> magnitudeFilter =
		vtkSmartPointer<vtkImageMagnitude>::New();
	magnitudeFilter->SetInputConnection(gradientFilter->GetOutputPort());
	magnitudeFilter->Update();

	double range[2];
	magnitudeFilter->GetOutput()->GetScalarRange(range);

	vtkSmartPointer<vtkImageShiftScale> ShiftScale =
		vtkSmartPointer<vtkImageShiftScale>::New();
	ShiftScale->SetOutputScalarTypeToUnsignedChar();
	ShiftScale->SetScale(255 / range[1]);
	ShiftScale->SetInputConnection(magnitudeFilter->GetOutputPort());
	ShiftScale->Update();

	vtkSmartPointer<vtkImageActor> originalActor =
		vtkSmartPointer<vtkImageActor>::New();
	originalActor->SetInputData(reader->GetOutput());

	vtkSmartPointer<vtkImageActor> gradActor =
		vtkSmartPointer<vtkImageActor>::New();
	gradActor->SetInputData(ShiftScale->GetOutput());

	double originalViewport[4] = { 0.0, 0.0, 0.5, 1.0 };
	double gradviewport[4] = { 0.5, 0.0, 1.0, 1.0 };

	vtkSmartPointer<vtkRenderer> originalRenderer =
		vtkSmartPointer<vtkRenderer>::New();
	originalRenderer->SetViewport(originalViewport);
	originalRenderer->AddActor(originalActor);
	originalRenderer->ResetCamera();
	originalRenderer->SetBackground(1.0, 1.0, 1.0);

	vtkSmartPointer<vtkRenderer> gradRenderer =
		vtkSmartPointer<vtkRenderer>::New();
	gradRenderer->SetViewport(gradviewport);
	gradRenderer->AddActor(gradActor);
	gradRenderer->ResetCamera();
	gradRenderer->SetBackground(1.0, 1.0, 1.0);

	vtkSmartPointer<vtkRenderWindow> renderWindow =
		vtkSmartPointer<vtkRenderWindow>::New();
	renderWindow->AddRenderer(originalRenderer);
	renderWindow->AddRenderer(gradRenderer);
	renderWindow->SetSize(640, 320);
	renderWindow->Render();
	renderWindow->SetWindowName("ImageGradientExample");

	vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	vtkSmartPointer<vtkInteractorStyleImage> style =
		vtkSmartPointer<vtkInteractorStyleImage>::New();

	renderWindowInteractor->SetInteractorStyle(style);
	renderWindowInteractor->SetRenderWindow(renderWindow);
	renderWindowInteractor->Initialize();
	renderWindowInteractor->Start();

	return EXIT_SUCCESS;

}

梯度是矢量,不能直接显示。使用vtkImageMagnitude对象来计算梯度矢量的2-范数,既矢量的模。利用vtkImageShiftScale将图像的数据范围调整到「0 255」然后显示。注意:彩色图像不能直接用来计算梯度,需要先转换为灰度图像。

 

索贝尔(Sobel)算子也是一种常用的梯度算子。采用3x3模板。计算时模板在图像上移动,并且在每个位置上计算对应中心像素的梯度值。VTK中用vtkSobel2D计算图像的Sobel算子。

///****************************************************/
///*  Examples/Chap05/5.4_SobelExample.cpp     */
///****************************************************/

#include <vtkSmartPointer.h>
#include <vtkJPEGReader.h>
#include <vtkImageSobel2D.h>
#include <vtkImageExtractComponents.h>
#include <vtkImageMathematics.h>
#include <vtkImageShiftScale.h>
#include <vtkImageData.h>
#include <vtkImageActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>

int main(int argn, char* argv[]) {

	// 读入灰度图像
	vtkSmartPointer<vtkJPEGReader> reader =
		vtkSmartPointer<vtkJPEGReader>::New();
	reader->SetFileName("D://lena_gray.jpg");
	reader->Update();

	vtkSmartPointer<vtkImageSobel2D> sobelFilter =
		vtkSmartPointer<vtkImageSobel2D>::New();
	sobelFilter->SetInputConnection(reader->GetOutputPort());

	vtkSmartPointer<vtkImageExtractComponents> extractXFilter =
		vtkSmartPointer<vtkImageExtractComponents>::New();
	extractXFilter->SetComponents(0);
	extractXFilter->SetInputConnection(sobelFilter->GetOutputPort());
	extractXFilter->Update();

	double xRange[2];
	extractXFilter->GetOutput()->GetScalarRange(xRange);

	vtkSmartPointer<vtkImageMathematics> xImageAbs =
		vtkSmartPointer<vtkImageMathematics>::New();
	xImageAbs->SetOperationToAbsoluteValue();
	xImageAbs->SetInputConnection(extractXFilter->GetOutputPort());
	xImageAbs->Update();

	vtkSmartPointer<vtkImageShiftScale> xShiftScale =
		vtkSmartPointer<vtkImageShiftScale>::New();
	xShiftScale->SetOutputScalarTypeToUnsignedChar();
	xShiftScale->SetScale(255 / xRange[1]);
	xShiftScale->SetInputConnection(xImageAbs->GetOutputPort());
	xShiftScale->Update();

	vtkSmartPointer<vtkImageExtractComponents> extractYFilter =
		vtkSmartPointer<vtkImageExtractComponents>::New();
	extractYFilter->SetComponents(1);
	extractYFilter->SetInputConnection(sobelFilter->GetOutputPort());
	extractYFilter->Update();

	double yRange[2];
	extractYFilter->GetOutput()->GetScalarRange(yRange);

	vtkSmartPointer<vtkImageMathematics> yImageAbs =
		vtkSmartPointer<vtkImageMathematics>::New();
	yImageAbs->SetOperationToAbsoluteValue();
	yImageAbs->SetInputConnection(extractYFilter->GetOutputPort());
	yImageAbs->Update();

	vtkSmartPointer<vtkImageShiftScale> yShiftScale =
		vtkSmartPointer<vtkImageShiftScale>::New();
	yShiftScale->SetOutputScalarTypeToUnsignedChar();
	yShiftScale->SetScale(255 / yRange[1]);
	yShiftScale->SetInputConnection(yImageAbs->GetOutputPort());
	yShiftScale->Update();

	vtkSmartPointer<vtkImageActor> originalActor =
		vtkSmartPointer<vtkImageActor>::New();
	originalActor->SetInputData(reader->GetOutput());

	vtkSmartPointer<vtkImageActor> xActor =
		vtkSmartPointer<vtkImageActor>::New();
	xActor->SetInputData(xShiftScale->GetOutput());

	vtkSmartPointer<vtkImageActor> yActor =
		vtkSmartPointer<vtkImageActor>::New();
	yActor->SetInputData(yShiftScale->GetOutput());

	double originalViewport[4] = { 0.0, 0.0, 0.33, 1.0 };
	double xViewport[4] = { 0.33, 0.0, 0.66, 1.0 };
	double yViewport[4] = { 0.66, 0.0, 1.0, 1.0 };

	vtkSmartPointer<vtkRenderer> originalRenderer =
		vtkSmartPointer<vtkRenderer>::New();
	originalRenderer->SetViewport(originalViewport);
	originalRenderer->AddActor(originalActor);
	originalRenderer->ResetCamera();
	originalRenderer->SetBackground(1.0, 1.0, 1.0);

	vtkSmartPointer<vtkRenderer> xRenderer =
		vtkSmartPointer<vtkRenderer>::New();
	xRenderer->SetViewport(xViewport);
	xRenderer->AddActor(xActor);
	xRenderer->ResetCamera();
	xRenderer->SetBackground(1.0, 1.0, 1.0);

	vtkSmartPointer<vtkRenderer> yRenderer =
		vtkSmartPointer<vtkRenderer>::New();
	yRenderer->SetViewport(yViewport);
	yRenderer->AddActor(yActor);
	yRenderer->ResetCamera();
	yRenderer->SetBackground(1.0, 1.0, 1.0);

	vtkSmartPointer<vtkRenderWindow> renderWindow =
		vtkSmartPointer<vtkRenderWindow>::New();
	renderWindow->SetSize(1200, 300);
	renderWindow->AddRenderer(originalRenderer);
	renderWindow->AddRenderer(xRenderer);
	renderWindow->AddRenderer(yRenderer);
	renderWindow->Render();
	renderWindow->SetWindowName("SobelExample");

	vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	vtkSmartPointer<vtkInteractorStyleImage> style =
		vtkSmartPointer<vtkInteractorStyleImage>::New();

	renderWindowInteractor->SetInteractorStyle(style);
	renderWindowInteractor->SetRenderWindow(renderWindow);
	renderWindowInteractor->Initialize();
	renderWindowInteractor->Start();

	return EXIT_SUCCESS;

}

5.4.2 Canny算子

 

5.4.3 拉普拉斯算子

拉普拉斯算子是一个二阶边缘算子,既梯度的散度。

///****************************************************/
///*  Examples/Chap05/5.4_ImageGradientExample.cpp     */
///****************************************************/

#include <vtkSmartPointer.h>
#include <vtkJPEGReader.h>
#include <vtkImageLaplacian.h>
#include <vtkImageShiftScale.h>
#include <vtkImageData.h>
#include <vtkImageActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>

int main(int argn, char* argv[]) {

	// 读入灰度图像
	vtkSmartPointer<vtkJPEGReader> reader =
		vtkSmartPointer<vtkJPEGReader>::New();
	reader->SetFileName("D://lena_gray.jpg");
	reader->Update();

	vtkSmartPointer<vtkImageLaplacian> lapFilter =
		vtkSmartPointer<vtkImageLaplacian>::New();
	lapFilter->SetInputConnection(reader->GetOutputPort());
	lapFilter->SetDimensionality(2);

	double range[2];
	lapFilter->GetOutput()->GetScalarRange(range);

	vtkSmartPointer<vtkImageShiftScale> ShiftScale =
		vtkSmartPointer<vtkImageShiftScale>::New();
	ShiftScale->SetOutputScalarTypeToUnsignedChar();
	ShiftScale->SetScale(255 / (range[1]- range[0]));
	ShiftScale->SetShift(-range[0]);
	ShiftScale->SetInputConnection(lapFilter->GetOutputPort());
	ShiftScale->Update();

	vtkSmartPointer<vtkImageActor> originalActor =
		vtkSmartPointer<vtkImageActor>::New();
	originalActor->SetInputData(reader->GetOutput());

	vtkSmartPointer<vtkImageActor> gradActor =
		vtkSmartPointer<vtkImageActor>::New();
	gradActor->SetInputData(ShiftScale->GetOutput());

	double originalViewport[4] = { 0.0, 0.0, 0.5, 1.0 };
	double gradviewport[4] = { 0.5, 0.0, 1.0, 1.0 };

	vtkSmartPointer<vtkRenderer> originalRenderer =
		vtkSmartPointer<vtkRenderer>::New();
	originalRenderer->SetViewport(originalViewport);
	originalRenderer->AddActor(originalActor);
	originalRenderer->ResetCamera();
	originalRenderer->SetBackground(1.0, 1.0, 1.0);

	vtkSmartPointer<vtkRenderer> gradRenderer =
		vtkSmartPointer<vtkRenderer>::New();
	gradRenderer->SetViewport(gradviewport);
	gradRenderer->AddActor(gradActor);
	gradRenderer->ResetCamera();
	gradRenderer->SetBackground(1.0, 1.0, 1.0);

	vtkSmartPointer<vtkRenderWindow> renderWindow =
		vtkSmartPointer<vtkRenderWindow>::New();
	renderWindow->AddRenderer(originalRenderer);
	renderWindow->AddRenderer(gradRenderer);
	renderWindow->SetSize(640, 320);
	renderWindow->Render();
	renderWindow->SetWindowName("LaplacianExample");

	vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	vtkSmartPointer<vtkInteractorStyleImage> style =
		vtkSmartPointer<vtkInteractorStyleImage>::New();

	renderWindowInteractor->SetInteractorStyle(style);
	renderWindowInteractor->SetRenderWindow(renderWindow);
	renderWindowInteractor->Initialize();
	renderWindowInteractor->Start();

	return EXIT_SUCCESS;

}

5.5 图像平滑

图像平滑常用于图像的预处理中,如计算梯度时先对图像进行平滑处理,可以减少噪声对梯度的影响。图像平滑一般是通过模板卷积运算实现。

卷积运算过程:先将模板中心依次与图像每个像素重合,然后通过模板各个系数与图像对应像素相乘来计算模板对应像素的加权平均值。最后将运算结果赋给图像中模板中心对应的像素。

5.5.1 均值滤波

均值滤波是一种常用的平滑方法,其对应的模板各个像素的值相同且和为1.

在VTK中没有直接实现均值滤波的类,但是可以通过图像卷积运算来实现均值滤波。

卷积运算通过vtkImageConvolve类实现。

/**********************************************************************

文件名: 5.5_MeanFilterExample.cpp
Copyright (c) 张晓东, 罗火灵. All rights reserved.
更多信息请访问:
http://www.vtkchina.org (VTK中国)
http://blog.csdn.net/www_doling_net (东灵工作室)

**********************************************************************/

#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkImageConvolve.h>
#include <vtkImageMandelbrotSource.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkRenderer.h>
#include <vtkImageActor.h>
#include <vtkImageCast.h>
#include <vtkJPEGReader.h>
#include <vtkImageShiftScale.h>

//测试图像:../data/lena-gray.jpg
int main(int argc, char* argv[])
{
		vtkSmartPointer<vtkJPEGReader> reader =
			vtkSmartPointer<vtkJPEGReader>::New();
		reader->SetFileName("D://lena_gray.jpg");
		reader->Update();

	vtkSmartPointer<vtkImageCast> originalCastFilter =
		vtkSmartPointer<vtkImageCast>::New();
	originalCastFilter->SetInputConnection(reader->GetOutputPort());
	originalCastFilter->SetOutputScalarTypeToFloat();
	originalCastFilter->Update();

	vtkSmartPointer<vtkImageConvolve> convolveFilter =
		vtkSmartPointer<vtkImageConvolve>::New();
	convolveFilter->SetInputConnection(originalCastFilter->GetOutputPort());

	double kernel[25] = { 0.04,0.04,0.04,0.04,0.04,
		0.04,0.04,0.04,0.04,0.04,
		0.04,0.04,0.04,0.04,0.04,
		0.04,0.04,0.04,0.04,0.04,
		0.04,0.04,0.04,0.04,0.04 };
	convolveFilter->SetKernel5x5(kernel);
	convolveFilter->Update();

	vtkSmartPointer<vtkImageCast> convCastFilter =
		vtkSmartPointer<vtkImageCast>::New();
	convCastFilter->SetInputData(convolveFilter->GetOutput());
	convCastFilter->SetOutputScalarTypeToUnsignedChar();
	convCastFilter->Update();

	vtkSmartPointer<vtkImageActor> originalActor =
		vtkSmartPointer<vtkImageActor>::New();
	originalActor->SetInputData(reader->GetOutput());

	vtkSmartPointer<vtkImageActor> convolvedActor =
		vtkSmartPointer<vtkImageActor>::New();
	convolvedActor->SetInputData(convCastFilter->GetOutput());

	double leftViewport[4] = { 0.0, 0.0, 0.5, 1.0 };
	double rightViewport[4] = { 0.5, 0.0, 1.0, 1.0 };

	vtkSmartPointer<vtkRenderer> originalRenderer =
		vtkSmartPointer<vtkRenderer>::New();
	originalRenderer->SetViewport(leftViewport);
	originalRenderer->AddActor(originalActor);
	originalRenderer->SetBackground(1.0, 1.0, 1.0);
	originalRenderer->ResetCamera();

	vtkSmartPointer<vtkRenderer> convolvedRenderer =
		vtkSmartPointer<vtkRenderer>::New();
	convolvedRenderer->SetViewport(rightViewport);
	convolvedRenderer->AddActor(convolvedActor);
	convolvedRenderer->SetBackground(1.0, 1.0, 1.0);
	convolvedRenderer->ResetCamera();

	vtkSmartPointer<vtkRenderWindow> renderWindow =
		vtkSmartPointer<vtkRenderWindow>::New();;
	renderWindow->AddRenderer(originalRenderer);
	renderWindow->AddRenderer(convolvedRenderer);
	renderWindow->SetSize(640, 320);
	renderWindow->Render();
	renderWindow->SetWindowName("MeanFilterExample");

	vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	vtkSmartPointer<vtkInteractorStyleImage> style =
		vtkSmartPointer<vtkInteractorStyleImage>::New();

	renderWindowInteractor->SetInteractorStyle(style);
	renderWindowInteractor->SetRenderWindow(renderWindow);
	renderWindowInteractor->Initialize();
	renderWindowInteractor->Start();

	return EXIT_SUCCESS;
}

5.5.2 高斯平滑

高斯平滑的原理类似于均值滤波。

高斯平滑需要根据像素与模板中心的距离来定义权重。

权重的计算方法是采用高斯分布,离中心越远,权重越小。

5.5.3 中值滤波

5.5.4 各向异性滤波

5.6 频域处理

5.6.1 快速傅里叶变换

5.6.2 低通滤波

5.6.3 高通滤波

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值