diff --git a/ChangeLog b/ChangeLog
index 9b69524c..8ff3e18a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/TODO b/TODO
index 42efe4a0..6f243468 100644
--- a/TODO
+++ b/TODO
@@ -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
diff --git a/libvips/colour/colour_dispatch.c b/libvips/colour/colour_dispatch.c
index 735eb254..7e8b242a 100644
--- a/libvips/colour/colour_dispatch.c
+++ b/libvips/colour/colour_dispatch.c
@@ -86,7 +86,7 @@
* of a and b.
*
* You cannot perform calculations on LabQ
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.
*
*
@@ -118,7 +118,15 @@
*
* XYZ
*
- * 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.
+ *
+ *
+ *
+ *
+ * Yxy
+ *
+ * CIE Yxy colour space represented as a three-band %IM_BANDFMT_FLOAT
* image.
*
*
@@ -146,7 +154,7 @@
*
*
*
- * LCh
+ * UCS
*
* A colour space based on the CMC(1:1) colour difference measurement.
* This is a highly uniform colour space, much better than CIELAB for
diff --git a/libvips/conversion/conver_dispatch.c b/libvips/conversion/conver_dispatch.c
index ad5a91ee..0fcfd3fe 100644
--- a/libvips/conversion/conver_dispatch.c
+++ b/libvips/conversion/conver_dispatch.c
@@ -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,
diff --git a/libvips/conversion/im_insert.c b/libvips/conversion/im_insert.c
index 0d993f94..0e80a6a2 100644
--- a/libvips/conversion/im_insert.c
+++ b/libvips/conversion/im_insert.c
@@ -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 );
+}
diff --git a/libvips/deprecated/deprecated_dispatch.c b/libvips/deprecated/deprecated_dispatch.c
index a7519979..f308a5d1 100644
--- a/libvips/deprecated/deprecated_dispatch.c
+++ b/libvips/deprecated/deprecated_dispatch.c
@@ -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,
diff --git a/libvips/deprecated/rename.c b/libvips/deprecated/rename.c
index e593ca1f..a2d8530d 100644
--- a/libvips/deprecated/rename.c
+++ b/libvips/deprecated/rename.c
@@ -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 ) );
+}
diff --git a/libvips/include/vips/conversion.h b/libvips/include/vips/conversion.h
index 79273eed..f48a6664 100644
--- a/libvips/include/vips/conversion.h
+++ b/libvips/include/vips/conversion.h
@@ -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 );
diff --git a/libvips/include/vips/deprecated.h b/libvips/include/vips/deprecated.h
index 1244d5d0..c0e18991 100644
--- a/libvips/include/vips/deprecated.h
+++ b/libvips/include/vips/deprecated.h
@@ -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
}
diff --git a/libvips/include/vips/inplace.h b/libvips/include/vips/inplace.h
index c5187195..4a01a307 100644
--- a/libvips/include/vips/inplace.h
+++ b/libvips/include/vips/inplace.h
@@ -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 );
diff --git a/libvips/include/vips/morphology.h b/libvips/include/vips/morphology.h
index 1a6ac7cb..780916dc 100644
--- a/libvips/include/vips/morphology.h
+++ b/libvips/include/vips/morphology.h
@@ -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
}
diff --git a/libvips/inplace/im_flood_other.c b/libvips/inplace/im_flood_other.c
index 30f3bce9..fb7947d7 100644
--- a/libvips/inplace/im_flood_other.c
+++ b/libvips/inplace/im_flood_other.c
@@ -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 );
-}
-
diff --git a/libvips/inplace/inplace_dispatch.c b/libvips/inplace/inplace_dispatch.c
index 49b8cd1b..2a5fa686 100644
--- a/libvips/inplace/inplace_dispatch.c
+++ b/libvips/inplace/inplace_dispatch.c
@@ -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
};
diff --git a/libvips/morphology/Makefile.am b/libvips/morphology/Makefile.am
index c57a9dd1..9de3bb12 100644
--- a/libvips/morphology/Makefile.am
+++ b/libvips/morphology/Makefile.am
@@ -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@
diff --git a/libvips/morphology/im_label_regions.c b/libvips/morphology/im_label_regions.c
new file mode 100644
index 00000000..2113c11d
--- /dev/null
+++ b/libvips/morphology/im_label_regions.c
@@ -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
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#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 );
+}
diff --git a/libvips/morphology/morph_dispatch.c b/libvips/morphology/morph_dispatch.c
index fda7907a..14e88567 100644
--- a/libvips/morphology/morph_dispatch.c
+++ b/libvips/morphology/morph_dispatch.c
@@ -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,