From cb96ed814e80f4cb5418fc2260b36e9b1d39e414 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Fri, 17 Jan 2014 11:18:05 +0000 Subject: [PATCH] redo im_cntlines() as a class --- ChangeLog | 1 + libvips/deprecated/vips7compat.c | 9 ++ libvips/include/vips/convolution.h | 2 - libvips/include/vips/internal.h | 2 + libvips/include/vips/morphology.h | 5 +- libvips/include/vips/vips7compat.h | 2 + libvips/iofuncs/init.c | 1 + libvips/morphology/Makefile.am | 3 +- libvips/morphology/countlines.c | 185 ++++++++++++++++++++++++++++ libvips/morphology/im_cntlines.c | 131 -------------------- libvips/morphology/morph_dispatch.c | 45 ------- libvips/morphology/morphology.c | 137 ++++++++++++++++++++ libvips/morphology/pmorphology.h | 77 ++++++++++++ 13 files changed, 420 insertions(+), 180 deletions(-) create mode 100644 libvips/morphology/countlines.c delete mode 100644 libvips/morphology/im_cntlines.c create mode 100644 libvips/morphology/morphology.c create mode 100644 libvips/morphology/pmorphology.h diff --git a/ChangeLog b/ChangeLog index 0f4ab56c..2c27bbd3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -37,6 +37,7 @@ - vips_colourspace() allows B_W, GREY16, RGB16 as source / target - added vips_thread_shutdown(), thanks Lovell - vips_linear() has a uchar output mode +- redone im_cntlines() as a class 9/1/14 started 7.36.6 - fix some clang compiler warnings diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index 3efdec01..e7e627cd 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -4488,3 +4488,12 @@ im_phasecor_fft( IMAGE *in1, IMAGE *in2, IMAGE *out ) return( 0 ); } + +int +im_cntlines( VipsImage *im, double *nolines, int flag ) +{ + return( vips_countlines( im, nolines, + flag == 0 ? + VIPS_DIRECTION_HORIZONTAL : VIPS_DIRECTION_VERTICAL, + NULL ) ); +} diff --git a/libvips/include/vips/convolution.h b/libvips/include/vips/convolution.h index 79125f75..5153e88d 100644 --- a/libvips/include/vips/convolution.h +++ b/libvips/include/vips/convolution.h @@ -83,8 +83,6 @@ int vips_sharpen( VipsImage *in, VipsImage **out, ... ) int vips_gaussblur( VipsImage *in, VipsImage **out, int radius, ... ) __attribute__((sentinel)); -void vips_convolution_operation_init( void ); - #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/libvips/include/vips/internal.h b/libvips/include/vips/internal.h index c9d1b1a8..39c233b6 100644 --- a/libvips/include/vips/internal.h +++ b/libvips/include/vips/internal.h @@ -287,6 +287,8 @@ void vips_colour_operation_init( void ); void vips_histogram_operation_init( void ); void vips_freqfilt_operation_init( void ); void vips_create_operation_init( void ); +void vips_morphology_operation_init( void ); +void vips_convolution_operation_init( void ); guint64 vips__parse_size( const char *size_string ); diff --git a/libvips/include/vips/morphology.h b/libvips/include/vips/morphology.h index b546bff0..6aea942c 100644 --- a/libvips/include/vips/morphology.h +++ b/libvips/include/vips/morphology.h @@ -38,13 +38,16 @@ extern "C" { #endif /*__cplusplus*/ +int vips_countlines( VipsImage *in, double *nolines, + VipsDirection direction, ... ) + __attribute__((sentinel)); + int im_rank( VipsImage *in, VipsImage *out, int width, int height, int index ); -int im_cntlines( VipsImage *im, double *nolines, int flag ); int im_zerox( VipsImage *in, VipsImage *out, int sign ); int im_label_regions( VipsImage *test, VipsImage *mask, int *segments ); diff --git a/libvips/include/vips/vips7compat.h b/libvips/include/vips/vips7compat.h index 6020b17c..f62f4ddd 100644 --- a/libvips/include/vips/vips7compat.h +++ b/libvips/include/vips/vips7compat.h @@ -975,6 +975,8 @@ int im_disp_ps( VipsImage *in, VipsImage *out ); int im_fractsurf( VipsImage *out, int size, double frd ); int im_phasecor_fft( VipsImage *in1, VipsImage *in2, VipsImage *out ); +int im_cntlines( VipsImage *im, double *nolines, int flag ); + #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/libvips/iofuncs/init.c b/libvips/iofuncs/init.c index 40a782d3..7ab48b77 100644 --- a/libvips/iofuncs/init.c +++ b/libvips/iofuncs/init.c @@ -271,6 +271,7 @@ vips__init( const char *argv0 ) vips_histogram_operation_init(); vips_convolution_operation_init(); vips_freqfilt_operation_init(); + vips_morphology_operation_init(); /* Load up any plugins in the vips libdir. We don't error on failure, * it's too annoying to have VIPS refuse to start because of a broken diff --git a/libvips/morphology/Makefile.am b/libvips/morphology/Makefile.am index eb75e9c5..8afaab28 100644 --- a/libvips/morphology/Makefile.am +++ b/libvips/morphology/Makefile.am @@ -1,7 +1,8 @@ noinst_LTLIBRARIES = libmorphology.la libmorphology_la_SOURCES = \ - im_cntlines.c \ + morphology.c \ + countlines.c \ hitmiss.c\ im_rank.c \ im_zerox.c \ diff --git a/libvips/morphology/countlines.c b/libvips/morphology/countlines.c new file mode 100644 index 00000000..49a28300 --- /dev/null +++ b/libvips/morphology/countlines.c @@ -0,0 +1,185 @@ +/* count lines + * + * Copyright: 1990, N. Dessipris. + * + * Author: Nicos Dessipris + * Written on: 02/05/1990 + * Modified on : + * + * 19/9/95 JC + * - tidied up + * 23/10/10 + * - gtk-doc + * 17/1/14 + * - redone as a class, now just a convenience function + */ + +/* + + This file is part of VIPS. + + VIPS is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA + + */ + +/* + + These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk + + */ + +/* +#define VIPS_DEBUG + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /*HAVE_CONFIG_H*/ +#include + +#include +#include +#include + +#include +#include +#include + +#include "pmorphology.h" + +typedef struct _VipsCountlines { + VipsMorphology parent_instance; + + double nolines; + VipsDirection direction; +} VipsCountlines; + +typedef VipsMorphologyClass VipsCountlinesClass; + +G_DEFINE_TYPE( VipsCountlines, vips_countlines, VIPS_TYPE_MORPHOLOGY ); + +static int +vips_countlines_build( VipsObject *object ) +{ + VipsMorphology *morphology = VIPS_MORPHOLOGY( object ); + VipsCountlines *countlines = (VipsCountlines *) object; + VipsImage *in = morphology->in; + VipsImage **t = (VipsImage **) vips_object_local_array( object, 7 ); + + double nolines; + + if( VIPS_OBJECT_CLASS( vips_countlines_parent_class )->build( object ) ) + return( -1 ); + + switch( countlines->direction ) { + case VIPS_DIRECTION_HORIZONTAL: + if( !(t[0] = vips_image_new_matrixv( 1, 2, -1.0, 1.0 )) || + vips_moreeq_const1( in, &t[1], 128, NULL ) || + vips_conv( t[1], &t[2], t[0], NULL ) || + vips_project( t[2], &t[3], &t[4], NULL ) || + vips_avg( t[3], &nolines, NULL ) ) + return( -1 ); + break; + + case VIPS_DIRECTION_VERTICAL: + if( !(t[0] = vips_image_new_matrixv( 2, 1, -1.0, 1.0 )) || + vips_moreeq_const1( in, &t[1], 128, NULL ) || + vips_conv( t[1], &t[2], t[0], NULL ) || + vips_project( t[2], &t[3], &t[4], NULL ) || + vips_avg( t[4], &nolines, NULL ) ) + return( -1 ); + break; + + default: + g_assert( 0 ); + + /* Keep -Wall happy. + */ + return( 0 ); + } + + g_object_set( object, "nolines", nolines / 255.0, NULL ); + + return( 0 ); +} + +static void +vips_countlines_class_init( VipsCountlinesClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); + + VIPS_DEBUG_MSG( "vips_countlines_class_init\n" ); + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + vobject_class->nickname = "countlines"; + vobject_class->description = _( "count lines in an image" ); + vobject_class->build = vips_countlines_build; + + VIPS_ARG_DOUBLE( class, "nolines", 2, + _( "Nolines" ), + _( "Number of lines" ), + VIPS_ARGUMENT_REQUIRED_OUTPUT, + G_STRUCT_OFFSET( VipsCountlines, nolines ), + 0, 10000000, 0.0 ); + + VIPS_ARG_ENUM( class, "direction", 3, + _( "direction" ), + _( "Countlines left-right or up-down" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsCountlines, direction ), + VIPS_TYPE_DIRECTION, VIPS_DIRECTION_HORIZONTAL ); + +} + +static void +vips_countlines_init( VipsCountlines *countlines ) +{ +} + +/** + * vips_countlines: + * @in: input image + * @nolines: output average number of lines + * @direction: count lines horizontally or vertically + * @...: %NULL-terminated list of optional named arguments + * + * Function which calculates the number of transitions + * between black and white for the horizontal or the vertical + * direction of an image. black<128 , white>=128 + * The function calculates the number of transitions for all + * Xsize or Ysize and returns the mean of the result + * Input should be one band, 8-bit. + * + * See also: vips_morph(), vips_zerox(), vips_conv(). + * + * Returns: 0 on success, -1 on error. + */ +int +vips_countlines( VipsImage *in, double *nolines, + VipsDirection direction, ... ) +{ + va_list ap; + int result; + + va_start( ap, direction ); + result = vips_call_split( "countlines", ap, in, nolines, direction ); + va_end( ap ); + + return( result ); +} diff --git a/libvips/morphology/im_cntlines.c b/libvips/morphology/im_cntlines.c deleted file mode 100644 index d7d25548..00000000 --- a/libvips/morphology/im_cntlines.c +++ /dev/null @@ -1,131 +0,0 @@ -/* count lines - * - * Copyright: 1990, N. Dessipris. - * - * Author: Nicos Dessipris - * Written on: 02/05/1990 - * Modified on : - * - * 19/9/95 JC - * - tidied up - * 23/10/10 - * - gtk-doc - */ - -/* - - This file is part of VIPS. - - VIPS is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#include - -#include - -/** - * im_cntlines: - * @im: input #IMAGE - * @nolines: output average number of lines - * @flag: 0 horizontal, 1 vertical - * - * Function which calculates the number of transitions - * between black and white for the horizontal or the vertical - * direction of an image. black<128 , white>=128 - * The function calculates the number of transitions for all - * Xsize or Ysize and returns the mean of the result - * Input should be one band, 8-bit. - * - * See also: im_erode(), im_zerox(), im_conv(). - * - * Returns: 0 on success, -1 on error. - */ -int -im_cntlines( IMAGE *im, double *nolines, int flag ) -{ - int x, y; - VipsPel *line; - int cnt; - - if( im_incheck( im ) || - im_check_uncoded( "im_cntlines", im ) || - im_check_mono( "im_cntlines", im ) || - im_check_format( "im_cntlines", im, IM_BANDFMT_UCHAR ) ) - return( -1 ); - if( flag != 0 && flag != 1 ) { - im_error( "im_cntlines", "%s", - _( "flag should be 0 (horizontal) or 1 (vertical)" ) ); - return( -1 ); - } - - line = im->data; - if( flag == 1 ) { - /* Count vertical lines. - */ - for( cnt = 0, y = 0; y < im->Ysize; y++ ) { - VipsPel *p = line; - - for( x = 0; x < im->Xsize - 1; x++ ) { - if( p[0] < 128 && p[1] >= 128 ) - cnt++; - else if( p[0] >= 128 && p[1] < 128 ) - cnt++; - - p++; - } - - line += im->Xsize; - } - - *nolines = (float) cnt / (2.0 * im->Ysize); - } - else { - /* Count horizontal lines. - */ - for( cnt = 0, y = 0; y < im->Ysize - 1; y++ ) { - VipsPel *p1 = line; - VipsPel *p2 = line + im->Xsize; - - for( x = 0; x < im->Xsize; x++ ) { - if( *p1 < 128 && *p2 >= 128 ) - cnt++; - else if( *p1 >= 128 && *p2 < 128 ) - cnt++; - - p1++; - p2++; - } - - line += im->Xsize; - } - - *nolines = (float) cnt / (2.0 * im->Xsize); - } - - return( 0 ); -} diff --git a/libvips/morphology/morph_dispatch.c b/libvips/morphology/morph_dispatch.c index 07786f89..1f573d35 100644 --- a/libvips/morphology/morph_dispatch.c +++ b/libvips/morphology/morph_dispatch.c @@ -39,51 +39,6 @@ #include -/** - * SECTION: morphology - * @short_description: morphological operators, rank filters and related image - * analysis - * @see_also: boolean - * @stability: Stable - * @include: vips/vips.h - * - * The morphological functions search images - * for particular patterns of pixels, specified with the mask argument, - * either adding or removing pixels when they find a match. They are useful - * for cleaning up images --- for example, you might threshold an image, and - * then use one of the morphological functions to remove all single isolated - * pixels from the result. - * - * If you combine the morphological operators with the mask rotators - * im_rotate_imask45(), for example) and apply them repeatedly, you - * can achieve very complicated effects: you can thin, prune, fill, open edges, - * close gaps, and many others. For example, see `Fundamentals of Digital - * Image Processing' by A. Jain, pp 384-388, Prentice-Hall, 1989 for more - * ideas. - * - * Beware that VIPS reverses the usual image processing convention, by - * assuming white objects (non-zero pixels) on a black background (zero - * pixels). - * - * The mask you give to the morphological functions should contain only the - * values 0 (for background), 128 (for don't care) and 255 (for object). The - * mask must have odd length sides --- the origin of the mask is taken to be - * the centre value. For example, the mask: - * - * 3 3 - * 128 255 128 - * 255 0 255 - * 128 255 128 - * - * applied to an image with im_erode(), will find all black pixels - * 4-way connected with white pixels. Essentially, im_dilate() - * sets pixels in the output if any part of the mask matches, whereas - * im_erode() sets pixels only if all of the mask matches. - * - * See im_andimage(), im_orimage() and im_eorimage() - * for analogues of the usual set difference and set union operations. - */ - /* Args to im_profile. */ static im_arg_desc profile_args[] = { diff --git a/libvips/morphology/morphology.c b/libvips/morphology/morphology.c new file mode 100644 index 00000000..355b6848 --- /dev/null +++ b/libvips/morphology/morphology.c @@ -0,0 +1,137 @@ +/* base class for all morphological operations + * + * properties: + * - one input image + */ + +/* + + Copyright (C) 1991-2005 The National Gallery + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA + + */ + +/* + + These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk + + */ + +/* +#define DEBUG + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /*HAVE_CONFIG_H*/ +#include + +#include +#include +#include + +#include +#include + +#include "pmorphology.h" + +/** + * SECTION: morphology + * @short_description: morphological operators, rank filters and related image + * analysis + * @see_also: boolean + * @stability: Stable + * @include: vips/vips.h + * + * The morphological functions search images + * for particular patterns of pixels, specified with the mask argument, + * either adding or removing pixels when they find a match. They are useful + * for cleaning up images --- for example, you might threshold an image, and + * then use one of the morphological functions to remove all single isolated + * pixels from the result. + * + * If you combine the morphological operators with the mask rotators + * im_rotate_imask45(), for example) and apply them repeatedly, you + * can achieve very complicated effects: you can thin, prune, fill, open edges, + * close gaps, and many others. For example, see `Fundamentals of Digital + * Image Processing' by A. Jain, pp 384-388, Prentice-Hall, 1989 for more + * ideas. + * + * Beware that VIPS reverses the usual image processing convention, by + * assuming white objects (non-zero pixels) on a black background (zero + * pixels). + * + * The mask you give to the morphological functions should contain only the + * values 0 (for background), 128 (for don't care) and 255 (for object). The + * mask must have odd length sides --- the origin of the mask is taken to be + * the centre value. For example, the mask: + * + * 3 3 + * 128 255 128 + * 255 0 255 + * 128 255 128 + * + * applied to an image with im_erode(), will find all black pixels + * 4-way connected with white pixels. Essentially, im_dilate() + * sets pixels in the output if any part of the mask matches, whereas + * im_erode() sets pixels only if all of the mask matches. + * + * See im_andimage(), im_orimage() and im_eorimage() + * for analogues of the usual set difference and set union operations. + */ + +G_DEFINE_ABSTRACT_TYPE( VipsMorphology, vips_morphology, + VIPS_TYPE_OPERATION ); + +static void +vips_morphology_class_init( VipsMorphologyClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + vobject_class->nickname = "morphology"; + vobject_class->description = _( "morphological operations" ); + + /* Inputs set by subclassess. + */ + + VIPS_ARG_IMAGE( class, "in", 0, + _( "Input" ), + _( "Input image argument" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsMorphology, in ) ); + +} + +static void +vips_morphology_init( VipsMorphology *morphology ) +{ +} + +/* Called from iofuncs to init all operations in this dir. Use a plugin system + * instead? + */ +void +vips_morphology_operation_init( void ) +{ + extern int vips_countlines_get_type( void ); + + vips_countlines_get_type(); +} diff --git a/libvips/morphology/pmorphology.h b/libvips/morphology/pmorphology.h new file mode 100644 index 00000000..51b4d7c0 --- /dev/null +++ b/libvips/morphology/pmorphology.h @@ -0,0 +1,77 @@ +/* base class for all morphology operations + */ + +/* + + Copyright (C) 1991-2005 The National Gallery + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA + + */ + +/* + + These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk + + */ + +#ifndef VIPS_PMORPHOLOGY_H +#define VIPS_PMORPHOLOGY_H + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +#include + +#define VIPS_TYPE_MORPHOLOGY (vips_morphology_get_type()) +#define VIPS_MORPHOLOGY( obj ) \ + (G_TYPE_CHECK_INSTANCE_CAST( (obj), \ + VIPS_TYPE_MORPHOLOGY, VipsMorphology )) +#define VIPS_MORPHOLOGY_CLASS( klass ) \ + (G_TYPE_CHECK_CLASS_CAST( (klass), \ + VIPS_TYPE_MORPHOLOGY, VipsMorphologyClass)) +#define VIPS_IS_MORPHOLOGY( obj ) \ + (G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_MORPHOLOGY )) +#define VIPS_IS_MORPHOLOGY_CLASS( klass ) \ + (G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_MORPHOLOGY )) +#define VIPS_MORPHOLOGY_GET_CLASS( obj ) \ + (G_TYPE_INSTANCE_GET_CLASS( (obj), \ + VIPS_TYPE_MORPHOLOGY, VipsMorphologyClass )) + +typedef struct _VipsMorphology VipsMorphology; + +struct _VipsMorphology { + VipsOperation parent_instance; + + VipsImage *in; + +}; + +typedef struct _VipsMorphologyClass { + VipsOperationClass parent_class; + +} VipsMorphologyClass; + +GType vips_morphology_get_type( void ); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /*VIPS_PMORPHOLOGY_H*/ + +