How to output the Cascading image

4 visualizzazioni (ultimi 30 giorni)
xiaoying wu
xiaoying wu il 23 Dic 2018
Modificato: DGM il 4 Giu 2022
If there are 24 pictures, how to use MATLAB to achieve this output effect
function h = op(file_path, pad,m,n)
img_path_list = dir(strcat(file_path,'*.jpg'));
num = length(img_path_list);%
% [m,n]=size(image);
fw=n+(num-1)*pad;
fh=m+(num-1)*pad;
%
h=figure('position',[0,0,fw+pad,fh+pad]);
for j = 1:num %
image_name = img_path_list(j).name;%
image = imread(strcat(file_path,image_name));%
hold on
pd=(j-1)*pad;
rpl=fw-n-pd;
rpb=fh-m-pd;
%%How to specify the location of the output on the image canvas
%%
% set('Position',[rpl rpb n m]);
% axes('position',[rpl rpb n m]);
imshow (image);
%
end
% h=gcf;
end

Risposte (1)

DGM
DGM il 4 Giu 2022
Modificato: DGM il 4 Giu 2022
Depends what you want to do with it. With a function name like op(), it's impossible to tell.
If your goal is to just visualize some images, fine. If your goal is to actually produce and save the result, then don't treat the figure as an image compositor. It's limited, cumbersome, and getting quality output without altering the component images is problematic. Taking a screenshot shouldn't be a part of an image manipulation workflow. Compose the image from its parts and then save the result.
Let's say we have the following images:
Starting simple, the image cascade can be constructed using basic direct indexing in a loop. This requires no special tools, and there's room to do the same from different approaches. The images don't have to be read all at once. Their size can be fetched using imfinfo() and then the files could be read one-by-one in the main loop. If there are a lot of images, or if the images are large, that might be preferable to conserve memory. See the last demo for an example of prefetching size info prior to reading. In this example, the background is a light gray simply so that it doesn't disappear into the awful white background of the webpage.
%% direct indexing
offset = [40 40]; % offset per frame ([y x] px)
padw = [20 70]; % border padding width ([y x] px)
% read a set of images into a cell array
% this loop could be more generalized and robust/safe
% but that's beside the point
inpict = cell(4,1);
for k = 1:4
inpict{k} = imread(sprintf('cman_%02d.png',k));
end
% calculate the required offsets and the padded image geometry
fsize0 = cell2mat(cellfun(@imsize,inpict,'uniform',false));
os = (offset.*(0:numel(inpict)-1).') + padw;
fsize = fsize0(:,1:2) + os;
% assumes all images are RGB
% and that output class should be forced uint8
% background matting is simply white(ish)
outpict = 200*ones([(max(fsize,[],1) + padw) 3],'uint8');
% insert each image into the base image by direct indexing
% this accomodates no alpha content or scalar opacity adjustment
for f = 1:numel(inpict)
yidx = os(f,1)+1:fsize(f,1);
xidx = os(f,2)+1:fsize(f,2);
% cast/scale to output class in case original class varies
outpict(yidx,xidx,:) = im2uint8(inpict{f});
end
The same could be done using multiplicative composition in the offset rectangular regions instead of doing simple indexing. That would be one way to implement partial layer transparency if desired, but there are easier ways.
Although it's not really meant for doing this sort of thing, MIMT imstacker() can be used to handle the preparation of a 4D image stack. At that point, one could do everything in RGBA. This also allows simple extra functionality like adjustable layer opacity without any extra complexity. Again, backgrounds don't have to be white.
%% imstacker with some flex
offset = [40 40]; % offset per frame ([y x] px)
padw = [20 70]; % border padding width ([y x] px)
layeropacity = 0.8; % layers can be semitransparent
% read a set of images into a cell array
inpict = mimread('cman_*.png');
% calculate the required offsets and the padded image geometry
fsize0 = cell2mat(cellfun(@imsize,inpict,'uniform',false));
os = (offset.*(0:numel(inpict)-1).') + padw;
fsize = fsize0(:,1:2) + os;
outsize = max(fsize,[],1) + padw;
% pad and stack the images into a 4D array
% this is indifferent to potential differences in color depth or image class
inpict = imstacker(inpict,'padding',[0 0],'offset',os,'size',outsize,'gravity','nw');
inpict = im2uint8(inpict);
% compose them in reverse stack order
% make sure "bottom" layer has correct output alpha
inpict(:,:,end,1) = inpict(:,:,end,1)*layeropacity;
outpict = mergedown(flip(inpict,4),layeropacity,'normal'); % any opacity
% create base matting and compose
matting = colorpict(imsize(outpict,2),[70 64 85],'uint8'); % any matting color/image
outpict = imblend(outpict,matting,1,'normal');
The given example includes a drop shadow effect. Stepping away from imstacker() for a minute, this can again be done by basic composition in a loop. In this example, before each image is incorporated into the current composition, a blurred rectangular patch is blended with the underlying content. In this way, the drop shadow from any one of the four frames is actually cast on the purple matting, but also on the underlying frames. The disadvantage is that the shadows stack when they overlap, which isn't physically correct. The drop shadow effect also conflicts with the illusion of height difference between the underlying frames, since it is offset on the matting by the same amount as it's offset on the underlying frames. The end result is that while this effect is flexible and can cast shadows on the underlying images, it won't really make sense unless the shadow offsets are in the same direction as the frame offsets.
%% adding a drop shadow using simple stacking in a loop
% this could be adapted to use incremental file reads
offset = [40 40]; % offset per frame ([y x] px)
padw = [20 70]; % border padding width ([y x] px)
dsos = [12 7]; % drop shadow offset ([y x] px)
dsdensity = 0.5; % density of drop shadow
layeropacity = 0.8; % layers can be semitransparent
% read a set of images into a cell array
inpict = mimread('cman_*.png');
% calculate the required offsets and the padded image geometry
fsize0 = cell2mat(cellfun(@imsize,inpict,'uniform',false));
os = (offset.*(0:numel(inpict)-1).') + padw;
fsize = fsize0(:,1:2) + os;
outsize = max(fsize,[],1) + padw;
% create base matting
gradct = [127 116 155; 12 11 15];
outpict = radgrad([outsize 3],[0.25 0.25],0.75,gradct,'cosine');
% insert each frame into the base image by compositing
for f = 1:numel(inpict)
yidx = os(f,1)+1:fsize(f,1);
xidx = os(f,2)+1:fsize(f,2);
% add drop shadow
% the way this stacks isn't technically correct
% but this is just a cheap effect, not a lighting simulation
yidxds = imclamp(yidx+dsos(1),[1 outsize(1)]);
xidxds = imclamp(xidx+dsos(2),[1 outsize(2)]);
thisds = ones(outsize);
thisds(yidxds,xidxds) = 0;
thisds = imgaussfilt(thisds,5);
outpict = imblend(thisds,outpict,dsdensity,'multiply');
% add image frame
thisroi = outpict(yidx,xidx,:);
outpict(yidx,xidx,:) = imblend(inpict{f},thisroi,layeropacity,'normal','linear');
end
Again, similar can be done with imstacker(). If we don't care about being able to cast shadows on underlying frames, then the shadow itself reduces to a single image that can be blended with the matting alone. Since the shadow blends only with one layer, you can do things like apply a displacement map to match the matting texture.
%% imstacker, but with drop shadow
offset = [40 40]; % offset per frame ([y x] px)
padw = [20 70]; % border padding width ([y x] px)
dsos = [12 7]; % drop shadow offset ([y x] px)
shadowambience = 0.5; % how much does ambient light dilute the drop shadow?
layeropacity = 0.8; % layers can be semitransparent
% read a set of images into a cell array
inpict = mimread('cman_*.png');
% calculate the required offsets and the padded image geometry
fsize0 = cell2mat(cellfun(@imsize,inpict,'uniform',false));
os = (offset.*(0:numel(inpict)-1).') + padw;
fsize = fsize0(:,1:2) + os;
outsize = max(fsize,[],1) + padw;
% create base matting
noisepict = imread('crumpledpaper.jpg');
noisepict = imresize(mono(noisepict,'y'),outsize);
gradct = [127 116 155; 12 11 15];
gradpict = radgrad([outsize 3],[0.25 0.25],0.75,gradct,'cosine');
outpict = imblend(noisepict,gradpict,1,'scaleadd',0.07);
% pad and stack the images into a 4D array
% this is indifferent to potential differences in color depth or image class
inpict = imstacker(inpict,'padding',[0 0],'offset',os,'size',outsize,'gravity','nw');
inpict = im2uint8(inpict);
% compose them in reverse stack order
% make sure "bottom" layer has correct output alpha
inpict(:,:,end,1) = inpict(:,:,end,1)*layeropacity;
allframes = mergedown(flip(inpict,4),layeropacity,'normal');
% create composite drop shadow from alpha channel of allframes
% this isn't technically correct, since shadows aren't cast on FG layers
% but this is just a cheap effect, not a lighting simulation
[~,shadowpict] = splitalpha(allframes);
shadowpict = imtranslate(iminv(shadowpict),fliplr(dsos),'fillvalues',255);
shadowpict = imgaussfilt(shadowpict,3);
% displace drop shadow to mimic matting texture
shadowpict = displace(shadowpict,[3 3],'xmap',noisepict,'ymap',noisepict);
% compose shadow with base matting
outpict = imblend(shadowpict,outpict,1-shadowambience,'multiply');
% compose frames with base matting
outpict = imblend(allframes,outpict,1,'normal','linear');
Finally, if you wanted to actually fix the original code and do this in a figure, you can. I'm going to strip some stuff out here, since intent is unknown. You'll have to adapt this to whatever your needs are.
% m,n were never used in the original function call
% and it wouldn't generally make sense to presume that all images
% have some specific size without actually checking or enforcing it
offset = [40 40]; % offset per frame ([y x] px)
padw = [20 70]; % border padding width ([y x] px)
img_path_list = dir('cman_*.png');
nframes = length(img_path_list);
% calculate the required offsets and the padded image geometry
% this can be done as each image is loaded,
% but it's just easier to have all the size info up front
fsize0 = zeros(nframes,2);
for k = 1:nframes
image_name = img_path_list(k).name;
S = imfinfo(image_name);
fsize0(k,:) = [S.Height S.Width];
end
os = (offset.*(0:nframes-1).') + padw;
fsize = fsize0(:,1:2) + os;
outsize = max(fsize,[],1) + padw;
% draw the images
for k = 1:nframes
image_name = img_path_list(k).name;
thisimage = imread(image_name);
xr = [os(k,2) fsize(k,2)];
yr = [os(k,1) fsize(k,1)];
imshow(thisimage,'xdata',xr,'ydata',yr);
hold on
end
% enforce axes extents
xlim([0.5 outsize(2)+0.5])
ylim([0.5 outsize(1)+0.5])
While the first and last example do not use MIMT tools, the others do. MIMT is a convenience for doing image composition, and can always be done with basic MATLAB tools if you're willing to implement the things that the MIMT tools do.

Community Treasure Hunt

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

Start Hunting!

Translated by