Montage from a cell array of image file names
Mostra commenti meno recenti
Hello all,
I'm having some trouble with the last step of a piece of code I've written. The aim of the project is to make one of those photos made up of lots of little photos. I've got most of it sorted (enough to run it as a test at least). The problem I'm having is with the montage command, but for context here's the overall process:
- Take all the image files on my computer
- Rename them numerically (with leading zeros)
- Resize them so they are square and a set size (400 x 400px at the moment)
- Find the mean value of each of the RGB layers and save in a database with the file name
- Take a main image, and divide it into squares (4 x 4px at the moment)
- Find the mean value of each of the RGB layers in this image
- Compare the RGB values to find the closest match in the image database to each small section of the main image
- Replace each small section of the main image with the closest matching image from the database, giving a matrix of image file names
- Replace the matrix of file names with the images themselves and save the image
So, the problem is...
I have a cell array called "replacer", which at the moment is a 400 wide 300 long array of file names (complete, e.g. 'cimage05886.jpg'). I now need to make this into the final image, which I have been trying to do like this:
mainmontage=montage(replacer, 'Size', [montageheight montagewidth]);
where montageheight = 300 and montagewidth = 400, and replacer is as above.
However it doesn't seem to work. I get an image, but it has a sort of repeated pattern in the montage (seems to be 4 times across the width), which is not there in the filenames in the replacer cell array.
My question is this:
Is the montage command the best way to create the matrix of images I'm after, or is there an alternative? If it is, can anyone suggest why I might be getting the error I am. I think I could be missing something with the size stipulation, because when I change it to [3 4] as a test (or even [1 1]) I get an over limit error:
>> mainmontage2=montage(replacer, 'Size', [3 4]);
Error using zeros
Requested 480x480x3x120000 (77.2GB) array exceeds maximum
array size preference. Creation of arrays greater than this
limit may take a long time and cause MATLAB to become
unresponsive. See array size limit or preference panel for
more information.
I don't get this with the original code, even though that is [300 400], which is surely bigger? I'm confused. I've read the documentation on montage but can't seem to make any progress. Any help gratefully received!
My full code is copied below. I'm sure it's horrible, but it gets me to the matrix of image files so I don't think the problem lies in the earlier code (though happy to be corrected!).
Thanks very much for any assistance, and apologies for the long post.
Stu
%RENAME
dirData = dir('*.jpg');
% Get the selected file data
fileNames = {dirData.name};
%Create a cell array of file names
for iFile = 1:numel(fileNames)
%Loop over the file names
newName = sprintf('image%05d.jpg',iFile);
% Make the new name
movefile(fileNames{iFile},newName,'f');
%Rename the file
end
%RESHAPE TO SQUARE
for i=1:iFile;
n=sprintf('%05d',i);
I=imread(horzcat('image',n,'.jpg'));
[height,width]=size(I(:,:,1));
if height>width;
diff=height-width;
halfdiff=diff/2;
hmin=0+halfdiff;
wmin=0;
%[xmin ymin width height]
J=imcrop(I,[wmin hmin width width-1]);
imwrite(J,horzcat('bimage',n,'.jpg'));
else if width>height;
diff=width-height;
halfdiff=diff/2;
wmin=0+halfdiff;
hmin=0;
%[xmin ymin width height]
J=imcrop(I,[wmin hmin height-1 height]);
imwrite(J,horzcat('bimage',n,'.jpg'));
else if width == height;
J=I;
imwrite(J,horzcat('bimage',n,'.jpg'));
end
end
end
end
%PUT AVERAGE COLOUR AND VARIATION IN TABLE
%row number tells you the name (ie 1=00001 400=00400 etc)
%added for simplicity while testing - run from here on
iFile=12100;
datatable=zeros(iFile,2);
clear i
clear I
for i=1:iFile;
n=sprintf('%05d',i);
%I=imread(horzcat('bimage',n,'.jpg'));
I=imread(horzcat('cimage',n,'.jpg'));
rmeanval=mean(I(:,:,1),'all');
gmeanval=mean(I(:,:,2),'all');
bmeanval=mean(I(:,:,3),'all');
%meanval gives us the mean colour of each image
%I2=abs(I-meanval);
%meandiff=mean(I2,'all');
%meandiff gives us the mean difference from the mean
%higher means a more widely coloured image
%lower means a more homogoneous image
%datatable(1,i)=meanval;
%datatable(2,i)=meandiff;
datatable(1,i)=rmeanval;
datatable(2,i)=gmeanval;
datatable(3,i)=bmeanval;
end
datatable3=datatable(1:3,:)'
datatable3(:,4)=1:iFile;
%then round to nearest whole number
colourref=round(datatable3);
%GOOD TO HERE!!
%BUT WE SHOULD RESIZE OR THERE IS GOING TO BE CHAAAAOOOOSSS!!!
clear i
clear I
clear J
clear n
for i=1:iFile;
n=sprintf('%05d',i);
I=imread(horzcat('bimage',n,'.jpg'));
J=imresize(I,[40 40]);
imwrite(J,horzcat('cimage',n,'.jpg'))
end
%% NOW WE NEED TO LOOK UP THE AVERAGE RGB CODE FOR A SMALL (4x4?) REGION OF THE MAIN IMAGE
mainimage=imread('mainimage.jpg');
mainimager=mainimage(:,:,1);
mainimageg=mainimage(:,:,2);
mainimageb=mainimage(:,:,3);
[mainh, mainw]=size(mainimage(:,:,1));
pixnumber=mainw*mainh;
boxdim=10;
boxheight=boxdim;
boxwidth=boxdim;
boxnumber=pixnumber/(boxheight*boxwidth);
%change that number to use larger or smaller boxes
for k=1:mainh/boxwidth;
for j=1:mainw/boxwidth;
meanr(k,j)=mean(mean(mainimage(((boxdim*k)-3):(boxdim*k),((boxdim*j)-3):(boxdim*j),1)));
meang(k,j)=mean(mean(mainimage(((boxdim*k)-3):(boxdim*k),((boxdim*j)-3):(boxdim*j),2)));
meanb(k,j)=mean(mean(mainimage(((boxdim*k)-3):(boxdim*k),((boxdim*j)-3):(boxdim*j),3)));
end
end
meanr=round(meanr);
meang=round(meang);
meanb=round(meanb);
%Then replace it with the closest matching image from the database
for l=1:mainh/boxheight;
%l to 750 if using 4px squares
for m=1:mainw/boxwidth;
%m to 1000 for the same
[idy idx]=min((abs(meanr(l,m)-colourref(:,1))+(abs(meanr(l,m)-colourref(:,2))+(abs(meanr(l,m)-colourref(:,3))))));
replacements(l,m)=idx;
end
end
montageheight=l;
montagewidth=m;
for o=1:mainh/boxheight;
for p=1:mainw/boxwidth;
replacer(o,p)={horzcat('cimage',sprintf('%05d',replacements(o,p)),'.jpg')};
end
end
mainmontage=montage(replacer, 'Size', [montageheight montagewidth]);
imwrite(mainmontage,'mainmontage.jpg');
3 Commenti
Praveen Iyyappan Valsala
il 8 Nov 2019
Your description and the code doesn't seem to match. How big is your mainimage and cimages? (10*750) X (10*1000) X 3 and 480X480X3 respectively?. If yes, then you are hardware limted because you are trying to create an image of resolution (750*400 X 1000*400 X3 color channels)
Try to create a monatge of first 100 images.
mainmontage=montage(replacer{1:10,1:10},'Size', [10 10]);
imshow(mainmontage)
Nevertheless, Your mean table calulation and mean calculation doesn't look right.
datatable=zeros(iFile,2); % your initialization
...
datatable(2,i)=gmeanval;
datatable(3,i)=bmeanval; % Indexing is wrong and didn't you get an idexing error?
%% should be
datatable=zeros(iFile,4); % your initialization
...
datatable(i,2)=gmeanval;
datatable(i,3)=bmeanval;
datatable(i,4)=i; %datatable3 is not required
Indexing in your mean calculation is messed up. use matlab routine whenever possible
meanr=blockproc(mainimage(:,:,1),[boxwidth boxheight],@(block) mean(block.data(:)));
If my guess is right, the person's face you are trying to create with monatge will be happy!;).
Good Luck
Stuart Walker
il 8 Nov 2019
Praveen Iyyappan Valsala
il 8 Nov 2019
There is small issue with my suggestion ..use ( instead {. Try
mainmontage=montage(replacer(1:10,1:10),'Size', [10 10]);
Also, montage function doesn't accept the 2D cell array of filenames. if that is really the case, try
replacer2=replacer(1:10,1:10);
mainmontage=montage(replacer2(:),'Size', [10 10]);
you initialized the vraiable datatable=zeros(iFile,2); and then you are accessing the vraible at datatable(2,i). If say i > 2, you should get index exceed error. if you didn't get any error. you are good to go.
Risposta accettata
Più risposte (1)
Stuart Walker
il 8 Nov 2019
0 voti
Categorie
Scopri di più su Matrix Indexing in Centro assistenza e File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!
