VTK知识学习(27)- 图像基本操作(二)

1、图像类型转换

1)vtkImageCast

图像数据类型转换在数字图像处理中会频繁用到。一些常用的图像算子(例如梯度算子)在计算时出于精度的考虑,会将结果存储为float或double类型,但在图像显示时,一般要求图像为 unsigned char 类型,这时就需要对数据类型进行转换。VTK 中最简单的类型转换 Filter就是 vtkmageCast,其使用方法如下:

cs 复制代码
vtkImageCast imageCast = vtkImageCast.New();
imageCast.SetInputConnection(reader.GetOutputPort());
imageCast.SetOutputScalarTypeToFloat();
imageCast.Update();

只需要把 SetOutputScalarTypeToxxX()设置成相应的输出类型即可。另外,该类中还有一个变量 ClampOverflow,用来标识是否需要截断数据。默认情况下,该变量值为0。当设置其值为1时,输出的像素值不能超过输出类型的最大值,超过时自动截断至最大值。该类在进行类型转换时,只是将数据进行强制转换,而没有进行比例的缩放,因此使用比较受限制,VTK中也不推荐使用该类。例如一幅 double 类型的图像,其数值范围为[-1,1],如果需要将图像转换为 unsigned char 类,则无法使用该 Filter 进行转换。这时就需要用到 vklmageShifScale。

2)vtkImageShiftScale

指定偏移和比例参数来对输入图像数据进行操作,例如一幅double 类型的图像,其数值范围为[-1,1],如果将其转换为 unsigned char 类型,需要设置 shif值为+1,比例系数设置为 127.5,那么输入数据-1映射为(-1+1)x127.5=0,而+1 则会映射为(+1+1)x127.5=255。对应代码如下:

cs 复制代码
vtkImageShiftScale imageShiftScale = vtkImageShiftScale.New();
imageShiftScale.SetInputConnection(reader.GetOutputPort());
 imageShiftScale.SetOutputScalarTypeToUnsignedChar();
imageShiftScale.SetShift(1);
imageShiftScale.SetScale(127.5);
imageShiftScale.Update();

SetShift()函数,用于设置偏移量 Shift

SetScale()函数,用于设置放缩值Scale,如果源图像的像素值为Val,那么输出值为(Val+shif)xScale。

SetOutputScalarTypeToUnsignedChar()用于设置输出类型为 unsigned char,当然,该类也提供了其他输出类型的设置函数。

该类中也有一个变量ClampOverfow,当其值为1时,如果输出值超过输出类型的最大值时,则自动截断。例如,输出类型为 unsigned char,数值范围为 0~255,当输出像素值为 257时,该类会自动截断取值为 255。默认情况下,变量 ClampOverflow 的值为 0,此时,当输出值为 257,输出类型为 unsigned char 时,该类不会将其截断,而是会产生溢出,最后取值为2。

2、图像颜色映射

1)图像灰度映射

vtkImageLuminance 负责将一个RGB 彩色图像转换为一个单组分的灰度图像。映射公

式为:

Luminance=0.3xR+0.59xG+0.11xB

R为输入图像的第一组分(红色),G为第二组分(绿色),B为第三组分(蓝色)。

这个公式用于计算一个RGB颜色的亮度。该类的使用也比较简单,用户无须设置参数。

cs 复制代码
private void TestColor2Gray()
{
    vtkBMPReader reader = vtkBMPReader.New();
    reader.SetFileName("F:\\code\\VTK\\TestActiViz\\bin\\Debug\\data\\lena.bmp");
    reader.Update();

    vtkImageLuminance luminance = vtkImageLuminance.New();
    luminance.SetInputData(reader.GetOutput());
    luminance.Update();

    vtkImageActor orgActor = vtkImageActor.New();
    orgActor.SetInputData(reader.GetOutput());

    vtkImageActor actor = vtkImageActor.New();
    actor.SetInputData(luminance.GetOutput());

    vtkRenderer orgRenderer = vtkRenderer.New();
    orgRenderer.AddActor(orgActor);
    orgRenderer.SetViewport(0.0, 0.0, 0.5, 1.0);
    orgRenderer.ResetCamera();
    orgRenderer.SetBackground(1, 1, 1);

    vtkRenderer renderer = vtkRenderer.New();
    renderer.SetViewport(0.5, 0.0, 1.0, 1.0);
    renderer.AddActor(actor);

    renderer.ResetCamera();
    renderer.SetBackground(1, 1, 1);

    vtkRenderWindow renderWindow = renderWindowControl.RenderWindow;
    renderWindow.AddRenderer(orgRenderer);
    renderWindow.AddRenderer(renderer);
    renderWindow.Render();
}
2)提取颜色组分

VTK 中利用 vtkImageExtractComponents 可以方便地提取彩色图像的各个颜色组分。使用该类时只需要设置要提取的组分序号即可。

cs 复制代码
private void TestExtractComponets()
 {
   vtkBMPReader reader = vtkBMPReader.New();
   reader.SetFileName("F:\\code\\VTK\\TestActiViz\\bin\\Debug\\data\\lena.bmp");
   reader.Update();

   //提取红色对应灰度图像
   vtkImageExtractComponents extractRed = vtkImageExtractComponents.New();
   extractRed.SetInputData(reader.GetOutput());
   extractRed.SetComponents(0);
   extractRed.Update();

   //提取绿色对应灰度图像
   vtkImageExtractComponents extractGreen = vtkImageExtractComponents.New();
   extractGreen.SetInputData(reader.GetOutput());
   extractGreen.SetComponents(1);
   extractGreen.Update();

   //提取蓝色对应灰度图像
   vtkImageExtractComponents extractBlue = vtkImageExtractComponents.New();
   extractBlue.SetInputData(reader.GetOutput());
   extractBlue.SetComponents(2);
   extractBlue.Update();

   vtkImageActor orgActor = vtkImageActor.New();
   orgActor.SetInputData(reader.GetOutput());

   vtkImageActor redActor = vtkImageActor.New();
   redActor.SetInputData(extractRed.GetOutput());

   vtkImageActor greenActor = vtkImageActor.New();
   greenActor.SetInputData(extractGreen.GetOutput());

   vtkImageActor blueActor = vtkImageActor.New();
   blueActor.SetInputData(extractBlue.GetOutput());

   vtkRenderer orgRenderer = vtkRenderer.New();
   orgRenderer.AddActor(orgActor);
   orgRenderer.SetViewport(0.0, 0.0, 0.25, 1.0);
   orgRenderer.ResetCamera();
   orgRenderer.SetBackground(1, 1, 1);

   vtkRenderer renderer = vtkRenderer.New();
   renderer.SetViewport(0.25, 0.0, 0.5, 1.0);
   renderer.AddActor(redActor);
   renderer.ResetCamera();
   renderer.SetBackground(1, 1, 1);

   vtkRenderer renderer2 = vtkRenderer.New();
   renderer2.SetViewport(0.5, 0.0, 0.75, 1.0);
   renderer2.AddActor(greenActor);
   renderer2.ResetCamera();
   renderer2.SetBackground(1, 1, 1);

   vtkRenderer renderer3 = vtkRenderer.New();
   renderer3.SetViewport(0.75, 0.0, 1, 1.0);
   renderer3.AddActor(blueActor);
   renderer3.ResetCamera();
   renderer3.SetBackground(1, 1, 1);

   vtkRenderWindow renderWindow = renderWindowControl.RenderWindow;
   renderWindow.AddRenderer(orgRenderer);
   renderWindow.AddRenderer(renderer);
   renderWindow.AddRenderer(renderer2);
   renderWindow.AddRenderer(renderer3);
   renderWindow.Render();
}

代码中定义了三个 vtkImageExtractComponents 对象,分别用来提取红、绿和蓝色组分图像,函数 SetComponents()用来设置要提取的组分号,红、绿、蓝三色分别对应0、1和2。设置完毕,执行Update()即可得到各个组分的数据。其输出为vtkImageData,每一个颜色组分数据即是一个灰度图像。

3)图像彩色映射

图像彩色映射的原理是:先生成一个颜色查找表,然后根据图像像素的一个标量值在颜色查找表中查找对应的颜色,并用新颜色值替代原来的像素值。VTK中以vkImageMapToColors 实现图像彩色映射,以 vkookUpTable 生成颜色查找表。

cs 复制代码
private void TestGray2Color()
        {
            vtkJPEGReader reader = vtkJPEGReader.New();
            reader.SetFileName("F:\\code\\VTK\\TestActiViz\\bin\\Debug\\data\\lena-gray.jpg");
            reader.Update();

            vtkLookupTable colorTable = vtkLookupTable.New();
            colorTable.SetRange(0, 255);
            colorTable.SetHueRange(0.1, 0.5);
            colorTable.SetValueRange(0.6, 1);
            colorTable.Build();

            vtkImageMapToColors colorMap = vtkImageMapToColors.New();
            colorMap.SetInputData(reader.GetOutput());
            colorMap.SetLookupTable(colorTable);
            colorMap.Update();

            vtkImageActor orgActor = vtkImageActor.New();
            orgActor.SetInputData(reader.GetOutput());

            vtkImageActor redActor = vtkImageActor.New();
            redActor.SetInputData(colorMap.GetOutput());

            vtkRenderer orgRenderer = vtkRenderer.New();
            orgRenderer.AddActor(orgActor);
            orgRenderer.SetViewport(0.0, 0.0, 0.5, 1.0);
            orgRenderer.ResetCamera();
            orgRenderer.SetBackground(1, 1, 1);

            vtkRenderer renderer = vtkRenderer.New();
            renderer.SetViewport(0.5, 0.0, 1, 1.0);
            renderer.AddActor(redActor);
            renderer.ResetCamera();
            renderer.SetBackground(1, 1, 0.8);

            vtkRenderWindow renderWindow = renderWindowControl.RenderWindow;
            renderWindow.AddRenderer(orgRenderer);
            renderWindow.AddRenderer(renderer);

            renderWindow.Render();
        }

示例先读取了一幅灰度图像,然后生成 vtkLookUpTable 颜色查找表。

构造颜色查找表有两种方法:一种是直接添加颜色;另一种是设置HSV颜色空间变化范围,然后自动生成颜色表。这里采用的是第二种方法,

SetRange()设置要映射的标量数据的范围:

SetHueRange()设置HSV 颜色空间的 Hue 值范围,最大范围为[0,1];

SetValueRange()设置 HSV 颜色空间的 Value 范围,最大范围为[0,1]:

设置完后,调用 Build()来生成颜色査找表。接着定义 vkImageMapToColors 对象,vtkImageMapToColors::SetLookupTable()设置相应的颜色查找表,执行 Update()后,其输出为一幅彩色图像。

4)颜色合成

VTK也支持将多个灰度图像合并成一个彩色图像。VTK 中的 vtkImageAppendComponents 类可用来合成彩色图像,其输入需要提供三个灰度图像。

cs 复制代码
private void TestColorAppend()
        {
            vtkImageCanvasSource2D red = vtkImageCanvasSource2D.New();
            red.SetScalarTypeToUnsignedChar();
            red.SetNumberOfScalarComponents(1);
            red.SetExtent(0, 100, 0, 100, 0, 0);
            red.SetDrawColor(0, 0, 0, 0);
            red.FillBox(0, 100, 0, 100);
            red.SetDrawColor(255, 0, 0, 0);
            red.FillBox(20, 40, 20, 40);
            red.Update();

            vtkImageCanvasSource2D green = vtkImageCanvasSource2D.New();
            green.SetScalarTypeToUnsignedChar();
            green.SetNumberOfScalarComponents(1);
            green.SetExtent(0, 100, 0, 100, 0, 0);
            green.SetDrawColor(0, 0, 0, 0);
            green.FillBox(0, 100, 0, 100);
            green.SetDrawColor(255, 0, 0, 0);
            green.FillBox(30, 50, 30, 50);
            green.Update();

            vtkImageCanvasSource2D blue = vtkImageCanvasSource2D.New();
            blue.SetScalarTypeToUnsignedChar();
            blue.SetNumberOfScalarComponents(1);
            blue.SetExtent(0, 100, 0, 100, 0, 0);
            blue.SetDrawColor(0, 0, 0, 0);
            blue.FillBox(0, 100, 0, 100);
            blue.SetDrawColor(255, 0, 0, 0);
            blue.FillBox(40, 60, 40, 60);
            blue.Update();

            vtkImageAppendComponents components = vtkImageAppendComponents.New();
            components.SetInputData(0, red.GetOutput());
            components.AddInputData(0, green.GetOutput());
            components.AddInputData(0, blue.GetOutput());
            components.Update();

            vtkImageActor redActor = vtkImageActor.New();
            redActor.SetInputData(red.GetOutput());

            vtkImageActor greenActor = vtkImageActor.New();
            greenActor.SetInputData(green.GetOutput());

            vtkImageActor blueActor = vtkImageActor.New();
            blueActor.SetInputData(blue.GetOutput());

            vtkImageActor combinedActor = vtkImageActor.New();
            combinedActor.SetInputData(components.GetOutput());

            vtkRenderer redRenderer = vtkRenderer.New();
            redRenderer.AddActor(redActor);
            redRenderer.SetViewport(0.0, 0.0, 0.25, 1.0);
            redRenderer.ResetCamera();
            redRenderer.SetBackground(1, 1, 1);

            vtkRenderer greenRenderer = vtkRenderer.New();
            greenRenderer.AddActor(greenActor);
            greenRenderer.SetViewport(0.25, 0.0, 0.5, 1.0);
            greenRenderer.ResetCamera();
            greenRenderer.SetBackground(1, 1, 1);

            vtkRenderer blueRenderer = vtkRenderer.New();
            blueRenderer.AddActor(blueActor);
            blueRenderer.SetViewport(0.5, 0.0, 0.75, 1.0);
            blueRenderer.ResetCamera();
            blueRenderer.SetBackground(1, 1, 1);

            vtkRenderer CombinedRenderer = vtkRenderer.New();
            CombinedRenderer.SetViewport(0.75, 0.0, 1, 1.0);
            CombinedRenderer.AddActor(combinedActor);
            CombinedRenderer.ResetCamera();
            CombinedRenderer.SetBackground(1, 1, 0.8);

            vtkRenderWindow renderWindow = renderWindowControl.RenderWindow;
            renderWindow.AddRenderer(redRenderer);
            renderWindow.AddRenderer(greenRenderer);
            renderWindow.AddRenderer(blueRenderer);
            renderWindow.AddRenderer(CombinedRenderer);

            renderWindow.Render();
        }

先利用 vtkImageCanvasSource2D定义了三个二值图像,每个图像中绘制了一个白色矩形,并且三个矩形有部分重叠;然后定义vkImageAppendComponents对象,并将三个图像设置为 vtkImageAppendComponents 对象的输入来合成图像。合成的效果为三个图像中对应的三个像素点的像素值合成一个RGB 像素值,如三个图像中第100个像素的像素值分别为255、0和 0,那么该点在输出图像中的像素值为(255.0.0),显示为红色。

相关推荐
西岸行者3 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意3 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码3 天前
嵌入式学习路线
学习
毛小茛4 天前
计算机系统概论——校验码
学习
babe小鑫4 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms4 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下4 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。4 天前
2026.2.25监控学习
学习
im_AMBER4 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J4 天前
从“Hello World“ 开始 C++
c语言·c++·学习