并行编程实战——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应…...

mysql密码正确SpringBoot和Datagrip却连接不上
报错信息:SQLException: Access denied for user ‘root‘‘localhost‘ (using password: YES) 原因可能是是有端口号冲突 我这里是禅道端口与MySQL冲突,禅道端口也是3306,ctrlaltdelete打开任务管理器,关闭mysqlzt …...
限流算法java实现
参考教程:2小时吃透4种分布式限流算法 1.计数器限流 public class CounterLimiter {// 开始时间private static long startTime System.currentTimeMillis();// 时间间隔,单位为msprivate long interval 1000L;// 限制访问次数private int limitCount…...

[概率论基本概念4]什么是无偏估计
关键词:Unbiased Estimation 一、说明 对于无偏和有偏估计,需要了解其叙事背景,是指整体和抽样的关系,也就是说整体的叙事是从理论角度的,而估计器原理是从实践角度说事;为了表明概率理论(不可…...
Axios学习笔记
Axios简介 axios前端异步请求库类似JQuery ajax技术, ajax用来在页面发起异步请求到后端服务,并将后端服务响应数据渲染到页面上, jquery推荐ajax技术,但vue里面并不推荐在使用jquery框架,vue推荐使用axios异步请求库。…...

前端杂货铺——TodoList
个人简介 👀个人主页: 前端杂货铺 🙋♂️学习方向: 主攻前端方向,正逐渐往全干发展 📃个人状态: 研发工程师,现效力于中国工业软件事业 🚀人生格言: 积跬步…...
camera功能真的那么难用吗
背景 Android开发工作过程中,经常需要用到camera相关能力,比如:人脸识别,ai识别,拍照预览,摄像头录制等等需求。都需要使用到camera,且需要拿到camera的预览数据。但是每次开发这块代码都比较繁…...
C++ const 修饰符深入浅出详解
C const 修饰符深入浅出详解 📅 更新时间:2025年6月6日 🏷️ 标签:C | const关键字 | 常量 | 多文件编程 | 现代C 文章目录 前言🌟 一、const 是什么?为什么要用?示例✅ const 的四大好处 &…...
RTOS学习之重难点
📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨ 📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 📢:文章若有幸对你有帮助,可点赞 👍…...

《绩效管理》要点总结与分享
目录 绩效管理与目标设定 绩效管理的循环:PDCA 绩效目标的设定要点 绩效设定的工具:SMART法则 绩效跟踪与评估 刻板印象:STAR法 晕轮效应:对比评价法 近因效应:关键事项评估表 绩效面谈 面谈前准备工作 汉堡…...

LangChain4j 学习教程项目
LangChain4j 学习教程 项目地址项目简介主要功能使用的技术和库项目环境配置环境要求 依赖版本每天学习内容和目标Day 01Day 02Day 03Day 04Day 05Day 06Day 07Day 08Day 09Day 10Day 11Day 12重点学习内容 RAG 经过为期12天(日均1小时)的LangChain4j源码…...