itk配准整理(1)

news2024/11/23 17:13:26

示例地址:

itk\ITK\Examples\RegistrationITKv4\ImageRegistration7.cxx

说明:itk二维图像的配准:平移+旋转+缩放

效果图:

在这里插入图片描述

运行结果:

52 53.6213 [0.8333298229719548, -0.17450270771316403, -12.806452097490313, -12.724475494918924]
53 53.5935 [0.8332372921962161, -0.17451072912054427, -12.80648932249624, -12.724405572299606]
Optimizer stop condition: RegularStepGradientDescentOptimizerv4: Step too small after 54 iterations. Current step (6.10352e-005) is less than minimum step (0.0001).

Result =
Scale = 0.833237
Angle (radians) = -0.174511
Angle (degrees) = -9.99873
Translation X = -12.8065
Translation Y = -12.7244
Fixed Center X = 111.204
Fixed Center Y = 131.591
Iterations = 55
Metric value = 53.6171

代码整理:

#include "mainwindow.h"

#include <QApplication>

#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL2)
VTK_MODULE_INIT(vtkRenderingFreeType)
VTK_MODULE_INIT(vtkRenderingContextOpenGL2)

#include "itkImageRegistrationMethodv4.h"
#include "itkMeanSquaresImageToImageMetricv4.h"
#include "itkRegularStepGradientDescentOptimizerv4.h"
#include "itkCenteredTransformInitializer.h"

#include "itkSimilarity2DTransform.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkResampleImageFilter.h"
#include "itkCastImageFilter.h"
#include "itkSubtractImageFilter.h"
#include "itkRescaleIntensityImageFilter.h"
#include "itkIdentityTransform.h"

#include "itkCommand.h"
class CommandIterationUpdate : public itk::Command
{
public:
  using Self = CommandIterationUpdate;
  using Superclass = itk::Command;
  using Pointer = itk::SmartPointer<Self>;
  itkNewMacro(Self);

protected:
  CommandIterationUpdate() = default;

public:
  using OptimizerType = itk::RegularStepGradientDescentOptimizerv4<double>;
  using OptimizerPointer = const OptimizerType *;

  void
  Execute(itk::Object * caller, const itk::EventObject & event) override
  {
    Execute((const itk::Object *)caller, event);
  }

  void
  Execute(const itk::Object * object, const itk::EventObject & event) override
  {
    auto optimizer = static_cast<OptimizerPointer>(object);
    if (!itk::IterationEvent().CheckEvent(&event))
    {
      return;
    }
    std::cout << optimizer->GetCurrentIteration() << "   ";
    std::cout << optimizer->GetValue() << "   ";
    std::cout << optimizer->GetCurrentPosition() << std::endl;
  }
};

#include "itkPNGImageIOFactory.h"
int main(int argc, char *argv[])
{
    itk::PNGImageIOFactory::RegisterOneFactory();
    constexpr unsigned int Dimension = 2;
    using PixelType = float;
    using FixedImageType = itk::Image<PixelType, Dimension>;
    using MovingImageType = itk::Image<PixelType, Dimension>;

    using TransformType = itk::Similarity2DTransform<double>;
    using OptimizerType = itk::RegularStepGradientDescentOptimizerv4<double>;
    using MetricType = itk::MeanSquaresImageToImageMetricv4<FixedImageType, MovingImageType>;
    using RegistrationType = itk::ImageRegistrationMethodv4<FixedImageType, MovingImageType, TransformType>;

    MetricType::Pointer       metric = MetricType::New();
    OptimizerType::Pointer    optimizer = OptimizerType::New();
    RegistrationType::Pointer registration = RegistrationType::New();
    registration->SetMetric(metric);
    registration->SetOptimizer(optimizer);

    TransformType::Pointer transform = TransformType::New();

    using FixedImageReaderType = itk::ImageFileReader<FixedImageType>;
    using MovingImageReaderType = itk::ImageFileReader<MovingImageType>;
    QString baseDir = "D:/learn/itk/ITK/Examples/Data/";
    FixedImageReaderType::Pointer fixedImageReader =
      FixedImageReaderType::New();
    MovingImageReaderType::Pointer movingImageReader =
      MovingImageReaderType::New();
    fixedImageReader->SetFileName((baseDir+"BrainProtonDensitySliceBorder20.png").toStdString());
    movingImageReader->SetFileName((baseDir+"BrainProtonDensitySliceR10X13Y17S12.png").toStdString());
    registration->SetFixedImage(fixedImageReader->GetOutput());
    registration->SetMovingImage(movingImageReader->GetOutput());

    //  In this example, we again use the helper class
    //  \doxygen{CenteredTransformInitializer} to compute a reasonable
    //  value for the initial center of rotation and scaling along with
    //  an initial translation.
    //使用CenteredTransformInitializer计算初始旋转和缩放中心的合理值以及初始平移。
    using TransformInitializerType =
      itk::CenteredTransformInitializer<TransformType,
                                        FixedImageType,
                                        MovingImageType>;

    TransformInitializerType::Pointer initializer = TransformInitializerType::New();
    initializer->SetTransform(transform);
    initializer->SetFixedImage(fixedImageReader->GetOutput());
    initializer->SetMovingImage(movingImageReader->GetOutput());
    initializer->MomentsOn();
    initializer->InitializeTransform();

    // The remaining parameters of the transform are initialized below.
    // 转换的其余参数在下面初始化。
    double initialScale = 1.0;
    double initialAngle = 0.0;
    transform->SetScale(initialScale);
    transform->SetAngle(initialAngle);
    //  Now the initialized transform object will be set to the registration
    //  method, and its initial parameters are used to initialize the
    //  registration process.
    //
    //  Also, by calling the \code{InPlaceOn()} method, this initialized
    //  transform will be the output transform
    //  object or ``grafted'' to the output of the registration process.
    //现在,将初始化的转换对象设置为注册方法,并使用其初始参数初始化注册过程。
    //此外,通过调用InPlaceOn()方法,这个初始化的转换将是输出转换对象或“嫁接”到注册过程的输出。

    registration->SetInitialTransform(transform);
    registration->InPlaceOn();

    //  Keeping in mind that the scale of units in scaling, rotation and
    //  translation are quite different, we take advantage of the scaling
    //  functionality provided by the optimizers. We know that the first element
    //  of the parameters array corresponds to the scale factor, the second
    //  corresponds to the angle, third and fourth are the remaining
    //  translation. We use henceforth small factors in the scales
    //  associated with translations.
    //请记住,缩放、旋转和平移的单位规模是非常不同的,我们利用优化器提供的缩放功能。我们知道参数数组的
    //第一个元素对应比例因子,第二个对应角度,第三和第四个是剩余的平移。今后,我们在与翻译相关的量表中使用小的因素。

    using OptimizerScalesType = OptimizerType::ScalesType;
    OptimizerScalesType optimizerScales(transform->GetNumberOfParameters());
    const double        translationScale = 1.0 / 100.0;
    optimizerScales[0] = 10.0;
    optimizerScales[1] = 1.0;
    optimizerScales[2] = translationScale;
    optimizerScales[3] = translationScale;
    optimizer->SetScales(optimizerScales);

    //  We also set the ordinary parameters of the optimization method. In this
    //  case we are using a
    //  \doxygen{RegularStepGradientDescentOptimizerv4}. Below we define the
    //  optimization parameters, i.e. initial learning rate (step length),
    //  minimal step length and number of iterations. The last two act as
    //  stopping criteria for the optimization.
    //我们还设置了优化方法的普通参数。 在这种情况下,我们使用 {RegularStepGradientDescentOptimizerv4}。
    //下面我们定义优化参数,即初始学习率(步长)、最小步长和迭代次数。 最后两个作为优化的停止标准。
    double steplength = 1.0;
    optimizer->SetLearningRate(steplength);
    optimizer->SetMinimumStepLength(0.0001);
    optimizer->SetNumberOfIterations(200);

    // Create the Command observer and register it with the optimizer.
    CommandIterationUpdate::Pointer observer = CommandIterationUpdate::New();
    optimizer->AddObserver(itk::IterationEvent(), observer);

    // One level registration process without shrinking and smoothing.
    constexpr unsigned int numberOfLevels = 1;

    RegistrationType::ShrinkFactorsArrayType shrinkFactorsPerLevel;
    shrinkFactorsPerLevel.SetSize(1);
    shrinkFactorsPerLevel[0] = 1;

    RegistrationType::SmoothingSigmasArrayType smoothingSigmasPerLevel;
    smoothingSigmasPerLevel.SetSize(1);
    smoothingSigmasPerLevel[0] = 0;

    registration->SetNumberOfLevels(numberOfLevels);
    registration->SetSmoothingSigmasPerLevel(smoothingSigmasPerLevel);
    registration->SetShrinkFactorsPerLevel(shrinkFactorsPerLevel);

    try
    {
      registration->Update();
      std::cout << "Optimizer stop condition: "
                << registration->GetOptimizer()->GetStopConditionDescription()
                << std::endl;
    }
    catch (const itk::ExceptionObject & err)
    {
      std::cerr << "ExceptionObject caught !" << std::endl;
      std::cerr << err << std::endl;
      return EXIT_FAILURE;
    }

    TransformType::ParametersType finalParameters = transform->GetParameters();
    const double finalScale = finalParameters[0];
    const double finalAngle = finalParameters[1];
    const double finalTranslationX = finalParameters[2];
    const double finalTranslationY = finalParameters[3];
    const double rotationCenterX =
      registration->GetOutput()->Get()->GetFixedParameters()[0];
    const double rotationCenterY =
      registration->GetOutput()->Get()->GetFixedParameters()[1];
    const unsigned int numberOfIterations = optimizer->GetCurrentIteration();
    const double bestValue = optimizer->GetValue();
    const double finalAngleInDegrees = finalAngle * 180.0 / itk::Math::pi;

    std::cout << std::endl;
    std::cout << "Result = " << std::endl;
    std::cout << " Scale           = " << finalScale << std::endl;
    std::cout << " Angle (radians) = " << finalAngle << std::endl;
    std::cout << " Angle (degrees) =  " << finalAngleInDegrees << std::endl;
    std::cout << " Translation X   = " << finalTranslationX << std::endl;
    std::cout << " Translation Y   = " << finalTranslationY << std::endl;
    std::cout << " Fixed Center X  = " << rotationCenterX << std::endl;
    std::cout << " Fixed Center Y  = " << rotationCenterY << std::endl;
    std::cout << " Iterations      = " << numberOfIterations << std::endl;
    std::cout << " Metric value    = " << bestValue << std::endl;

    //  The second image is the result of intentionally rotating the first image
    //  by $10$ degrees, scaling by $1/1.2$ and then translating by $(-13,-17)$.
    //  Both images have unit-spacing and are shown in Figure
    //  \ref{fig:FixedMovingImageRegistration7}. The registration takes $53$
    //  iterations and produces:

    //  [0.833237, -0.174511, -12.8065, -12.7244 ]
    //  That are interpreted as
    //  \item Scale factor  =       $0.833237$
    //  \item Angle         =       $-0.174511$   radians
    //  \item Translation   = $( -12.8065, -12.7244 )$ millimeters

    //  These values approximate the misalignment intentionally introduced into
    //  the moving image. Since $10$ degrees is about $0.174532$ radians.
    //
    // Figure \ref{fig:ImageRegistration7Outputs} shows the output of the
    // registration. The right image shows the squared magnitude of pixel
    // differences between the fixed image and the resampled moving image.

    // \includegraphics[height=0.32\textwidth]{ImageRegistration7TraceMetric}
    // \includegraphics[height=0.32\textwidth]{ImageRegistration7TraceAngle}
    // \includegraphics[height=0.32\textwidth]{ImageRegistration7TraceScale}
    // \includegraphics[height=0.32\textwidth]{ImageRegistration7TraceTranslations}
    // \itkcaption[Simularity2DTransform registration plots]{Plots of the
    // Metric, rotation angle, scale factor, and translations during the
    // registration using Similarity2D transform.}

    //  Figure \ref{fig:ImageRegistration7Plots} shows the plots of the main
    //  output parameters of the registration process. The metric values at
    //  every iteration are shown on the left. The rotation angle and scale
    //  factor values are shown in the two center plots while the translation
    //  components of the registration are presented in the plot on the right.
    //
    //  Software Guide : EndLatex

    using ResampleFilterType =
      itk::ResampleImageFilter<MovingImageType, FixedImageType>;
    ResampleFilterType::Pointer resampler = ResampleFilterType::New();
    resampler->SetTransform(transform);
    resampler->SetInput(movingImageReader->GetOutput());
    FixedImageType::Pointer fixedImage = fixedImageReader->GetOutput();
    resampler->SetSize(fixedImage->GetLargestPossibleRegion().GetSize());
    resampler->SetOutputOrigin(fixedImage->GetOrigin());
    resampler->SetOutputSpacing(fixedImage->GetSpacing());
    resampler->SetOutputDirection(fixedImage->GetDirection());
    resampler->SetDefaultPixelValue(100);

    using OutputPixelType = unsigned char;
    using OutputImageType = itk::Image<OutputPixelType, Dimension>;
    using CastFilterType =
      itk::CastImageFilter<FixedImageType, OutputImageType>;
    using WriterType = itk::ImageFileWriter<OutputImageType>;
    WriterType::Pointer     writer = WriterType::New();
    CastFilterType::Pointer caster = CastFilterType::New();
    writer->SetFileName("./ImageRegistration7Output.png");
    caster->SetInput(resampler->GetOutput());
    writer->SetInput(caster->GetOutput());
    writer->Update();

    using DifferenceFilterType =itk::SubtractImageFilter<FixedImageType, FixedImageType, FixedImageType>;
    DifferenceFilterType::Pointer difference = DifferenceFilterType::New();
    using RescalerType =itk::RescaleIntensityImageFilter<FixedImageType, OutputImageType>;
    RescalerType::Pointer intensityRescaler = RescalerType::New();
    intensityRescaler->SetInput(difference->GetOutput());
    intensityRescaler->SetOutputMinimum(0);
    intensityRescaler->SetOutputMaximum(255);
    difference->SetInput1(fixedImageReader->GetOutput());
    difference->SetInput2(resampler->GetOutput());
    resampler->SetDefaultPixelValue(1);
    WriterType::Pointer writer2 = WriterType::New();
    writer2->SetInput(intensityRescaler->GetOutput());
    // Compute the difference image between the fixed and resampled moving image.
    {
      writer2->SetFileName("./ImageRegistration7DifferenceAfter.png");
      writer2->Update();
    }
    using IdentityTransformType = itk::IdentityTransform<double, Dimension>;
    IdentityTransformType::Pointer identity = IdentityTransformType::New();
    // Compute the difference image between the fixed and moving image before registration.
    {
      resampler->SetTransform(identity);
      writer2->SetFileName("./ImageRegistration7DifferenceBefore.png");
      writer2->Update();
    }
    return EXIT_SUCCESS;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/28484.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在Win10中使用YAMAHA S-YXG50软波表

曾经非常经典的一款软波表YAMAHA S-YXG50我个人非常的喜欢。在XP系统的时代&#xff0c;是我必装的软件&#xff0c;用来听一些MIDI音质和效果很好。而如今玩MIDI的人越来越少了&#xff0c;软波表的时代也被人渐渐的遗忘了。 如今想要怀旧的话&#xff0c;只能够找一台老电脑…

LINUX的XEN和KVM到底区别在什么地方?

本文调研的是 Completely Fair Scheduler 算法, 它当前是 Linux 中 SCHED_NORMAL(非实时任务) 一类 task 的默认调度器. 实际上, 运行在 Guest OS 中的应用程序线程还受到 Guest OS 的调度, 分时运行在 vCPU 上, 但这不在本文调研范围内. 本文仅调研 vCPU 被如何调度到 pCPU 上…

WebDAV之葫芦儿·派盘+无聊笔记

无聊笔记 支持webdav方式连接葫芦儿派盘。 无聊笔记是一款深受用户认可的系统工具,随时都可以进行软件的操作,也可以在线进行笔记的记录,系统会进行智能的保存,满足了用户日常中的需求,可以把软件作为备忘录,笔记本,摘抄录等。 无聊笔记是一个功能强大的记录工具,您…

代码随想录算法训练营第四十二天| LeetCode416. 分割等和子集

一、LeetCode416. 分割等和子集 1&#xff1a;题目描述&#xff08;416. 分割等和子集&#xff09; 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集&#xff0c;使得两个子集的元素和相等。 2&#xff1a;解题思路 本题需要使用01背包的…

合作动态 | 方正璞华与日立签订战略合作协议,加快推进数字化管理变革!

2022年10月27日&#xff0c;方正璞华PLM事业部负责人王志起先生与日立方代表正式签订“方正璞华PLM产品销售合作框架协议”。 根据协议&#xff0c;双方将围绕璞华PLM产品推广、客户拓展、全生命周期运营服务等领域&#xff0c;开展多元化、多层级的深度融合合作&#xff0c;共…

HTML制作一个介绍自己家乡的网站——贵阳,排版整洁,内容丰富,主题鲜明

家乡旅游景点网页作业制作 网页代码运用了DIV盒子的使用方法&#xff0c;如盒子的嵌套、浮动、margin、border、background等属性的使用&#xff0c;外部大盒子设定居中&#xff0c;内部左中右布局&#xff0c;下方横向浮动排列&#xff0c;大学学习的前端知识点和布局方式都有…

CV:计算机视觉技最强学习路线之CV简介(传统视觉技术/相关概念)、早期/中期/近期应用领域(偏具体应用)、经典CNN架构(偏具体算法)概述、常用工具/库/框架/产品、环境安装、常用数据集、编程技巧

CV&#xff1a;计算机视觉技最强学习路线之CV简介(传统视觉技术/相关概念)、早期/中期/近期应用领域(偏具体应用)、经典CNN架构(偏具体算法)概述、常用工具/库/框架/产品、环境安装、常用数据集、编程技巧 导读&#xff1a;计算机视觉技最强学习路线&#xff0c;博主花了三个晚…

Class加载过程

文章目录java解释执行热点代码编译类生命周期加载&#xff08;Loading&#xff09;验证&#xff08;Verification&#xff09;准备&#xff08;Preparation&#xff09;解析&#xff08;Resolution&#xff09;初始化&#xff08;Initialization&#xff09;使用&#xff08;Us…

并发编程(三)原子性(2)

【 悲观锁与乐观锁 】&#xff1a; 【悲观锁】&#xff1a; 一定会被别人打断&#xff1b;我必须得上锁。synchronized就是悲观锁。 【乐观锁】&#xff1a; 乐观锁又称之为——无锁、自旋锁、CAS 。 厕所里的人认为不会有其他人来上厕所和我竞争。 【举例解释CAS操作】&a…

SOHO帮客户找新品,如何拿到最优价?要不要选择大型机械类产品?

做外贸&#xff0c;无论是贸易公司还是工厂&#xff0c;又或者是SOHO。都有机会帮助客户采购自己主打产品之外的其他产品&#xff0c;有些人就会问&#xff0c;对于客户咨询的新产品&#xff0c;我们本身没有熟悉的供应商&#xff0c;这个时候要怎么去找到好的供货商&#xff1…

世界技能大赛夺冠背后,亚马逊云科技如何培养云计算技能人才?

云计算相关专业的就业前景如何&#xff1f; 人社部数据显示&#xff0c;到2025年我国云计算人才缺口将高达近150万。另一方面&#xff0c;根据艾瑞咨询《中国云计算行业洞察与人才分析》报告&#xff0c;2019年云计算领域人才月均薪酬在1万元以上的占比达93.7%&#xff0c;3万元…

VK3606D抗电机马达干扰直接输出6键触摸芯片,电容式6通道触控检测IC低电平有效,无触摸4秒进入待机模式常用于工控面板/空调/风扇/家电等

VINKA/永嘉微电的VK3606D SOP16是一种具有自动校准功能&#xff0c;低待机电流&#xff0c;抗电压波动等特性的&#xff0c;6按键电容式触摸触控检测IC&#xff0c;适用于温控器&#xff0c;86面板触摸开关&#xff0c;智能家居等抗干扰场所 型号&#xff1a;VK3606D 封装形…

WebGL、GPU硬件加速、GLSL、光栅化

一、介绍 WebGL经常被当成3D API&#xff0c;人们总想“我可以使用WebGL和一些神奇的东西做出炫酷的3D作品”。 事实上WebGL仅仅是一个光栅化引擎&#xff0c;它可以根据你的代码绘制出点&#xff0c;线和三角形。 想要利用WebGL完成更复杂任务&#xff0c;取决于你能否提供合…

CentOS Stream 9 配置静态 IP

系统环境&#xff1a; OS&#xff1a;CentOS Stream 9 CentOS Stream 9 不同于以往版本的 CentOS&#xff0c;没有之前的网络设置相关的命令&#xff0c;如&#xff1a; service network start/restart/status systemctl start/restart/status network设置网卡 IP 的配置文件…

新媒体研究杂志社新媒体研究编辑部新媒体研究杂志2022年第18期目录

本期聚焦 出版学核心期刊自媒体运营状况与其学术影响力关系研究 程海燕;季佳乐; 1-5 理论研究 《新媒体研究》投稿&#xff1a;cnqikantg126.com 网络社群网民情绪感染研究综述 单悦影;祁凯; 6-922 基于CiteSpace的被遗忘权研究综述 徐怡; 10-14 应用研究 …

MCE | RNA 逆转录小提示

Tips 1&#xff1a;防止 RNA 模板的降解毫无疑问&#xff0c;RNA 质量对 cDNA 合成结果会产生重要影响。但 RNA 很脆弱&#xff0c;易于降解。为了保证 RNA 的完整性&#xff0c;我们需要小心又小心&#xff0c;比如在冰上操作&#xff0c;用 RNase-free 的枪头和离心管&#x…

力扣27.移除元素【顺序表】

&#x1f648;个人主页&#xff1a;阿伟t &#x1f449;系列专栏&#xff1a;【C语言–大佬之路】 &#x1f388;今日心语&#xff1a;你所看到的惊艳&#xff0c;都曾被平庸所历练。 前言&#xff1a; 在解题过程中一定要画图进行思考&#xff0c;然后再敲代码。 文章目录移除…

计算属性computed、过滤器定义Vue.filter()

计算属性是为了计算得到一个结果而设计的&#xff1b;放在Vue中computed里面定义&#xff1a;如果我们想在页面上打印一个变量&#xff0c;那就直接“{{变量}}”放在大括号里面&#xff0c;然后变量在data里面定义好初始值&#xff0c;就可以在页面上输出了&#xff0c;比如&am…

策略验证_指标买点分析技法_运用KDJ随机指标选择买点

写在前面&#xff1a; 1. 本文中提到的“股票策略校验工具”的具体使用操作请查看该博文&#xff1b; 2. 文中知识内容来自书籍《同花顺炒股软件从入门到精通》 3. 本系列文章是用来学习技法&#xff0c;文中所得内容都仅仅只是作为演示功能使用 目录 解说 策略代码 结果 解…

tftp服务配置的详细过程,简单快速

主机端编译的Linux内核影像必须有至少一种方式下载到目标板上执行。通常是目标板的引导程序负责把主机端的影像文件下载到内存中。根据不同的连接方式&#xff0c;可以有多种文件传输方式&#xff0c;每一种方式都需要相应的传输软件和协议。 在linux开发中最常用的传输方式为网…