并行编程实战——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应…...
mxbai-embed-large-v1 应用开发:从零构建智能文档检索系统
mxbai-embed-large-v1 应用开发:从零构建智能文档检索系统 1. 项目概述与核心价值 mxbai-embed-large-v1 是由 mixedbread-ai 开发的高性能文本嵌入模型,在 MTEB 基准测试中超越了 OpenAI text-embedding-3-large 等商业模型。该模型能够将文本转换为高…...
gh_mirrors/eg/eggs深度解析:一站式解决所有服务器部署难题
gh_mirrors/eg/eggs深度解析:一站式解决所有服务器部署难题 【免费下载链接】eggs Service eggs for the pterodactyl panel 项目地址: https://gitcode.com/gh_mirrors/eg/eggs 在服务器管理领域,快速部署和高效运维一直是开发者和管理员面临的核…...
革命性本地AI聊天应用ChatRTX:基于TensorRT-LLM和RAG的完整指南
革命性本地AI聊天应用ChatRTX:基于TensorRT-LLM和RAG的完整指南 【免费下载链接】trt-llm-rag-windows 项目地址: https://gitcode.com/gh_mirrors/tr/trt-llm-rag-windows ChatRTX是一款革命性的本地AI聊天应用程序,它基于NVIDIA的TensorRT-LLM…...
ESP32按键状态机设计:工业级去抖与多事件识别
1. ESP32-Button 库深度解析:面向工业级人机交互的按键状态机设计与实现1.1 工程背景与设计动因在嵌入式系统开发中,按键处理看似简单,实则暗藏诸多工程陷阱。裸写digitalRead()配合delay()的“抖动延时法”在教学Demo中尚可接受,…...
C++并发编程实战:std::atomic的exchange与compare_exchange操作到底怎么选?
C并发编程实战:std::atomic的exchange与compare_exchange操作到底怎么选? 在构建高性能并发系统时,开发者常面临一个关键抉择:当需要原子更新共享数据时,究竟该选择exchange、compare_exchange_weak还是compare_exchan…...
记一次攻防演练复盘(蓝队)
事件:某省大数据局主导的一次攻防演练中午时段遭受大量攻击。 告警信息(TOP 5):[疑似目录穿越攻击URI] [漏洞攻击: Apache log4j RCE Attempt (http ldap) (CVE-2021-44228)] [web路径遍历漏洞攻击-Linux环境] [XSS跨站脚本攻击U…...
1929年大萧条的真相
29年的大萧条,传统经济学将那场灾难归因于投机过热,银行脆弱、需求不足等,但这只是表面因素。大萧条的本质是一场货币危机——黄金的物理极限与生产力指数级增长之间的总爆发。一战后,全球建立金本位体系,要求各国货币…...
深入解析Infineon BTS54040-LBF高边芯片的SPI控制与汽车电子应用
1. BTS54040-LBF高边芯片的核心特性解析 第一次接触英飞凌的BTS54040-LBF时,我正负责一个汽车氛围灯控制项目。这块指甲盖大小的芯片让我印象深刻——它把四路高边开关、SPI控制和完善的保护机制集成在单个封装里。先说说最关键的几个特性: 四通道智能开…...
Knowledge Repo转换器终极指南:10个技巧实现Jupyter、R Markdown等多格式完美转换
Knowledge Repo转换器终极指南:10个技巧实现Jupyter、R Markdown等多格式完美转换 【免费下载链接】knowledge-repo A next-generation curated knowledge sharing platform for data scientists and other technical professions. 项目地址: https://gitcode.com…...
暗黑破坏神2终极单机插件:PlugY生存工具包完全指南
暗黑破坏神2终极单机插件:PlugY生存工具包完全指南 【免费下载链接】PlugY PlugY, The Survival Kit - Plug-in for Diablo II Lord of Destruction 项目地址: https://gitcode.com/gh_mirrors/pl/PlugY 如果你是一名暗黑破坏神2的单机玩家,是否曾…...
