0
$\begingroup$

So I've written a personal volume renderer which currently visualizes datasets (CT-Scans mostly) that have a .raw extension and the values are in the range 0-255 or uint8.

Now I searched the net and found some datasets that had uint16 (ranging from 0-4095) and float which was arbitrary but went from like 0-20 or something. I think the uint16 dataset corresponds to values in Hounsfield scale but I'm unsure of how do I map these to 0-255.

I haven't implemented any fancy transfer functions currently. For the uint8 datasets I just read the isovalues from the dataset and use that value for all the channels (r,g,b) as it is giving me a grayscale image.

EDIT:- To clarify further, I have implemented a gpu based ray marching algorithm taking help from this site here, I'm taking the datasets from here, As mentioned in the comments I don't really know how you should interpret these values, but a quick read shows that normally the CT data is based on Hounsfield units which represents density afaik.

$\endgroup$
  • $\begingroup$ Could you be more specific? What exactly are you asking? $\endgroup$ – ivokabel Nov 11 '19 at 18:27
  • $\begingroup$ Simply stating I want to know how to interpret values outside 0-255 range? How do i map them to 0-255 $\endgroup$ – gallickgunner Nov 11 '19 at 18:41
  • 1
    $\begingroup$ What are you using the 0-255 values for? Density? $\endgroup$ – lightxbulb Nov 11 '19 at 21:30
  • 1
    $\begingroup$ Yes, I think. Are there other ways to use those values? I don't really have much knowledge about it since there is so little on the internet regarding volume rendering especially one related to scientific visualization. The sites from where I get these datasets don't tell what unit are the values supposed to be in or how to interpret them. Updated the post with the sites. $\endgroup$ – gallickgunner Nov 12 '19 at 11:21
  • 1
    $\begingroup$ I would suggest remapping both the uint8 and uint16 version to [0,1]. Then you can multiply by some factor if necessary. More precisely: v= v / max_v. $\endgroup$ – lightxbulb Nov 12 '19 at 16:15
2
$\begingroup$

Ok after searching a whole lot on the internet I found a slide which answered most of my questions and doubts. I'm dumping it here in-case anybody else is curious what these datasets usually contain and what should be (in my opinion) the correct way to handle mappings.

So apparently the CT scanner always records the densities of the substances in Hounsfield Scale. The Hounsfield Scale itself is a little interesting. For body organs and stuff, the scale has the range from -1024 to 3000. This was the scale I talked about earlier as when normalized the values usually lie between 0-4096. However metals usually go past this 3k boundary and some metals like stainless steel and gold having HU number as high as 13k and 30k respectively. This is usually called the "extended" Hounsfield Scale. Some volumetric datasets contain data for computer simulations mostly fluids etc. For these type of datasets either density or flow velocity is captured. Precision is important for these datasets hence float is used.

Hence the uint8 datasets are probably grey-scale data converted from the original HU units. uint16 datasets contain the original Hounsfield data while float may contain density or velocity.

Now for the mapping part, as others stated one way might be to just divide by the max value of the data type or the max value of the data itself, to get the uint16 or float data in 0-1 range then multiply by 255 to get a grey-scale image. However doing so may lower the contrast and hide minute details. For example, dividing a uint16 dataset that contained only HU units in range 300-2000 with the $2^{16}$ will map the HU units to only a small range of grey values. Dividing by 2000 in this case is surely better. However after reading how CT-scanners work, it's better to let the user set the minimum and maximum range of Hounsfield units they wish to observe. This is usually called the window width. And then map this window width to the whole 0-255 range of grey levels as YardenJ2R mentioned in his second formula. This is more in line with how radiologists visualise the data.

For fancy transfer functions which I haven't implemented yet, we might have to convert the Hounsfield units to opacity or grey scale as mentioned above then map that opacity to color or there might be a way to directly map it to colors using a LUT as defined by the user's control point settings.

$\endgroup$
1
$\begingroup$

It seems you want to work with values between 0-255. For uint16 datasets, you can put it inside 0-255 range like this:

$newValue = 255 * \frac{oldValue}{(2^{16} - 1)}$

where $oldValue$ is an uint16 value and $2^{16} - 1$ is the uint16 max number. For the float ones without any previous knowledge about its range, you could read all the values from the dataset in order to find out the min and the max values. Then, you could map this way:

$newValue = 255 * \frac{oldValue - min}{max - min}$

The key idea is to map first to range 0-1 and then map it to 0-255 by multiplying it by 255. Don't forget to round/ceil/floor your value as you want an integer, not a float number.

$\endgroup$
  • $\begingroup$ I think you are misunderstanding the situation probably. Firstly although it's a uint16 dataset, the values are in the range 0-4095 which I guess are in Hounsfield units. For a simple remapping you should be dividing by 4095 instead of $2^{16}$. Again this seems more like just refitting the data range which I thought of initially but posted the question since I was thinking of a specific mapping operation which depends on what those values represent initially. Again my speculation can be wrong and if you really are sure about it then I'll wait for other answers $\endgroup$ – gallickgunner Nov 12 '19 at 15:55
  • $\begingroup$ Yes, in this case you should divide it by 4095. I don't see why you shouldn't use this mapping. Perhaps, you would need to do a previous one. I don't know this Hounsfield units, but suppose you would like to work with cm instead of meters. The dataset is uint16 with range 0-4095 in meters. Then, first you would have to multiply $oldValue$ by 100 (this is just an example). Although, as you said, I might be misunderstanding the situation. $\endgroup$ – YardenJ2R Nov 12 '19 at 16:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.