POV-Ray : Newsgroups : povray.binaries.images : multiple image_maps as media density-- 'fake' .df3 : multiple image_maps as media density-- 'fake' .df3 Server Time
31 Oct 2024 08:18:27 EDT (-0400)
  multiple image_maps as media density-- 'fake' .df3  
From: Kenneth
Date: 26 Oct 2024 17:40:00
Message: <web.671d5e03ca529ae591c33a706e066e29@news.povray.org>
A recent post by user 'yesbird' described using a .df3 media-density file made
from a medical CT scan, and rendered in POV-ray...

https://news.povray.org/povray.advanced-users/thread/%3C66f2f986%40news.povray.org%3E/?mtop=444143

I was inspired by that to try a different method, just to see if it would work:
skipping the CT-scan-to-.df3 conversion step and instead using the 'stack' of
multiple CT-scan images themselves as the media density, for the full 3-D
volume.

[I had to use one of the 3.8 betas for this test, because of a limitation in
'official' 3.7.0 of a maximum 256 entries in a pigment_map.]

For the test, I used a CT scan of my own, acquired from a recent visit to my
dentist (for a 'root canal' procedure-- which was painless, I am happy to say!)
In one of the file folders on the CD, I found the original numbered grayscale
image 'slices' that make up the scan-- 358 of them, at 523 X 523 pixel
resolution. Unfortunately, those 16-bit images were in a .dcm file format that
POV-ray cannot directly read as image_maps, so I batch-converted them to .png
files in Irfanview. (That app has a built-in dcm-to-png conversion filter,
although it is not turned on by default.) The one drawback is that the resulting
files were  'down-converted' to 8-bit grayscale...but that was adequate for my
test. The CT scan itself was of rather low-quality anyway.

Image_maps (or 'pigments' in general) cannot be used directly as media density--
but a *function* of the image_maps can. The trick was to get all of the 358
images loaded into a single pigment_map, for conversion to a function; I used an
automated 'string' set-up to do that, in a #for loop. (A typical pigment_map
uses index values between 0.0 and 1.0, which corresponds to 1 unit in z-space by
default. The 358 images fill that volume.)

pigment{
gradient z
pigment_map{
#for(i,1,358)
[i/358
image_map{
png concat("3DSlice",str(i,0,0),".png") gamma 3 interpolate 2 once
         }
]
// a higher than normal gamma has the effect of  increasing the
// image contrast
#end
.....

It produces the same result as laboriously specifying the individual images
themselves:

[1/358 image_map{png "3DSlice1.png" gamma 3 interpolate 2 once]
[2/358 image_map{png "3DSlice2.png" gamma 3 interpolate 2 once]
.....
[357/358 image_map{png "3DSlice357.png" gamma 3 interpolate 2 once]
[358/358 image_map{png "3DSlice358.png" gamma 3 interpolate 2 once]

(Just a reminder: The images need to be in a file folder location that POV-ray
can find; an additional Library_Path can be added to your master povray.ini
file if needed.)

To be honest, I was not sure *what* the end result of this media scheme would
look like, because of the image_maps being 'stacked together' in z, AND with
small gaps between their z-spacing. (They are just 2-D images.) But in effect,
they produce a kind of 'fake' .df3 appearance-- with a .df3's 'voxel depth'
being replaced by each image's media inbetween the image slices. Apparently,
each image's z-depth media extends only until the next image_map is
encountered-- instead of creating one ugly media blur in the enclosing box.

In the media code, a color_map can be used to give different colors to the
different 'densities'-- meaning, the varying grayscale values of the image_maps.
And the map's colors and index values can be played with to get interesting
effects, like supressing certain densities while accentuating others.

I will  also post an animation of the rotating media box, at p.b.f. animations
in the newsgroups.
----
The one unknown value was the 'spacing' of the individual images in the CT
scan-- the CT machine's spatial resolution as the x-ray slices progressed
through my teeth! I just assumed that a 1-unit cube (a box) would suffice as the
full 'depth', more or less. (I actually used <523,523,358>/523 for the scaling)
----
My code:

#version 3.8;
global_settings{assumed_gamma 1.0}
// #default{finish{ambient .05 emission 0 diffuse .9}}

camera {
  perspective
  location  <0, 0, -1.1>
  look_at   <0, 0,  0>
  right     x*image_width/image_height
  angle 67
}

#declare PIG_SLICES =
function{
pigment{
gradient z
pigment_map{
#for(i,1,358) // 358 images
[i/358
 image_map{png concat("3DSlice",str(i,0,0),".png") gamma 3 interpolate 2 once}
]
#end
           } // end of pigment_map
       } // end of pigment
} // end of function

box{0,.999 translate .0005
hollow
pigment{rgbt 1}
interior{
    media{
      emission 4
      //absorption...
      //scattering...
      method 3 intervals 1 samples 60 aa_level 4
    density{
        function{PIG_SLICES(x,y,z).gray} // or .red or .green or .blue
        color_map{
            [0 transmit 1]
            [.01 transmit 1]
            [.1 rgb <0,0,1>]
            [.2 rgb <0,1,0>]
            [.5 rgb <0,1,0>]
            [.5 rgb <1,0,0>]
            [1 rgb <1,0,0>]
                 }
           } // end of density
         } // end of media
       } // end of interior
translate -.5
scale <523,523,358>/523
//rotate...
}


Post a reply to this message


Attachments:
Download 'ct_scan_to_media_density_1_kw_10_2024.jpg' (226 KB)

Preview of image 'ct_scan_to_media_density_1_kw_10_2024.jpg'
ct_scan_to_media_density_1_kw_10_2024.jpg


 

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.