Overlay image, code as function and code as script give differnt results

1 view (last 30 days)
I want to overlay a colored image onto a gray image, and I found a solution here. If I run it as a script, it works perfectly. However, if I wrap it as a function, the colorbar would be at the wrong position. What makes this more bizarre is that if I add a breakpoint at the end of the fucntion, it would behave properly. This can be reproduced on my PC with R2018a, R2020a, and R2021a.
clear
im1 = imread('pout.tif'); % background image
im2 = rand(size(im1)) * double(max(im1(:))); % overlaid colored image
mask = false(size(im1));
mask(50:100,50:100) = true;
% call as a function, behaves improperly
simple_overlay(im1, im2, mask);
% run as script, behaves properly
figure;
ax1 = axes;
imagesc(im1);
colormap(ax1,'gray');
ax2 = axes;
imagesc(ax2,im2,'alphadata',mask);
colormap(ax2,'jet');
caxis(ax2,[min(nonzeros(im2)) max(nonzeros(im2))]);
ax2.Visible = 'off';
linkprop([ax1 ax2],'Position');
colorbar;
function simple_overlay(im1, im2,mask)
figure;
ax1 = axes;
imagesc(im1);
colormap(ax1,'gray');
ax2 = axes;
imagesc(ax2,im2,'alphadata',mask);
colormap(ax2,'jet');
caxis(ax2,[min(nonzeros(im2)) max(nonzeros(im2))]);
ax2.Visible = 'off';
linkprop([ax1 ax2],'Position');
colorbar;
end % add a breakpoint at this line, then the two methods will be the same

Accepted Answer

Image Analyst
Image Analyst on 6 Jul 2021
Another reason for me to not use imagesc. I always use imshow() instead. To fix, put drawnow before the end of the function:
drawnow;
end % add a breakpoint at this line, then the two methods will be the same
  3 Comments
Image Analyst
Image Analyst on 6 Jul 2021
With imshow() you can give it a colormap, even a custom one if you want, and with caxis() you can customize what gray levels get mapped to which colors. With imagesc() I hate the fact that it chooses some default colormap that is almost always no good for your images. It's much better to design the colormap yourself.
rgbImage1 = imread('peppers.png');
rgbImage2 = flipud(rgbImage1); % Upside down version
% Method using imshow()
subplot(1, 2, 1);
imshow(rgbImage1);
hold on;
hImage = imshow(rgbImage2);
hImage.AlphaData = 0.3;
axis('on', 'image');
title('Using imshow', 'FontSize', 15);
% Method using imagesc()
subplot(1, 2, 2);
imagesc(rgbImage1);
hold on;
imagesc(rgbImage2, 'AlphaData', 0.3);
axis('on', 'image');
title('Using imagesc', 'FontSize', 15);
So the same result, but imshow() requires one extra line of code to set the transparency of the second/topmost image.
Xingwang Yong
Xingwang Yong on 7 Jul 2021
Yes, you are right, with imshow(), I can also have a simple way to speficify 'alphadata'.

Sign in to comment.

More Answers (1)

Walter Roberson
Walter Roberson on 6 Jul 2021
The difficulty here is that
linkprop([ax1 ax2],'Position');
uses the current position associated with ax1 as the Position for both, but then you colorbar against ax2. Meanwhile, ax1 and ax2 only have nominal positions instead of real positions, because they have never been rendered after they are created. Without drawnow() or pause() or figure() call, rendering is done the next time the program is ready to issue a command prompt.
If you add a drawnow() at the end of your function, then you will get a result in which the spacing is the same on both figures.
If you move the colorbar() to before the linkprop(), then you will get a result in which the colorbars are visible on both figures, but that the spacing of the two figures is not the same (the image space stays the same but the colorbar on one gets pushed to the right.)
It isn't really a bug: you are asking it to synchronize sizes that are not determined yet, and the ordering of determining sizes for the two axes is not always obvious. Like if ax1 determines a size for itself not knowing that a colorbar is hanging around, and that size gets transferred to ax2, and then ax2 resizes because of the colorbar, but doesn't push the new size back to ax1 because of infinite loop avoidance...
It does play out oddly, but not a bug.
Here is a version that works out without needing the drawnow():
function simple_overlay(im1, im2,mask)
figure;
ax1 = axes;
imagesc(im1);
colormap(ax1,'gray');
ax2 = axes;
imagesc(ax2,im2,'alphadata',mask);
colormap(ax2,'jet');
caxis(ax2,[min(nonzeros(im2)) max(nonzeros(im2))]);
ax2.Visible = 'off';
colorbar(ax2);
linkprop([ax2 ax1],'Position');
end
That is, inform ax2 that it has a colorbar, and then push the ax2 position over to ax1.
  1 Comment
Xingwang Yong
Xingwang Yong on 7 Jul 2021
Wow, thanks for your clear explanation. If I use drawnow(), there is the problem that if I maximize the figure, then the two images will be misaligned. But with your version, this is fine.

Sign in to comment.

Products


Release

R2020a

Community Treasure Hunt

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

Start Hunting!