changeset 11349:0c68e7e7b2e2 octave-forge

imdilate: * implementing shape option for black and white images * do not require same class for image and SE * bug fix to respect border values (use -Inf on call to ordfiltn) * fix documentation
author carandraug
date Fri, 04 Jan 2013 03:08:25 +0000
parents ce3e76d49427
children b5c35a53e358
files main/image/NEWS main/image/inst/imdilate.m main/image/inst/imerode.m
diffstat 3 files changed, 57 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/main/image/NEWS	Fri Jan 04 02:41:54 2013 +0000
+++ b/main/image/NEWS	Fri Jan 04 03:08:25 2013 +0000
@@ -30,6 +30,18 @@
 
       imerode
 
+ ** The functions `imerode' and `imdilate' no longer require that image and
+    structuring element be of same class. They now perform faster for all black
+    and white images, independently of their class, and always return an image
+    of same class as the input image.
+
+ ** The shape option has been implemented for `imerode' and `imdilate' for black
+    and white images.
+
+ ** With the increased performance in `imerode' and `imdilate', all other
+    functions that use them, such `imopen' and `imclose', also get a performance
+    boost for black and white images.
+
 Summary of important user-visible changes for image 2.0.0:
 -------------------------------------------------------------------
 
--- a/main/image/inst/imdilate.m	Fri Jan 04 02:41:54 2013 +0000
+++ b/main/image/inst/imdilate.m	Fri Jan 04 03:08:25 2013 +0000
@@ -16,48 +16,60 @@
 ## this program; if not, see <http://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn {Function File} {@var{B} =} imdilate (@var{A}, @var{se})
+## @deftypefn  {Function File} {@var{im2} =} imdilate (@var{im}, @var{se})
+## @deftypefnx {Function File} {@var{im2} =} imdilate (@var{im}, @var{se}, @var{shape})
 ## Perform morphological dilation on a given image.
 ##
-## The image @var{A} must be a grayscale or binary image, and @var{se} a
-## structuring element. Both must have the same class, e.g., if @var{A} is a
-## logical matrix, @var{se} must also be logical. Note that the erosion
-## algorithm is different for each class, being much faster for logical
-## matrices. As such, if you have a binary matrix, you should use @code{logical}
-## first. This will also reduce the memory usage of your code.
+## The image @var{im} must be black and white or grayscale image, with any number
+## of dimensions.
+##
+## @var{se} is the structuring element used for the erosion and must be a matrix
+## of 0's and 1's.
+##
+## The size of the result is determined by the optional @var{shape} argument
+## which takes the following values:
 ##
-## The center of @var{SE} is calculated using floor((size(@var{SE})+1)/2).
+## @table @asis
+## @item "same" (default)
+## Return image of the same size as input @var{im}.
+## 
+## @item "full"
+## Return the full erosion (image is padded to accomodate @var{se} near the
+## borders). Not implemented for grayscale images.
+## @end table
 ##
-## Pixels outside the image are considered to be 0.
+## The center of @var{SE} is at the indices @code{floor ([size(@var{B})/2] + 1)}.
 ##
 ## @seealso{imerode, imopen, imclose}
 ## @end deftypefn
 
-function retval = imdilate(im, se)
-  ## Checkinput
-  if (nargin != 2)
+function im = imdilate (im, se, shape = "same")
+
+  if (nargin < 2 || nargin > 3)
     print_usage();
+  elseif (! ischar (shape) || ! any (strcmpi (shape, {"same", "full"})))
+    error ("imdilate: SHAPE must be `same' or `full'")
   endif
-  if (!ismatrix(im) || !isreal(im))
-    error("imdilate: first input argument must be a real matrix");
-  elseif (!ismatrix(se) || !isreal(se))
-    error("imdilate: second input argument must be a real matrix");
-  elseif ( !strcmp(class(im), class(se)) )
-    error("imdilate: image and structuring element must have the same class");
+
+  if (! isbw (im, "non-logical"))
+    error ("imerode: SE must be a matrix of 0's and 1's");
   endif
 
-  ## Perform filtering
-  ## Filtering must be done with the reflection of the structuring element (they
-  ## are not always symmetrical)
-  se      = imrotate(se, 180);
-
-  ## If image is binary/logical, try to use filter2 (much faster)
-  if (islogical(im))
-    retval  = filter2(se,im)>0;
+  cl = class (im);
+  if (isbw (im, "non-logical"))
+    im = convn (im, se, shape) > 0;
+  elseif (isimage (im))
+    ## TODO needs to implement the shape option here. Most likely requires a
+    ##      to be padded first (padarray), and use of __spatial_filtering__
+    ##      directly (that's what ordfiltn does) with the "max" method. The
+    ##      same needs to be done for imerode
+    im = ordfiltn (im, nnz (se), se, -Inf);
   else
-    retval  = ordfiltn(im, sum(se(:)!=0), se, 0);
+    error ("imdilate: IM must be a grayscale or black and white matrix");
   endif
 
+  ## we return image on same class as input
+  im = cast (im, cl);
 endfunction
 
 %!demo
--- a/main/image/inst/imerode.m	Fri Jan 04 02:41:54 2013 +0000
+++ b/main/image/inst/imerode.m	Fri Jan 04 03:08:25 2013 +0000
@@ -58,7 +58,7 @@
     if (ismatrix (se))
       se = strel ("arbitrary", se);
     elseif (! isa (se, "strel"))
-      error("imerode: SE must a strel object, or a matrix of 0's and 1's");
+      error ("imerode: SE must a strel object, or a matrix of 0's and 1's");
     endif
     se = getsequence (se);
   endif
@@ -83,13 +83,14 @@
       ## this is just like a minimum filter so we need to have the outside of
       ## the image above all possible values (hence Inf)
       ## FIXME what to do with non-flat se?
-      ## FIXME needs to implement the shape optino here. Most likely requires a
-      ##       to be padded first (padarray), and use of __spatial_filtering__
-      ##       directly (that's what ordfiltn does) with the "min" method
+      ## TODO needs to implement the shape optino here. Most likely requires a
+      ##      to be padded first (padarray), and use of __spatial_filtering__
+      ##      directly (that's what ordfiltn does) with the "min" method. The
+      ##      same needs to be done for imdilate
       im = ordfiltn (im, 1, getnhood (se{k}), Inf);
     endfor
   else
-    error("imerode: IM must be a grayscale or black and white matrix");
+    error ("imerode: IM must be a grayscale or black and white matrix");
   endif
 
   ## we return image on same class as input