Quickest way to join images preserving each colormap in MATLAB

I am a having problem finding a way to join images preserving each colormap. I basically want to read images from a folder, place them in a rectangular grid (image11, image12; image21, image22) each with its own colormap. I have tried imtile() but I get black boxes at times and also for some reason the colormap is a greyscale instead of colours.
What would be the quickest way to do this? maybe forming a supermatrix containing all pixels of all images and then saving that as an image?
My pseudocode is simple:
for namefiles
im = imread(namefile);
imshow(im); %this works
out=imtile(im,'GridSize', [ypos xpos]); %this shows the pictures in black and white
imshow(out)
end

2 Kommentare

can you provide a sample set and can you show an image of your problem/error.
Are all images of same size, is the position only defined by the file name and which colormap do you want to use? or do you mean the colors as they should be when you use imshow() on them?
I am actually not convinced that imtile() is what I want, that's why I didn't provide my code, I have now added it. Yes, all images are the same size. I can provide the position in the "grid" by looping indices. Yes, the colours of imshow(im) are the right ones, the colors in imshow(out) are not (black and white for a reason that I don't know).

Melden Sie sich an, um zu kommentieren.

 Akzeptierte Antwort

DGM
DGM am 4 Jul. 2022
Bearbeitet: DGM am 4 Jul. 2022
Read the images into a cell array in the loop. If the images are indexed color images, then convert them to RGB using ind2rgb() before storing them. Call imtile() or montage() on the cell array outside the loop.
nframes = 4;
C = cell(nframes,1);
for f = 1:nframes
[thisframe map] = imread(sprintf('pepframe%d.png',f));
if ~isempty(map)
thisframe = ind2rgb(thisframe,map);
end
C{f} = thisframe;
end
montage(C)

5 Kommentare

[comment-as-answer moved here to preserve thread structure]
Hi DGM,
Thanks, I managed to get it working with your script (see attached). However, the size (and resolution) are very small. Would it be possible to preserve the original resolution? (the resulting montage would exceed the screen limits but I could zoom in, there would be no problem about that)
I'm not sure what's going on here. You should be able to zoom in and see the images. I have two guesses:
One is that you're trying to save the image after it's been displayed with montage(). If so, don't. Like imshow(), montage() is a display tool. Saving its output is like taking a screenshot. There's no assurance that the image resolution or quality is preserved. If that's the case, use imtile() instead of montage(). Using imtile() lets you get the actual image array. Once you have the tiled image as an array, you can display it using imshow() or save it using imwrite().
There's another possibility that has to do with the behavior of imtile/montage. In either case, the images are all scaled to fit within the size of the first frame. It looks like all your images should be about the same size, so the behavior of montage/imtile should be such that their sizes are roughly preserved. If the image sizes do vary significantly, you could explicitly specify the image size.
nframes = 4;
tsize = zeros(nframes,2);
C = cell(nframes,1);
for f = 1:nframes
[thisframe map] = imread(sprintf('pepindexedframe%d.png',f));
if ~isempty(map)
thisframe = ind2rgb(thisframe,map);
end
C{f} = thisframe;
tsize(f,:) = [size(thisframe,1) size(thisframe,2)];
end
% get union of image sizes
% by default, imtile()/montage() will scale all images to the size of the first image
% by using the union, images will still be scaled, but they'll never be scaled down.
tsize = max(tsize,[],1)
tsize =
173 174
% you could use either montage() or imtile()
%montage(C,'thumbnailsize',tsize); % montage just throws an image in a figure
CC = imtile(C,'thumbnailsize',tsize); % imtile is useful if you want to save the image
imshow(CC)
This should work even if you have a large number of images:
nframes = 133; % a lot more frames
tsize = zeros(nframes,2);
C = cell(nframes,1);
for f = 1:nframes
imgnum = mod(f,4)+1; % i'm doing this so i can reuse the same 4 demo images
[thisframe map] = imread(sprintf('pepindexedframe%d.png',imgnum));
if ~isempty(map)
thisframe = ind2rgb(thisframe,map);
end
C{f} = thisframe;
tsize(f,:) = [size(thisframe,1) size(thisframe,2)];
end
% get union of image sizes
tsize = max(tsize,[],1)
tsize =
173 174
% you could use either montage() or imtile()
%montage(C,'size',[19 7],'thumbnailsize',tsize)
CC = imtile(C,'gridsize',[19 7],'thumbnailsize',tsize);
imshow(CC)
sz = size(CC) % image is large
sz(1:2)./tsize % geometry is an integer-multiple of the specified size
sz =
3287 1218 3
ans =
19 7
I hate to add to the confusion, but for what it's worth, I would normally do this sort of thing using third-party tools for the sake of simplicity and flexibility. Using MIMT tools to do the job allows for more flexibility in the padding/scaling behavior, and the amount of code that needs to be written is minimal.
The point of confusion here is that MIMT imtile() is not the same as IPT imtile(). They are similar, but MIMT imtile() has a much narrower purpose and is reversible. Until I rename MIMT imtile(), the conflict is an annoyance that I have to disclose.
% read all images into a cell array
% mimread will automatically convert indexed images to RGB
C = mimread('sources/standardmods/indexedpep/pepindexedframe*.png');
% arrange images into a 4D stack
% pad images to common geometry (union of sizes)
% preserve each original image resolution
C = imstacker(C,'padding',0);
% tile the images (this is MIMT imtile(), not IPT imtile())
CC = imtile(C,[2 2]);
imshow(CC)
Instead of using a rigid fit that exactly preserves the image resolutions, you could also replicate the montage() behavior where the images are scaled and padded to fit within the tile geometry:
% read all images into a cell array
% mimread will automatically convert indexed images to RGB
C = mimread('sources/standardmods/indexedpep/pepindexedframe*.png');
% arrange images into a 4D stack
% scale and pad images to common geometry (union of sizes)
% this is the same as the example with montage()/imtile() when using max(tsize)
C = imstacker(C,'fit','inscribe','padding',0);
% tile the images (this is MIMT imtile(), not IPT imtile())
CC = imtile(C,[2 2]);
imshow(CC)
Alternatively (though not likely useful in your case), you could fit images by scaling and cropping.
% read all images into a cell array
% mimread will automatically convert indexed images to RGB
C = mimread('sources/standardmods/indexedpep/pepindexedframe*.png');
% arrange images into a 4D stack
% scale and crop images to common geometry (union of sizes)
% this is the same as the example with montage()/imtile() when using max(tsize)
C = imstacker(C,'fit','circumscribe','padding',0);
% tile the images (this is MIMT imtile(), not IPT imtile())
CC = imtile(C,[2 2]);
imshow(CC)
Gravity, fit, size, padding color, and offsets can all be specified using imstacker(), which makes a imstacker/imtile workflow more flexible than IPT imtile() or montage(). Just throwing that out there.
Thank you so much for all the detailed information. Unfortunately I now run into an 'Out of memory' error. My code is based on yours. How can I get around this?
for f = 1:length(files_array)
namefile=strcat(directory,strtrim(name_case_plot(sim_case,:)),'_vel1_',num2str(files_array(f)*10-1),'.png');
[thisframe map] = imread(namefile);
if ~isempty(map)
thisframe = ind2rgb(thisframe,map);
end
f
C{f,sim_case} = thisframe;
end
end
imtile(C','GridSize', [19 7])
DGM
DGM am 8 Jul. 2022
Bearbeitet: DGM am 8 Jul. 2022
Ah. I didn't think about that. By default, ind2rgb() produces an array of class 'double'. You can reduce the memory requirements by a factor of 8 by doing:
C{f,sim_case} = im2uint8(thisframe);
If they still won't fit in memory, then the problem gets more complicated. There may have to be some compromises made. If there are further memory issues, it would be helpful to know how large the images actually are (height, width) and how much memory is available. That way I can at least estimate what might fit. If the images are all the same size, the requirements can be reduced by a factor of about 2.
The memory constraints would also mean that using mimread()/imstacker() from MIMT would be out of the question.

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (0)

Tags

Gefragt:

am 4 Jul. 2022

Bearbeitet:

DGM
am 8 Jul. 2022

Community Treasure Hunt

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

Start Hunting!

Translated by