0001 function hIm = imdisp(I, varargin)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070 [map layout gap indices lims] = parse_inputs(varargin);
0071
0072 if nargin == 0 || (iscell(I) && isempty(I))
0073
0074 I = get_im_names;
0075 if isempty(I)
0076
0077 if nargout > 0
0078 hIm = [];
0079 end
0080 return
0081 end
0082 end
0083
0084
0085 if ischar(I)
0086 [x y c] = size(I);
0087 if (x > 1 && y > 1) || c > 1
0088 I = num2cell(I, 2);
0089 else
0090 I = {I(:)'};
0091 end
0092 end
0093
0094
0095 if isnumeric(I) || islogical(I)
0096 [y x c n] = size(I);
0097 if isempty(lims)
0098 lims = min_max(I);
0099 elseif isequal(0, lims)
0100 lims = default_limits(I);
0101 elseif c == 3
0102
0103 if ~isfloat(I)
0104 I = single(I);
0105 end
0106 I = min(max((I - lims(1)) ./ (lims(2) - lims(1)), 0), 1);
0107 end
0108 if isfloat(I) && c == 3 && n > 1
0109 I = uint8(I * 256 - 0.5);
0110 lims = round(lims * 256 - 0.5);
0111 end
0112 elseif iscell(I)
0113 n = numel(I);
0114 A = I{1};
0115 if ischar(A)
0116
0117 if n == 1
0118 I = imread_rgb_multi(A);
0119 if iscell(I)
0120 n = numel(I);
0121 A = I{1};
0122 [y x c] = size(A);
0123 else
0124 [y x c n] = size(I);
0125 A = I;
0126 end
0127 else
0128 A = imread_rgb(A);
0129 I{1} = A;
0130 [y x c] = size(A);
0131 end
0132 else
0133 [y x c] = size(A);
0134 end
0135
0136 if isempty(lims) || isequal(0, lims)
0137 lims = default_limits(A);
0138 end
0139 else
0140 error('I not of recognized type.');
0141 end
0142
0143
0144 if ~isequal(indices, -1)
0145 if iscell(I)
0146 I = I(indices);
0147 n = numel(I);
0148 else
0149 I = I(:,:,:,indices);
0150 n = size(I, 4);
0151 end
0152 end
0153
0154
0155 hFig = get(0, 'CurrentFigure');
0156 if isempty(hFig)
0157
0158 hFig = figure;
0159 elseif n > 1
0160
0161 hFig = clf(hFig, 'reset');
0162 end
0163
0164
0165 set(hFig, 'Colormap', map);
0166
0167
0168 if n == 0
0169 hIm = display_image([], gca, [0 1]);
0170
0171 if nargout == 0
0172 clear hIm
0173 end
0174 return
0175 elseif n == 1
0176
0177
0178 hAx = gca;
0179 if iscell(I)
0180 I = I{1};
0181 end
0182 hIm = display_image(I, hAx, lims);
0183
0184 if nargout == 0
0185 clear hIm
0186 end
0187
0188
0189 if numel(findobj(get(hFig, 'Children'), 'Type', 'axes')) > 1
0190 return
0191 end
0192
0193 axesPos = get(hAx, 'Position');
0194 newAxesPos = [gap(1) gap(end) 1-2*gap(1) 1-2*gap(end)];
0195 if isequal(axesPos, get(hFig, 'DefaultAxesPosition'))
0196
0197
0198 set(hAx, 'Units', 'normalized', 'Position', newAxesPos);
0199 axesPos = newAxesPos;
0200 end
0201 if ~isequal(axesPos, newAxesPos)
0202
0203 return
0204 end
0205 layout = [1 1];
0206 else
0207
0208
0209 layout = choose_layout(n, y, x, layout);
0210
0211
0212 num = prod(layout);
0213 state.num = num * ceil(n / num);
0214 hIm = zeros(layout);
0215 hAx = zeros(layout);
0216
0217
0218 index = mod(0:num-1, state.num) + 1;
0219 hw = 1 ./ layout;
0220 gap = gap ./ layout;
0221 dims = hw - 2 * gap;
0222 dims = dims([2 1]);
0223 for a = 1:layout(1)
0224 for b = 1:layout(2)
0225 c = index(b + (layout(1) - a) * layout(2));
0226 if c > n
0227 A = [];
0228 elseif iscell(I)
0229 A = I{c};
0230 if ischar(A)
0231 A = imread_rgb(A);
0232 I{c} = A;
0233 end
0234 else
0235 A = I(:,:,:,c);
0236 end
0237 hAx(a,b) = axes('Position', [(b-1)*hw(2)+gap(2) (a-1)*hw(1)+gap(1) dims], 'Units', 'normalized');
0238 hIm(a,b) = display_image(A, hAx(a,b), lims);
0239 end
0240 end
0241
0242
0243 if n > num
0244
0245 state.hIm = hIm;
0246 state.hAx = hAx;
0247 state.index = 1;
0248 state.layout = layout;
0249 state.n = n;
0250 state.I = I;
0251
0252 set(hFig, 'KeyPressFcn', @keypress_callback, 'Interruptible', 'off', 'BusyAction', 'cancel', 'UserData', state);
0253 end
0254
0255
0256 hIm = hIm(end:-1:1,:);
0257
0258 if nargout == 0
0259 clear hIm
0260 end
0261 end
0262
0263 if strcmp(get(hFig, 'WindowStyle'), 'docked')
0264
0265 return
0266 end
0267
0268
0269
0270 ImSz = layout([2 1]) .* [x y] ./ (1 - 2 * gap([end 1]));
0271
0272
0273 figPosCur = get(hFig, 'Position');
0274
0275 MonSz = get(0, 'MonitorPositions');
0276 MonOn = size(MonSz, 1);
0277 if MonOn > 1
0278
0279 correction = 0;
0280 if ispc
0281 for a = 1:MonOn
0282 if isequal(MonSz(a,1:2), [1 1])
0283 correction = MonSz(a,4);
0284 break
0285 end
0286 end
0287 end
0288
0289 figCenter = figPosCur(1:2) + figPosCur(3:4) / 2;
0290 figCenter = MonSz - repmat(figCenter, [MonOn 2]);
0291 MonOn = all(sign(figCenter) == repmat([-1 -1 1 1], [MonOn 1]), 2);
0292 MonOn(1) = MonOn(1) | ~any(MonOn);
0293 MonSz = MonSz(MonOn,:);
0294
0295 MonSz(3:4) = MonSz(3:4) - MonSz(1:2) + 1;
0296
0297 if correction
0298 MonSz(2) = correction - MonSz(4) - MonSz(2) + 2;
0299 end
0300 end
0301
0302
0303
0304 if isequal(MonSz([1 3]), figPosCur([1 3]))
0305
0306 return
0307 end
0308
0309
0310 MaxSz = MonSz(3:4) - [20 120];
0311 RescaleFactor = min(MaxSz ./ ImSz);
0312 if RescaleFactor > 1
0313
0314 MaxSz = min(MaxSz, [1200 800]);
0315 RescaleFactor = max(floor(min(MaxSz ./ ImSz)), 1);
0316 end
0317 figPosNew = ceil(ImSz * RescaleFactor);
0318
0319
0320 if isequal(figPosCur(3:4), figPosNew)
0321 return
0322 end
0323
0324
0325 figPosNew = [floor(figPosCur(1:2)+(figPosCur(3:4)-figPosNew)/2) figPosNew];
0326
0327
0328 figPosNew(1:2) = min(max(figPosNew(1:2), MonSz(1:2)+6), MonSz(1:2)+MonSz(3:4)-[6 101]-figPosNew(3:4));
0329
0330
0331 set(hFig, 'Position', figPosNew);
0332 return
0333
0334
0335
0336 function keypress_callback(fig, event_data)
0337
0338 switch event_data.Character
0339 case 28
0340 up = -1;
0341 case 29
0342 up = 1;
0343 case 30
0344 up = -0.1;
0345 case 31
0346 up = 0.1;
0347 otherwise
0348
0349 return
0350 end
0351
0352 if ~isempty(event_data.Modifier)
0353 up = up * (2 ^ (strcmpi(event_data.Modifier, {'shift', 'control'}) * [1; 2]));
0354 end
0355
0356 state = get(fig, 'UserData');
0357
0358 index = state.index;
0359
0360 n = prod(state.layout);
0361
0362 if abs(up) < 1
0363
0364 index = index + state.layout(2) * (up * 10) - 1;
0365 else
0366 if state.layout(1) == 1
0367
0368 index = index + up - 1;
0369 else
0370
0371 index = index + n * up - 1;
0372 end
0373 end
0374 index = mod(index:index+n, state.num) + 1;
0375
0376 figure(fig);
0377 for a = 1:state.layout(1)
0378 for b = 1:state.layout(2)
0379
0380 c = index(b + (state.layout(1) - a) * state.layout(2));
0381 if c > state.n
0382
0383 set(state.hIm(a,b), 'CData', []);
0384 elseif iscell(state.I)
0385 A = state.I{c};
0386 if ischar(A)
0387
0388 A = imread_rgb(A);
0389 state.I{c} = A;
0390 end
0391
0392 set(state.hIm(a,b), 'CData', A);
0393
0394 if ~isempty(A)
0395 set(state.hAx(a,b), 'XLim', [0.5 size(A, 2)+0.5], 'YLim', [0.5 size(A, 1)+0.5]);
0396 end
0397 else
0398
0399 set(state.hIm(a,b), 'CData', state.I(:,:,:,c));
0400 end
0401 end
0402 end
0403 drawnow;
0404
0405 state.index = index(1);
0406 set(fig, 'UserData', state);
0407 return
0408
0409
0410 function hIm = display_image(A, hAx, lims)
0411 if isempty(A)
0412 hIm = image(zeros(1, 1, 3));
0413 set(hIm, 'CData', []);
0414 else
0415 hIm = image(A);
0416 end
0417 set(hAx, 'Visible', 'off', 'DataAspectRatio', [1 1 1], 'DrawMode', 'fast', 'CLim', lims);
0418 set(get(hAx, 'XLabel'), 'Visible', 'on');
0419 set(get(hAx, 'YLabel'), 'Visible', 'on');
0420 set(get(hAx, 'Title'), 'Visible', 'on');
0421 set(hIm, 'CDataMapping', 'scaled');
0422 return
0423
0424
0425 function layout = choose_layout(n, y, x, layout)
0426 v = numel(layout);
0427 N = isnan(layout);
0428 if v == 0 || all(N)
0429
0430 sz = get(0, 'ScreenSize');
0431 sz = sz(3:4) ./ [x y];
0432 layout = ceil(sz([2 1]) ./ sqrt(prod(sz) / n));
0433
0434 while 1
0435 switch ([prod(layout - [1 0]) prod(layout - [0 1])] >= n) * [2; 1]
0436 case 0
0437 break;
0438 case 1
0439 layout = layout - [0 1];
0440 case 2
0441 layout = layout - [1 0];
0442 case 3
0443 if min(sz .* (layout - [0 1])) > min(sz .* (layout - [1 0]))
0444 layout = layout - [0 1];
0445 else
0446 layout = layout - [1 0];
0447 end
0448 end
0449 end
0450 elseif v == 1
0451 layout = layout([1 1]);
0452 elseif any(N)
0453 layout(N) = ceil(n / layout(~N));
0454 end
0455 layout = reshape(layout, 1, 2);
0456 return
0457
0458
0459 function A = imread_rgb(name)
0460 try
0461 [A map alpha] = imread(name);
0462 catch
0463
0464 A = eye(101) | diag(ones(100, 1), 1) | diag(ones(100, 1), -1);
0465 A = (uint8(1) - uint8(A | flipud(A))) * uint8(255);
0466 A = cat(3, zeros(size(A), 'uint8')+uint8(255), A, A);
0467 return
0468 end
0469 A = A(:,:,:,1);
0470 if ~isempty(map)
0471 map = uint8(map * 256 - 0.5);
0472 A = reshape(map(uint32(A)+1,:), [size(A) size(map, 2)]);
0473 elseif size(A, 3) == 4
0474 if lower(name(end)) == 'f'
0475
0476 if isfloat(A)
0477 A = A * 255;
0478 else
0479 A = single(A);
0480 end
0481 A = 255 - A;
0482 A(:,:,4) = A(:,:,4) / 255;
0483 A = uint8(A(:,:,1:3) .* A(:,:,[4 4 4]));
0484 else
0485
0486 alpha = A(:,:,4);
0487 A = A(:,:,1:3);
0488 end
0489 end
0490 if ~isempty(alpha)
0491
0492 if isa(alpha, 'uint8')
0493 alpha = double(alpha) / 255;
0494 end
0495 A = double(A) .* alpha(:,:,ones(1, size(A, 3)));
0496 sqSz = max(size(alpha));
0497 sqSz = floor(max(log(sqSz / 100), 0) * 10 + 1 + min(sqSz, 100) / 20);
0498 grid = repmat(85, ceil(size(alpha) / sqSz));
0499 grid(2:2:end,1:2:end) = 171;
0500 grid(1:2:end,2:2:end) = 171;
0501 grid = kron(grid, ones(sqSz));
0502 alpha = grid(1:size(A, 1),1:size(A, 2)) .* (1 - alpha);
0503 A = uint8(A + alpha(:,:,ones(1, size(A, 3))));
0504 end
0505 return
0506
0507
0508 function A = imread_rgb_multi(name)
0509 try
0510
0511 info = imfinfo(name);
0512 catch
0513
0514 A = imread_rgb(name);
0515 return
0516 end
0517 if numel(info) < 2
0518
0519 A = imread_rgb(name);
0520 return
0521 else
0522
0523 switch lower(info(1).Format)
0524 case 'gif'
0525 [A map] = imread(name, 'frames', 'all');
0526 if ~isempty(map)
0527 map = uint8(map * 256 - 0.5);
0528 A = reshape(map(uint32(A)+1,:), [size(A) size(map, 2)]);
0529 A = permute(A, [1 2 5 4 3]);
0530 end
0531 case {'tif', 'tiff'}
0532 A = cell(numel(info), 1);
0533 for a = 1:numel(A)
0534 [A{a} map] = imread(name, 'Index', a, 'Info', info);
0535 if ~isempty(map)
0536 map = uint8(map * 256 - 0.5);
0537 A{a} = reshape(map(uint32(A{a})+1,:), [size(A) size(map, 2)]);
0538 end
0539 if size(A{a}, 3) == 4
0540
0541 if isfloat(A{a})
0542 A{a} = A{a} * 255;
0543 else
0544 A{a} = single(A{a});
0545 end
0546 A{a} = 255 - A{a};
0547 A{a}(:,:,4) = A{a}(:,:,4) / 255;
0548 A{a} = uint8(A(:,:,1:3) .* A{a}(:,:,[4 4 4]));
0549 end
0550 end
0551 otherwise
0552
0553 A = imread_rgb(name);
0554 return
0555 end
0556 end
0557 return
0558
0559
0560 function L = get_im_names
0561 D = dir;
0562 n = 0;
0563 L = cell(size(D));
0564
0565 for a = 1:numel(D)
0566
0567 if numel(D(a).name) > 4 && ~D(a).isdir && (any(strcmpi(D(a).name(end-3:end), {'.png', '.tif', '.jpg', '.bmp', '.ppm', '.pgm', '.pbm', '.gif', '.ras'})) || any(strcmpi(D(a).name(end-4:end), {'.tiff', '.jpeg'})))
0568 n = n + 1;
0569 L{n} = D(a).name;
0570 end
0571 end
0572 L = L(1:n);
0573 return
0574
0575
0576 function [map layout gap indices lims] = parse_inputs(inputs)
0577
0578
0579 map = [];
0580 layout = [];
0581 gap = 0;
0582 indices = -1;
0583 lims = 0;
0584
0585
0586 for b = 1:numel(inputs)
0587 if ~isnumeric(inputs{b})
0588 b = b - 1;
0589 break;
0590 end
0591 if size(inputs{b}, 2) == 3
0592 map = inputs{b};
0593 elseif numel(inputs{b}) < 3
0594 lims = inputs{b};
0595 end
0596 end
0597
0598
0599 for a = b+1:2:numel(inputs)
0600 switch lower(inputs{a})
0601 case 'map'
0602 map = inputs{a+1};
0603 if ischar(map)
0604 map = feval(map, 256);
0605 end
0606 case {'size', 'grid'}
0607 layout = inputs{a+1};
0608 case {'gap', 'border'}
0609 gap = inputs{a+1};
0610 case 'indices'
0611 indices = inputs{a+1};
0612 case {'lims', 'displayrange'}
0613 lims = inputs{a+1};
0614 otherwise
0615 error('Input option %s not recognized', inputs{a});
0616 end
0617 end
0618
0619 if isempty(map)
0620 map = gray(256);
0621 end
0622 return
0623
0624
0625 function lims = default_limits(A)
0626 if size(A, 3) == 1
0627 lims = min_max(A);
0628 else
0629 lims = [0 1];
0630 if ~isfloat(A)
0631 lims = lims * double(intmax(class(A)));
0632 end
0633 end
0634 return
0635
0636
0637 function lims = min_max(A)
0638 M = isfinite(A);
0639 lims = double([min(A(M)) max(A(M))]);
0640 if isempty(lims)
0641 lims = [0 1];
0642 elseif lims(1) == lims(2)
0643 lims(2) = lims(1) + 1;
0644 end
0645 return