fixed color scale with volshow

8 次查看(过去 30 天)
Lara
Lara 2025-5-12
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??

回答(3 个)

Walter Roberson
Walter Roberson 2025-5-12
After you getframe(fig) use rescale() specifying "InputMin" and "InputMax"
  1 个评论
Lara
Lara 2025-5-13
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.

请先登录,再进行评论。


Umar
Umar 2025-5-13

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 2025-5-16

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]?

类别

Help CenterFile Exchange 中查找有关 Color and Styling 的更多信息

产品


版本

R2023b

Community Treasure Hunt

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

Start Hunting!

Translated by