diff --git a/ChangeLog b/ChangeLog index 6e6ab201..fe5a49ba 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,7 +5,7 @@ - operations can be tagged as "deprecated" - redo im_draw_circle(), im_draw_flood(), im_draw_line(), im_draw_mask(), im_draw_image(), im_draw_rect(), im_draw_point(), im_read_point(), - im_draw_smudge() as classes + im_draw_smudge(), im_label_regions() as classes - better rounding in vips_flatten() - VipsStatistic operations are sequential diff --git a/TODO b/TODO index 99b20608..962d400a 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,4 @@ -- need to do im_label_regions in morph - -- swap VipsArea ink for VipsArrayDouble? +- nip2 make check is failing - ink to vec etc. should work for complex .. output or accept a double-length vector @@ -18,6 +16,9 @@ current behaviour of imaginary == 0 always + + + - try $ vips getpoint @@ -46,19 +47,18 @@ y-array - Array of vertical positions, output VipsArrayInt don't list out-array or out as args in the usage line, since they don't need - an arg ... these args should be in a separet section I guess? + an arg ... these args should be in a separate section, I guess? put description first + + + - try: $ vips max babe.v --x-array --size 0 Segmentation fault (core dumped) - - - - - try: im = VIPS::Image.new(ARGV[0]) diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index 2932c1a8..53a2ba0e 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -4498,6 +4498,23 @@ im_cntlines( VipsImage *im, double *nolines, int flag ) NULL ) ); } +int +im_label_regions( IMAGE *test, IMAGE *mask, int *segments ) +{ + VipsImage *x; + + if( vips_labelregions( test, &x, "segments", segments, NULL ) ) + return( -1 ); + + if( im_copy( x, mask ) ) { + g_object_unref( x ); + return( -1 ); + } + g_object_unref( x ); + + return( 0 ); +} + int im_rank( IMAGE *in, IMAGE *out, int width, int height, int index ) { @@ -4653,10 +4670,12 @@ im_draw_flood( IMAGE *image, int x, int y, VipsPel *ink, Rect *dout ) NULL ) ) return( -1 ); - dout->left = left; - dout->top = top; - dout->width = width; - dout->height = height; + if( dout ) { + dout->left = left; + dout->top = top; + dout->width = width; + dout->height = height; + } return( 0 ); } @@ -4683,10 +4702,12 @@ im_draw_flood_blob( IMAGE *image, int x, int y, VipsPel *ink, Rect *dout ) NULL ) ) return( -1 ); - dout->left = left; - dout->top = top; - dout->width = width; - dout->height = height; + if( dout ) { + dout->left = left; + dout->top = top; + dout->width = width; + dout->height = height; + } return( 0 ); } @@ -4695,15 +4716,12 @@ int im_draw_flood_other( IMAGE *image, IMAGE *test, int x, int y, int serial, Rect *dout ) { - double vec[1]; int left; int top; int width; int height; - vec[0] = serial; - - if( vips_draw_flood( image, vec, 1, x, y, + if( vips_draw_flood1( image, serial, x, y, "test", test, "equal", TRUE, "left", &left, @@ -4713,10 +4731,12 @@ im_draw_flood_other( IMAGE *image, NULL ) ) return( -1 ); - dout->left = left; - dout->top = top; - dout->width = width; - dout->height = height; + if( dout ) { + dout->left = left; + dout->top = top; + dout->width = width; + dout->height = height; + } return( 0 ); } diff --git a/libvips/draw/drawink.h b/libvips/draw/drawink.h index 9400788e..addf1000 100644 --- a/libvips/draw/drawink.h +++ b/libvips/draw/drawink.h @@ -55,9 +55,7 @@ extern "C" { typedef struct _VipsDrawink { VipsDraw parent_instance; - /* Parameters. - */ - VipsArea *ink; /* With this */ + VipsArrayDouble *ink; /* Ink cast to pixel type. */ diff --git a/libvips/include/vips/morphology.h b/libvips/include/vips/morphology.h index 89d17aec..c330764c 100644 --- a/libvips/include/vips/morphology.h +++ b/libvips/include/vips/morphology.h @@ -50,16 +50,14 @@ int vips_morph( VipsImage *in, VipsImage **out, VipsImage *mask, int vips_rank( VipsImage *in, VipsImage **out, int width, int height, int index, ... ) __attribute__((sentinel)); +int vips_median( VipsImage *in, VipsImage **out, int size, ... ) + __attribute__((sentinel)); int vips_countlines( VipsImage *in, double *nolines, VipsDirection direction, ... ) __attribute__((sentinel)); -int vips_median( VipsImage *in, VipsImage **out, int size, ... ) +int vips_labelregions( VipsImage *in, VipsImage **out, ... ) __attribute__((sentinel)); - - -int im_label_regions( VipsImage *test, VipsImage *mask, int *segments ); - #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/libvips/include/vips/vips7compat.h b/libvips/include/vips/vips7compat.h index 9ddcbf00..d0e856fe 100644 --- a/libvips/include/vips/vips7compat.h +++ b/libvips/include/vips/vips7compat.h @@ -998,6 +998,7 @@ 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 ); +int im_label_regions( VipsImage *test, VipsImage *mask, int *segments ); int im_rank( VipsImage *in, VipsImage *out, int width, int height, int index ); int im_zerox( VipsImage *in, VipsImage *out, int sign ); diff --git a/libvips/morphology/Makefile.am b/libvips/morphology/Makefile.am index cee68843..a35a4941 100644 --- a/libvips/morphology/Makefile.am +++ b/libvips/morphology/Makefile.am @@ -7,6 +7,6 @@ libmorphology_la_SOURCES = \ rank.c \ hitmiss.c \ morph.c \ - im_label_regions.c + labelregions.c AM_CPPFLAGS = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@ diff --git a/libvips/morphology/im_label_regions.c b/libvips/morphology/im_label_regions.c deleted file mode 100644 index e7574e0d..00000000 --- a/libvips/morphology/im_label_regions.c +++ /dev/null @@ -1,117 +0,0 @@ -/* im_label_regions.c - * - * 5/11/09 - * - renamed from im_segment() - */ - -/* - - 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_label_regions: - * @test: image to test - * @mask: write labelled regions here - * @segments: return number of regions here - * - * im_label_regions() repeatedly scans @test for regions of 4-connected pixels - * with the same pixel value. Every time a region is discovered, those - * pixels are marked in @mask with a unique serial number. Once all pixels - * have been labelled, the operation returns, setting @segments to the number - * of discrete regions which were detected. - * - * @mask is always a 1-band %IM_BANDFMT_UINT image of the same dimensions as - * @test. - * - * This operation is useful for, for example, blob counting. You can use the - * morphological operators to detect and isolate a series of objects, then use - * im_label_regions() to number them all. - * - * Use im_histindexed() to (for example) find blob coordinates. - * - * See also: im_histindexed() - * - * Returns: 0 on success, -1 on error. - */ -int -im_label_regions( IMAGE *test, IMAGE *mask, int *segments ) -{ - IMAGE *t[2]; - int serial; - int *m; - int x, y; - - /* Create the zero mask image. - */ - if( im_open_local_array( mask, t, 2, "im_label_regions", "p" ) || - im_black( t[0], test->Xsize, test->Ysize, 1 ) || - im_clip2fmt( t[0], t[1], IM_BANDFMT_INT ) ) - return( -1 ); - - /* Search the mask image, flooding as we find zero pixels. - */ - if( im_rwcheck( t[1] ) ) - return( -1 ); - serial = 0; - m = (int *) t[1]->data; - for( y = 0; y < test->Ysize; y++ ) { - for( x = 0; x < test->Xsize; x++ ) { - if( !m[x] ) { - /* - if( im_flood_other_old( t[1], test, - x, y, serial ) ) - */ - if( im_flood_other( test, t[1], - x, y, serial, NULL ) ) -// if( im_flood_other_old( t[1], test, -// x, y, serial ) ) - return( -1 ); - - serial += 1; - } - } - - m += test->Xsize; - } - - /* Copy result to mask. - */ - if( im_copy( t[1], mask ) ) - return( -1 ); - if( segments ) - *segments = serial; - - return( 0 ); -} diff --git a/libvips/morphology/labelregions.c b/libvips/morphology/labelregions.c new file mode 100644 index 00000000..117c6ad8 --- /dev/null +++ b/libvips/morphology/labelregions.c @@ -0,0 +1,182 @@ +/* labelregions.c + * + * 5/11/09 + * - renamed from im_segment() + * 11/2/14 + * - redo as a class + */ + +/* + + 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 + +#include "pmorphology.h" + +typedef struct _VipsLabelregions { + VipsMorphology parent_instance; + + VipsImage *mask; + int segments; +} VipsLabelregions; + +typedef VipsMorphologyClass VipsLabelregionsClass; + +G_DEFINE_TYPE( VipsLabelregions, vips_labelregions, VIPS_TYPE_MORPHOLOGY ); + +static int +vips_labelregions_build( VipsObject *object ) +{ + VipsMorphology *morphology = VIPS_MORPHOLOGY( object ); + VipsImage *in = morphology->in; + VipsImage **t = (VipsImage **) vips_object_local_array( object, 7 ); + + int serial; + int *m; + int x, y; + + if( VIPS_OBJECT_CLASS( vips_labelregions_parent_class )-> + build( object ) ) + return( -1 ); + + /* Create the zero mask image. + */ + if( vips_black( &t[0], in->Xsize, in->Ysize, 1, NULL ) || + vips_cast( t[0], &t[1], VIPS_FORMAT_INT, NULL ) ) + return( -1 ); + + /* Search the mask image, flooding as we find zero pixels. + */ + if( vips_image_inplace( t[1] ) ) + return( -1 ); + + serial = 0; + m = (int *) t[1]->data; + for( y = 0; y < t[1]->Ysize; y++ ) { + for( x = 0; x < t[1]->Xsize; x++ ) { + if( !m[x] ) { + if( vips_draw_flood1( t[1], serial, x, y, + "test", in, + "equal", TRUE, + NULL ) ) + return( -1 ); + + serial += 1; + } + } + + m += t[1]->Xsize; + } + + g_object_set( object, + "mask", t[1], + "segments", serial, + NULL ); + + return( 0 ); +} + +static void +vips_labelregions_class_init( VipsLabelregionsClass *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 = "labelregions"; + vobject_class->description = _( "label regions in an image" ); + vobject_class->build = vips_labelregions_build; + + VIPS_ARG_IMAGE( class, "mask", 2, + _( "Mask" ), + _( "Mask of region labels" ), + VIPS_ARGUMENT_REQUIRED_OUTPUT, + G_STRUCT_OFFSET( VipsLabelregions, mask ) ); + + VIPS_ARG_INT( class, "segments", 3, + _( "Segments" ), + _( "Number of discrete contigious regions" ), + VIPS_ARGUMENT_OPTIONAL_OUTPUT, + G_STRUCT_OFFSET( VipsLabelregions, segments ), + 0, 1000000000, 0 ); + +} + +static void +vips_labelregions_init( VipsLabelregions *labelregions ) +{ +} + +/** + * vips_labelregions: + * @test: image to test + * @mask: write labelled regions here + * + * Optional arguments: + * + * @segments: return number of regions found here + * + * Repeatedly scans @test for regions of 4-connected pixels + * with the same pixel value. Every time a region is discovered, those + * pixels are marked in @mask with a unique serial number. Once all pixels + * have been labelled, the operation returns, setting @segments to the number + * of discrete regions which were detected. + * + * @mask is always a 1-band #VIPS_FORMAT_INT image of the same dimensions as + * @test. + * + * This operation is useful for, for example, blob counting. You can use the + * morphological operators to detect and isolate a series of objects, then use + * vips_labelregions() to number them all. + * + * Use vips_hist_find_indexed() to (for example) find blob coordinates. + * + * See also: vips_hist_find_indexed(). + * + * Returns: 0 on success, -1 on error. + */ +int +vips_labelregions( VipsImage *in, VipsImage **mask, ... ) +{ + va_list ap; + int result; + + va_start( ap, mask ); + result = vips_call_split( "labelregions", ap, in, mask ); + va_end( ap ); + + return( result ); +}