This commit is contained in:
John Cupitt 2009-11-05 13:35:21 +00:00
parent 8229aceac4
commit be6306172c
16 changed files with 269 additions and 140 deletions

View File

@ -49,7 +49,7 @@
and else parts
- better im_check() functions
- added im_flood_other() as start of simple segmentation operator
- added im_segment()
- added im_label_regions()
- im_printlines(), im_debugim() deprecated (use im_vips2csv() instead)
- meta, header, callback, error, region, check, generate, memory gtkdocs
- removed printlines tool, vips2csv is much better
@ -67,7 +67,7 @@
- threadgroup no longer has any default action, you must attach a work
function
- added im_copy_file()
- added im_insertplaceset()
- added im_insertset()
- im_insertplace() allows small to be outside big
- added im__colour_difference(), colour ops now work on any image format
- added im_col_display_get_table(), so display tables are now shared by name

6
TODO
View File

@ -1,11 +1,9 @@
- vips.c should drop "set" suffix from operators
- poor SMP scaling in benchmark
avg is different? used to 120.134, now 120.151
- segment should be in morph
- insertplaceset should be with insert in conversion
- _raw() variants should be deprecated?
- look through more sections for stuff in the wrong place

View File

@ -86,7 +86,7 @@
* of a and b.
*
* You cannot perform calculations on <code>LabQ</code> images (they are
* tagged with IM_CODING_LABQ), though a few operations such as
* tagged with %IM_CODING_LABQ), though a few operations such as
* im_extract_area() will work directly with them.
* </para>
* </listitem>
@ -118,7 +118,15 @@
* <para>
* <emphasis><code>XYZ</code></emphasis>
*
* CIE XYZ colour space represented as a three-band #IM_BANDFMT_FLOAT
* CIE XYZ colour space represented as a three-band %IM_BANDFMT_FLOAT
* image.
* </para>
* </listitem>
* <listitem>
* <para>
* <emphasis><code>Yxy</code></emphasis>
*
* CIE Yxy colour space represented as a three-band %IM_BANDFMT_FLOAT
* image.
* </para>
* </listitem>
@ -146,7 +154,7 @@
* </listitem>
* <listitem>
* <para>
* <emphasis><code>LCh</code></emphasis>
* <emphasis><code>UCS</code></emphasis>
*
* A colour space based on the CMC(1:1) colour difference measurement.
* This is a highly uniform colour space, much better than CIELAB for

View File

@ -921,6 +921,47 @@ static im_function insert_desc = {
insert_args /* Arg list */
};
/* Args for im_insertset.
*/
static im_arg_desc insertset_args[] = {
IM_INPUT_IMAGE( "main" ),
IM_INPUT_IMAGE( "sub" ),
IM_OUTPUT_IMAGE( "out" ),
IM_INPUT_INTVEC( "x" ),
IM_INPUT_INTVEC( "y" )
};
/* Call im_insertplaceset via arg vector.
*/
static int
insertset_vec( im_object *argv )
{
im_intvec_object *xv = (im_intvec_object *) argv[3];
im_intvec_object *yv = (im_intvec_object *) argv[4];
if( xv->n != yv->n ) {
im_error( "im_insertset", "%s",
_( "vectors not same length" ) );
return( -1 );
}
if( im_insertset( argv[0], argv[1], argv[2], xv->n, xv->vec, yv->vec ) )
return( -1 );
return( 0 );
}
/* Description of im_insertset.
*/
static im_function insertset_desc = {
"im_insertset", /* Name */
"insert sub into main at every position in x, y",
0, /* Flags */
insertset_vec, /* Dispatch function */
IM_NUMBER( insertset_args ), /* Size of arg list */
insertset_args /* Arg list */
};
/* Call im_insert_noexpand via arg vector.
*/
static int
@ -1376,6 +1417,7 @@ static im_function *conv_list[] = {
&gbandjoin_desc,
&grid_desc,
&insert_desc,
&insertset_desc,
&insert_noexpand_desc,
&embed_desc,
&lrjoin_desc,

View File

@ -385,3 +385,28 @@ im_insert_noexpand( IMAGE *main, IMAGE *sub, IMAGE *out, int x, int y )
return( 0 );
}
/* Insert sub repeatedly. This can be a lot quicker for large n, but will use
* (potentially) a lot of memory.
*/
int
im_insertset( IMAGE *main, IMAGE *sub, IMAGE *out, int n, int *x, int *y )
{
IMAGE *t;
int i;
/* Copy to a memory image, zap that, then copy to out.
*/
if( !(t = im_open_local( out, "im_insertset", "t" )) ||
im_copy( main, t ) )
return( -1 );
for( i = 0; i < n; i++ )
if( im_insertplace( t, sub, x[i], y[i] ) )
return( -1 );
if( im_copy( t, out ) )
return( -1 );
return( 0 );
}

View File

@ -361,6 +361,37 @@ static im_function icc_export_desc = {
icc_export_args /* Arg list */
};
/* Args for im_segment().
*/
static im_arg_desc segment_args[] = {
IM_INPUT_IMAGE( "test" ),
IM_OUTPUT_IMAGE( "mask" ),
IM_OUTPUT_INT( "segments" )
};
/* Call im_segment() via arg vector.
*/
static int
segment_vec( im_object *argv )
{
IMAGE *test = argv[0];
IMAGE *mask = argv[1];
int *serial = (int *) argv[2];
return( im_segment( test, mask, serial ) );
}
/* Description of im_segment().
*/
static im_function segment_desc = {
"im_segment", /* Name */
"number continuous regions in an image",
0, /* Flags */
segment_vec, /* Dispatch function */
IM_NUMBER( segment_args ),/* Size of arg list */
segment_args /* Arg list */
};
static int
print_vec( im_object *argv )
{
@ -778,6 +809,7 @@ static im_function *deprecated_list[] = {
&print_desc,
&slice_desc,
&bernd_desc,
&segment_desc,
&line_desc,
&thresh_desc,
&similarity_area_desc,

View File

@ -226,3 +226,9 @@ im_icc_export( IMAGE *in, IMAGE *out,
return( im_icc_export_depth( in, out,
8, output_profile_filename, intent ) );
}
int
im_segment( IMAGE *test, IMAGE *mask, int *segments )
{
return( im_label_regions( test, mask, segments ) );
}

View File

@ -94,6 +94,7 @@ int im_bandjoin( IMAGE *in1, IMAGE *in2, IMAGE *out );
int im_gbandjoin( IMAGE **in, IMAGE *out, int n );
int im_insert( IMAGE *main, IMAGE *sub, IMAGE *out, int x, int y );
int im_insert_noexpand( IMAGE *main, IMAGE *sub, IMAGE *out, int x, int y );
int im_insertset( IMAGE *main, IMAGE *sub, IMAGE *out, int n, int *x, int *y );
int im_lrjoin( IMAGE *in1, IMAGE *in2, IMAGE *out );
int im_tbjoin( IMAGE *in1, IMAGE *in2, IMAGE *out );
int im_replicate( IMAGE *in, IMAGE *out, int across, int down );

View File

@ -350,6 +350,7 @@ int im_bernd( const char *tiffname, int x, int y, int w, int h );
int im_resize_linear( IMAGE *, IMAGE *, int, int );
int im_line( IMAGE *, int, int, int, int, int );
int im_segment( IMAGE *test, IMAGE *mask, int *segments );
#ifdef __cplusplus
}

View File

@ -54,7 +54,7 @@ int im_flood_blob_copy( IMAGE *in, IMAGE *out, int x, int y, PEL *ink );
int im_flood_other( IMAGE *mask, IMAGE *test, int x, int y, int serial );
int im_flood_other_copy( IMAGE *mask, IMAGE *test, IMAGE *out,
int x, int y, int serial );
int im_segment( IMAGE *test, IMAGE *mask, int *segments );
int im_lineset( IMAGE *in, IMAGE *out, IMAGE *mask, IMAGE *ink,
int n, int *x1v, int *y1v, int *x2v, int *y2v );

View File

@ -50,6 +50,7 @@ int im_maxvalue( IMAGE **in, IMAGE *out, int n );
int im_cntlines( IMAGE *im, double *nolines, int flag );
int im_zerox( IMAGE *in, IMAGE *out, int flag );
int im_profile( IMAGE *in, IMAGE *out, int dir );
int im_label_regions( IMAGE *test, IMAGE *mask, int *segments );
#ifdef __cplusplus
}

View File

@ -328,50 +328,3 @@ im_flood_other_copy( IMAGE *mask, IMAGE *test, IMAGE *out,
return( 0 );
}
/* Now: segment with im_flood_other().
*/
int
im_segment( 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_segment", "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_incheck( 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( 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

@ -162,55 +162,6 @@ static im_function lineset_desc = {
lineset_args /* Arg list */
};
/* Args for im_insertplaceset.
*/
static im_arg_desc insertplaceset_args[] = {
IM_INPUT_IMAGE( "main" ),
IM_INPUT_IMAGE( "sub" ),
IM_OUTPUT_IMAGE( "out" ),
IM_INPUT_INTVEC( "x" ),
IM_INPUT_INTVEC( "y" )
};
/* Call im_insertplaceset via arg vector.
*/
static int
insertplaceset_vec( im_object *argv )
{
im_intvec_object *xv = (im_intvec_object *) argv[3];
im_intvec_object *yv = (im_intvec_object *) argv[4];
int i;
if( xv->n != yv->n ) {
im_error( "im_insertplaceset", "%s",
_( "vectors not same length" ) );
return( -1 );
}
/* Copy the image then repeatedly im_insertplace(). This will make
* "out" into a "t", usually.
*/
if( im_copy( argv[0], argv[2] ) )
return( -1 );
for( i = 0; i < xv->n; i++ )
if( im_insertplace( argv[2], argv[1], xv->vec[i], yv->vec[i] ) )
return( -1 );
return( 0 );
}
/* Description of im_insertplaceset.
*/
static im_function insertplaceset_desc = {
"im_insertplaceset", /* Name */
"insert sub into main at every position in x, y",
0, /* Flags */
insertplaceset_vec, /* Dispatch function */
IM_NUMBER( insertplaceset_args ), /* Size of arg list */
insertplaceset_args /* Arg list */
};
/* Calculate a pixel for an image from a vec of double. Valid while im is
* valid.
*/
@ -320,37 +271,6 @@ static im_function flood_other_copy_desc = {
flood_other_copy_args /* Arg list */
};
/* Args for im_segment().
*/
static im_arg_desc segment_args[] = {
IM_INPUT_IMAGE( "test" ),
IM_OUTPUT_IMAGE( "mask" ),
IM_OUTPUT_INT( "segments" )
};
/* Call im_segment() via arg vector.
*/
static int
segment_vec( im_object *argv )
{
IMAGE *test = argv[0];
IMAGE *mask = argv[1];
int *serial = (int *) argv[2];
return( im_segment( test, mask, serial ) );
}
/* Description of im_segment().
*/
static im_function segment_desc = {
"im_segment", /* Name */
"number continuous regions in an image",
0, /* Flags */
segment_vec, /* Dispatch function */
IM_NUMBER( segment_args ),/* Size of arg list */
segment_args /* Arg list */
};
/* To do:
* these all need some kind of pel type
*
@ -369,9 +289,7 @@ static im_function *inplace_list[] = {
&circle_desc,
&flood_blob_copy_desc,
&flood_other_copy_desc,
&segment_desc,
&insertplace_desc,
&insertplaceset_desc,
&lineset_desc
};

View File

@ -8,6 +8,7 @@ libmorphology_la_SOURCES = \
im_rank_image.c \
im_zerox.c \
morph_dispatch.c \
im_label_regions.c \
im_profile.c
INCLUDES = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@

View File

@ -0,0 +1,111 @@
/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif /*WITH_DMALLOC*/
/**
* im_label_regions():
* @test: image to test
* @mask: write labelled regions here
* @segments: return number of regions here
*
* The @test image is repeatedly scanned and regions of 4-connected pixels
* with the same pixel value found. 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.
*/
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( 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

@ -331,10 +331,41 @@ static im_function rank_raw_desc = {
"rank filter nth element of xsize/ysize window, no border",
IM_FN_PIO, /* Flags */
rank_raw_vec, /* Dispatch function */
IM_NUMBER( rank_args ), /* Size of arg list */
IM_NUMBER( rank_args ), /* Size of arg list */
rank_args /* Arg list */
};
/* Args for im_label_regions().
*/
static im_arg_desc label_regions_args[] = {
IM_INPUT_IMAGE( "test" ),
IM_OUTPUT_IMAGE( "mask" ),
IM_OUTPUT_INT( "segments" )
};
/* Call im_label_regions() via arg vector.
*/
static int
label_regions_vec( im_object *argv )
{
IMAGE *test = argv[0];
IMAGE *mask = argv[1];
int *serial = (int *) argv[2];
return( im_label_regions( test, mask, serial ) );
}
/* Description of im_label_regions().
*/
static im_function label_regions_desc = {
"im_label_regions", /* Name */
"number continuous regions in an image",
0, /* Flags */
label_regions_vec, /* Dispatch function */
IM_NUMBER( label_regions_args ),/* Size of arg list */
label_regions_args /* Arg list */
};
/* Package up all these functions.
*/
static im_function *morph_list[] = {
@ -343,6 +374,7 @@ static im_function *morph_list[] = {
&rank_desc,
&rank_image_desc,
&maxvalue_desc,
&label_regions_desc,
&zerox_desc,
&rank_raw_desc,
&dilate_raw_desc,