fixed color scale with volshow

10 views (last 30 days)
Lara
Lara on 12 May 2025
Answered: Tim Jackman on 16 May 2025
I have a code where I image hemoglobin levels across different frames.
%% Normalize All Volumes
all_data = cat(4, compressed_hbt_all{:});
% globalMin = min(all_data(:));
% globalMax = max(all_data(:));
globalMin = -1;
globalMax = 2;
normalized_hbt_all = cell(1, num_frames);
% Extract only rows 10 to 30 from norm_vol for each frame
startRow = 1;
endRow = 41;
for i = 1:num_frames
mu_thb2 = mu_thb;
vol_i = compressed_hbt_all{i};
vol_i = vol_i(startRow:endRow, :, :);
% vol_i(vol_i<=0) = 0;
mu_thb2 = mu_thb2(startRow:endRow, :, :);
norm_vol = (vol_i - globalMin) / (globalMax - globalMin);
norm_vol = min(max(norm_vol, 0), 1); % clip between 0 and 1
norm_vol(mu_thb2 == 0) = 0;
normalized_hbt_all{i} = norm_vol;
end
%% Second Pass: Visualization
% cmap = cmocean('balance');
cmap = jet(256);
alphaMap = (linspace(0, 0.7, 256).^2);
alphaMap(1) = 0;
fig = uifigure(); uip = uipanel(fig,Units="normalized",Position=[0 0 .90 1],BorderType="none");
viewer = viewer3d(uip);
viewer.BackgroundColor = [1 1 1];
viewer.BackgroundGradient = "off";
vol = volshow(normalized_hbt_all{1}, 'Colormap', cmap, 'Alphamap', alphaMap, Parent=viewer);
ax = axes(fig, Visible="off");
ax.Colormap = cmap;
ax.CLim = [globalMin, globalMax];
cb = colorbar(ax,"Units","normalized","Color",[.8 .8 .8]);
cb.Position(1) = 0.90; cb.Label.String = 'HbT concentration [M]';
cb.Label.FontSize = 20; cb.Label.Rotation = 270; cb.Label.VerticalAlignment = 'bottom';
frameLabel = uilabel(fig); frameLabel.Position = [10 fig.Position(4)-40 150 30]; frameLabel.FontSize = 16;
for i = 1:num_frames
frameLabel.Text = sprintf('Time: %d s', i);
vol.Data = normalized_hbt_all{i};
drawnow;
frame = getframe(fig);
writeVideo(writerObj, frame);
end
close(writerObj);
toc
I already tried normalizing the values for volshow, but for each frame the colors are newly generated. so if frame 1 has hemoglobin levels from 0.01 until 0.1 the higher hemoglobin levels will still be red. and frame 45 has hemoglobin levels from 0.5 until 5 it has the same color distribution. (It just depends on the dynamic range of my values)
Clim does not work with volshow but I have been looking for a workaround / or maybe manipulatiing the volshow function but i could not achieve a reasonable result. Is there anyway i can implement a fixed colorscale for all the frames that i have??

Answers (3)

Walter Roberson
Walter Roberson on 12 May 2025
After you getframe(fig) use rescale() specifying "InputMin" and "InputMax"
  1 Comment
Lara
Lara on 13 May 2025
i tried this:
for i = 1:num_frames
frameLabel.Text = sprintf('Time: %d s', i);
vol.Data = normalized_hbt_all{i};
drawnow;
frame = getframe(fig);
img = im2double(frame.cdata); % Convert to double for rescale to work properly
rescaled_img = rescale(img, 'InputMin', 0, 'InputMax', 1); % Fix color brightness range
rescaled_frame = im2uint8(rescaled_img); % Convert back to uint8 for video
writeVideo(writerObj, rescaled_frame);
% writeVideo(writerObj, frame);
end
close(writerObj);
toc
But it still changes with different global minimas and maximas, it is not consistent over all the frames. There is still the dynamic range colormap focus instead of the values.

Sign in to comment.


Umar
Umar on 13 May 2025

Hi @Lara ,

To achieve a consistent color scale across all frames in your volumetric visualization, you can follow these steps:

1. Define a Fixed Color Scale:You need to set fixed limits for the color scale (CLim) that applies uniformly to all frames. This involves determining the minimum and maximum hemoglobin concentration values across all frames before visualization.

2. Update Normalization Logic:Instead of normalizing each frame individually based on its own min-max values, normalize all frames based on the global minimum and maximum values determined earlier.

3. Implementation Example: Here’s how you can adjust your code to implement a fixed color scale across all frames:

   % Step 1: Determine global min and max across all volumes
   all_data = cat(4, compressed_hbt_all{:});
   globalMin = min(all_data(:)); % Compute the global minimum
   globalMax = max(all_data(:)); % Compute the global maximum
   % Step 2: Normalize using global min and max
   normalized_hbt_all = cell(1, num_frames);
   for i = 1:num_frames
       vol_i = compressed_hbt_all{i};
       norm_vol = (vol_i - globalMin) / (globalMax - globalMin);
       norm_vol = min(max(norm_vol, 0), 1);  % Clip between 0 and 1
       normalized_hbt_all{i} = norm_vol;
   end
   % Step 3: Visualization with fixed CLim
   cmap = jet(256); 
   alphaMap = (linspace(0, 0.7, 256).^2);
   alphaMap(1) = 0;
   fig = uifigure();
   uip = uipanel(fig, Units="normalized", Position=[0 0 .90 1], BorderType="none");
   viewer = viewer3d(uip);
   viewer.BackgroundColor = [1 1 1];
   for i = 1:num_frames
       vol = volshow(normalized_hbt_all{i}, 'Colormap', cmap, 'Alphamap', alphaMap,               Parent=viewer);
       ax = axes(fig, Visible="off");
       ax.Colormap = cmap;
       ax.CLim = [0, 1]; % Set fixed color limits
       cb = colorbar(ax,"Units","normalized","Color",[.8 .8 .8]);
       cb.Position(1) = 0.90; 
       cb.Label.String = 'HbT concentration [M]';
       cb.Label.FontSize = 20; 
       cb.Label.Rotation = 270; 
       cb.Label.VerticalAlignment = 'bottom';
       frameLabel.Text = sprintf('Time: %d s', i);
       drawnow;
       frame = getframe(fig);
       writeVideo(writerObj, frame);
   end
   close(writerObj);

Here are some additional insights that can help further

Dynamic Range Consideration: By setting `globalMin` and `globalMax` based on the entire dataset rather than per-frame values, you ensure that the same color mapping applies consistently throughout your visualization.

Colormap Selection: The choice of colormap (`jet` in this case) can significantly impact the interpretation of data. Consider using perceptually uniform colormaps like `parula` or `cmocean`, which may provide better visual clarity.

By following these guidelines, you should be able to maintain a consistent and accurate representation of hemoglobin levels across your volumetric visualizations.

Hope this helps.


Tim Jackman
Tim Jackman on 16 May 2025

I didn’t see it in your code, but I assume you are already setting the volshow colormap to match the cmap you used for the colorbar.

Have you tried specifying the DisplayRange property for volshow and setting it to [globalMin, globalMin]?

Categories

Find more on Color and Styling in Help Center and File Exchange

Products


Release

R2023b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!