3D图像双线性插值

news2024/11/24 9:44:11

文章目录

  • 前言
  • 结论
    • 说明:
    • 公式
  • 测试

前言

看了一下2d图像的双线性插值的理论,基本上都是在原图上找到对应的浮点坐标 p f p_f pf后,将以 p f p_f pf外围的4个点进行计算。计算的方法类似于二维直线方程的理论,但是写成了权重的方式。我看了一下,权重的方式还蛮好理解的。因为要用到,不自量力类推了一下3d图像插值,如果有错误,麻烦看到的大佬指出,感谢。

结论

在这里插入图片描述

说明:

v ( x , y , z ) v(x,y,z) v(x,y,z): ( x , y , z ) (x,y,z) (x,y,z)点处的value
v n e w v_{new} vnew: 新值
v o l d v_{old} vold: 旧值

公式

v n e w ( x , y , z ) =     v o l d ( x 1 , y 1 , z 2 ) ( x 2 − x ) ( y 2 − y ) ( z − z 1 ) + v o l d ( x 2 , y 2 , z 1 ) ( x − x 1 ) ( y − y 1 ) ( z 2 − z ) + v o l d ( x 2 , y 1 , z 2 ) ( x − x 1 ) ( y 2 − y ) ( z − z 1 ) + v o l d ( x 1 , y 2 , z 1 ) ( x 2 − x ) ( y − y 1 ) ( z 2 − z ) + v o l d ( x 2 , y 2 , z 2 ) ( x − x 1 ) ( y − y 1 ) ( z − z 1 ) + v o l d ( x 1 , y 1 , z 1 ) ( x 2 − x ) ( y 2 − y ) ( z 2 − z ) + v o l d ( x 1 , y 2 , z 2 ) ( x 2 − x ) ( y − y 1 ) ( z − z 1 ) + v o l d ( x 2 , y 1 , z 1 ) ( x − x 1 ) ( y 2 − y ) ( z 2 − z ) v_{new}(x,y,z)=\\ \ \ \ v_{old}(x1,y1,z2)(x2-x)(y2-y)(z-z1) \\+v_{old}(x2,y2,z1)(x-x1)(y-y1)(z2-z) \\+v_{old}(x2,y1,z2)(x-x1)(y2-y)(z-z1) \\+v_{old}(x1,y2,z1)(x2-x)(y-y1)(z2-z) \\+v_{old}(x2,y2,z2)(x-x1)(y-y1)(z-z1) \\+v_{old}(x1,y1,z1)(x2-x)(y2-y)(z2-z) \\+v_{old}(x1,y2,z2)(x2-x)(y-y1)(z-z1) \\+v_{old}(x2,y1,z1)(x-x1)(y2-y)(z2-z) vnew(x,y,z)=   vold(x1,y1,z2)(x2x)(y2y)(zz1)+vold(x2,y2,z1)(xx1)(yy1)(z2z)+vold(x2,y1,z2)(xx1)(y2y)(zz1)+vold(x1,y2,z1)(x2x)(yy1)(z2z)+vold(x2,y2,z2)(xx1)(yy1)(zz1)+vold(x1,y1,z1)(x2x)(y2y)(z2z)+vold(x1,y2,z2)(x2x)(yy1)(zz1)+vold(x2,y1,z1)(xx1)(y2y)(z2z)

测试

我在3d图像上测试了一下放大1.5倍,效果看起来还行
在这里插入图片描述

// 测试 3d 双线性插值

#include<iostream>
#include<itkImage.h>
#include<itkImageFileReader.h>
#include<itkImageFileWriter.h>
#include<itkNiftiImageIO.h>
#include<itkPNGImageIO.h>

using namespace std;

using PixelType = short;
const int Dimension = 3;
using ImageType = itk::Image<PixelType, Dimension>;
using ImagePointerType = ImageType::Pointer;


template<typename image_type, typename image_pointer>
void readData(const std::string& file_path, image_pointer& out_image) {
	using imageIOType = itk::NiftiImageIO;
	//using imageIOType = itk::PNGImageIO;
	using readerType = itk::ImageFileReader<image_type>;

	auto reader = readerType::New();
	auto imageIO = imageIOType::New();

	reader->SetImageIO(imageIO);
	reader->SetFileName(file_path);
	try {
		reader->Update();
	}
	catch (const itk::ExceptionObject& e) {
		cout << e.what() << endl;
	}

	out_image = reader->GetOutput();
}

template<typename image_type, typename image_pointer>
void writeData(const image_pointer& write_image, const std::string& write_path) {
	using writerType = itk::ImageFileWriter<image_type>;
	auto writer = writerType::New();

	using ImageIOType = itk::NiftiImageIO;
	// using ImageIOType = itk::PNGImageIO;
	auto ImageIO = ImageIOType::New();
	writer->SetImageIO(ImageIO);

	writer->SetInput(write_image);
	writer->SetFileName(write_path);
	writer->Update();
}

void createNewImage(
	ImagePointerType& new_image,
	const ImageType::SpacingType& spacing,
	const ImageType::DirectionType& direction,
	const ImageType::PointType& origin,
	const ImageType::SizeType& size)
{
	new_image = ImageType::New();
	ImageType::IndexType start;
	start[0] = 0; // x轴起始值
	start[1] = 0; // y轴起始值
	start[2] = 0; // z轴起始值
	ImageType::RegionType region;
	region.SetSize(size);
	region.SetIndex(start);
	new_image->SetRegions(region);
	new_image->Allocate();
	new_image->SetSpacing(spacing);
	new_image->SetDirection(direction);
	new_image->SetOrigin(origin);
	PixelType* regionBuffer = new_image->GetBufferPointer();
	for (int x = 0; x < size[0]; x++) {
		for (int y = 0; y < size[1]; y++) {
			for (int z = 0; z < size[2]; z++) {
				int index = size[0] * size[1] * z +
					size[0] * y + x;
				regionBuffer[index] = 0;
			}
		}
	}
}


void bilinearInterpolation(const ImagePointerType& input_image,
	ImagePointerType& out_image)
{
	// 取出各自的size
	ImageType::SizeType inputSize = input_image->GetBufferedRegion().GetSize();
	ImageType::SizeType outSize = out_image->GetBufferedRegion().GetSize();

	PixelType* inputBuffer = input_image->GetBufferPointer();
	PixelType* outBuffer = out_image->GetBufferPointer();

	int XInput = inputSize[0], YInput = inputSize[1], ZInput = inputSize[2];
	int XOut = outSize[0], YOut = outSize[1], ZOut = outSize[2];
	float deltax = XInput * 1.0 / XOut, deltay = YInput * 1.0 / YOut, deltaz = ZInput * 1.0 / ZOut;
	cout << deltax << ", " << deltay << ", " << deltaz << endl;
	// 目标: 求得outImage(xi,yi,zi)下的像素值
	for (int xi = 0; xi < XOut; ++xi) {
		for (int yi = 0; yi < YOut; ++yi) {
			for (int zi = 0; zi < ZOut; ++zi) {
				// 计算对应到inputImage的浮点坐标
				float x = xi * deltax, y = yi * deltay, z = zi * deltaz;
				// 计算(x1,y1,z1)
				int x1 = floor(x), y1 = floor(y), z1 = floor(z);
				// 计算(x2,y2,z2)
				int x2 = x1 + 1, y2 = y1 + 1, z2 = z1 + 1;

				int index = XOut * YOut * zi + XOut * yi + xi;

				if (x2 >= XInput || y2 >= YInput || z2 >= ZInput) {
					int index_x1y1z1 = XInput * YInput * z1 + XInput * y1 + x1;
					outBuffer[index] = inputBuffer[index_x1y1z1];
					continue;
				}
				// 执行插值计算
				// x1,y1,z2
				int index_x1y1z2 = XInput * YInput * z2 + XInput * y1 + x1;
				PixelType v_x1y1z2 = inputBuffer[index_x1y1z2];
				// cout << "here1" << endl;
				// x2,y2,z1
				int index_x2y2z1 = XInput * YInput * z1 + XInput * y2 + x2;
				PixelType v_x2y2z1 = inputBuffer[index_x2y2z1];
				// cout << "here2" << endl;
				// x2,y1,z2
				int index_x2y1z2 = XInput * YInput * z2 + XInput * y1 + x2;
				PixelType v_x2y1z2 = inputBuffer[index_x2y1z2];
				// cout << "here3" << endl;
				// x1, y2, z1
				int index_x1y2z1 = XInput * YInput * z1 + XInput * y2 + x1;
				PixelType v_x1y2z1 = inputBuffer[index_x1y2z1];
				// cout << "here4" << endl;
				// x2, y2, z2
				int index_x2y2z2 = XInput * YInput * z2 + XInput * y2 + x2;
				PixelType v_x2y2z2 = inputBuffer[index_x2y2z2];
				// cout << "here5" << endl;				
				// x1, y1, z1
				int index_x1y1z1 = XInput * YInput * z1 + XInput * y1 + x1;
				PixelType v_x1y1z1 = inputBuffer[index_x1y1z1];
				// cout << "here6" << endl;
				// x1, y2, z2
				int index_x1y2z2 = XInput * YInput * z2 + XInput * y2 + x1;
				PixelType v_x1y2z2 = inputBuffer[index_x1y2z2];
				// cout << "here7" << endl;
				// x2, y1, z1
				int index_x2y1z1 = XInput * YInput * z1 + XInput * y1 + x2;
				PixelType v_x2y1z1 = inputBuffer[index_x2y1z1];
				// cout << "here8" << endl;

				PixelType value = v_x1y1z2 * (x2 - x) * (y2 - y) * (z - z1)
					+ v_x2y2z1 * (x - x1) * (y - y1) * (z2 - z)
					+ v_x2y1z2 * (x - x1) * (y2 - y) * (z - z1)
					+ v_x1y2z1 * (x2 - x) * (y - y1) * (z2 - z)
					+ v_x2y2z2 * (x - x1) * (y - y1) * (z - z1)
					+ v_x1y1z1 * (x2 - x) * (y2 - y) * (z2 - z)
					+ v_x1y2z2 * (x2 - x) * (y - y1) * (z - z1)
					+ v_x2y1z1 * (x - x1) * (y2 - y) * (z2 - z);
				// 赋值							
				outBuffer[index] = value;			
			}
		}
	}
	
}


int main()
{
	const string inputImagePath = "G:/blood_vessel2023/images/train/62.nii.gz";
	ImagePointerType inputImage;
	readData<ImageType, ImagePointerType>(inputImagePath, inputImage);
	ImageType::SizeType inputSize = inputImage->GetBufferedRegion().GetSize();
	cout << inputSize << endl;	

	ImageType::SizeType outSize; // 1.5倍输入大小
	outSize[0] = inputSize[0] * 1.5; outSize[1] = inputSize[1] * 1.5; outSize[2] = inputSize[2] * 1.5;
	cout << outSize << endl;
	// char c = getchar();

	ImagePointerType outImage;
	createNewImage(outImage,
		inputImage->GetSpacing(), inputImage->GetDirection(), inputImage->GetOrigin(),
		outSize);

	// 插值
	bilinearInterpolation(inputImage, outImage);
	writeData<ImageType, ImagePointerType>(outImage, "bilinear.nii.gz");

	return 0;
}

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

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

相关文章

《低代码指南》——维格云低代码管理系统解决方案,成倍降低开发成本

目录 典型场景介绍 一、采购管理 二、产品BOM管理 三、成本核算管理 “我之前是打算自己去开发ERP系统,大概要用上八九个月时间,而且还不是很稳定。但现在用维格云,我们一个人做个一两个月,就可以做到很稳定了。因此,即使需要付出一些学习成本,但无代码的确能极大的帮…

自动驾驶系统中摄像头相对地面的在线标定

文章&#xff1a;Online Camera-to-ground Calibration for Autonomous Driving 作者&#xff1a;Binbin Li, Xinyu Du, Yao Hu, Hao Yu, and Wende Zhang 编辑&#xff1a;点云PCL 欢迎各位加入知识星球&#xff0c;获取PDF论文&#xff0c;欢迎转发朋友圈。文章仅做学术分享&…

记录--前端小票打印、网页打印

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 一、小票打印 目前市面上的小票打印机大多采用的打印指令集为ESC/POS指令&#xff0c;它可以使用ASCII码、十进制、十六进制来控制打印&#xff0c;我们可以使用它来控制字体大小、打印排版、字体加粗…

如何用 ChatGPT 做数据进阶可视化?(三维交互图与动图视频)

你只需输入数据和需求&#xff0c;结果自然来。 自动可视化 在《如何用 ChatGPT 帮你自动分析数据&#xff1f;》这篇文章里&#xff0c;我已经为你介绍过 Code Interpreter 。它是 ChatGPT 的一个模式&#xff0c;目前还在 alpha 测试阶段。 Code Interpreter 可以接收文件输入…

Android 图片编码之必备技能

在进行 Android 开发时&#xff0c;不可避免地会接触到许多图片格式&#xff0c;例如 JPEG、PNG 等。就以 JPEG 格式为例&#xff0c;它是一种有损压缩模式&#xff0c;使用 YCbCr 的颜色空间来保存色彩信息。当需要在屏幕上显示图片时&#xff0c;会将 JPEG 数据解码成 RGB 进…

淘宝用户体验分析方法论

本专题共10篇内容&#xff0c;包含淘宝APP基础链路过去一年在用户体验数据科学领域&#xff08;包括商详、物流、性能、消息、客服、旅程等&#xff09;一些探索和实践经验&#xff0c;本文为该专题第一篇。 在商详页基于用户动线和VOC挖掘用户决策因子带来浏览体验提升&#x…

chatgpt赋能python:Python扫描IP段的简介

Python 扫描 IP 段的简介 Python 是一种广泛应用于数据科学、机器学习、Web 开发等领域的高级编程语言。作为一种通用编程语言&#xff0c;Python 也可以应用于网络安全领域。其中&#xff0c;Python 可以用于扫描 IP 段的网络安全工具开发。 Python 扫描 IP 段 Python 扫描…

5.27下周黄金行情走势预测及开盘操作策略

近期有哪些消息面影响黄金走势&#xff1f;下周黄金多空该如何研判&#xff1f; ​黄金消息面解析&#xff1a;周五(5月26日)黄金大幅下跌&#xff0c;主要受到美国数据影响&#xff0c;美国公布的4月PCE和耐用品订单数据向好&#xff0c;再次强化市场对美联储的鹰派押注。现货…

软件测试之自动化测试【webdriver API】

目录 一、webdriver API 1.元素的定位 2.操作测试对象 3.添加等待 3.1 sleep 强制等待 3.2 隐式等待 3.3 显式等待 4.打印信息 5.浏览器的操作 5.1 浏览器的前进和后退 5.2 浏览器滚动条操作 5.3 浏览器最大化及设置浏览器宽、高 6.键盘按键 7. 鼠标事件 8.定位…

chatgpt赋能python:Python找零-让你的生活更轻松

Python 找零 - 让你的生活更轻松 在我们日常生活中&#xff0c;找零是一个很常见的问题。无论是在超市买东西、给朋友拿钱、或者是做商业交易&#xff0c;都需要进行找零操作。而使用 Python 编程语言&#xff0c;可以让这个问题更加简单易懂&#xff0c;让我们来一起学习 Pyt…

Python中的布尔类型以及布尔值介绍

什么是布尔类型&#xff1f; 布尔类型是一种逻辑类型&#xff0c;它只有两个取值&#xff1a;True&#xff08;真&#xff09;和False&#xff08;假&#xff09;。在Python中&#xff0c;True和False是内置的布尔类型常量&#xff0c;用于表示真和假的状态。 布尔运算符 在P…

一场九年前的“出发”:奠基多模态,逐鹿大模型

原创&#xff1a;谭婧 全球AI大模型的技术路线&#xff0c;没有多少秘密&#xff0c;就那几条路线&#xff0c;一只手都数得过来。 而举世闻名的GPT-4浑身上下都是秘密。 这两件事并不矛盾。为什么呢&#xff1f; 这就好比&#xff0c;回答“如何制造一台光刻机&#xff1f;”。…

Yolov5/Yolov7涨点技巧:MobileViT移动端轻量通用视觉transformer,MobileViTAttention助力小目标检测,涨点显著

1. MobileViT介绍 论文:https://arxiv.org/abs/2110.02178 现有博客都是将MobileViT作为backbone引入Yolov5,因此存在的问题点是训练显存要求巨大,本文引入自注意力的Vision Transformer(ViTs):MobileViTAttention MobileViT是一种基于Transformers的轻量级模型,它可以用于…

chatgpt赋能python:Python操作手机:SEO指南

Python 操作手机&#xff1a;SEO 指南 在移动设备占据互联网用户市场大头的今天&#xff0c;应用程序的互动变得越来越受欢迎。这就需要我们在开发和优化网站时将手机端无缝集成到我们的计划中。使用 Python 语言可以有效地实现此目标&#xff0c;本文将探讨如何使用 Python 操…

【一篇文章带你掌握HTML中ul、ol和dl列表的使用 - 超详细】

【一篇文章带你掌握HTML中ul、ol和dl列表的使用 - 超详细】_dl标签_China_YF的博客-CSDN博客 前提 在项目开发过程中&#xff0c;列表是非常常见的&#xff0c;因此列表标签也是我们使用相对频繁的标签&#xff0c;但是当我们遇到列表的时候有没有停顿思考一下&#xff0c;我在…

提醒!手机卡注销前,一定要做的四件事!

现在更换手机卡的情况对小伙伴们来说都是家常便饭的事情了&#xff0c;但是很多小伙伴在手机换号的时候&#xff0c;经常忘记解绑以前手机号绑定的一些业务&#xff0c;为此产生了很多不必要的麻烦&#xff0c;今天的这篇文章就是要告诫大家换号之前一定要做的几件事&#xff0…

基于yolov5的双目鱼体长度检测

前言 在水产养殖行业中&#xff0c;鱼体长度是衡量鱼类品质和成熟度的重要指标。然而&#xff0c;传统的鱼体长度测量方法需要手动测量&#xff0c;不仅耗时耗力还容易出现误差。正好最近做了一个基于双目视觉的鱼体检测项目&#xff0c;在这里和大家分享以下思路。 步骤 第一…

跨境电商环境搭建和买家账号培养的关键考虑因素

作为跨境电商环境搭建和买家账号培养的专业技术开发人员&#xff0c;我深知在亚马逊、速卖通、阿里国际、速卖通、美客多、shopee、Lazada、ebay、Temu等平台上运营的卖家面临的挑战 其中&#xff0c;补单是一项关键的工作&#xff0c;它能帮助卖家增加商品列表和评价数量&…

这个 冒泡排序详解过程 我能吹一辈子!!!

文章目录 冒泡排序概念冒泡排序算法思路冒泡排序代码实现冒泡排序优化 冒泡排序概念 冒泡排序是比较基础的排序算法之一&#xff0c;其思想是相邻的元素两两比较&#xff0c;较大的数下沉&#xff0c;较小的数冒起来&#xff0c;这样一趟比较下来&#xff0c;最大(小)值就会排列…

ES2020新语法:可选链操作符

目录 一、前言 二、案例 三、方法一&#xff1a;AND运算符 四、方法二&#xff1a;可选链操作符( ?. ) 1. 语法 2. 可选链与函数调用 3. 处理可选的回调函数或事件处理器 4.可选链和表达式 5.可选链访问数组元素 6.使用空值合并操作符 一、前言 今天看一个实习生写的…