stuff
This commit is contained in:
parent
8229aceac4
commit
be6306172c
@ -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
6
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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 ) );
|
||||
}
|
||||
|
@ -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 );
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 );
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 );
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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@
|
||||
|
111
libvips/morphology/im_label_regions.c
Normal file
111
libvips/morphology/im_label_regions.c
Normal 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 );
|
||||
}
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user