function slide=ipss003
%IPSS003 Correction of nonuniform illumination.
%
%   This slideshow demonstrates a method for correcting nonuniform
%   illumination in an image of rice grains.  The background
%   brightness function is estimated by taking the minimum
%   of each 32-by-32 block and then resizing the result to be the  
%   same size as the image.  The background illumination is then 
%   subtracted from the original image and intensity adjustment 
%   is applied to the result.
%
%   See also BLKPROC, IMADJUST, IMRESIZE.

%   Chris Griffin, Feb. 1997
%   $Revision: 1.7 $  $Date: 1998/02/19 16:29:36 $ 
%   Copyright 1993-1998 The MathWorks, Inc.  All Rights Reserved.

if nargout<1,
   playshow ipss003
else
   %========== Slide 1 ==========
   
   slide(1).code={
      'FigHandle = gcf;',
      'if ~isfield(slideData, ''Initialized'')',
      '   slideData.Initialized = 1;',
      '   set(FigHandle, ''DoubleBuffer'', ''on'');', 
      '   set(FigHandle, ''Colormap'', gray(128));',
      '   set(FigHandle, ''Name'', ''Correction of Nonuniform Illumination'');',
      '   pos = get(FigHandle, ''Position'');',
      '   ',
      '   % Adjust the size of the figure window',
      '   pos(3:4) = [560 420];',
      '   horizDecorations = 10;  % resize controls, etc. ',
      '   vertDecorations = 45;   % title bar, etc.',
      '   screenSize = get(0,''ScreenSize'');',
      '   if (screenSize(3) <= 1)',
      '      screenSize(3:4) = [100000 100000];',
      '   end',
      '   if (((pos(3) + horizDecorations) > screenSize(3)) | ((pos(4) + vertDecorations) > screenSize(4)))',
      '      delete(fig);',
      '      error([''Screen resolution is too low (or text fonts are too big) to run this demo'']);',
      '   end',
      '   dx = screenSize(3) - pos(1) - pos(3) - horizDecorations;',
      '   dy = screenSize(4) - pos(2) - pos(4) - vertDecorations;',
      '   if (dx < 0)',
      '       pos(1) = max(5,pos(1) + dx);',
      '   end',
      '   if (dy < 0)',
      '       pos(2) = max(5,pos(2) + dy);',
      '   end',
      '   set(FigHandle, ''Position'', pos)',
      '   set(FigHandle, ''Resize'', ''off'');',
      '   if ~isfield(slideData, ''Images''),',
      '      slideData.Images = [];',
      '   end',
      '   if isempty(slideData.Images) | ~isfield(slideData.Images,''rice''),',
      '      rice3 = [];',
      '      load imdemos rice3',
      '      slideData.Images.rice = double(rice3)/255;',
      '   end',
      '   rotate3d off',
      '   ',
      '   %%% Resize the frame and text field for 256 square image',
      '   frames = findobj(FigHandle, ''style'', ''frame'');',
      '   for i=1:length(frames)',
      '      frmPos = get(frames(i), ''position'');',
      '      if frmPos(1) < .1, txtFrame = frames(i); break; end',
      '   end',
      '   texts = findobj(FigHandle, ''style'', ''text'');'
      '   for i=1:length(texts)',
      '      txtPos = get(texts(i), ''position'');',
      '      if txtPos(1) < .1, txtField = texts(i); break; end',
      '   end',
      '   txtPos(4) = txtPos(4) - .05;',
      '   frmPos(4) = frmPos(4) - .05;',
      '   set(txtField, ''Position'', txtPos)',
      '   set(txtFrame, ''Position'', frmPos)',
      '   drawnow',
      '   ',
      '   %%% Create the axes and image',
      '   ax = findobj(FigHandle, ''type'', ''axes'');', 
      '   slideData.meshAx = ax(1);',
      '   set(slideData.meshAx, ''Visible'', ''off'')',
      '   axChildren = get(slideData.meshAx, ''Children'');',
      '   delete(axChildren)',
      '   ax1left = (pos(3)*.78)/2-128;',
      '   frmTop = pos(4)*(frmPos(2)+frmPos(4));',
      '   ax1bot = frmTop+(pos(4)-frmTop)/2-128;',
      '   wid = 256; ht = 256;',
      '   frameLeft = .78;',
      '   slideData.axes1 = axes( ''Units'', ''Pixels''',
      '     ''Parent'', FigHandle',
      '     ''ydir'', ''reverse''',
      '     ''XLim'', [.5 256.5]',
      '     ''YLim'', [.5 256.5]',
      '     ''CLim'', [0 1]',
      '     ''Position'',[ax1left ax1bot wid ht]',
      '     ''Tag'', ''axis1''',
      '     ''XTick'',[],''YTick'',[]);',
      '   slideData.image1 = image(''CData'', slideData.Images.rice',
      '     ''CDataMapping'', ''scaled''',
      '     ''Parent'',slideData.axes1',
      '     ''Xdata'', [1 256]',
      '     ''Ydata'', [1 256]',
      '     ''Tag'', ''image1''',
      '     ''EraseMode'', ''none'');',
      'else',  
      '   set(FigHandle, ''Colormap'', gray(128));',
      '   set(slideData.meshAx, ''Visible'', ''off'')',
      '   axChildren = get(slideData.meshAx, ''Children'');',
      '   delete(axChildren)',
      '   rotate3d off',
      '   set(slideData.image1, ''CData'', slideData.Images.rice)',
      '   set([slideData.axes1 slideData.image1], ''visible'', ''on''), drawnow',
      'end',
      ''  };

   slide(1).text={
      'This slideshow demonstrates correction of nonuniform ',
      'illumination in an image of rice grains.   Notice that ',
      'the background of the image is much brighter in the ',
      'top-central part of the image than in the bottom part.',
      '',
      '» rice = imread(''rice.tif'');',
      '» rice = im2double(rice);  % Convert to double precision',
      '» imshow(rice)',
      ''};
   
   %========== Slide 2 ==========
   
   slide(2).code={
      'set([slideData.axes1 slideData.image1 slideData.meshAx], ''visible'', ''off''), drawnow',
      'if ~isfield(slideData.Images,''min''),',
      '   slideData.Images.min = blkproc(slideData.Images.rice,[32 32],''min(x(:))'');',
      'end',
      'axes(slideData.meshAx)',
      'surf(slideData.Images.min)',
      'colormap(jet)',
      'rotate3d ON',
      'shading faceted',
      'set(slideData.meshAx, ''Visible'', ''on'')',
      ''};
   slide(2).text={
      'The BLKPROC command is used to find a coarse estimate of the',
      'background illumination, by determining the minimum of each',
      '32-by-32 block in the image.  A surface plot of the coarse',
      'estimate is shown above.  Drag the plot to rotate the view.'
      '',
      '» bg32 = blkproc(rice,[32 32],''min(x(:))'');',
      '» surf(bg32), rotate3d on',
      ''};
   
   %========== Slide 3 ==========
   
   slide(3).code={
      'set([slideData.axes1 slideData.image1 slideData.meshAx], ''visible'', ''off'')',
      'rotate3d off',
      'axChildren = get(slideData.meshAx, ''Children'');',
      'delete(axChildren), drawnow',
      'set(FigHandle, ''Colormap'', gray(128));',
      'if ~isfield(slideData.Images,''J''),',
      '   slideData.Images.J = imresize(slideData.Images.min,[256 256], ''bicubic'');',
      'end',
      'set(slideData.image1, ''CData'', slideData.Images.J)',
      'set([slideData.axes1 slideData.image1], ''visible'', ''on'')',
      '' };
   slide(3).text={
      'The coarse estimate is then expanded in size using the function',
      'IMRESIZE so that it is the same size as the original image.',
      'Bicubic interpolation is used to ensure that the data is smooth.',
      '',
      '» bg256 = imresize(bg32 ,[256 256], ''bicubic'');',
      '» imshow(bg256)',
      ''};
   

   %========== Slide 4 ==========
   
   slide(4).code={
      'set([slideData.axes1 slideData.image1 slideData.meshAx], ''visible'', ''off''), drawnow',
      'if ~isfield(slideData.Images,''rice_diff''),',
      '   slideData.Images.rice_diff = slideData.Images.rice - slideData.Images.J;',
      'end',
      'set(slideData.image1, ''CData'', slideData.Images.rice_diff)',
      'set([slideData.axes1 slideData.image1], ''visible'', ''on'')',
      '' };
   slide(4).text={
      'The computed illumination is subtracted from the original image',
      'to correct for the nonuniformity.  Unfortunately, this operation',
      'also darkens the rice grains.',
      '',
      '» d = rice - bg256;',
      '» imshow(d)',
      ''};
   
   %========== Slide 5 ==========
   
   slide(5).code={
      'set([slideData.axes1 slideData.image1 slideData.meshAx], ''visible'', ''off''), drawnow',
      'if ~isfield(slideData.Images,''adjusted''),',
      '   slideData.Images.adjusted = imadjust(slideData.Images.rice_diff, [0 max(slideData.Images.rice_diff(:))],[]);',
      'end',     
      'set(slideData.image1, ''CData'', slideData.Images.adjusted)',
      'set([slideData.axes1 slideData.image1], ''visible'', ''on'')',
      '' };
   slide(5).text={
      'The IMADJUST command is used to rescale the pixel ',
      'intensities to fill the entire intensity range.  This makes the ',
      'rice grains brighter, with more visible details.'
      '',
      '» adjusted = imadjust(d, [0 max(d(:))], [0 1], 1);',
      '» imshow(adjusted)',
      ''};
   
end