ITK-重采样
作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处
什么是重采样
重采样(Resampling) 是一种用于图像处理的技术,主要应用于对图像进行尺寸调整、旋转、平移、变形等几何变换时重构像素数据。在图像处理中的重采样,是通过插值计算在新图像坐标系下的像素值,以保证图像在几何变换后的视觉效果和数据准确性。
重采样的主要目的:
- 尺寸缩放:改变图像的分辨率,使其变大或变小。例如,缩小图像可用于节省存储空间或加速处理,而放大图像用于查看细节。
- 旋转、平移、仿射变换:对图像进行各种几何变换,保持图像特征不失真。
- 图像配准:将一幅图像对齐到另一幅图像中,通常用于医学图像处理、多视角影像合成等领域。
重采样的过程:
- 几何变换:根据目标图像的需求(缩放、旋转、平移等),使用相应的几何变换(如仿射变换、刚体变换)将原图像的坐标映射到新图像的坐标系。
- 插值计算:由于原始图像中的像素点坐标通常不能直接映射到新图像中的整数坐标,需要通过插值算法(如线性插值、双三次插值等)来估算新位置像素值。
- 输出图像生成:根据插值计算得到的像素值生成新的图像。
重采样的核心之一是插值方法,用于计算新图像中每个像素点的值。常见的插值方法有:
-
最近邻插值:
- 最简单的插值方法,新像素值取与之最近的旧像素点的值。
- 优点:计算量小,速度快。
- 缺点:图像缩放后容易产生锯齿效应,图像不够平滑。
-
双线性插值:
- 通过周围 2x2 个像素点的加权平均,计算出新像素值。
- 优点:生成的图像较平滑,效果好于最近邻插值。
- 缺点:相比最近邻插值,计算复杂度稍高。
-
双三次插值:
- 通过周围 4x4 个像素点进行插值计算,考虑更多像素的信息。
- 优点:图像质量较好,适合大规模缩放。
- 缺点:计算量较大。
-
样条插值(Spline Interpolation):
- 通过样条曲线对图像进行插值,能保证图像边缘的平滑性。
- 优点:插值精度高,能保留较多细节。
- 缺点:计算较复杂。
重采样的应用:
- 医学图像处理:重采样用于将多模态(如 CT、MRI)或多时间点图像进行配准,以便医生进行精确分析。
- 计算机视觉:对图像进行缩放或旋转以适应不同的应用需求,如目标识别、特征提取。
- 遥感影像处理:遥感影像需要在不同分辨率下进行分析和配准,重采样是关键步骤之一。
重采样的挑战:
- 图像失真:在缩放和旋转等操作中,重采样可能会引入失真,尤其是最近邻插值容易导致锯齿或模糊效果。
- 计算量:复杂的插值方法(如双三次插值、样条插值)会增加计算时间,在实时处理应用中可能会带来性能问题。
总结来说,重采样是图像处理中的一种基础技术,能够对图像进行精确的几何变换,适用于图像配准、缩放、旋转等多种应用场景,且插值方法的选择直接影响到处理后的图像质量。
环境准备
参见:Windows下用CMake编译ITK及配置测试_itk配置-CSDN博客
功能解析
下面以图像扩展2倍为例,展示重采样的使用方法。
1.引入必要的头文件:
#include <itkImage.h>
#include <itkImageFileReader.h>
#include <itkImageFileWriter.h>
#include <itkResampleImageFilter.h>
#include <itkAffineTransform.h>
#include <itkLinearInterpolateImageFunction.h>
#include <itkRescaleIntensityImageFilter.h>
#include <itkJPEGImageIOFactory.h>
2.初始化图像类型和读写器:
// 定义图像类型
typedef itk::Image<unsigned char, 2> ImageType;
typedef itk::ImageFileReader<ImageType> ReaderType;
typedef itk::ImageFileWriter<ImageType> WriterType;
// 注册JPEG格式支持
itk::JPEGImageIOFactory::RegisterOneFactory();
// 创建读取器和写入器
ReaderType::Pointer reader = ReaderType::New();
WriterType::Pointer writer = WriterType::New();
3.设置文件名:
// 设置要读取和写入的文件
reader->SetFileName("test.jpg");
writer->SetFileName("output_2x_resized.jpg");
4.读取图像信息:
// 读取图像
reader->Update();
// 获取原始图像的大小和空间信息
ImageType::Pointer inputImage = reader->GetOutput();
ImageType::SpacingType inputSpacing = inputImage->GetSpacing();
ImageType::SizeType inputSize = inputImage->GetLargestPossibleRegion().GetSize();
// 计算输出图像的空间信息(将图像扩展为原来的2倍)
ImageType::SpacingType outputSpacing;
outputSpacing[0] = inputSpacing[0] / 2.0; // 水平方向的间距缩小一半(像素数变成两倍)
outputSpacing[1] = inputSpacing[1] / 2.0; // 垂直方向的间距缩小一半
ImageType::SizeType outputSize;
outputSize[0] = inputSize[0] * 2; // 水平方向的像素数扩展为两倍
outputSize[1] = inputSize[1] * 2; // 垂直方向的像素数扩展为两倍
5.创建仿射变换、插值器、重采样滤波器:
// 创建一个仿射变换,用于调整图像空间
typedef itk::AffineTransform<double, 2> TransformType;
TransformType::Pointer transform = TransformType::New();
transform->SetIdentity();
// 创建插值器(线性插值)
typedef itk::LinearInterpolateImageFunction<ImageType, double> InterpolatorType;
InterpolatorType::Pointer interpolator = InterpolatorType::New();
// 创建重采样滤波器
typedef itk::ResampleImageFilter<ImageType, ImageType> ResampleFilterType;
ResampleFilterType::Pointer resampleFilter = ResampleFilterType::New();
resampleFilter->SetInput(inputImage);
resampleFilter->SetTransform(transform);
resampleFilter->SetInterpolator(interpolator);
resampleFilter->SetOutputSpacing(outputSpacing);
resampleFilter->SetSize(outputSize);
resampleFilter->SetOutputOrigin(inputImage->GetOrigin());
resampleFilter->SetOutputDirection(inputImage->GetDirection());
// 执行重采样
try
{
resampleFilter->Update();
}
catch (itk::ExceptionObject &error)
{
std::cerr << "Error: " << error << std::endl;
return EXIT_FAILURE;
}
6.连接过滤器输出到写入器并执行写入操作:
// 保存输出图像
writer->SetInput(resampleFilter->GetOutput());
try
{
writer->Update();
}
catch (itk::ExceptionObject &error)
{
std::cerr << "Error: " << error << std::endl;
return EXIT_FAILURE;
}
完整代码
#include <itkImage.h>
#include <itkImageFileReader.h>
#include <itkImageFileWriter.h>
#include <itkResampleImageFilter.h>
#include <itkAffineTransform.h>
#include <itkLinearInterpolateImageFunction.h>
#include <itkRescaleIntensityImageFilter.h>
#include <itkJPEGImageIOFactory.h>
int main()
{
// 定义图像类型
typedef itk::Image<unsigned char, 2> ImageType;
typedef itk::ImageFileReader<ImageType> ReaderType;
typedef itk::ImageFileWriter<ImageType> WriterType;
// 注册JPEG格式支持
itk::JPEGImageIOFactory::RegisterOneFactory();
// 创建读取器和写入器
ReaderType::Pointer reader = ReaderType::New();
WriterType::Pointer writer = WriterType::New();
// 设置要读取和写入的文件
reader->SetFileName("test.jpg");
writer->SetFileName("output_2x_resized.jpg");
// 读取图像
reader->Update();
// 获取原始图像的大小和空间信息
ImageType::Pointer inputImage = reader->GetOutput();
ImageType::SpacingType inputSpacing = inputImage->GetSpacing();
ImageType::SizeType inputSize = inputImage->GetLargestPossibleRegion().GetSize();
// 计算输出图像的空间信息(将图像扩展为原来的2倍)
ImageType::SpacingType outputSpacing;
outputSpacing[0] = inputSpacing[0] / 2.0; // 水平方向的间距缩小一半(像素数变成两倍)
outputSpacing[1] = inputSpacing[1] / 2.0; // 垂直方向的间距缩小一半
ImageType::SizeType outputSize;
outputSize[0] = inputSize[0] * 2; // 水平方向的像素数扩展为两倍
outputSize[1] = inputSize[1] * 2; // 垂直方向的像素数扩展为两倍
// 创建一个仿射变换,用于调整图像空间
typedef itk::AffineTransform<double, 2> TransformType;
TransformType::Pointer transform = TransformType::New();
transform->SetIdentity();
// 创建插值器(线性插值)
typedef itk::LinearInterpolateImageFunction<ImageType, double> InterpolatorType;
InterpolatorType::Pointer interpolator = InterpolatorType::New();
// 创建重采样滤波器
typedef itk::ResampleImageFilter<ImageType, ImageType> ResampleFilterType;
ResampleFilterType::Pointer resampleFilter = ResampleFilterType::New();
resampleFilter->SetInput(inputImage);
resampleFilter->SetTransform(transform);
resampleFilter->SetInterpolator(interpolator);
resampleFilter->SetOutputSpacing(outputSpacing);
resampleFilter->SetSize(outputSize);
resampleFilter->SetOutputOrigin(inputImage->GetOrigin());
resampleFilter->SetOutputDirection(inputImage->GetDirection());
// 执行重采样
try
{
resampleFilter->Update();
}
catch (itk::ExceptionObject &error)
{
std::cerr << "Error: " << error << std::endl;
return EXIT_FAILURE;
}
// 保存输出图像
writer->SetInput(resampleFilter->GetOutput());
try
{
writer->Update();
}
catch (itk::ExceptionObject &error)
{
std::cerr << "Error: " << error << std::endl;
return EXIT_FAILURE;
}
std::cout << "Image resized to 2x original size successfully!" << std::endl;
return EXIT_SUCCESS;
}
测试效果
如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!