/* * * Copyright (C) 2015-2022, Open Connections GmbH * All rights reserved. See COPYRIGHT file for details. * * This software and supporting documentation are maintained by * * OFFIS e.V. * R&D Division Health * Escherweg 2 * D-26121 Oldenburg, Germany * * * Module: dcmseg * * Author: Michael Onken * * Purpose: Helper functions for the dcmseg module * */ #include "dcmtk/config/osconfig.h" #include "dcmtk/dcmiod/iodutil.h" #include "dcmtk/dcmseg/segdef.h" #include "dcmtk/dcmseg/segutils.h" DcmIODTypes::Frame* DcmSegUtils::packBinaryFrame(const Uint8* pixelData, const Uint16 rows, const Uint16 columns) { // Sanity checking const size_t numPixels = OFstatic_cast(size_t, rows) * columns; if (numPixels == 0) { DCMSEG_ERROR("Unable to pack binary segmentation frame: Rows or Columns is 0"); return NULL; } if (!pixelData) { DCMSEG_ERROR("Unable to pack binary segmentation frame: No pixel data provided"); return NULL; } DcmIODTypes::Frame* frame = new DcmIODTypes::Frame(); if (frame == NULL) { DCMSEG_ERROR("Could not pack binary segmentation frame: Memory exhausted"); return NULL; } frame->length = getBytesForBinaryFrame(numPixels); frame->pixData = new Uint8[frame->length]; if (frame->pixData == 0) { delete frame; return NULL; } memset(frame->pixData, 0, frame->length); size_t bytePos = 0; for (size_t count = 0; count < numPixels; count++) { // Compute byte position bytePos = count / 8; frame->pixData[bytePos] |= (pixelData[count] != 0) /* value to set */ << (count % 8 /* bit position (0-7) within byte */); } return frame; } DcmIODTypes::Frame* DcmSegUtils::unpackBinaryFrame(const DcmIODTypes::Frame* frame, Uint16 rows, Uint16 cols) { // Sanity checking if ((frame == NULL) || (rows == 0) || (cols == 0)) { DCMSEG_ERROR("Cannot unpack binary frame, invalid input data"); return NULL; } // Create result frame in memory size_t numBits = OFstatic_cast(size_t, rows) * cols; DcmIODTypes::Frame* result = new DcmIODTypes::Frame(); if (result) { result->pixData = new Uint8[numBits]; if (!result->pixData) { delete result; return NULL; } result->length = numBits; } if (!result || !(result->pixData)) { DCMSEG_ERROR("Cannot unpack binary frame, memory exhausted"); return NULL; } memset(result->pixData, 0, result->length); // Transform and copy from packed frame to unpacked result frame size_t bytePos = 0; for (size_t count = 0; count < numBits; count++) { // Compute byte position bytePos = count / 8; // Bit position (0-7) within byte Uint8 bitpos = (count % 8); if ((frame->pixData[bytePos] & (1 << bitpos) /* check whether bit at bitpos is set*/)) { result->pixData[count] = 1; } else { result->pixData[count] = 0; } } return result; } size_t DcmSegUtils::getBytesForBinaryFrame(const size_t& numPixels) { // check whether the 1-bit pixels exactly fit into bytes size_t remainder = numPixels % 8; // number of bytes that work on an exact fit size_t bytesRequired = numPixels / 8; // add one byte if we have a remainder if (remainder > 0) bytesRequired++; return bytesRequired; } void DcmSegUtils::alignFrameOnBitPosition(Uint8* buf, const size_t bufLen, const Uint8 numBits) { if (numBits > 7) { DCMSEG_ERROR("Invalid input data: alignFrameOnBitPosition() can only shift 0-7 bits"); return; } Uint8 carryOver = 0; for (size_t x = 0; x < bufLen; x++) { // Store current byte since we need to restore its first bits later Uint8 current = buf[x]; // Shift pixels given num bits to the left, creating (8 - num bits) // empty bits at the right buf[x] <<= numBits; // If there is a carry over from the previous byte, add it in again (will always be at the end, // see carry over calculation in next step) buf[x] |= carryOver; // Compute carry over bits for next byte to be handled, i.e. those bits at the left that will be // overwritten in the next byte carryOver = OFstatic_cast(unsigned char, current) >> (8 - numBits); } } void DcmSegUtils::alignFrameOnByteBoundary(Uint8* buf, const size_t bufLen, const Uint8 numBits) { return DcmIODUtil::alignFrameOnByteBoundary(buf, bufLen, numBits); } void DcmSegUtils::debugDumpBin(Uint8* buffer, size_t length, const char* what) { for (size_t n = 0; n < length; n++) { DCMSEG_DEBUG(what << " #" << n << ": " << OFstatic_cast(size_t, (buffer[n])) << ", bytepos " << &(buffer[n]) << " (" << debugByte2Bin((buffer[n])) << ")"); } DCMSEG_DEBUG(""); } OFString DcmSegUtils::debugByte2Bin(Uint8 b) { OFString result("00000000"); for (int i = 7; i >= 0; i--) { result[i] = (b & 1) + '0'; b = OFstatic_cast(unsigned char, b) >> 1; } return result; }