1. 程式人生 > >5.3.8 影象運算

5.3.8 影象運算

1、數學運算

vtkImageMathematics提供了基本的一元和二元數學操作。根據不同的操作,需要一個或者兩個輸入影象。二元數字操作要求兩個輸入影象具有相同的畫素資料型別,顏色分量。當兩個影象大小不同時,輸出影象的範圍為兩個輸入影象範圍的並集,並且原點和畫素間隔與第一個輸入影象保持一致。

#include <vtkMath.h>
#include <vtkSmartPointer.h>
#include <vtkImageCanvasSource2D.h>
#include <vtkImageMathematics.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkRenderer.h>
#include <vtkImageActor.h>

int main(int, char *[])
{
	vtkSmartPointer<vtkImageCanvasSource2D> imageSource = vtkSmartPointer<vtkImageCanvasSource2D>::New();//建立的畫布影象
	imageSource->SetNumberOfScalarComponents(3);
	imageSource->SetScalarTypeToUnsignedChar();
	imageSource->SetExtent(0, 4, 0, 4, 0, 0);
	imageSource->SetDrawColor(100.0, 0, 0);
	imageSource->FillBox(0, 4, 0, 4);
	imageSource->Update();

	vtkSmartPointer<vtkImageMathematics> imageMath = vtkSmartPointer<vtkImageMathematics>::New();
	imageMath->SetOperationToMultiplyByK();//將影象中所有畫素值乘以常數K
	imageMath->SetConstantK(2.0);
	imageMath->SetInputConnection(imageSource->GetOutputPort());
	imageMath->Update();

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

	vtkSmartPointer<vtkImageActor> mathActor = vtkSmartPointer<vtkImageActor>::New();
	mathActor->SetInputData(imageMath->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->ResetCamera();
	originalRenderer->SetBackground(1.0, 1.0, 1.0);

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

	vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
	renderWindow->AddRenderer(originalRenderer);
	renderWindow->AddRenderer(gradientMagnitudeRenderer);
	renderWindow->SetSize(640, 480);
	renderWindow->Render();
	renderWindow->SetWindowName("ImageMathematicsExample");

	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;
}
執行結果:


上例中生成了一副影象,影象中繪製了一個暗紅色矩形;然後定義vtkImageMathematics物件,並呼叫SetOperationToMultiplyByK()函式來將影象中所有的畫素值乘以一個常數K,這裡常數值為2.0

vtkImageMathematics中支援的二元數學操作有:

SetOperationToAdd:兩個影象對應畫素加法運算

SetOperationToSubtract:兩個影象對應畫素減法運算

SetOperationToMultiply:兩個影象對應畫素相乘運算

SetOperationToDivide:兩個影象對應畫素相除運算

SetOperationToConjugate:將兩個標量影象對應畫素組合為共軛複數

SetOperationToComplexMultiply:兩個影象對應畫素複數乘法運算

SetOperationToMin:取兩個影象中對應畫素較小值

SetOperationToMax:取兩個影象中對應畫素較大值

一元操作有:

SetOperationToInvert:影象畫素值取倒數運算

SetOperationToSin:影象畫素值正弦運算

SetOperationToCos:影象畫素值餘弦運算

SetOperationToExp:影象畫素值自然指數運算

SetOperationToLog:影象畫素值自然對數運算

SetOperationToAbsoluteValue:影象畫素值取絕對值

SetOperationToSquare:影象畫素值平方運算

SetOperationToSquareRoot:影象畫素值平凡根運算

SetOperationToATAN:影象畫素值正切運算

SetOperationToATAN2:影象畫素值反正切運算

SetOperationToMultiplyByK:影象畫素值乘以常數K,需要先呼叫SetConstantK()設定K值

SetOperationToAddConstant:影象畫素值加上常數K,需要先呼叫SetConstantK()設定K值

SetOperationToReplaceCByK:將影象中畫素為C的畫素值替換為K,需要先呼叫SetConstantK()和SetConstantC設定K和C值

2、邏輯運算

vtkImageLogic接收一個或者兩個影象進行布林邏輯運算,該類主要支援與(AND),或(OR),異或(XOR),與非(NAND),或非(NOR)和非(NOT)。當選擇一元操作符時,只對第一個輸入影象有效。 當選擇二元操作符時,兩個輸入影象的型別必須一致。

/*邏輯運算*/
#include <vtkSmartPointer.h>
#include <vtkMath.h>   //
#include <vtkImageData.h>
#include <vtkImageCanvasSource2D.h>
#include <vtkImageLogic.h>   //
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkRenderer.h>
#include <vtkImageActor.h>

int main(int, char *[])
{
	vtkSmartPointer<vtkImageCanvasSource2D> imageSource1 =	vtkSmartPointer<vtkImageCanvasSource2D>::New();
	imageSource1->SetScalarTypeToUnsignedChar();
	imageSource1->SetNumberOfScalarComponents(1);
	imageSource1->SetExtent(0, 100, 0, 100, 0, 0);
	imageSource1->SetDrawColor(0.0);
	imageSource1->FillBox(0, 100, 0, 100);
	imageSource1->SetDrawColor(255);
	imageSource1->FillBox(20, 60, 20, 60);
	imageSource1->Update();

	vtkSmartPointer<vtkImageCanvasSource2D> imageSource2 =	vtkSmartPointer<vtkImageCanvasSource2D>::New();
	imageSource2->SetNumberOfScalarComponents(1);
	imageSource2->SetScalarTypeToUnsignedChar();
	imageSource2->SetExtent(0, 100, 0, 100, 0, 0);
	imageSource2->SetDrawColor(0.0);
	imageSource2->FillBox(0, 100, 0, 100);
	imageSource2->SetDrawColor(255.0);
	imageSource2->FillBox(40, 80, 40, 80);
	imageSource2->Update();

	vtkSmartPointer<vtkImageLogic> imageLogic =	vtkSmartPointer<vtkImageLogic>::New();
	imageLogic->SetInput1Data(imageSource1->GetOutput());
	imageLogic->SetInput2Data(imageSource2->GetOutput());
	imageLogic->SetOperationToXor();
	imageLogic->SetOutputTrueValue(128);
	imageLogic->Update();

	vtkSmartPointer<vtkImageActor> originalActor1 =	vtkSmartPointer<vtkImageActor>::New();
	originalActor1->SetInputData(imageSource1->GetOutput());

	vtkSmartPointer<vtkImageActor> originalActor2 = vtkSmartPointer<vtkImageActor>::New();
	originalActor2->SetInputData(imageSource2->GetOutput());

	vtkSmartPointer<vtkImageActor> logicActor =	vtkSmartPointer<vtkImageActor>::New();
	logicActor->SetInputData(imageLogic->GetOutput());

	double leftViewport[4] = { 0.0, 0.0, 0.33, 1.0 };
	double midViewport[4] = { 0.33, 0.0, 0.66, 1.0 };
	double rightViewport[4] = { 0.66, 0.0, 1.0, 1.0 };

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

	vtkSmartPointer<vtkRenderer> originalRenderer2 = vtkSmartPointer<vtkRenderer>::New();
	originalRenderer2->SetViewport(midViewport);
	originalRenderer2->AddActor(originalActor2);
	originalRenderer2->ResetCamera();
	originalRenderer2->SetBackground(0.8, 0.8, 0.8);

	vtkSmartPointer<vtkRenderer> logicRenderer = vtkSmartPointer<vtkRenderer>::New();
	logicRenderer->SetViewport(rightViewport);
	logicRenderer->AddActor(logicActor);
	logicRenderer->ResetCamera();
	logicRenderer->SetBackground(0.6, 0.6, 0.6);

	vtkSmartPointer<vtkRenderWindow> renderWindow =	vtkSmartPointer<vtkRenderWindow>::New();
	renderWindow->AddRenderer(originalRenderer1);
	renderWindow->AddRenderer(originalRenderer2);
	renderWindow->AddRenderer(logicRenderer);
	renderWindow->SetSize(640, 320);
	renderWindow->Render();
	renderWindow->SetWindowName("ImageLogicExample");

	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;
}

執行結果:


上例中首先生成了兩個二值影象,兩個影象中前景為兩個部分重疊矩形。然後定義vtkImageLogic物件,並設定兩個影象為輸入,SetOperationToXor()設定邏輯操作運算元為異或操作,並且SetOutputTrueValue()設定當兩個影象對應畫素值異或結果為真時的輸出畫素值,其執行結果如下,可以看成兩個矩形的重疊部分畫素值相同,因此輸出為0;矩形的不重疊部分畫素值一個為0,一個為255,因此異或結果為真,那麼輸出值為128。

vtkImageLogic設定邏輯運算的函式有:

SetOperationToAnd():邏輯與操作

SetOperationToOr():邏輯或操作

SetOperationToXor():邏輯異或

SetOperationToNand():邏輯與非

SetOperationToNor():邏輯或非

SetOperationToNot():邏輯非

注:imageLogic->SetInput1Data(imageSource1->GetOutput());
       imageLogic->SetInput2Data(imageSource2->GetOutput());

vtkImageShrink3D通過SetShrinkFactors()設定X、Y和Z方向的取樣率,引數為三個int型別資料。vtkImageMagnify通過SetMagnificationFactors設定相應的放大采樣率。從圖中可以看成,重取樣影象已經變得十分模糊了。而升取樣影象則變化不大。程式中輸出了原圖和重取樣影象的維數和畫素間隔,從輸出來看,原影象的維數為512x512,縮小16倍後,影象維數變為32x32。需要注意的是,原圖的畫素間隔為(1,1,1),而重取樣後像素間隔變為(16, 16, 1),這是因為取樣是在世界座標系下進行的,當取樣影象的維數減小時,取樣的畫素間隔也相應的變大,這樣保持影象的區域不會發生改變。同樣的道理,當升取樣後圖像的維數變為原來的10倍,而畫素間隔變為原來的十分之一。

注:此文知識學習筆記,僅記錄完整程式和實現結果,具體原理參見:

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

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

參考資料:

1.《The Visualization Toolkit – AnObject-Oriented Approach To 3D Graphics (4th Edition)》
2. 張曉東, 羅火靈. VTK圖形影象開發進階[M]. 機械工業出版社, 2015.

所用軟體:vtk7.0+visual studio 2013