im_label_regions() is a class

This commit is contained in:
John Cupitt 2014-02-11 14:55:31 +00:00
parent 487e6ed95e
commit 025e56c894
9 changed files with 233 additions and 151 deletions

View File

@ -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

16
TODO
View File

@ -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])

View File

@ -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 );
}

View File

@ -55,9 +55,7 @@ extern "C" {
typedef struct _VipsDrawink {
VipsDraw parent_instance;
/* Parameters.
*/
VipsArea *ink; /* With this */
VipsArrayDouble *ink;
/* Ink cast to pixel type.
*/

View File

@ -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*/

View File

@ -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 );

View File

@ -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@

View File

@ -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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <vips/vips.h>
/**
* 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 );
}

View File

@ -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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <vips/vips.h>
#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 );
}