当前位置: 首页 > news >正文

并行编程实战——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(), &timestampSeconds);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(&timestampSeconds, &timestampFrac);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&#xff0c;可以简称为IGTL。它是一个专供医疗应用的网络通信库。IGTL可以应用各种传感器、手术机器人和成像仪等的数据传输。OpenIGTLink是有一系列的协议在底层支持的&#xff0c;它是跨平台的&#xff0c;应用也非常简单。 OpenIGTLink迭代还是…...

【Golang 面试题】每日 3 题(八)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/UWz06 &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 Golang 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏…...

11. 日常算法

1. 141. 环形链表 题目来源 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接…...

FPGA三模冗余TMR工具(二)

学术和商业领域有许多自动化的三模冗余TMR工具&#xff0c;本文介绍当前主流的基于寄存器传输级的三模冗余工具&#xff08;Register-Transfer Level&#xff0c;RTL&#xff09;&#xff0c;基于重要软核资源的三模冗余工具&#xff0c;以及新兴的基于高层次综合的三模冗余工具…...

springboot499基于javaweb的城乡居民基本医疗信息管理系统(论文+源码)_kaic

摘 要 信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#xff0c;还是安全性&#xff0c;还是可操作性等各个方面来讲&#xff0c;遇到了互联网时代才发现能补上自古…...

MF248:复制工作表形状到Word并调整多形状位置

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…...

微信流量主挑战:用户破16!新增文档转换(新纪元3)

朋友们&#xff0c;报告好消息&#xff01;我的小程序用户数量已经涨到16个了&#xff01;没错&#xff0c;真没拉朋友圈亲戚好友来撑场子&#xff0c;全靠实力&#xff08;和一点点运气&#xff09;吸引了16位陌生小伙伴光临&#xff01;这波进步&#xff0c;连我自己都感动了…...

SelectionArea 实现富文本

使用 SelectionArea Text.rich TextSpan WidgetSpan实现富文本。 前置知识点学习 SelectionArea SelectionArea 是 Flutter 中的一个组件&#xff0c;用于管理文本的选择功能。它允许用户在应用中选择和复制文本&#xff0c;这是在支持文本选择的应用程序中常见的功能。Se…...

upload-labs关卡记录17

该关卡&#xff0c;依旧是上传图片马到服务器&#xff0c;然后借助文件包含漏洞来运行一句话木马&#xff0c;这里还是老样子&#xff0c;先上传我们之前制作的图片马&#xff1a; 上传成功后&#xff0c;复制链接然后通过文件包含漏洞来尝试&#xff0c;发现不可行&#xff1a…...

【Next.js】002-路由篇|App Router

【Next.js】002-路由篇|App Router 文章目录 【Next.js】002-路由篇|App Router一、前言二、文件系统&#xff08;file-system&#xff09;1、说明2、演练创建代码运行访问让 Cursor 分析错误别偷懒&#xff0c;还是探究一下 Pages Router 方式吧创建代码运行并访问项目/about …...

如何在 Ubuntu 22.04 上使用 systemctl 管理 systemd 服务教程

简介 Systemd 是许多现代 Linux 发行版提供核心功能的默认服务管理器&#xff0c;而 systemctl 是用户与 systemd 服务交互的方式。这使得 systemctl 成为 Linux 管理员工具箱中重要的一部分。 在本文中&#xff0c;我们将探讨如何使用 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命令

模拟触摸、按键等操作&#xff0c;直接在命令行输入对应命令即可。命令行如何识别并操作此命令&#xff0c;执行操作的是shell程序&#xff0c;还是java程序&#xff1f;是不是可以添加自定义的命令&#xff1f; 以下在Android13的代码中分析input命令 Android系统中使用了一…...

Unity游戏环境交互系统

概述 交互功能使用同一个按钮或按钮列表&#xff0c;在不同情况下显示不同的内容&#xff0c;按下执行不同的操作。 按选项个数分类 环境交互系统可分为两种&#xff0c;单选项交互&#xff0c;一般使用射线检测&#xff1b;多选项交互&#xff0c;一般使用范围检测。第一人…...

TOP K问题:利用堆排序找出数组中最小的k个数

设计一个算法&#xff0c;找出数组中最小的k个数。以任意顺序返回这k个数均可。 找小的数需要建大堆来解决&#xff0c;首先将数组中前K个数建成一个大堆&#xff0c;将从k1个数直到数组结束的所有数与堆顶的数进行比较&#xff0c;如果比堆顶的数小&#xff0c;则替换堆顶的数…...

《信息传播:人工智能助力驱散虚假信息阴霾》

在信息爆炸的时代&#xff0c;虚假信息和谣言如同脱缰野马&#xff0c;肆意传播&#xff0c;对社会秩序和公众生活造成了严重影响。人工智能作为一种强大的技术工具&#xff0c;正逐渐成为信息传播的有力助手&#xff0c;为防止虚假信息和谣言扩散提供了新的途径。 虚假信息和…...

数据权限和角色权限区别

1、概念 角色权限&#xff08;Role-Based Access Control, RBAC&#xff09;和数据权限&#xff08;Data Access Control&#xff09;是两种不同的权限管理策略&#xff0c;它们在权限控制的侧重点和应用场景上有所区别&#xff1a; 角色权限&#xff08;RBAC&#xff…...

Flink的多流转换(分流-侧输出流、合流-union、connect、join)

在实际应用中&#xff0c;我们可能要将多个不同来源的数据连接合并在一起进行处理&#xff0c;也有可能要将一条流拆分成多条流进行处理&#xff0c;这就涉及到了Flink的多流转换问题。简单来说&#xff0c;就是分流和合流两大操作&#xff0c;分流主要通过侧输出流实现&#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安全框架&#xff0c;它提供了全面的安全认证和授权的支持。 2 SpringSecurity配置类&#xff08;源码逐行解析&#xff09; Spring Security的配置类是实现安全控制的核心部分 开启Spring Security各种功能&#xff0c;以确保Web应…...

mysql密码正确SpringBoot和Datagrip却连接不上

报错信息&#xff1a;SQLException: Access denied for user ‘root‘‘localhost‘ (using password: YES&#xff09; 原因可能是是有端口号冲突 我这里是禅道端口与MySQL冲突&#xff0c;禅道端口也是3306&#xff0c;ctrlaltdelete打开任务管理器&#xff0c;关闭mysqlzt …...

限流算法java实现

参考教程&#xff1a;2小时吃透4种分布式限流算法 1.计数器限流 public class CounterLimiter {// 开始时间private static long startTime System.currentTimeMillis();// 时间间隔&#xff0c;单位为msprivate long interval 1000L;// 限制访问次数private int limitCount…...

[概率论基本概念4]什么是无偏估计

关键词&#xff1a;Unbiased Estimation 一、说明 对于无偏和有偏估计&#xff0c;需要了解其叙事背景&#xff0c;是指整体和抽样的关系&#xff0c;也就是说整体的叙事是从理论角度的&#xff0c;而估计器原理是从实践角度说事&#xff1b;为了表明概率理论&#xff08;不可…...

Axios学习笔记

Axios简介 axios前端异步请求库类似JQuery ajax技术&#xff0c; ajax用来在页面发起异步请求到后端服务&#xff0c;并将后端服务响应数据渲染到页面上&#xff0c; jquery推荐ajax技术&#xff0c;但vue里面并不推荐在使用jquery框架&#xff0c;vue推荐使用axios异步请求库。…...

前端杂货铺——TodoList

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…...

camera功能真的那么难用吗

背景 Android开发工作过程中&#xff0c;经常需要用到camera相关能力&#xff0c;比如&#xff1a;人脸识别&#xff0c;ai识别&#xff0c;拍照预览&#xff0c;摄像头录制等等需求。都需要使用到camera&#xff0c;且需要拿到camera的预览数据。但是每次开发这块代码都比较繁…...

C++ const 修饰符深入浅出详解

C const 修饰符深入浅出详解 &#x1f4c5; 更新时间&#xff1a;2025年6月6日 &#x1f3f7;️ 标签&#xff1a;C | const关键字 | 常量 | 多文件编程 | 现代C 文章目录 前言&#x1f31f; 一、const 是什么&#xff1f;为什么要用&#xff1f;示例✅ const 的四大好处 &…...

RTOS学习之重难点

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…...

《绩效管理》要点总结与分享

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

LangChain4j 学习教程项目

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