并行编程实战——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 connection
			waitAsyncForConnection();
		}
	}
		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 reply
    if (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 Class

  igtl::TrackingDataMessage::Pointer trackingData;
  trackingData = igtl::TrackingDataMessage::New();
  trackingData->SetMessageHeader(header);
  trackingData->AllocatePack();

  // Receive body from the socket
  m_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 representation
    uint32_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,所以按照其协议的说明一看就明白了。

四、总结

国外的框架库,一个比较让人头疼的就是里面用了非常多的其它相关的库。这样的好处当然很明显,就是完成具体的工作的效率会大幅提高。但对于学习者来说就比较麻烦了,需要不断的学习这个库那个库,然后才能把整个框架运行起来并初步掌握。
但真正掌握后会发现,写这方面的代码会简单很多,至少比自己想象的要简单很多!如果做应用开发的话,这确实是一个好的方法!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值