function filtdemo(action,varargin) %FILTDEMO - shows the effects of 2d filter spatial coefficients on % its frequency response. % % Author: J. Yang, 5/99 % Copyright: Professor Jan. Allebach. % Revision: 1.02 %--------- << Sub function lists: >> --------- % 1. init ; % 2. ImageSet ; % 3. FilterType ; % 4. Close ; % 5. CV_edit, (cancel) ; % 6. CV_apply ; % 7. Spatial_mask -- not implemented ; % 8. CV_field ; %--------------------------------------------- % dispatch appropriate actions %{ if nargin < 1 action='init' ; end ; feval(action,varargin{:}) ; return ; %} %---------------- Screen layout ------------------------- % % % | | 3x3 | % | f[m,n] | h[k,l] | g[m,n] % | | mask | % | +---------- | % +---------- +---------+ +--------- % (5,317) | 9 edit | % color bar | boxes | color bar % | +-+ | =can=app| +-+| % | | | +---------+ | || G(u,v) % | log|F(u,v)| | | | |H(u,v)| | || % | | | | mesh plot | || % +---------- +-+ +---------- +-++--------- (780,) % (5,33) (266,)+10 (296,) (375,) (380) % +---------------------------------------------------+ % | buttons | % +---------------------------------------------------+ %------------------( 800 -20) x (600 -30 ) --------------- function init() %{ h = findobj(allchild(0), 'tag', 'Spatial Filter Demo'); if ~isempty(h) figure(h) return end global GParm ; %------------------------------------------ % Set up for screen frame and attributes % FIGURE GParm.figure = figure('Color',[0.7 0.7 0.7], ... 'MenuBar','none', ... 'Colormap',gray(256), ... 'Name','Spatial Filtering Demo', ... 'Visible','on', 'Resize','off', ... % initially not drawn 'NumberTitle','off', ... 'Units','pixels', ... 'Position',[5 5 790 595], ... 'Pointer','watch', ... 'Tag','Spatial Filter Demo'); % 'ShareColor','off', ... % 'RendererMode','manual','Renderer','painters', ... %----------------- % button layout % BUTTON posbox = [5 1 786 30] ; h = uicontrol('Style','frame', ... 'Parent',GParm.figure, ... 'Background',[.45 .45 .45], ... 'Units','pixels', ... 'Position',posbox) ; %% Image list button labelpos = [12 9 55 16] ; h = uicontrol('Parent',GParm.figure, ... 'Style','text', 'Units','pixel', ... 'position',labelpos, ... 'String','Image', ... 'Horiz','left') ; % 'Verti','center', ... posbox = [67 7 100 20] ; GParm.imglist = uicontrol( ... 'Parent',GParm.figure, ... 'Style','popupmenu', ... 'Units','pixel', ... 'BusyAction','queue','Interruptible','off', ... 'Position',posbox, ... 'value',1, ... 'String','Racing|Checker|Grid|Rectangle|Circle|Cross' , ... 'Callback','filtdemo(''ImageSet'');' ... ) ; %% Filter type list button labelpos = [312 9 55 16] ; h = uicontrol('Parent',GParm.figure, ... 'Style','text', 'Units','pixel', ... 'position',labelpos, ... 'String','Filter :', ... 'Horiz','left') ; posbox = [367 7 100 20] ; GParm.typelist = uicontrol( ... 'Parent',GParm.figure, ... 'Style','popupmenu', ... 'Units','pixel', ... 'BusyAction','queue','Interruptible','off', ... 'Position',posbox, ... 'String','LPF|HPF|EDGE|Edit', ... 'value',1 , ... % means pressed or released 'Callback','filtdemo(''FilterType'');'... ) ; %% Close button posbox = [647 7 100 20] ; GParm.close = uicontrol( ... 'Parent',GParm.figure, ... 'Style','Pushbutton', ... 'BusyAction','queue','Interruptible','off', ... 'Units','pixel', ... 'String','Close', ... 'Position',posbox, ... 'Callback','filtdemo(''Close'');' ... ) ; %------------------------- % axes, image, surface % AXES % --- left axes and images --- xdim = 256 ; ydim = 256; xs = 5 ; ys = 317 ; yb = 33 ; GParm.fmnAxe = axes( ... 'Parent',GParm.figure, ... 'Units','pixels', ... 'BusyAction','Queue','Interruptible','off',... 'ydir', 'reverse', ... 'Layer', 'top', ... 'Nextplot','add', ... 'Drawmode','fast', ... 'XLim', [-1 xdim+2], ... 'YLim', [-1 ydim+2],... 'CLim', [0 1], ... 'Position',[xs ys xdim ydim], ... 'Box','on', ... 'XTick',[],'YTick',[], ... 'Tag','f[m,n]' ... ) ; GParm.fmnimg = image( ... % sampling grid interactive 'Parent',GParm.fmnAxe, ... 'Visible', 'on', ... 'CData', [], ... 'BusyAction','Queue','Interruptible','off',... 'CDataMapping', 'direct', ... 'XData', [1:xdim],... 'YData', [1:ydim],... 'EraseMode', 'normal' ... ); title('Original image : f[m,n]') ; % --- left bottom and DFT plot --- GParm.logFuvAxe = axes( ... 'Parent',GParm.figure, ... 'Units','pixels', ... 'BusyAction','Queue','Interruptible','off',... 'ydir', 'reverse', ... 'XLim', [-1 xdim+2], ... 'YLim', [-1 ydim+2],... 'CLim', [0 1], ... 'Position',[xs yb xdim ydim], ... 'Drawmode','fast', ... 'Box','on', ... 'Layer','top', ... % show grid line above image 'XGrid','on','YGrid','on', ... 'XTick',[129],'YTick',[129], ... 'Tag','Log|F(u,v)|' ... ); GParm.Fuvdft = image(... 'Parent',GParm.logFuvAxe, ... 'Visible', 'on', ... 'CData', [], ... 'BusyAction','Queue','Interruptible','off',... 'CDataMapping', 'scaled', ... 'XData', [1:xdim],... 'YData', [1:ydim],... 'EraseMode', 'normal' ... ) ; title('DFT of original image : Log|F[u,v]|') ; % -- color bar axes needed ---- GParm.colorAxe1 = axes( ... 'Parent',GParm.figure, ... 'Units','pixels', ... 'BusyAction','Queue','Interruptible','off',... 'XLim', [-1 16], ... 'YLim', [-1 ydim+2],... 'CLim', [0 1], ... 'Position',[xs+xdim+2 yb 15 ydim], ... 'YaxisLocation','right', ... 'Drawmode','fast', ... 'xtick',[],'ytick',[], ... 'Box','on' ... ); cd = jet(256) ; GParm.cd = cd ; cd1 = repmat(cd(:,1),1,15) ; cd2 = repmat(cd(:,2),1,15) ; cd3 = repmat(cd(:,3),1,15) ; GParm.colorbarimg = image( ... 'Parent',GParm.colorAxe1, ... 'visible','on', ... 'CData',cat(3,cd1,cd2,cd3) , ... 'CDatamapping','direct', ... 'XData',[1:15], 'YData',[1:ydim], ... 'Erasemode','normal' ... ) ; %-- -- -- -- -- -- -- -- -- -- -- -- -- % --- middle axes and Filter coeffs --- xs = 296 ; ym = ys - 80 ; posbox = [ xs-3 ys-3 246 ydim+6] ; %h = uicontrol('Style','frame','Parent',GParm.figure, ... % 'Units','pixels','Position',posbox) ; GParm.hklAxe = axes(... 'Parent',GParm.figure, ... 'Units','pixels', ... 'BusyAction','Queue','Interruptible','off',... 'Xlim', [.9 3.1], ... 'YLim', [.9 3.1], ... 'Zlim', [-1.2 1.2], ... 'CLim', [0 1], ... 'Position',[xs+10 ym+135 180 180], ... 'Nextplot','add', ... 'Visible','on', ... 'view',[-37.5, 30], ... 'Box','off', ... 'Xgrid','on','Ygrid','on','Zgrid','on', ... 'XTick',[1 2 3],'YTick',[1 2 3], ... 'Tag','h[k,l]' ... ); title('Spatial Filter Coefficient h(m,n)') ; GParm.zerolevel = patch(... 'Parent',GParm.hklAxe, ... 'Xdata',[1 1 3 3], ... 'Ydata',[1 3 3 1], ... 'Zdata',[0 0 0 0], ... 'FaceColor',[.8 .1 .1], ... 'FaceLighting','flat', ... 'Erasemode','xor' ... ); cmd1 = 'set(gcf,''WindowButtonMotionFcn'',''filtdemo(''''Spatial_mask'''',0)'');' ; cmd2 = 'set(gcf,''WindowButtonUpFcn'',''filtdemo(''''Spatial_mask'''',1)'');' ; GParm.LPF_coeff = [ 1/16 1/8 1/16 ; 1/8 1/4 1/8; 1/16 1/8 1/16] ; GParm.HPF_coeff = [ -1 -1 -1;-1 17 -1; -1 -1 -1]/9 ; GParm.EDGE_coeff = [-10 -10 -10;-10 80 -10; -10 -10 -10]/9 ; GParm.filt = GParm.LPF_coeff ; GParm.savefilt = []; GParm.editAxe = axes( ... 'Parent',GParm.figure, ... 'Units','pixels', ... 'layer','top', ... 'box','on', 'Gridlinestyle','-', ... 'Position',[xs-6 ym+50 72*3 20*3], ... 'Xlim', [1 216],'Ylim',[1 60], ... 'XTick',[72 144],'YTick',[20 40], ... 'Xgrid','on','Ygrid','on','Tickdir','in', ... 'XTickLabel',{' ',' '},'YTickLabel',{' ',' '}, ... % don't draw the tick labels 'Tag','edittableaxes' ... ); GParm.editbox = uicontrol(... 'Parent',GParm.figure, ... 'style','edit', ... 'callback','filtdemo(''CV_edit'',1'');', ... 'visible','off' ... ) ; for i=1:3 ; for j=1:3 ; GParm.hklline(i,j) = line(... 'Parent',GParm.hklAxe,'Visible','on','Color','blue','Linestyle', '-', ... 'XData',[i i],'YData',[j j],'ZData',[0 GParm.filt(i,j)], ... 'Erasemode','xor' ... ) ; GParm.hklmark(i,j) = line(... 'Parent',GParm.hklAxe,'Visible','on','Color','blue','Linestyle', '-', ... 'Marker','o','MarkerFacecolor','b', ... 'XData',[i], 'YData',[j], 'Zdata',[GParm.filt(i,j)], ... 'ButtonDownFcn',strcat(cmd1,cmd2), ... 'Erasemode','xor' ... ) ; posbox = [ 72*i-35, 20*j - 10] ; %% cmd = sprintf('%s,%d,%d%s','filtdemo(''CV_edit''',i,j,');' ) ; GParm.edittext(i,j) = text(... 'Parent',GParm.editAxe, ... 'HorizontalAlign','center', ... % 'VerticalAlign',middle is default 'Clipping','on','visible','on', ... 'units','pixels', 'Position',posbox, ... 'Erasemode','xor', ... 'String',num2str(GParm.filt(i,j),'%0.4g'), ... 'ButtondownFcn','filtdemo(''CV_edit'',0'');'... ) ; end ; end ; posbox=[xs+20 ym+20 70 25] ; GParm.cancelpush = uicontrol(... % shared with cancel, displayed on top of coeff axe 'Parent',GParm.figure, ... 'Style','Pushbutton', ... 'BusyAction','queue','Interruptible','off', ... 'Units','pixel', ... 'Enable','off', ... 'String','Cancel', ... 'Position',posbox, ... 'value',0 , ... % pressed or released -> cancel or edit toggle 'Callback','filtdemo(''CV_cancel'');' ... ) ; posbox=[xs+120 ym+20 70 25] ; GParm.applypush = uicontrol(... 'Parent',GParm.figure, ... 'Style','Pushbutton', ... 'BusyAction','queue','Interruptible','off', ... 'Units','pixel', 'Enable','off', ... 'String','Apply', ... 'Position',posbox, ... 'value',0, ... % pressed or released 'Callback','filtdemo(''CV_apply'');' ... ); %-- -- -- -- -- -- -- -- -- -- GParm.HuvAxe = axes(... 'Parent',GParm.figure, ... 'Units','pixels', ... 'View', [-37.5 30], ... 'Position',[xs+15 yb+15 180 180], ... 'XTick',[-1 0 1],'YTick',[-1 0 1], ... 'Zgrid','on','Xgrid','on','Ygrid','on', ... 'Tag','filtdftaxes' ... ); title('Frequency Response H(u,v)') ; %-- -- -- -- -- -- -- -- % --- right axes and images --- xs = xs + xdim - 20 ; GParm.gmnAxe = axes(... 'Parent',GParm.figure, ... 'Units','pixels', ... 'XLim', [-1 xdim+2], ... 'YLim', [-1 ydim+2],... 'CLim', [0 1], ... 'Position',[xs ys xdim+1 ydim+1], ... 'ydir','reverse', ... 'layer','top', ... 'Box','on', ... 'Drawmode','fast', ... 'XTick',[],'YTick',[], ... 'Tag','outimgaxes' ... ); GParm.gmnimg = image(... 'Parent',GParm.gmnAxe, ... 'Visible', 'on', ... 'CData', [], ... 'CDataMapping', 'direct', ... 'XData', [1:xdim],... 'YData', [1:ydim],... 'EraseMode', 'normal' ... ) ; title('f[m,n] ** h[m,n] result image') ; GParm.GuvAxe = axes(... 'Parent',GParm.figure, ... 'Units','pixels', ... 'BusyAction','Queue','Interruptible','off',... 'ydir', 'reverse', ... 'XLim', [-1 xdim+2], ... 'YLim', [-1 ydim+2],... 'CLim', [0 1], ... 'Position',[xs yb xdim+1 ydim+1], ... 'Drawmode','fast', ... 'Box','on', ... 'Layer','top', ... % show grid line above image 'XGrid','on','YGrid','on', ... 'XTick',[129],'YTick',[129], ... 'XTicklabel','','YTicklabel','',... 'Tag','recodftaxes' ... ); GParm.Guvdft = image(... 'Parent',GParm.GuvAxe, ... 'Visible', 'on', ... 'CData', [], ... 'BusyAction','Queue','Interruptible','off',... 'CDataMapping', 'direct', ... 'XData', [1:xdim],... 'YData', [1:ydim],... 'EraseMode', 'normal' ... ) ; title('DFT of result image: Log|G[u,v]|') ; GParm.colorAxe = axes( ... 'Parent',GParm.figure, ... 'Units','pixels', ... 'BusyAction','Queue','Interruptible','off',... 'XLim', [-1 32], ... 'YLim', [-1 ydim+2],... 'CLim', [0 1], ... 'Position',[xs-17 yb 15 ydim], ... 'Drawmode','fast', ... 'xtick',[],'ytick',[], ... 'Box','on' ... ); cd = GParm.cd ; cd1 = repmat(cd(:,1),1,15) ; cd2 = repmat(cd(:,2),1,15) ; cd3 = repmat(cd(:,3),1,15) ; GParm.colorbarimg = image( ... 'Parent',GParm.colorAxe, ... 'visible','on', ... 'CData',cat(3,cd1,cd2,cd3) , ... 'CDatamapping','direct', ... 'XData',[1:30], 'YData',[1:ydim], ... 'Erasemode','normal' ... ) ; t = gray(256) ; GParm.graymap = t(:,1) ; %-- -- -- -- -- -- -- -- GParm.fmndata = [] ; % origin gray img data %-- -- -- GParm.Huvdata = [] ; %-- -- -- GParm.gmndata = [] ; %-- -- -- ImageSet ; % to draw initial orig image disp_hkl_Huv ; set(GParm.figure,'Pointer','arrow') ; drawnow return ; %} function disp_fmn_Fuv() %{ global GParm ; f = GParm.fmndata ; F = fftshift(fft2(f)) ; G = log(abs(F) + 1) ; uf = GParm.graymap(floor(f + 1.5)) ; set(GParm.fmnimg,'CData',cat(3,uf,uf,uf),'visible','on','CDatamapping','direct') ; set(GParm.Fuvdft,'CData',map_color(G),'visible','on','CDatamapping','direct') ; return ; %} function disp_hkl_Huv() %{ global GParm ; h = GParm.filt ; [r,f1,f2] = freqz2(h,16,16) ; r = real(r) ; rmin = min(r(:)) ; rmax = max(r(:)) ; delete( findobj(get(GParm.HuvAxe,'children'),'type','surface') ); GParm.Huvdft = surface(f1,f2,r,'Parent',GParm.HuvAxe, ... 'edgecolor','b','CData',r,'edgelighting','flat','facelighting','gouraud') ; % set(GParm.HuvAxe,'zlim',[rmin-(.05*abs(rmin)) rmax*1.05]) ; return; %} function disp_gmn_Guv() %{ global GParm ; g = filter2(GParm.filt,GParm.fmndata,'same') ; % sample domain convolution gg = floor( min(255,max(g(1:256,1:256),0) ) + 1.5 ) ; ug = GParm.graymap( gg ) ; G = fftshift(fft2(g)) ; H = log(abs(G) + 1) ; set(GParm.gmnimg,'CData',cat(3,ug,ug,ug),'visible','on','CDatamapping','direct') ; set(GParm.Guvdft,'CData',map_color(H),'visible','on','CDatamapping','direct') ; return ; %} function znorm = map_color(x) %{{{ global GParm ; % need to unify max and min value through all dft's to yield same color range cmap = jet(256);%bone %jet(256) ; zmax = max(max(x)) ; alpha = 255/zmax ; zidx = floor( x * alpha + 1.5) ; for i=1:256,; znorm(i,:,:) = cmap(zidx(i,:),:) ; end ; return ; %}}} %----------------- % Menu control %----------------- function ImageSet() %%{ global GParm ; h = GParm.imglist ; % handle for image list button v = get(h,{'value','String'}) ; name = deblank(v{2}(v{1},:)) ; set(GParm.figure,'pointer','watch') ; switch name case 'Racing' load demo1 Racing ; GParm.fmndata = double(Racing) ; Racing = [] ; case 'Checker' load demo1 Checker ; GParm.fmndata = double(Checker) ; Checker = [] ; case 'Grid' load demo1 Grid ; GParm.fmndata = double(Grid) ; Grid = [] ; case 'Rectangle' load demo1 Rectangle ; GParm.fmndata = double(Rectangle) ; Rectangle = [] ; case 'Circle' load demo1 Circle ; GParm.fmndata = double(Circle ); Circle = [] ; case 'Cross' load demo1 Cross ; GParm.fmndata = double(Cross) ; Cross = [] ; end ; disp_fmn_Fuv ; disp_gmn_Guv ; set(GParm.figure,'pointer','arrow') ; return ; %%} function FilterType() %%{ global GParm ; h = GParm.typelist ; % handle for filter type list v = get(h,'value') ; set(GParm.figure,'pointer','watch') ; switch v case 1 %'LPF' GParm.filt = GParm.LPF_coeff ; case 2 %'HPF' GParm.filt = GParm.HPF_coeff ; case 3 %'EDGE' GParm.filt = GParm.EDGE_coeff ; case 4 %'Edit' -- This uses input dialog for bulk coeff input prompt = 'Enter 9 values (comma delimted):' ; title = '3x3 Filter coefficient input' ; ans = inputdlg(prompt,title,1) ; if( ~isempty(ans) ) r = ans{1} ; delim = ' \t\n,;:"' ; i = 1 ; j = 1 ; while ( size(r,2) ~= 0 ) [t,r] = strtok(r,delim) ; if( i < 4 ), GParm.filt(j,i) = str2num(t) ; end ; % bypass more than 9 input j = j+1 ; if( j > 3 ), j = 1 ; i = i + 1 ; end ; end ; end ; end ; disp_mask ; draw_mask ; disp_hkl_Huv ; disp_gmn_Guv ; set(GParm.figure,'pointer','arrow') ; return ; %%} function Close() %%{ global GParm ; %% close(gcf) ; close(GParm.figure) ; clear global GParm ; return ; %%} %-------------------- User interaction Call backs -------------- function disp_mask() %{{ global GParm ; %%norm = sum(sum(GParm.filt)) ; %%GParm.filt = GParm.filt/norm ; for i = 1:3 ; for j = 1:3 ; set(GParm.edittext(i,j),'String',num2str(GParm.filt(i,j),'%.3f') ) ; end ; end ; return ; %}} function draw_mask() %{{ global GParm ; zmax = max(GParm.filt(:)) ; set(GParm.hklAxe,'zlim',[-1.05*abs(zmax) 1.05*abs(zmax)]) ; for i = 1:3 ; for j= 1:3 ; hl = GParm.hklline(i,j) ; set(hl,'XData',[i i],'YData',[j j],'ZData',[0 GParm.filt(i,j)]); hm = GParm.hklmark(i,j); set(hm,'XData',[i], 'YData',[j], 'Zdata',[GParm.filt(i,j)]); end ; end ; return ; %}} function Spatial_mask(mode) %{{ return ; %}} function CV_cancel() %{{ global GParm ; set(GParm.figure,'pointer','watch') ; GParm.filt = GParm.savefilt ; set([GParm.cancelpush GParm.applypush],'enable','off') ; disp_mask ; set(GParm.figure,'pointer','arrow') ; drawnow ; return ; %}} function CV_apply() %{{ global GParm ; set(GParm.figure,'pointer','watch') ; set([GParm.applypush GParm.cancelpush],'enable','off') ; get_maskvalue ; draw_mask ; disp_hkl_Huv ; disp_gmn_Guv ; set(GParm.figure,'pointer','arrow') ; drawnow ; return ; %}} function CV_edit(mode) %{{ global GParm ; % mouse initiated field move --> just show editbox if ( ~mode ) h = get(GParm.figure,'currentobj') ; [r,c] = find(GParm.edittext==h) ; str = get(h,'string') ; pos = get(GParm.editAxe,'position') ; x = pos(1); y = pos(2) ; pos = get(h,'position') ; x = x+pos(1)-36; y = y+pos(2)-10 ; set(GParm.editbox,'position',[x y 70 20],'visible','on','string',str, ... 'userdata',[r,c]) ; drawnow ; return ; % editbox is activated by mouse hit else set(GParm.editbox,'visible','off') ; str = get(GParm.editbox,'string') ; s = str2num(str) ; id = get(GParm.editbox,'userdata') ; r = id(1); c = id(2) ; % check number string if( isempty(s) ) msgbox('Non-number entries ignored!') ; return ; end ; % check precision bound ( -x.xxxx 4 digit below fraction point ) s = round(s*10000) / 10000 ; if( length(str)>8 | abs(s)>9999 ), msgbox('Too many digits -> rounded') ; end ; s = max(-9999, min(s, 9999) ) ; GParm.filt(r,c) = s ; set(GParm.edittext(r,c),'string',num2str(s,'%0.4g') ) ; end ; % first time before apply if strcmp(get(GParm.applypush,'enable'),'off' ), GParm.savefilt = GParm.filt ; end ; set([GParm.applypush GParm.cancelpush], 'enable', 'on') ; return ; %}} function get_maskvalue() %{{ global GParm ; s = GParm.edittext ; v = GParm.filt ; for i=1:3 ; for j=1:3 ; v(i,j) = str2num(get(s(i,j),'String')) ; end; end ; disp_mask ; return ; %}}