5.4.1 边缘检测—梯度算子

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kateyabc/article/details/83549188

图像中不连续的灰度值会产生边缘,图像的边缘检测是基于边界的图像分割方法,如分水岭算法,通常是分割原图的梯度图像,梯度实际上也是反应的图像边缘信息。图像边缘一般常用图像一阶导数和二阶导数来检测。
梯度算子对应于图像一阶导数。图像一阶导数计算一般是通过差分运算来近似的。VTK中可以使用vtkImageGradient计算图像梯度。注意图像梯度是一个向量,具有方向和大小。因此vtkImageGradient的计算结果是一个梯度场,也就是每个像素值都是一个梯度向量。显示梯度图像时需要计算每个像素点的梯度大小,即模值。
下面代码如何利用VTK怎么计算图像梯度:

//梯度算子
#include"vtkSmartPointer.h"
#include"vtkJPEGReader.h"
#include"vtkImageGradient.h"
#include"vtkImageMagnitude.h"
#include"vtkImageData.h"
#include"vtkImageShiftScale.h"
#include"vtkImageActor.h"
#include"vtkRenderer.h"
#include"vtkRenderWindow.h"
#include"vtkRenderWindowInteractor.h"
#include"vtkInteractorStyleImage.h"

int main()
{
	vtkSmartPointer<vtkJPEGReader> reader =	vtkSmartPointer<vtkJPEGReader>::New();
	reader->SetFileName("data\\lena-gray.jpg");
	reader->Update();

	vtkSmartPointer<vtkImageGradient> imgGradient =	vtkSmartPointer<vtkImageGradient>::New();//vtkImageGradient计算图像梯度,是一个矢量
	imgGradient->SetInputConnection(reader->GetOutputPort());
	imgGradient->SetDimensionality(2);//SetDimensionality用于要计算的图像的维数

	vtkSmartPointer<vtkImageMagnitude> imgMagnitude = vtkSmartPointer<vtkImageMagnitude>::New();//imgMagnitude用于计算梯度矢量的2范数(模),矢量不能直接显示
	imgMagnitude->SetInputConnection(imgGradient->GetOutputPort());
	imgMagnitude->Update();

	double Range[2];
	vtkSmartPointer<vtkImageData> getRange = vtkSmartPointer<vtkImageData>::New();
	imgMagnitude->GetOutput()->GetScalarRange(Range);//图像灰度范围最小值、最大值

	vtkSmartPointer<vtkImageShiftScale> imgShiftScale =	vtkSmartPointer<vtkImageShiftScale>::New();//vtkImageShiftScale调整图像的数据范围为[0,255]
	imgShiftScale->SetOutputScalarTypeToUnsignedChar(); //强制类型转换 0~255
	imgShiftScale->SetScale(255 / Range[1]); //灰度映射间距
	imgShiftScale->SetInputConnection(imgMagnitude->GetOutputPort());
	imgShiftScale->Update();

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

	vtkSmartPointer<vtkImageActor> GradientActor =	vtkSmartPointer<vtkImageActor>::New();
	GradientActor->SetInputData(imgShiftScale->GetOutput());
	////////////////////////////////////////////////////////////////////////////////////
	double origView[4] = { 0, 0, 0.5, 1 };
	double gradientView[4] = { 0.5, 0, 1, 1 };
	vtkSmartPointer<vtkRenderer> origRender = vtkSmartPointer<vtkRenderer>::New();
	origRender->SetViewport(origView);
	origRender->AddActor(origActor);
	origRender->ResetCamera();
	origRender->SetBackground(1.0, 1, 1);

	vtkSmartPointer<vtkRenderer> gradientRender = vtkSmartPointer<vtkRenderer>::New();
	gradientRender->SetViewport(gradientView);
	gradientRender->AddActor(GradientActor);
	gradientRender->ResetCamera();
	gradientRender->SetBackground(1, 1, 1);
	////////////////////////////////////////////////////////////////////////////////////////
	vtkSmartPointer<vtkRenderWindow> rw =	vtkSmartPointer<vtkRenderWindow>::New();
	rw->AddRenderer(origRender);
	rw->AddRenderer(gradientRender);
	rw->SetSize(640, 320);
	rw->SetWindowName("Image Gradient");

	vtkSmartPointer<vtkRenderWindowInteractor> rwi = vtkSmartPointer<vtkRenderWindowInteractor>::New();
	vtkSmartPointer<vtkInteractorStyleImage> style = vtkSmartPointer<vtkInteractorStyleImage>::New();
	rwi->SetRenderWindow(rw);
	rwi->SetInteractorStyle(style);
	rwi->Initialize();
	rwi->Start();

	return 0;
}

执行结果如图所示:

vtkImageGradient的使用比较简单,只需要设置输入图像即可。
计算梯度时,采用的是中间差分法,即像素在每个方向的差分,都是利用的前后两个像素值之差。这样在图像在边界处的差分计算需要特殊处理。其内部定义了HandleBoundaries变量,通过函数SetHandleBoundaries()定赋值。当HandleBoundaries为真时算子会特殊处理计算边界像素的梯度;当为假时不计算边界像素的梯度值,因此输出图像大小要小于输入图像。
另外函数SetDimensionality()用于设置要计算的图像维数,默认为二维,此时梯度向量也为二维。
前面也提到过,梯度是一个向量,不能直接显示。
因此上面代码中定义了vtkImageMagnitude对象来计算梯度向量的2范数,即向量的模。
利用vtkImageShiftScale将图像的数据范围调整到0-255然后显示。
另外还可以通过vtkImageExtractComponents来提取每个方向的梯度分量进行显示。
注意,彩色图像不能直接用来计算梯度,需要先转换为灰度图像。

参考资料:

1.《The Visualization Toolkit – AnObject-Oriented Approach To 3D Graphics (4th Edition)》
2. 张晓东, 罗火灵. VTK图形图像开发进阶[M]. 机械工业出版社, 2015.

所用软件:vtk7.0+visual studio 2013


注:此文知识学习笔记,仅记录完整程序和实现结果,具体原理参见:

https://blog.csdn.net/www_doling_net/article/details/8541534

https://blog.csdn.net/shenziheng1/article/category/6114053/4

猜你喜欢

转载自blog.csdn.net/kateyabc/article/details/83549188
今日推荐