How to decode and visualize DICOM curve data in Python 3? - python

I am trying to visualize a DICOM file with Python 3 and pyDicom which should contain a black 100x100 image with some curves drawn in it. The pixel data is extracted from header (7fe0,0010) and when printed shows b'\x00\x00\x00...'. This I can easily convert to a 100x100 numpy array.
However, the curve data in (5000,3000) shows me b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0H#\x00\x00\x00\x00\x00\xc0X#\x00\x00\x00\x00\x00\xc0H#' which I am not able to convert to x,y coordinates in my 100x100 pixel image. In the DICOM file it says
curve dimensions: 2
number of points: 2
type of data: poly
data value representation: 3
curve label: horizontal axis
curve data: 32 elements
The main question is: How do I decode the coordinates required for retracing the curve within my 100x100 image? My main concern is the fact that there should be 32 elements, but only 26 hex values in the output. Also I have no clue how to deal with the \xc0H# and \xc0X#. When I print those, it yields 192 72 64 and 192 88 64. How does python decode these 2 hex codes to 6 numbers? And what do these numbers represent?
EDIT:
Apparently data value representation 3 means the data is represented as a floating point double. On the other hand, there should be two points in the data, so each point is represented by 16 elements? I don't see how these two statements are compatible. What is interesting is that the first \xc0H# translates to 3 numbers as mentioned before, and by doing so complete the first 16 elements of the curve data. How can I convert this into a point in my 2D image?

Curve data has been retired in DICOM since 2004, so you will find the relevant information in the DICOM standard from 2004 (thanks to #kritzel_sw for the link).
As you already found out, Data Value Representation 3 means that the data entries are in double format, and with a Type of Data of polygon, you have x/y tuples in your data. As a double value is saved in 8 bytes, there are 16 bytes per point -- in your case (32 bytes of data) 2 points overall.
Pydicom does not (and probably will not) directly support the retired Curve module (though support for the Waveform module, the current equivalent, has been added in pydicom 2.1), so you have to decode the data yourself. You can do something like this (given double numbers):
from struct import unpack
from pydicom import dcm_read
ds = dcm_read(filename)
data = ds[0x50003000].value
# unpack('d') unpacks 8 bytes into a double
numbers = [unpack('d', data[i:i+8])[0] for i in range(0, len(data), 8)]
# I'm sure there is a nicer way for this...
coords = [(numbers[i], numbers[i+1]) for i in range(0, len(numbers), 2)]
In your example data, this will return:
[(0.0, 49.5), (99.0, 49.5)]
e.g. the x/y coordinates (0, 49.9) and (99.0, 49.5), which corresponds to a horizontal line in the middle of your image.
As to the mismatch of 26 hex elements vs 32 bytes: a byte string representation shows only the bytes that cannot be converted to ASCII in hex string notation, the rest is just shown as the representation of the corresponding ASCII characters. So, for example this part of your byte string: \x00\xc0H# is 4 bytes long and could also be represented as \x00\xc0\x48\x40 in hex string notation.

Related

Not able to convert binary data from dicom file with python

I have a Vector Grid Data from a Deformable Registration Grid Sequence whos type is binary.
i'm Trying to convert this data to a list of, i think, signed floating point value elements. but can find the function that allows me perform this operation. Let me show you a piece of the information.
b' dZ=\x00\x90\xb3=\x00\x18\x89\xbd \xe9}=\x00\xc0\xd6=\x00\xa0\xa5\xbd\xe0]\x93=\x00\x10\xfd=\x00\xa8\xc4\xbd\xc0\x8e\xa9=
...
\x95\xf9\xbb\xbc\x00\x80\x06=\xc6\x88(=\xa9\xcb\x82\xbc\x00#\xa6<A\xce\xc6<\xc5\xd5\x19\xbc\x00\x00\x0e<k\xba\x17<\x02\x07i\xbb'
i'll appreciate your help
Vector Grid Data consists of triplets of 4 byte floating point values. Try
from struct import unpack
data = b"..."
values = unpack(f"<{len(data) / 4}f", data)

How to get the 10bit per pixel from a raw image file?

I have a 10bit .raw file which is coded into 8 bit. so after the 4 bytes, the 5th byte contains the 2 bits or each 4bytes. ( so total after decode I should get 10 bits per pixel).
raw file : <_io.TextIOWrapper name='img_10bit.raw' mode='r' encoding='cp1252'>
size of 1d array after reading using np.uint8 = (2611200,)
check this image for the bits placement
How to get the 10 bit data per pixel to reconstruct the image? , i need to do this in python.
Hint:
Read four bytes and shift them left by two bits.
Read a fifth byte and slice it in four parts:
"bitwise and" with 3;
shift right by two bits.
Add the results of the "bitwise and" to the respective bytes and you get four 10 bits numbers.

How can read, manipulate, and write a range of (less than 8) bits of a byte array in Python?

I'm looking for a way to read, manipulate, and write specific ranges of (less than 8) bits in a byte array.
I want something like, let's say I want to work with the 6-8th bit of a byte array:
R0 = bytearray(8)
bits = readBits(R0, 6, 2) # bytearray, position, range
print(bits) # [0, 0] or maybe it's easier to work with a byte
# with the irrelevant bits zeroed, you tell me
# do stuff ... XOR, AND, ETC
writeBits(R0, bits, 6) # target, source, position
I'm writing an x86-64 emulator in Python and some instructions in the General Purpose Registers can reference 2 bit segments of the 64 bit register, which I've been representing as bytearray(8). The smallest unit of a byte array seems to be a byte (go figure). Is there a way to select bits? Let's say I want to read, manipulate, and update the 6th-8th bits of an 8 byte object? What does that look like?
Maybe there's a more granular data structure I should be using rather than a byte array?
One answer to a similar question working with a hex string suggests:
i = int("140900793d002327", 16)
# getting bit at position 28 (counting from 0 from right)
i >> 28 & 1
# getting bits at position 24-27
bin(i >> 24 & 0b111)
But this code isn't explained super well, for example what does 0b111 do here and how do I use this approach dynamically to isolate any desired range of bits as with my imaginary readBits and writeBits funcs, rather than the hard-coded functionality here?

Convert hex to 15 bit RGB value in python

im a beginner with python and want to make a program that converts a hex RGB value to a 15 bit RGB one (5 bits for every color) i heard that it can be done by bitshifts but i don´t get how i also didn´t find anything helpful on the internet can someone please help me
If you're doing this manually (say, for homework), think of the problem like this:
If you have a six character hex representation of a color ("7FD87F" for instance), it's made up of the RGB components R: 7F, G: D8, B: 7F.
Two hexadecimal digits can encode 256 different states (16^2 = 256), so each of these components is 8 bits in size (256 = 2^8).
You want to transform your value into a color space where each component is represented in 5 bits. The way to do this is to throw away the three least significant bits from each of the components. For example:
0b10101010 => 0b10101
As you correctly mentioned, you would do this via bit-shifting. You'll then need to recombine the components. As a hint, here's how I would recombine the original 8-bit components into a single 24-bit representation:
(R << 16) + (G << 8) + (B << 0)
# or just B since a shift by zero is equivalent to
# multiplying by 2^0 is
# multiplying by 1 is
# the multiplicative identity
So the sketch of your algorithm, assuming you are starting with a hex string and not an integer:
Split the hex string into individual color components
Convert the string representations to numeric representations
Bit shift the components
Recombine the 5-bit components into a 15-bit representation
Additionally, steps 1 and 2 are interchangible with some bit-masking and a little more bit-shifting.

How would I implement a bit map?

I wish to implement a 2d bit map class in Python. The class would have the following requirements:
Allow the creating of arbitrarily sized 2d bitmaps. i.e. to create an 8 x 8 bitmap (8 bytes), something like:
bitmap = Bitmap(8,8)
provide an API to access the bits in this 2d map as boolean or even integer values, i.e.:
if bitmap[1, 2] or bitmap.get(0, 1)
Able to retrieve the data as packed Binary data. Essentially it would be each row of the bit map concatenated and returned as Binary data. It may be padded to the nearest byte or something similar.
bitmap.data()
Be able to create new maps from the binary data retrieved:
new_bitmap = Bitmap(8, 8, bitmap.data())
I know Python is able to perform binary operations, but I'd like some suggestions as how best to use them to implement this class.
Bit-Packing numpy ( SciPY ) arrays does what you are looking for.
The example shows 4x3 bit (Boolean) array packed into 4 8-bit bytes. unpackbits unpacks uint8 arrays into a Boolean output array that you can use in computations.
>>> a = np.array([[[1,0,1],
... [0,1,0]],
... [[1,1,0],
... [0,0,1]]])
>>> b = np.packbits(a,axis=-1)
>>> b
array([[[160],[64]],[[192],[32]]], dtype=uint8)
If you need 1-bit pixel images, PIL is the place to look.
No need to create this yourself.
Use the very good Python Imaging Library (PIL)

Categories