并行编程实战——TBB框架的应用之五Supra中IGTL的应用
一、OpenIGTLink
OpenIGTLink,可以简称为IGTL。它是一个专供医疗应用的网络通信库。IGTL可以应用各种传感器、手术机器人和成像仪等的数据传输。OpenIGTLink是有一系列的协议在底层支持的,它是跨平台的,应用也非常简单。
OpenIGTLink迭代还是比较快的,目前已经到了3.0版本。更多的对其的技术相关资料,请查阅相关的资料或访问其官方地址及github。
二、IGTL的应用
IGTL在医疗行业应用还是比较多的,它的优点是相对简单,支持的场景也相对较多。缺点就是相对简单,无法处理一些复杂的网络应用。不过话又说回来,在医疗行业这种场景下,一般也没有复杂的网络应用,一般就是几台机器通信,能复杂到哪儿。
IGTL的应用重点还是在业务上,即它支持医疗行业的设备间的状态(STATUS)、图像(IMAGE)和命令(COMMAND)等各种消息格式。其实如果认真的向下看Message构成的情况就会发现,和传统的网络通信中定义的协议没有什么不同。封装起来的目的就是为了简单好用。
三、Supra中的应用
在初步简单了解了一下IGTL后,就看一下在Supra中如何使用这个库,相关代码如下:
1、做为服务端使用
void OpenIGTLinkOutputDevice::initializeOutput(){log_info("IGTL: server port: ", m_server->GetServerPort());if (m_server->CreateServer(m_port) != 0) {m_isReady = false;}else {m_isReady = true;//Wait asynchronously for the connectionwaitAsyncForConnection();}}template <typename T>void OpenIGTLinkOutputDevice::sendImageMessageTemplated(shared_ptr<const USImage> imageData){static_assert(std::is_same<T, uint8_t>::value ||std::is_same<T, int16_t>::value ||std::is_same<T, float>::value,"Image only implemented for uchar, short and float at the moment");auto properties = imageData->getImageProperties();if (properties->getImageType() == USImageProperties::BMode ||properties->getImageType() == USImageProperties::Doppler){double resolution = properties->getImageResolution();vec3s imageSize = imageData->getSize();igtl::ImageMessage::Pointer pImageMsg = igtl::ImageMessage::New();pImageMsg->SetDimensions((int)imageSize.x, (int)imageSize.y, (int)imageSize.z);pImageMsg->SetSpacing(resolution, resolution, resolution);if (is_same<T, uint8_t>::value){pImageMsg->SetScalarTypeToUint8();}if (is_same<T, int16_t>::value){pImageMsg->SetScalarTypeToInt16();}if (is_same<T, float>::value){pImageMsg->SetScalarType(igtl::ImageMessage::TYPE_FLOAT32);}pImageMsg->SetEndian(igtl::ImageMessage::ENDIAN_LITTLE);igtl::Matrix4x4 m;igtl::IdentityMatrix(m);m[0][0] = -1;m[1][1] = -1;pImageMsg->SetMatrix(m);pImageMsg->SetNumComponents(1);pImageMsg->SetDeviceName(m_streamName.c_str());pImageMsg->AllocateScalars();igtl::TimeStamp::Pointer pTimestamp = igtl::TimeStamp::New();double timestampSeconds;double timestampFrac = modf(imageData->getSyncTimestamp(), ×tampSeconds);pTimestamp->SetTime((uint32_t)timestampSeconds, (uint32_t)(timestampFrac*1e9));pImageMsg->SetTimeStamp(pTimestamp);auto imageContainer = imageData->getData<T>();if (!imageContainer->isHost()){imageContainer = make_shared<Container<T> >(LocationHost, *imageContainer);}size_t numElements = imageSize.x * imageSize.y * imageSize.z;memcpy(pImageMsg->GetScalarPointer(), imageContainer->get(), numElements * sizeof(T));pImageMsg->Pack();int sendResult = m_clientConnection->Send(pImageMsg->GetPackPointer(), pImageMsg->GetPackSize());if (sendResult == 0) //when it could not be sent{m_isConnected = false;log_info("IGTL: Lost connection. Waiting for next connection.");waitAsyncForConnection();}}}void OpenIGTLinkOutputDevice::waitAsyncForConnection(){if (m_pConnectionThread && m_pConnectionThread->joinable()){m_pConnectionThread->join();}m_pConnectionThread = unique_ptr<thread>(new thread([this]() {log_info("IGTL: waiting for connection");m_clientConnection = m_server->WaitForConnection();m_isConnected = true;log_info("IGTL: got connection!");}));}
代码很简单,如果配合着IGTL自带的示例代码会更容易弄明白。
2、做为客户端使用
void TrackerInterfaceIGTL::startAcquisition() {m_callFrequency.setName("TrIGTL");while (getRunning()) {if (!m_connected) {lock_guard<mutex> lock(m_objectMutex);connectToSever();}//------------------------------------------------------------// Wait for a replyif (m_connected) {igtl::MessageHeader::Pointer headerMsg;headerMsg = igtl::MessageHeader::New();headerMsg->InitPack();int rs = m_socket->Receive(headerMsg->GetPackPointer(),headerMsg->GetPackSize());{lock_guard<mutex> lock(m_objectMutex);if (rs == 0) {logging::log_warn("TrackerInterfaceIGTL: Connection closed.");closeSocket();continue;}if (rs != headerMsg->GetPackSize()) {logging::log_warn("TrackerInterfaceIGTL: Message size information ""and actual data size don't match.");closeSocket();continue;}if (!m_frozen) {headerMsg->Unpack();if (strcmp(headerMsg->GetDeviceType(), "TDATA") == 0) {receiveTrackingData(headerMsg);} else {m_socket->Skip(headerMsg->GetBodySizeToRead(), 0);}}}} else {logging::log_warn("TrackerInterfaceIGTL: Could not reconnect to the server '",m_hostname, ":", m_port, "'. Retrying in ", m_reconnectInterval,"s.");duration<long, std::milli> sleepDuration =milliseconds((long long)round(m_reconnectInterval * 1e3));this_thread::sleep_for(sleepDuration);}}{lock_guard<mutex> lock(m_objectMutex);closeSocket();}
}void TrackerInterfaceIGTL::connectToSever() {if (!m_connected) {int r = m_socket->ConnectToServer(m_hostname.c_str(), m_port);if (r != 0) {m_connected = false;logging::log_warn("TrackerInterfaceIGTL: Could not reconnect to the server '",m_hostname, ":", m_port, "'");} else {m_connected = true;logging::log_info("TrackerInterfaceIGTL: Connected to the server '",m_hostname, ":", m_port, "'");}}
}void TrackerInterfaceIGTL::closeSocket() {m_connected = false;logging::log_warn("TrackerInterfaceIGTL: Closing socket to the server '",m_hostname, ":", m_port, "'");m_socket->CloseSocket();
}bool TrackerInterfaceIGTL::receiveTrackingData(igtl::MessageHeader::Pointer &header) {//------------------------------------------------------------// Allocate TrackingData Message Classigtl::TrackingDataMessage::Pointer trackingData;trackingData = igtl::TrackingDataMessage::New();trackingData->SetMessageHeader(header);trackingData->AllocatePack();// Receive body from the socketm_socket->Receive(trackingData->GetPackBodyPointer(),trackingData->GetPackBodySize());// Deserialize the transform data// If you want to skip CRC check, call Unpack() without argument.int c = trackingData->Unpack(1);bool crcFine = (c & igtl::MessageHeader::UNPACK_BODY) > 0;if (crcFine) // if CRC check is OK{std::vector<TrackerData> trackerData;// compute float timestamp format from IGTL representationuint32_t timestampSeconds;uint32_t timestampFrac;trackingData->GetTimeStamp(×tampSeconds, ×tampFrac);double timestamp = (double)timestampSeconds + ((double)timestampFrac) / 1e9;int nElements = trackingData->GetNumberOfTrackingDataElements();for (int i = 0; i < nElements; i++) {igtl::TrackingDataElement::Pointer trackingElement;trackingData->GetTrackingDataElement(i, trackingElement);igtl::Matrix4x4 igtlMatrix;trackingElement->GetMatrix(igtlMatrix);TrackerData::Matrix matrix;matrix[0 + 0] = igtlMatrix[0][0];matrix[0 + 1] = igtlMatrix[0][1];matrix[0 + 2] = igtlMatrix[0][2];matrix[0 + 3] = igtlMatrix[0][3];matrix[4 + 0] = igtlMatrix[1][0];matrix[4 + 1] = igtlMatrix[1][1];matrix[4 + 2] = igtlMatrix[1][2];matrix[4 + 3] = igtlMatrix[1][3];matrix[8 + 0] = igtlMatrix[2][0];matrix[8 + 1] = igtlMatrix[2][1];matrix[8 + 2] = igtlMatrix[2][2];matrix[8 + 3] = igtlMatrix[2][3];matrix[12 + 0] = igtlMatrix[3][0];matrix[12 + 1] = igtlMatrix[3][1];matrix[12 + 2] = igtlMatrix[3][2];matrix[12 + 3] = igtlMatrix[3][3];trackerData.push_back(TrackerData(matrix, 100, 666, trackingElement->GetName(), timestamp));}auto pTrackingDataSet =make_shared<TrackerDataSet>(trackerData, timestamp, timestamp);addData<0>(pTrackingDataSet);m_callFrequency.measure();} else {logging::log_warn("TrackerInterfaceIGTL: IGTL message CRC error, skipping message");}return crcFine;
}
void TrackerInterfaceIGTL::initializeDevice() {// try to connect already here, so we are directly good to go!lock_guard<mutex> lock(m_objectMutex);m_socket = igtl::ClientSocket::New();connectToSever();
}
这段代码是接收TrackerData的,代码也很容易理解。其实主要是要和IGTL中的相关格式对应,此处就是TDATA,所以按照其协议的说明一看就明白了。
四、总结
国外的框架库,一个比较让人头疼的就是里面用了非常多的其它相关的库。这样的好处当然很明显,就是完成具体的工作的效率会大幅提高。但对于学习者来说就比较麻烦了,需要不断的学习这个库那个库,然后才能把整个框架运行起来并初步掌握。
但真正掌握后会发现,写这方面的代码会简单很多,至少比自己想象的要简单很多!如果做应用开发的话,这确实是一个好的方法!
相关文章:
并行编程实战——TBB框架的应用之五Supra中IGTL的应用
一、OpenIGTLink OpenIGTLink,可以简称为IGTL。它是一个专供医疗应用的网络通信库。IGTL可以应用各种传感器、手术机器人和成像仪等的数据传输。OpenIGTLink是有一系列的协议在底层支持的,它是跨平台的,应用也非常简单。 OpenIGTLink迭代还是…...
【Golang 面试题】每日 3 题(八)
✍个人博客:Pandaconda-CSDN博客 📣专栏地址:http://t.csdnimg.cn/UWz06 📚专栏简介:在这个专栏中,我将会分享 Golang 面试中常见的面试题给大家~ ❤️如果有收获的话,欢迎点赞👍收藏…...
11. 日常算法
1. 141. 环形链表 题目来源 给你一个链表的头节点 head ,判断链表中是否有环。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接…...
FPGA三模冗余TMR工具(二)
学术和商业领域有许多自动化的三模冗余TMR工具,本文介绍当前主流的基于寄存器传输级的三模冗余工具(Register-Transfer Level,RTL),基于重要软核资源的三模冗余工具,以及新兴的基于高层次综合的三模冗余工具…...
springboot499基于javaweb的城乡居民基本医疗信息管理系统(论文+源码)_kaic
摘 要 信息数据从传统到当代,是一直在变革当中,突如其来的互联网让传统的信息管理看到了革命性的曙光,因为传统信息管理从时效性,还是安全性,还是可操作性等各个方面来讲,遇到了互联网时代才发现能补上自古…...
MF248:复制工作表形状到Word并调整多形状位置
我给VBA的定义:VBA是个人小型自动化处理的有效工具。利用好了,可以大大提高自己的工作效率,而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套,分为初级、中级、高级三大部分,教程是对VBA的系统讲解&#…...
微信流量主挑战:用户破16!新增文档转换(新纪元3)
朋友们,报告好消息!我的小程序用户数量已经涨到16个了!没错,真没拉朋友圈亲戚好友来撑场子,全靠实力(和一点点运气)吸引了16位陌生小伙伴光临!这波进步,连我自己都感动了…...
SelectionArea 实现富文本
使用 SelectionArea Text.rich TextSpan WidgetSpan实现富文本。 前置知识点学习 SelectionArea SelectionArea 是 Flutter 中的一个组件,用于管理文本的选择功能。它允许用户在应用中选择和复制文本,这是在支持文本选择的应用程序中常见的功能。Se…...
upload-labs关卡记录17
该关卡,依旧是上传图片马到服务器,然后借助文件包含漏洞来运行一句话木马,这里还是老样子,先上传我们之前制作的图片马: 上传成功后,复制链接然后通过文件包含漏洞来尝试,发现不可行:…...
【Next.js】002-路由篇|App Router
【Next.js】002-路由篇|App Router 文章目录 【Next.js】002-路由篇|App Router一、前言二、文件系统(file-system)1、说明2、演练创建代码运行访问让 Cursor 分析错误别偷懒,还是探究一下 Pages Router 方式吧创建代码运行并访问项目/about …...
如何在 Ubuntu 22.04 上使用 systemctl 管理 systemd 服务教程
简介 Systemd 是许多现代 Linux 发行版提供核心功能的默认服务管理器,而 systemctl 是用户与 systemd 服务交互的方式。这使得 systemctl 成为 Linux 管理员工具箱中重要的一部分。 在本文中,我们将探讨如何使用 systemctl 在使用 systemd 的系统上执行…...
Springboot关于格式化记录
日期格式化 返回前端日期需要格式化 <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.2</version> </dependency>JsonFormat(pattern "yyyy-MM-dd…...
Android 自定义shell命令
模拟触摸、按键等操作,直接在命令行输入对应命令即可。命令行如何识别并操作此命令,执行操作的是shell程序,还是java程序?是不是可以添加自定义的命令? 以下在Android13的代码中分析input命令 Android系统中使用了一…...
Unity游戏环境交互系统
概述 交互功能使用同一个按钮或按钮列表,在不同情况下显示不同的内容,按下执行不同的操作。 按选项个数分类 环境交互系统可分为两种,单选项交互,一般使用射线检测;多选项交互,一般使用范围检测。第一人…...
TOP K问题:利用堆排序找出数组中最小的k个数
设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。 找小的数需要建大堆来解决,首先将数组中前K个数建成一个大堆,将从k1个数直到数组结束的所有数与堆顶的数进行比较,如果比堆顶的数小,则替换堆顶的数…...
《信息传播:人工智能助力驱散虚假信息阴霾》
在信息爆炸的时代,虚假信息和谣言如同脱缰野马,肆意传播,对社会秩序和公众生活造成了严重影响。人工智能作为一种强大的技术工具,正逐渐成为信息传播的有力助手,为防止虚假信息和谣言扩散提供了新的途径。 虚假信息和…...
数据权限和角色权限区别
1、概念 角色权限(Role-Based Access Control, RBAC)和数据权限(Data Access Control)是两种不同的权限管理策略,它们在权限控制的侧重点和应用场景上有所区别: 角色权限(RBACÿ…...
Flink的多流转换(分流-侧输出流、合流-union、connect、join)
在实际应用中,我们可能要将多个不同来源的数据连接合并在一起进行处理,也有可能要将一条流拆分成多条流进行处理,这就涉及到了Flink的多流转换问题。简单来说,就是分流和合流两大操作,分流主要通过侧输出流实现&#x…...
DirectUI属性表
<?xml version"1.0" encoding"UTF-8"?> <Controls><Window parent""><Attribute name"size" default"0,0" type"SIZE" comment"窗口的初始化大小,如(800,600)"/><Attribu…...
RBAC权限控制
1、Spring Security 是一个功能强大的Java安全框架,它提供了全面的安全认证和授权的支持。 2 SpringSecurity配置类(源码逐行解析) Spring Security的配置类是实现安全控制的核心部分 开启Spring Security各种功能,以确保Web应…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...
