create one Dicom file from multiple images

All other questions regarding DCMTK

Moderator: Moderator Team

Message
Author
arthur
Posts: 4
Joined: Tue, 2011-08-30, 21:52

create one Dicom file from multiple images

#1 Post by arthur »

Hi
I am pretty new in DICOM field
Now I have a project need to do ... is generate one dicom file from multiple images

I know the img2dcm command can generate one dicom file from a single image but not allow multiple images....

Is ther any DCMTK command able to do that? or where can I find the dicom file spec/format for that? maybe I could try dcmodify command to create the file

Thanks

Michael Onken
DCMTK Developer
Posts: 2048
Joined: Fri, 2004-11-05, 13:47
Location: Oldenburg, Germany
Contact:

#2 Post by Michael Onken »

Hi Arthur,

you are right, img2dcm does only handle single frame images.

The format description of a DICOM image is not really easy to point to. The information what has to be in the images can be found in DICOM part 3 which describes the information objects using Information Object Definitions (IODs) which again refer to modules containing the attributes inside a DICOM (image) object. You must choose one of the Multi Frame IODs, e.g. the grayscale or color Secondary Capture IOD. Especially all multiframes (in contrast to the single frame images) contain attributes from the Multi-frame module, that has essential attributes like Number of Frames.
Part 5 of the DICOM standard describes the encoding of those attributes for transmission and storage, including information about pixel data encoding.

Thestandard is available from the NEMA for free.

If you like to test the files you created for correctness, I recommend using a DICOM checker like dcmcheck or dciodvfy.

Generally, you can use dcmodify for composing multi-frames. Multi-frame images (if uncompressed) are just inserted into the Pixel Data element as a large blob, each frame one after another. Be sure to use dcmodify's "--insert-from-file" option in order to insert large binary values like pixel data.

If this is very important for you and you like to spend money on it, we may extend img2dcm for you to support multi frames, of course.

Good luck,
Michael

arthur
Posts: 4
Joined: Tue, 2011-08-30, 21:52

#3 Post by arthur »

Hi Michael

Thank you for the quick response.
Yes I probably need that multi frames function. but before that can you send me some multi frames dicom file for me to import to the PACS and see if it is just what we want.

Then what is the price for the extend img2dcm to support multi frames?


Thanks

Michael Onken
DCMTK Developer
Posts: 2048
Joined: Fri, 2004-11-05, 13:47
Location: Oldenburg, Germany
Contact:

#4 Post by Michael Onken »

Hi Arthur,

we do not have any demo images we could send you, since we do not have img2dcm for multiframe so far and we cannot offer some of our "private" image collections. However, there should be other sources -- some free DICOM image source we listed in our wiki. Especially the page of Sébastien Barré seems to have many multiframes (scroll down).

An img2dcm extension price quote also depends on the features you actually need, so please write an email to dicom at offis dot de. Thanks!

Best regards,
Michael

arthur
Posts: 4
Joined: Tue, 2011-08-30, 21:52

#5 Post by arthur »

I tried to send email to dicom/at/offis/dot/de
but it was rejected

Admin: Obfucated email address.

J. Riesmeier
DCMTK Developer
Posts: 2501
Joined: Tue, 2011-05-03, 14:38
Location: Oldenburg, Germany
Contact:

#6 Post by J. Riesmeier »

What was the reason for the rejection (error message from our mail server)?

arthur
Posts: 4
Joined: Tue, 2011-08-30, 21:52

#7 Post by arthur »

here is the message i got .... but i 'll try my private email

This is the mail system at host sophos.simonmed.com.

I'm sorry to have to inform you that your message could not be delivered to one or more recipients. It's attached below.

For further assistance, please send mail to <postmaster>

If you do so, please include this problem report. You can delete your own text from the attached returned message.

The mail system

<dicom/at/offis/dot/de>: host offis2.offis.uni-oldenburg.de[134.106.52.6] said: 550
5.7.1 Client host rejected: cannot find your hostname, [70.169.91.82] (in
reply to RCPT TO command)

Admin: Obfucated email address.

J. Riesmeier
DCMTK Developer
Posts: 2501
Joined: Tue, 2011-05-03, 14:38
Location: Oldenburg, Germany
Contact:

#8 Post by J. Riesmeier »

Here is the reason for the rejection:
Client host rejected: cannot find your hostname
Our mail server does not talk to other systems that are not correctly configured (e.g. no DNS entry) in order to avoid too much SPAM.
i 'll try my private email
That's probably a good idea.

hugie
Posts: 2
Joined: Thu, 2015-09-10, 13:32

Re: create one Dicom file from multiple images

#9 Post by hugie »

Hi,

i know this is a quite old topic, but we implemented a patch for this functionality a few weeks ago.

The patch was implemented on top of repo version "9a80174a27877f1b32d6c4b7a6f1e6cc0fffd6c6".
I have not applied and tested it on the latest repository version.

I also sent this patch to offis, but have no status info. Maybe there is some tweeking necessary.

The patched img2dcm.exe is working for us so far.

The patch is available here:
https://drive.google.com/file/d/0ByKi5m ... sp=sharing

J. Riesmeier
DCMTK Developer
Posts: 2501
Joined: Tue, 2011-05-03, 14:38
Location: Oldenburg, Germany
Contact:

Re: create one Dicom file from multiple images

#10 Post by J. Riesmeier »

Thank you for your posting and your proposed patch.

Could you please resend your email to "info/at/dcmtk/dot/org"?

anilta
Posts: 60
Joined: Thu, 2014-04-10, 08:50

Re: create one Dicom file from multiple images

#11 Post by anilta »

Hi, Riesmeier,

Which is the snapshot version corresponding to repo version "9a80174a27877f1b32d6c4b7a6f1e6cc0fffd6c6".
Can you please provide the link to download this version.

I am not able to find this. I would like to patch and understand this functionality.

Thanks for your time.

J. Riesmeier
DCMTK Developer
Posts: 2501
Joined: Tue, 2011-05-03, 14:38
Location: Oldenburg, Germany
Contact:

Re: create one Dicom file from multiple images

#12 Post by J. Riesmeier »

Here's the link to the gitweb repository (in case you do not use any other git tool): http://git.dcmtk.org/web?p=dcmtk.git;a= ... cc0fffd6c6

amunaaser
Posts: 40
Joined: Thu, 2020-03-26, 10:29

Re: create one Dicom file from multiple images

#13 Post by amunaaser »

Hi!

I know that this was an old post, but the topic is quite intersting for me right now.
My question: is there any function(s) in DCMTK, that nowadays can handle multiframe DICOM images like ultrasound, i.e. for instance
- read a multiframe image
- return the pure image without the tags in order to be able to process it (for example putting a mask for hiding burned-in patient information)
- write back to the image

Thanks in advance
Nasser Hosseini

Marco Eichelberg
OFFIS DICOM Team
OFFIS DICOM Team
Posts: 1437
Joined: Tue, 2004-11-02, 17:22
Location: Oldenburg, Germany
Contact:

Re: create one Dicom file from multiple images

#14 Post by Marco Eichelberg »

There is no command line tool in DCMTK that would allow you to do this, but the underlying class library contains everything needed to implement such functionality. Look at the following sample code, which expects a DICOM dataset that has been already loaded (DcmFileFormat::loadFile()) and overwrites a certain rectangle with black. I think this also works for multiframe images, but probably not for all possible color models and weird combinations of BitsAllocated/BitsStored.

Code: Select all

OFCondition createClippedImage(
  DcmItem& dset,
  Sint32 value,
  Uint16 offsetX,
  Uint16 offsetY,
  Uint32 sizeX,
  Uint32 sizeY)
{
  Uint16 bitsAllocated = 0;
  Uint16 bitsStored = 0;
  Uint16 highBit = 0;
  Uint16 pixelRepresentation = 0;
  Uint16 samplesPerPixel = 0;
  Uint16 columns = 0;
  Uint16 rows = 0;
  Uint16 planarConfiguration = 0;
  Sint32 numberOfFrames = 1;

  // retrieve descriptive attributes from Image Pixel Module
  OFCondition result = dset.findAndGetUint16(DCM_BitsAllocated, bitsAllocated);
  if (result.good() && ((bitsAllocated != 8) && (bitsAllocated != 16)))
  {
    result = makeOFCondition(APPCOND, 1, OF_error, "bitsAllocated not 8 or 16");
  }

  if (result.good()) result = dset.findAndGetUint16(DCM_BitsStored, bitsStored);
  if (result.good() && ((bitsStored == 0) || (bitsStored > bitsAllocated)))
  {
    result = makeOFCondition(APPCOND, 2, OF_error, "bitsStored has illegal value");
  }

  if (result.good()) result = dset.findAndGetUint16(DCM_HighBit, highBit);
  if (result.good() && (((Uint16)(highBit+1) < bitsStored) || (highBit > (Uint16)(bitsAllocated-1))))
  {
    result = makeOFCondition(APPCOND, 3, OF_error, "highBit has illegal value");
  }

  if (result.good()) result = dset.findAndGetUint16(DCM_SamplesPerPixel, samplesPerPixel);
  if (result.good() && (samplesPerPixel > 1))
  {
    result = dset.findAndGetUint16(DCM_PlanarConfiguration, planarConfiguration);
  }

  if (result.good()) result = dset.findAndGetUint16(DCM_PixelRepresentation, pixelRepresentation);
  if (result.good()) result = dset.findAndGetUint16(DCM_Columns, columns);
  if (result.good()) result = dset.findAndGetUint16(DCM_Rows, rows);
  if (result.good() && (columns < 1 || rows < 1))
  {
    result = makeOFCondition(APPCOND, 5, OF_error, "colums/rows have illegal value");
  }

  if (result.good())
  {
    result = dset.findAndGetSint32(DCM_NumberOfFrames, numberOfFrames);
    if (result.bad() || numberOfFrames < 1) numberOfFrames = 1;
    result = EC_Normal;
  }

  // find pixel data, verify size
  DcmElement *pixelData = NULL;
  if (result.good())
  {
    DcmStack stack;
    result = dset.search(DCM_PixelData, stack, ESM_fromHere, OFFalse);
    if (result.good())
    {
      pixelData = (DcmElement *)stack.top();
      unsigned long  structureSize = (bitsAllocated == 8) ? 1 : 2;
      if (pixelData->getLength() < structureSize * columns * rows * numberOfFrames * samplesPerPixel)
      {
        result = makeOFCondition(APPCOND, 6, OF_error, "pixel data too short, maybe 4:2:2 color model");
      }
    }
  }

  // check if rectangle fits into frame
  if (result.good())
  {
    if (offsetX + sizeX > columns)
    {
      result = makeOFCondition(APPCOND, 7, OF_error, "clip rectangle too wide");
    }
    if (offsetY + sizeY > rows)
    {
      result = makeOFCondition(APPCOND, 8, OF_error, "clip rectangle too high");
    }
  }

  // compute minimal and maximal pixel value, pixel shift within cell
  if (result.good())
  {
    long minVal = 0;
    long maxVal = 0;

    if (pixelRepresentation == 0)
    {
        maxVal = (1 << bitsStored) -1;
    }
    else
    {
        minVal = -(1 << (bitsStored-1));
        maxVal = (1 << (bitsStored-1)) -1;
    }

    if (value < minVal)
    {
        result = makeOFCondition(APPCOND, 9, OF_error, "pixel value too small");
    }
    else if (value > maxVal)
    {
        result = makeOFCondition(APPCOND, 10, OF_error, "pixel value too large");
    }
    else
    {
      Uint32 ic, ir, is;

      // compute offset factor for sample
      Uint32 sampleOffset = 0;
      Uint32 rowOffset = 0;
      Uint32 colOffset = 0;
      if (planarConfiguration == 0)
      {
         sampleOffset = 1;
         rowOffset = columns * samplesPerPixel;
         colOffset = samplesPerPixel;
      }
      else
      {
         sampleOffset = columns * rows;
         rowOffset = columns;
         colOffset = 1;
      }

      // access image pixel data, adjust byte order, verify size
      if (bitsAllocated == 8)
      {
        Uint8 *data8 = NULL;
        Uint8 *frame8;
        Uint8 val8 = (Uint8)(value << (highBit + 1 - bitsStored));
        result = pixelData->getUint8Array(data8);
        if (result.good())
        {
          for (Sint32 fr = 0; fr < numberOfFrames; ++fr)
          {
              // compute start of frame
              frame8 = data8 + (columns * rows * samplesPerPixel * fr);
              for (ir = 0; ir < sizeY; ++ir)
                for (ic = 0; ic < sizeX; ++ic)
                  for (is = 0; is < samplesPerPixel; ++is)
                  {
                    // compute position of pixel and write pixel
                    *(frame8 + ((ir + offsetY) * rowOffset) + ((ic+offsetX) * colOffset) + (is * sampleOffset)) = val8;
                  }
          }
        }
      }
      else
      {
        Uint16 *data16 = NULL;
        Uint16 *frame16;
        Uint16 val16 = (Uint16)(value << (highBit + 1 - bitsStored));
        result = pixelData->getUint16Array(data16);
        if (result.good())
        {
          for (Sint32 fr = 0; fr < numberOfFrames; ++fr)
          {
              // compute start of frame
              frame16 = data16 + (columns * rows * samplesPerPixel * fr);
              for (ic = 0; ic < sizeX; ++ic)
                for (ir = 0; ir < sizeY; ++ir)
                  for (is = 0; is < samplesPerPixel; ++is)
                  {
                    // compute position of pixel and write pixel
                    *(frame16 + ((ir + offsetY) * rowOffset) + ((ic+offsetX) * colOffset) + (is * sampleOffset)) = val16;
                  }
          }
        }
      }
    }
  }

  // done
  return result;
}

amunaaser
Posts: 40
Joined: Thu, 2020-03-26, 10:29

Re: create one Dicom file from multiple images

#15 Post by amunaaser »

Thank you, dear Marco!
I actually use MATLAB as my programming environment. I'll see, if I could implement this function in MATLAB, perhaps as an external function.

Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Bing [Bot] and 1 guest