MakieOrg / Makie.jl

Interactive data visualizations and plotting in Julia
https://docs.makie.org/stable
MIT License
2.4k stars 307 forks source link

More volume rendering algorithms #423

Closed goaud27 closed 4 years ago

goaud27 commented 4 years ago

True volume rendering rendering algorithm

I tried to render a dataset (3d array of intensities) and only Maximum Intensity Projection algorithm makes it look slightly realistic, although I see a lot of missing data, and it doesn't look very 3D after all. The question is how can I truly render a volume with a custom-made colorscale that has fine-tuned alpha values to emphasize signal and make all the low-intensity noise transparent? I could do that with ipyvolume setting a custom transfer function with alpha = some_strongly_non-linear_function(r,g,b). I could also do the same in Igor Pro (though it takes hours to render). May be you can take an inspiration of true volume rendering from the ipyvolume?

SimonDanisch commented 4 years ago

You can pass an array of RGBA values to colormap:

volume(colormap =  some_strongly_non_linear_function(r,g,b))

That should give you all control needed ;)

SimonDanisch commented 4 years ago

Ok, the code sample is confusing. You need to convert it to an array of colors in the range of values you're looking at (colorrange=extrema(volume_to_plot))

goaud27 commented 4 years ago

Thank you for the lightning fast reply :) I will test this asap and get back.

goaud27 commented 4 years ago

Here is the original render from IgorPro that I am trying to replicate: az0_1p7_3p8_2

And here is what I managed to do with Julia: JuliaCube I believe it's pretty close, just in case of Julia an extra normalization is required.

If I understand correctly the definition the :mip algorithm is supposed to "fake" 3d volume by showing only the max intensity element along the "line of view", and the :absorption is supposed to render a true volume with cumulative absorption by all "particles" along the "line of view". In my case the :absorption always gives me a black "potato" even though there is no black color in the colorscale:

CubeJulia_absorption

And it doesn't seem to react to the colorrange settings at all. Do I understand these algorithms correctly?

P.S. Sorry for weirdly rotated images in Julia: for some reason the camera rotation screen on hiDPI monitor is crazily fast, so it's impossible to rotate it correctly. P.S.S. How does Makie treat negative alpha values? Just considers them to be zero?

SimonDanisch commented 4 years ago

Absorption is a bit sensitive^^ Try playing around with the absorption multiplier:

using Makie

scene = volume(rand(Float32, 100, 100, 100), algorithm=:absorption)

p = scene[end]

p.absorption = 9.0

9 was the first value that gave me something reasonable: image

goaud27 commented 4 years ago

Thanks for the advice. Indeed, playing with the absorption coefficient made the volume visible. But as I understood this algorithm uses gray RGB colorscale and completely ignores the "colorscale" keyword parameter, so it's impossible to play with the transparency.

Nevertheless, after normalizing the data and using :mip algorithm I am very close to what I wanted:

JuliaCube2 Thanks for all your help

SimonDanisch commented 4 years ago

Btw, you should also try contours, which currently generates the nicest volume plots! https://simondanisch.github.io/ReferenceImages/gallery/3d_contour_with_2d_contour_slices/index.html

goaud27 commented 4 years ago

Looks beautiful! Thank you for the suggestion

goaud27 commented 4 years ago

Closing the issue since the :mip algorithm seems to do the job for now

timholy commented 4 years ago

Contours aren't great for "noisy" data (e.g., biomedical images). This reminds me to get back to some of the outstanding issues discussed in https://github.com/JuliaGL/GLVisualize.jl/pull/199

SimonDanisch commented 4 years ago

I added some fixes in https://github.com/JuliaPlots/GLMakie.jl/pull/61... So Array{RGB, 3} works now again, and you can also give a colormap to absorption... But it's a bit annoying admittedly, since for a good rendering you need to use fine grained control of the alpha value of the colormap

goaud27 commented 4 years ago

In order to test your fix for absorption, would it be sufficient to just "rm GLMakie" and "add GLMakie#master"? Or will it break the whole installation? P.S. I am new to Julia and decided to give it a try only because of your amazing package :)

SimonDanisch commented 4 years ago

Once this gets merged: https://github.com/JuliaRegistries/General/pull/7988, you can just run ]up GLMakie... Before, you can try ]add GLMakie#master without the remove ;)

SimonDanisch commented 4 years ago

That's how I tested it btw:

using Makie, NRRD, FileIO, Colors
brain = Float32.(load(joinpath(homedir(), "Desktop", "brain.nrrd")) ./ 219)
scene = volume(brain, algorithm=:absorption)
display(scene)
cmap = RGBAf0.(to_colormap(:viridis, 100), 0.0)
r = 15:30
cmap[r] .= RGBAf0.(color.(cmap[r]), 1.0)
scene[end].colormap[] = cmap
scene[end].colorrange[] = (0.2, 0.3)

image

SimonDanisch commented 4 years ago

Tag got merged, so now you can just do ]up GLMakie