changeset 858:af3c7946534b

Follow coding guidelines and fix tests. * imgradient.m, imgradientxy.m: turn the %! comments into test blocks, style changes to follow coding guidelines (more whitespace, use of double quotes, error messages, leave a single sentence at start of help text), set default method in function prototype, replace windows CRLF with Unix LF. * imgradient.m: compute second output argument if (nargout > 1) instead of (nargout == 2), simplify the two possible usage to reduce code,
author Carnë Draug <carandraug@octave.org>
date Sun, 05 Jan 2014 08:27:27 +0000
parents 75d6748324de
children 9e4ecfd52273
files inst/imgradient.m inst/imgradientxy.m
diffstat 2 files changed, 225 insertions(+), 234 deletions(-) [+]
line wrap: on
line diff
--- a/inst/imgradient.m
+++ b/inst/imgradient.m
@@ -1,115 +1,92 @@
-## Copyright (C) 2013 Brandon Miles  <brandon.miles7 at gmail.com>
-## 
-## This program is free software; you can redistribute it and/or modify it
-## under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 3 of the License, or
-## (at your option) any later version.
-## 
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-## 
-## You should have received a copy of the GNU General Public License
-## along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-## -*- texinfo -*- 
-## @deftypefn {Function File} {[@var{gradMag}, @var{gradDir}] =} imgradient (@var{image}, @var{method})
-## @deftypefn {Function File} {[@var{gradMag}, @var{gradDir}] =} imgradient (@var{gx}, @var{gy})
-## Compute the gradient magnitude and direction in degrees for an image.  These are computed from the 
-## x and y gradients using imgradientxy.  The first input @var{image} is a gray
-## scale image to compute the edges on.  The second input @var{method} controls the method used to calculate 
-## the gradients. Alternatively the first input @var{gx} can be the x gradient and the second input @var{gy} can be the y gradient.
-## The first output @var{gradMag} returns the magnitude of the gradient.  The second output
-## @var{gradDir} returns the direction in degrees.  
-##
-## The @var{method} input argument can be any of the following strings (the default
-## value is "Sobel")
-##
-## @table @asis
-## @item "Sobel"
-## Calculates the gradient in @var{image} using the Sobel approximation to the
-## derivatives.
-##
-## @item "Prewitt"
-## Calculates the gradient in @var{image} using the Prewitt approximation to the
-## derivatives. This method works just like "Sobel" except a different approximation of
-## the gradient is used.
-##
-## @item "Central Difference"
-## Calculates the gradient in @var{image} using the central difference approximation to the
-## derivatives: (x(i-1) - x(i+1))/2.
-##
-## @item "Intermediate Difference"
-## Calculates the gradient in @var{image} using the intermediate difference approximation to
-## the derivatives: x(i) - x(i+1).
-##
-## @end table
-##
-## @seealso{edge, gradientxy}
-## @end deftypefn
-
-function [gradMag, gradDir] = imgradient (var1, var2)
-
-  ## Get the image
-  if (nargin == 0)
-    error("imgradient: not enough input arguments");
-  endif
-  if ( ndims(var1) > 2 )
-    error("imgradient: first input must be a gray-scale image");
-  endif
-
-  ## Get the method
-  if (nargin == 1)
-    method = "Sobel";
-    image = var1;
-    [gradX, gradY] = imgradientxy(image, method);
-  endif
-  
-  ## determine whether the two inputs are the same size
-  if(nargin == 2)
-    ## test for var2 as a string
-    if( ischar(var2))
-      image  = var1;
-      method = var2;
-      [gradX, gradY] = imgradientxy(image, method);
-      
-    ## use gx, gy instead
-    else
-      if( size(var2) !=  size(var1))
-        error("imgradient: expected inputs gx, gy to be the same size")
-      endif
-      gradX = var1;
-      gradY = var2;
-    endif
-  endif
-  
-  gradMag = sqrt(gradX.^2 + gradY.^2);
-  
-  ## use atan2(-gy,gx)*pi/180 
-  ## see:  http://stackoverflow.com/questions/18549015/why-imgradient-invert-vertical-when-computing-the-angle
-  if (nargout == 2)
-    gradDir = atan2d(-gradY,gradX);
-  end
-  
-endfunction
-
-%% run tests
-%!A = [0 1 0; 1 1 1; 0 1 0]; 
-%![gMag,gDir] = imgradient(A);
-%!assert(gMag,[sqrt(18),4,sqrt(18); 4 0 4; sqrt(18),4,sqrt(18)]);
-%!assert(gDir,[-45 -90 -135; -0 -0 -180; 45 90 135]);
-%%
-%% Test combinations
-%![gxSobel, gySobel] = imgradientxy(A);
-%![gxSobel2, gySobel2] = imgradientxy(A,'Sobel');
-%![gxPrewitt,gyPrewitt] = imgradientxy(A,'Prewitt');
-%![gxCd,gyCd] = imgradientxy(A,'CentralDifference');
-%![gxId,gyId] = imgradientxy(A,'IntermediateDifference');
-%%
-%!assert(imgradient(A),imgradient(gxSobel,gySobel));
-%!assert(imgradient(A,'Sobel'),imgradient(gxSobel2,gySobel2));
-%!assert(imgradient(A,'Prewitt'),imgradient(gxPrewitt,gyPrewitt));
-%!assert(imgradient(A,'CentralDifference'),imgradient(gxCd,gyCd));
-%!assert(imgradient(A,'IntermediateDifference'),imgradient(gxId,gyId));
-    
\ No newline at end of file
+## Copyright (C) 2013 Brandon Miles <brandon.miles7@gmail.com>
+##
+## This program is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*- 
+## @deftypefn  {Function File} {[@var{gradMag}, @var{gradDir}] =} imgradient (@var{img})
+## @deftypefn  {Function File} {[@var{gradMag}, @var{gradDir}] =} imgradient (@var{img}, @var{method})
+## @deftypefnx {Function File} {[@var{gradMag}, @var{gradDir}] =} imgradient (@var{gx}, @var{gy})
+## Compute the gradient magnitude and direction in degrees for an image.
+##
+## These are computed from the @var{gx} and @var{xy} gradients using
+## @code{imgradientxy}.  The first input @var{img} is a gray scale image to
+## compute the edges on.  The second input @var{method} controls the method
+## used to calculate the gradients.  Alternatively the first input @var{gx}
+## can be the x gradient and the second input @var{gy} can be the y gradient.
+##
+## The first output @var{gradMag} returns the magnitude of the gradient.
+## The second output @var{gradDir} returns the direction in degrees.
+##
+## The @var{method} input argument must be a string specifying one of the
+## methods supported by @code{imgradientxy}.
+##
+## @seealso{edge, imgradientxy}
+## @end deftypefn
+
+function [gradMag, gradDir] = imgradient (img, method = "sobel")
+
+  if (nargin < 1 || nargin > 2)
+    print_usage ();
+  elseif (ndims (img) != 2)
+    error("imgradient: IMG must be a 2 dimensional matrix");
+  endif
+
+  if (ischar (method))
+    [gradX, gradY] = imgradientxy (img, method);
+  else
+    ## we already got gX and gY, just confirm it's good data
+    if (! size_equal (img, method))
+      error("imgradient: GX and GY must be of equal size")
+    endif
+    gradX = img;
+    gradY = method;
+  endif
+
+  gradMag = sqrt (gradX.^2 + gradY.^2);
+
+  if (nargout > 1)
+    ## Why imgradient invert vertical when computing the angle
+    ## Use atan2(-gy,gx)*pi/180. See http://stackoverflow.com/questions/18549015
+    gradDir = atan2d (-gradY, gradX);
+  endif
+
+endfunction
+
+%!test
+%! A = [0 1 0
+%!      1 1 1
+%!      0 1 0];
+%!
+%! [gMag, gDir] = imgradient (A);
+%! assert (gMag,[sqrt(18) 4 sqrt(18); 4 0 4; sqrt(18),4,sqrt(18)]);
+%! assert (gDir,[-45 -90 -135; -0 -0 -180; 45 90 135]);
+%!
+%! ## the following just test if passing gx and gy separately gets
+%! ## us the same as the image and method though imgradient
+%! [gxSobel, gySobel] = imgradientxy (A, "Sobel");
+%! [gxPrewitt, gyPrewitt] = imgradientxy (A, "Prewitt");
+%! [gxCd, gyCd] = imgradientxy (A, "CentralDifference");
+%! [gxId, gyId] = imgradientxy (A, "IntermediateDifference");
+%!
+%! assert (imgradient (A),
+%!         imgradient (gxSobel, gySobel));
+%! assert (imgradient (A, "Sobel"),
+%!         imgradient (gxSobel, gySobel));
+%! assert (imgradient (A, "Prewitt"),
+%!         imgradient(gxPrewitt, gyPrewitt));
+%! assert (imgradient (A, "CentralDifference"),
+%!         imgradient (gxCd, gyCd));
+%! assert (imgradient (A, "IntermediateDifference"),
+%!         imgradient (gxId, gyId));
+
--- a/inst/imgradientxy.m
+++ b/inst/imgradientxy.m
@@ -1,119 +1,133 @@
-## Copyright (C) 2013 Brandon Miles  <brandon.miles7 at gmail.com>
-## 
-## This program is free software; you can redistribute it and/or modify it
-## under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 3 of the License, or
-## (at your option) any later version.
-## 
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-## 
-## You should have received a copy of the GNU General Public License
-## along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-## -*- texinfo -*- 
-## @deftypefn {Function File} {[@var{gradX}, @var{gradY}] =} imgradientxy (@var{image}, @var{method})
-## Compute the x and y gradients of an image using various methods.  The first input @var{image} is the gray
-## scale image to compute the edges on.  The second input @var{method} controls the method used to calculate 
-## the gradients.  The first output @var{gradX} returns the gradient in the x direction.  The second output
-## @var{gradY} returns the gradient in the y direction.  
-##
-## The @var{method} input argument can be any of the following strings (the default
-## value is "Sobel")
-##
-## @table @asis
-## @item "Sobel"
-## Calculates the gradient in @var{image} using the Sobel approximation to the
-## derivatives.
-##
-## @item "Prewitt"
-## Calculates the gradient in @var{image} using the Prewitt approximation to the
-## derivatives. This method works just like "Sobel" except a different approximation of
-## the gradient is used.
-##
-## @item "Central Difference"
-## Calculates the gradient in @var{image} using the central difference approximation to the
-## derivatives: (x(i-1) - x(i+1))/2.
-##
-## @item "Intermediate Difference"
-## Calculates the gradient in @var{image} using the intermediate difference approximation to
-## the derivatives: x(i) - x(i+1).
-##
-## @end table
-##
-## @seealso{edge, gradientxy}
-## @end deftypefn
-
-function [gradX gradY] = imgradientxy (image, method)
-  ## Get the image
-  if (nargin == 0)
-    error("gradientxy: not enough input arguments");
-  endif
-  if ( ndims(image) > 2 )
-    error("gradientxy: first input must be a gray-scale image");
-  endif
-
-  ## Get the method
-  if (nargin == 1)
-    method = "Sobel";
-  endif
-  if (!ischar(method))
-    error("gradientxy: second argument must be a string");
-  endif
-  method = lower(method);
- 
-  switch(method)
-    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-    %% Sobel, Prewitt
-    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-    case {'sobel','prewitt'}
-      ker = fspecial(method); # horizontal
-    
-    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-    %% Central Difference
-    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
-    case {'centraldifference'}
-      ker = [0.5; 0; -0.5];
-    
-    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-    %% Intermediate Difference
-    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-    case {'intermediatedifference'}
-      ker = [1; -1];
- 
-    otherwise
-      error('Unrecognized method');
-  end
-  
-  gradX = conv2(image, ker', 'same');
-  gradY = conv2(image, ker, 'same');
-
-endfunction
-
-%% run tests
-%!A = [0 1 0; 1 1 1; 0 1 0]; 
-%![gxSobel, gySobel] = imgradientxy(A);
-%![gxSobel2, gySobel2] = imgradientxy(A,'Sobel');
-%![gxPrewitt,gyPrewitt] = imgradientxy(A,'Prewitt');
-%![gxCd,gyCd] = imgradientxy(A,'CentralDifference');
-%![gxId,gyId] = imgradientxy(A,'IntermediateDifference');
-%%
-%!assert(gxSobel,gxSobel2);
-%!assert(gySobel,gySobel2);
-%%
-%% Test Sobel
-%!assert(gxSobel,[3 0 -3; 4 0 -4; 3 0 -3]);
-%!assert(gySobel,[3 4  3; 0 0 0; -3 -4 -3]);
-%%
-%% Test Prewitt
-%!assert(gxPrewitt,[2 0 -2; 3 0 -3; 2 0 -2]);
-%!assert(gyPrewitt,[2 3 2; 0 0 0; -2 -3 -2]);
-%%
-%% Test Central Difference
-%!assert(gxCd,[0.5 0 -0.5; 0.5 0 -0.5; 0.5 0  -0.5]);
-%!assert(gyCd,[0.5 0.5 0.5; 0 0 0; -0.5 -0.5 -0.5]);
-%% 
-%!assert(gxId,[1 -1 0; 0 0 -1; 1 -1 0]);
-%!assert(gyId,[1 0 1; -1 0 -1; 0 -1 0]);
+## Copyright (C) 2013 Brandon Miles <brandon.miles7@gmail.com>
+##
+## This program is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*- 
+## @deftypefn  {Function File} {[@var{gradX}, @var{gradY}] =} imgradientxy (@var{img})
+## @deftypefnx {Function File} {[@var{gradX}, @var{gradY}] =} imgradientxy (@var{img}, @var{method})
+## Compute the x and y gradients of an image using various methods.
+##
+## The first input @var{img} is the gray scale image to compute the edges
+## on.  The second input @var{method} controls the method used to calculate
+## the gradients.
+##
+## The first output @var{gradX} returns the gradient in the x direction.
+## The second output @var{gradY} returns the gradient in the y direction.
+##
+## The @var{method} input argument can be any of the following strings:
+##
+## @table @asis
+## @item @qcode{"sobel"} (default)
+## Calculates the gradient using the Sobel approximation to the
+## derivatives.
+##
+## @item @qcode{"prewitt"}
+## Calculates the gradient using the Prewitt approximation to the
+## derivatives.  This method works just like Sobel except a different
+## approximation of the gradient is used.
+##
+## @item @qcode{"central difference"}
+## Calculates the gradient using the central difference approximation to the
+## derivatives: @code{(x(i-1) - x(i+1))/2}.
+##
+## @item @qcode{"intermediate difference"}
+## Calculates the gradient in using the intermediate difference approximation
+## to the derivatives: @code{x(i) - x(i+1)}.
+##
+## @end table
+##
+## @seealso{edge, imgradient}
+## @end deftypefn
+
+function [gradX, gradY] = imgradientxy (img, method = "sobel")
+
+  if (nargin < 1 || nargin > 2)
+    print_usage ();
+  elseif (! isgray (img))
+    error ("imgradientxy: IMG must be a gray-scale image");
+  elseif (! ischar (method))
+    error ("imgradientxy: METHOD must be a string");
+  endif
+
+  switch (tolower (method))
+    case {"sobel", "prewitt"}
+      ker = fspecial (method); # horizontal
+
+    case {"centraldifference"}
+      ker = [0.5; 0; -0.5];
+
+    case {"intermediatedifference"}
+      ker = [1; -1];
+
+    otherwise
+      error("imgradientxy: unrecognized METHOD %s", method);
+  endswitch
+
+  gradX = conv2 (img, ker', "same");
+  if (nargout > 1)
+    gradY = conv2 (img, ker, "same");
+  endif
+
+endfunction
+
+%!test
+%! A = [0 1 0
+%!      1 1 1
+%!      0 1 0];
+%!
+%! [gxSobel,  gySobel]  = imgradientxy (A);
+%! [gxSobel2, gySobel2] = imgradientxy (A, "Sobel");
+%! assert (gxSobel,
+%!         [ 3   0  -3
+%!           4   0  -4
+%!           3   0  -3]);
+%! assert (gySobel,
+%!         [ 3   4   3
+%!           0   0   0
+%!          -3  -4  -3]);
+%!
+%! ## test default method
+%! assert(gxSobel, gxSobel2);
+%! assert(gySobel, gySobel2);
+%!
+%! [gxPrewitt, gyPrewitt] = imgradientxy (A, "Prewitt");
+%! assert (gxPrewitt,
+%!         [ 2   0  -2
+%!           3   0  -3
+%!           2   0  -2]);
+%! assert (gyPrewitt,
+%!         [ 2   3   2
+%!           0   0   0
+%!          -2  -3  -2]);
+%!
+%! [gxCd, gyCd] = imgradientxy (A, "CentralDifference");
+%! assert (gxCd,
+%!         [ 0.5   0.0  -0.5
+%!           0.5   0.0  -0.5
+%!           0.5   0.0  -0.5]);
+%! assert (gyCd,
+%!         [ 0.5   0.5   0.5
+%!           0     0     0
+%!          -0.5  -0.5  -0.5]);
+%!
+%! [gxId, gyId] = imgradientxy(A, "IntermediateDifference");
+%! assert (gxId,
+%!         [ 1  -1   0
+%!           0   0  -1
+%!           1  -1   0]);
+%! assert (gyId,
+%!         [ 1   0   1
+%!          -1   0  -1
+%!           0  -1   0]);
+