Hi-Resolution Image Navigation
Sample shows how to implement a simple hi-resolution image navigation. Similar to imtool.
Use the mouse to move the preview window, and the scroll wheel to change the preview size.
Sources:
function varargout = hi_res_browse_demo(im) % load hi-res image if nargin < 1 if true img = generateImageWalk2D(2048); elseif true img = generateImageMandelbrot(2048); elseif ~mexopencv.isOctave() && mexopencv.require('images') img = imread(which('concordaerial.png')); end cv.imwrite(fullfile(tempdir(),'gen.png'), img); elseif ischar(im) img = imread(im); else img = im; end % create the UI h = buildGUI(img); if nargout > 0, varargout{1} = h; end end function img = generateImageWalk2D(sz, nwalks) %GENERATEIMAGEWALK2D Generate a big image of 2D random walks if nargin < 2, nwalks = 6; end if nargin < 3, niter = 1e5; end DO_STEPS = false; if DO_STEPS % list of possible directions to take at each step [X,Y] = meshgrid(linspace(-1,1,15), linspace(-1,1,15)); dirs = [X(:) Y(:)] * 0.18; dirs(ismember(dirs, [0 0], 'rows'),:) = []; % remove zero move end % create black canvas img = zeros(sz,sz,3,'uint8'); % random walks of different colors clr = uint8(255 * hsv(nwalks)); fprintf('Generating random walks'); for i=1:nwalks fprintf('.'); % generate a random 2D walk if DO_STEPS p = randi(size(dirs,1), niter, 1); p = cumsum(dirs(p,:)); else p = cumsum(rand(niter,2) - 0.5); end % scaled and shifted to start from center of image p = bsxfun(@plus, p*25, [sz sz]/2); % draw walk on image img = cv.polylines(img, int32(p), ... 'Color',clr(i,:), 'Closed',false, 'LineType','AA'); end fprintf('\n'); end function img = generateImageMandelbrot(sz, niter) %GENERATEIMAGEMANDELBROT The Mandelbrot Set if nargin < 2, niter = 500; end xlims = [-0.748766713922161, -0.748766707771757]; % [-2, 1] ylims = [ 0.123640844894862, 0.123640851045266]; % [-1.5, 1.5] x = linspace(xlims(1), xlims(2), sz); y = linspace(ylims(1), ylims(2), sz); [x,y] = meshgrid(x,y); z0 = complex(x,y); z = z0; count = ones(size(z0)); fprintf('Generating Mandelbrot set'); for n=0:niter if rem(n,50) == 0, fprintf('.'); end z = z.*z + z0; count = count + (abs(z) <= 2); end count = log(count); fprintf('\n'); cmap = [jet(128); flipud(jet(127)); 0 0 0]; img = (count - min(count(:))) / (max(count(:)) - min(count(:))); img = ind2rgb(uint8(255*img), cmap); img = uint8(255*img); end function small = createThumbnail(img) %CREATETHUMBNAIL Downsample image a few times to create a thumbnail image small = img; [h,w,~] = size(small); while max(h,w) > 512 small = cv.pyrDown(small); [h,w,~] = size(small); end end function onMouseMove(~,~,h) %ONMOUSEMOVE Mouse motion callback function % make sure cropped figure is still open if ~ishghandle(h.fig(2)) set(h.fig(1), 'Pointer','arrow', ... 'WindowButtonMotionFcn', '', 'WindowScrollWheelFcn',''); delete(h.rect); return; end % get current point location [x,y] xy = get(h.ax(1), 'CurrentPoint'); xy = xy(1,1:2); if false % convert axes coordinates to image pixel coordinates xy(1) = axes2pix(h.szThumb(2), [1 h.szThumb(2)], xy(1)); xy(2) = axes2pix(h.szThumb(1), [1 h.szThumb(1)], xy(2)); end % get current crop size szCrop = get(h.rect, 'UserData'); % update rectangle position sz = szCrop .* (h.szThumb ./ h.szImg); set(h.rect, 'Position',[xy - sz/2, sz]); % extract subimage from original image center = xy .* (h.szImg ./ h.szThumb); cropped = cv.getRectSubPix(h.src, szCrop, center); % show the cropped image set(h.img(2), 'CData',cropped); drawnow; end function onMouseScroll(~,e,h) %ONMOUSESCROLL Mouse scroll callback function % make sure cropped figure is still open if ~ishghandle(h.fig(2)) set(h.fig(1), 'Pointer','arrow', ... 'WindowButtonMotionFcn', '', 'WindowScrollWheelFcn',''); delete(h.rect); return; end % increase/decrease crop size (not too small, not too big) szCrop = get(h.rect, 'UserData'); szCrop = round(szCrop * (1.1)^(e.VerticalScrollCount)); szCrop = min(max(szCrop, floor(h.szImg/32)), floor(h.szImg/2)); set(h.rect, 'UserData',szCrop); % update title, and ajust axis limits so that new image fills it set(h.fig(2), 'Name',sprintf('Sub Image (%dx%d)',szCrop)); set(h.ax(2), 'XLim',[1 szCrop(1)]-0.5, 'YLim',[1 szCrop(2)]-0.5); % invalidate plot onMouseMove([], [], h); end function h = buildGUI(img) %BUILDGUI Creates the UI % source image h = struct(); h.src = img; [h.szImg(2), h.szImg(1), ~] = size(img); % create image thumbnail thumb = createThumbnail(img); [h.szThumb(2), h.szThumb(1), ~] = size(thumb); % create cropped image cropped = cv.Rect.crop(img, [0 0 min([512 512], h.szImg)]); [szCrop(2), szCrop(1), ~] = size(cropped); % thumnail figure h.fig(1) = figure('Name',sprintf('Image (%dx%d)',h.szImg), ... 'NumberTitle','off', 'Menubar','none', ... 'Position',[100 200 h.szThumb]); h.ax(1) = axes('Parent',h.fig(1), 'Units','normalized', 'Position',[0 0 1 1]); if ~mexopencv.isOctave() h.img(1) = imshow(thumb, 'Parent',h.ax(1)); else %HACK: https://savannah.gnu.org/bugs/index.php?45473 axes(h.ax(1)); h.img(1) = imshow(thumb); end h.rect = rectangle('Position',[1 1 1 1], ... 'EdgeColor','g', 'LineWidth',2, 'Parent',h.ax(1)); % cropped figure h.fig(2) = figure('Name',sprintf('Sub Image (%dx%d)',szCrop), ... 'NumberTitle','off', 'Menubar','none', ... 'Position',[200+h.szThumb(1) 200 szCrop]); h.ax(2) = axes('Parent',h.fig(2), 'Units','normalized', 'Position',[0 0 1 1]); if ~mexopencv.isOctave() h.img(2) = imshow(cropped, 'Parent',h.ax(2)); else %HACK: https://savannah.gnu.org/bugs/index.php?45473 axes(h.ax(2)); h.img(2) = imshow(cropped); end % store crop size in UI component UserData set(h.rect, 'UserData',szCrop); % hook event handlers, and trigger default start set(h.fig(1), 'WindowButtonMotionFcn',{@onMouseMove,h}, ... 'WindowScrollWheelFcn',{@onMouseScroll,h}, ... 'Pointer','fleur', 'Interruptible','off', 'BusyAction','cancel'); onMouseMove([], [], h); end
Generating random walks......