This commit is contained in:
John Cupitt 2010-08-21 11:34:34 +00:00
parent 048ba1c211
commit f5faed779c
9 changed files with 424 additions and 130 deletions

View File

@ -13,6 +13,7 @@
- revise window_offset / window_size, again
- fix a mixup with ANY hints that caused performance problems on the main
benchmark
- rewritten im_circle as im_draw_circle, im_circle moved to almostdeprecated
12/5/10 started 7.22.2
- the conditional image of ifthenelse can be any format, a (!=0) is added if

5
TODO
View File

@ -1,6 +1,7 @@
- im__print_all() should work even without DEBUG
- rename most of the inplace ops as im_draw_line() etc.
use a hash for im__open_images
nip2 should be able to call RW image ops by copying them, see
im_draw_circle_copy()
- use D65 in cmsCreateLab4Profile() ? not sure

View File

@ -1217,6 +1217,40 @@ static im_function convf_desc = {
conv_dmask /* Arg list */
};
/* Args for im_circle.
*/
static im_arg_desc circle_args[] = {
IM_RW_IMAGE( "image" ),
IM_INPUT_INT( "cx" ),
IM_INPUT_INT( "cy" ),
IM_INPUT_INT( "radius" ),
IM_INPUT_INT( "intensity" )
};
/* Call im_circle via arg vector.
*/
static int
circle_vec( im_object *argv )
{
int cx = *((int *) argv[1]);
int cy = *((int *) argv[2]);
int radius = *((int *) argv[3]);
int intensity = *((int *) argv[4]);
return( im_circle( argv[0], cx, cy, radius, intensity ) );
}
/* Description of im_circle.
*/
static im_function circle_desc = {
"im_circle", /* Name */
"plot circle on image",
0, /* Flags */
circle_vec, /* Dispatch function */
IM_NUMBER( circle_args ), /* Size of arg list */
circle_args /* Arg list */
};
/* Package up all these functions.
*/
static im_function *deprecated_list[] = {
@ -1262,7 +1296,8 @@ static im_function *deprecated_list[] = {
&dilate_raw_desc,
&erode_raw_desc,
&similarity_area_desc,
&similarity_desc
&similarity_desc,
&circle_desc
};
/* Package of functions.

View File

@ -424,3 +424,37 @@ im_cache( IMAGE *in, IMAGE *out, int width, int height, int max )
0,
NULL, NULL ) );
}
/**
* im_circle:
* @im: image to draw on
* @cx: centre of circle
* @cy: centre of circle
* @radius: circle radius
* @intensity: value to draw
*
* Draws a circle on a 1-band 8-bit image.
*
* This an inplace operation, so @im is changed. It does not thread and will
* not work well as part of a pipeline. On 32-bit machines it will be limited
* to 2GB images.
*
* See also: im_fastline().
*
* Returns: 0 on success, or -1 on error.
*/
int
im_circle( IMAGE *im, int cx, int cy, int radius, int intensity )
{
PEL ink[1];
if( im_rwcheck( im ) ||
im_check_uncoded( "im_circle", im ) ||
im_check_mono( "im_circle", im ) ||
im_check_format( "im_circle", im, IM_BANDFMT_UCHAR ) )
return( -1 );
ink[0] = intensity;
return( im_draw_circle( im, cx, cy, radius, FALSE, ink ) );
}

View File

@ -206,9 +206,6 @@ 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 );
int im_convf( IMAGE *in, IMAGE *out, DOUBLEMASK *mask );
int im_convsepf( IMAGE *in, IMAGE *out, DOUBLEMASK *mask );
int im_conv_raw( IMAGE *in, IMAGE *out, INTMASK *mask );
@ -229,6 +226,12 @@ int im_erode_raw( IMAGE *in, IMAGE *out, INTMASK *m );
int im_dilate_raw( IMAGE *in, IMAGE *out, INTMASK *m );
int im_rank_raw( IMAGE *in, IMAGE *out, int xsize, int ysize, int order );
/* inplace
*/
int im_circle( IMAGE *im, int cx, int cy, int radius, int intensity );
int im_line( IMAGE *, int, int, int, int, int );
int im_segment( IMAGE *test, IMAGE *mask, int *segments );
#ifdef __cplusplus
}
#endif /*__cplusplus*/

View File

@ -41,7 +41,10 @@ int im_plotmask( IMAGE *im, int ix, int iy, PEL *ink, PEL *mask, Rect *r );
int im_smear( IMAGE *im, int ix, int iy, Rect *r );
int im_smudge( IMAGE *im, int ix, int iy, Rect *r );
int im_paintrect( IMAGE *im, Rect *r, PEL *ink );
int im_circle( IMAGE *im, int cx, int cy, int radius, int intensity );
int im_draw_circle( IMAGE *im,
int cx, int cy, int radius, gboolean fill, PEL *ink );
int im_draw_circle_copy( IMAGE *in, IMAGE *out,
int cx, int cy, int radius, gboolean fill, PEL *ink );
int im_insertplace( IMAGE *main, IMAGE *sub, int x, int y );
int im_fastline( IMAGE *im, int x1, int y1, int x2, int y2, PEL *pel );
int im_fastlineuser( IMAGE *im,

View File

@ -246,12 +246,10 @@ flood_scanline( Flood *flood, int x, int y, int *x1, int *x2 )
int i;
int len;
/*
g_assert( flood_connected( flood,
(PEL *) IM_IMAGE_ADDR( flood->test, x, y ) ) );
g_assert( !flood_painted( flood,
(PEL *) IM_IMAGE_ADDR( flood->mark, x, y ) ) );
*/
/* Search to the right for the first non-connected pixel. If the start
* pixel is unpainted, we know all the intervening pixels must be
@ -398,11 +396,11 @@ flood_free( Flood *flood )
}
static Flood *
flood_build( IMAGE *test, IMAGE *mark, int x, int y, PEL *ink, Rect *dout )
flood_new( IMAGE *test, IMAGE *mark, int x, int y, PEL *ink, Rect *dout )
{
Flood *flood = IM_NEW( NULL, Flood );
Flood *flood;
if( !flood )
if( !(flood = IM_NEW( NULL, Flood )) )
return( NULL );
flood->test = test;
flood->mark = mark;
@ -445,7 +443,8 @@ flood_build( IMAGE *test, IMAGE *mark, int x, int y, PEL *ink, Rect *dout )
* bounded by pixels that are equal to the ink colour, in other words, it
* searches for pixels enclosed by a line of @ink.
*
* The bounding box of the modified pixels is returned in @dout.
* The bounding box of the modified pixels is returned in @dout. @dout may be
* NULL.
*
* This an inplace operation, so @im is changed. It does not thread and will
* not work well as part of a pipeline. On 32-bit machines, it will be limited
@ -463,7 +462,7 @@ im_flood( IMAGE *im, int x, int y, PEL *ink, Rect *dout )
if( im_rwcheck( im ) ||
im_check_coding_known( "im_flood", im ) )
return( -1 );
if( !(flood = flood_build( im, im, x, y, ink, dout )) )
if( !(flood = flood_new( im, im, x, y, ink, dout )) )
return( -1 );
/* Flood to != ink.
@ -490,7 +489,8 @@ im_flood( IMAGE *im, int x, int y, PEL *ink, Rect *dout )
* bounded by pixels that are equal to the start pixel, in other words, it
* searches for a blob of same-coloured pixels.
*
* The bounding box of the modified pixels is returned in @dout.
* The bounding box of the modified pixels is returned in @dout. @dout may be
* NULL.
*
* This an inplace operation, so @im is changed. It does not thread and will
* not work well as part of a pipeline. On 32-bit machines, it will be limited
@ -509,7 +509,7 @@ im_flood_blob( IMAGE *im, int x, int y, PEL *ink, Rect *dout )
if( im_rwcheck( im ) ||
im_check_coding_known( "im_flood", im ) )
return( -1 );
if( !(flood = flood_build( im, im, x, y, ink, dout )) )
if( !(flood = flood_new( im, im, x, y, ink, dout )) )
return( -1 );
/* Edge is set by colour of start pixel.
@ -547,7 +547,8 @@ im_flood_blob( IMAGE *im, int x, int y, PEL *ink, Rect *dout )
* other words, it searches @test for a blob of same-coloured pixels, marking
* those pixels in @mark with @serial.
*
* The bounding box of the modified pixels is returned in @dout.
* The bounding box of the modified pixels is returned in @dout. @dout may be
* NULL.
*
* This an inplace operation, so @mark is changed. It does not thread and will
* not work well as part of a pipeline. On 32-bit machines, it will be limited
@ -578,7 +579,7 @@ im_flood_other( IMAGE *test, IMAGE *mark, int x, int y, int serial, Rect *dout )
if( *m == serial )
return( 0 );
if( !(flood = flood_build( test, mark, x, y, (PEL *) &serial, dout )) )
if( !(flood = flood_new( test, mark, x, y, (PEL *) &serial, dout )) )
return( -1 );
/* Edge is set by colour of start pixel.

View File

@ -1,13 +1,4 @@
/* @(#) writes a circle in a vasari file
* @(#) The circle is centred in the middle of the file (xsize/2, ysize/2)
* @(#) im must be a valid image
* @(#) int im_circle(pim, cx, cy, radius, intensity)
* @(#) IMAGE *pim;
* @(#) int cx, cy, radius, intensity;
* @(#)
* @(#) Return -1 on error 0 on sucess.
*
* Copyright 1990, N. Dessipris.
/* draw a circle on an image
*
* Author N. Dessipris
* Written on 30/05/1990
@ -21,6 +12,9 @@
* 6/3/10
* - don't im_invalidate() after paint, this now needs to be at a higher
* level
* 18/8/10
* - gtkdoc
* - rewritten: clips, fills, any bands, any format
*/
/*
@ -54,8 +48,6 @@
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <vips/vips.h>
@ -64,72 +56,243 @@
#include <dmalloc.h>
#endif /*WITH_DMALLOC*/
int
im_circle( IMAGE *im, int cx, int cy, int radius, int intensity )
{
PEL *start;
int size = 0;
int x, y, d, offset;
/* Our state.
*/
typedef struct {
/* Parameters.
*/
IMAGE *im; /* Test this image */
int cx, cy;
int radius;
gboolean fill;
PEL *ink; /* Copy of ink param */
if( im_rwcheck( im ) )
/* Derived stuff.
*/
size_t lsize;
size_t psize;
PEL *centre;
/* If the circle is entirely within the image, we have a faster
* noclip path.
*/
gboolean noclip;
} Circle;
/* Faster than memcpy for n < about 20.
*/
static inline void
circle_paint_pel( Circle *circle, PEL *q )
{
int j;
for( j = 0; j < circle->psize; j++ )
q[j] = circle->ink[j];
}
/* Paint, with clip.
*/
static void
circle_paint_pel_clip( Circle *circle, int x, int y )
{
if( x < 0 || x >= circle->im->Xsize )
return;
if( y < 0 || y >= circle->im->Ysize )
return;
circle_paint_pel( circle, (PEL *) IM_IMAGE_ADDR( circle->im, x, y ) );
}
/* Fill a scanline between points x1 and x2 inclusive. x1 < x2.
*/
static void
circle_paint_scanline( Circle *circle, int y, int x1, int x2 )
{
PEL *mp;
int i;
int len;
g_assert( x1 <= x2 );
if( y < 0 || y > circle->im->Ysize )
return;
if( x1 < 0 && x2 < 0 )
return;
if( x1 > circle->im->Xsize && x2 > circle->im->Xsize )
return;
x1 = IM_CLIP( 0, x1, circle->im->Xsize - 1 );
x2 = IM_CLIP( 0, x2, circle->im->Xsize - 1 );
mp = (PEL *) IM_IMAGE_ADDR( circle->im, x1, y );
len = x2 - x1 + 1;
for( i = 0; i < len; i++ ) {
circle_paint_pel( circle, mp );
mp += circle->psize;
}
}
static void
circle_octants( Circle *circle, int x, int y )
{
if( circle->fill ) {
const int cx = circle->cx;
const int cy = circle->cy;
circle_paint_scanline( circle, cy + y, cx - x, cx + x );
circle_paint_scanline( circle, cy - y, cx - x, cx + x );
circle_paint_scanline( circle, cy + x, cx - y, cx + y );
circle_paint_scanline( circle, cy - x, cx - y, cx + y );
}
else if( circle->noclip ) {
const size_t lsize = circle->lsize;
const size_t psize = circle->psize;
PEL *centre = circle->centre;
circle_paint_pel( circle, centre + lsize * y - psize * x );
circle_paint_pel( circle, centre + lsize * y + psize * x );
circle_paint_pel( circle, centre - lsize * y - psize * x );
circle_paint_pel( circle, centre - lsize * y + psize * x );
circle_paint_pel( circle, centre + lsize * x - psize * y );
circle_paint_pel( circle, centre + lsize * x + psize * y );
circle_paint_pel( circle, centre - lsize * x - psize * y );
circle_paint_pel( circle, centre - lsize * x + psize * y );
}
else {
const int cx = circle->cx;
const int cy = circle->cy;
circle_paint_pel_clip( circle, cx + y, cy - x );
circle_paint_pel_clip( circle, cx + y, cy + x );
circle_paint_pel_clip( circle, cx - y, cy - x );
circle_paint_pel_clip( circle, cx - y, cy + x );
circle_paint_pel_clip( circle, cx + x, cy - y );
circle_paint_pel_clip( circle, cx + x, cy + y );
circle_paint_pel_clip( circle, cx - x, cy - y );
circle_paint_pel_clip( circle, cx - x, cy + y );
}
}
static void
circle_free( Circle *circle )
{
IM_FREE( circle->ink );
im_free( circle );
}
static Circle *
circle_new( IMAGE *im, int cx, int cy, int radius, gboolean fill, PEL *ink )
{
Circle *circle;
if( !(circle = IM_NEW( NULL, Circle )) )
return( NULL );
circle->im = im;
circle->cx = cx;
circle->cy = cy;
circle->radius = radius;
circle->fill = fill;
circle->ink = NULL;
circle->lsize = IM_IMAGE_SIZEOF_LINE( im );
circle->psize = IM_IMAGE_SIZEOF_PEL( im );
circle->centre = (PEL *) IM_IMAGE_ADDR( im, cx, cy );
circle->noclip = FALSE;
if( !(circle->ink = (PEL *) im_malloc( NULL, circle->psize )) ) {
circle_free( circle );
return( NULL );
}
memcpy( circle->ink, ink, circle->psize );
if( cx - radius >= 0 && cx + radius < im->Xsize &&
cy - radius >= 0 && cy + radius < im->Ysize )
circle->noclip = TRUE;
return( circle );
}
static void
circle_paint( Circle *circle )
{
int x, y, d;
y = circle->radius;
d = 3 - 2 * circle->radius;
for( x = 0; x < y; x++ ) {
circle_octants( circle, x, y );
if( d < 0 )
d += 4 * x + 6;
else {
d += 4 * (x - y) + 10;
y--;
}
}
if( x == y )
circle_octants( circle, x, y );
}
/**
* im_draw_circle:
* @im: image to draw on
* @cx: centre of circle
* @cy: centre of circle
* @radius: circle radius
* @fill: fill the circle
* @ink: value to draw
*
* Draws a circle on an image. If @fill is %TRUE then the circle is filled,
* otherwise a 1-pixel-wide perimeter is drawn.
*
* @ink is an array of bytes containing a valid pixel for the image's format.
* It must have at least IM_IMAGE_SIZEOF_PEL( @im ) bytes.
*
* This an inplace operation, so @im is changed. It does not thread and will
* not work well as part of a pipeline. On 32-bit machines it will be limited
* to 2GB images.
*
* See also: im_fastline().
*
* Returns: 0 on success, or -1 on error.
*/
int
im_draw_circle( IMAGE *im, int cx, int cy, int radius, gboolean fill, PEL *ink )
{
Circle *circle;
if( cx + radius < 0 || cx - radius >= im->Xsize ||
cy + radius < 0 || cy - radius >= im->Ysize )
return( 0 );
if( im_rwcheck( im ) ||
im_check_coding_known( "im_draw_circle", im ) ||
!(circle = circle_new( im, cx, cy, radius, fill, ink )) )
return( -1 );
circle_paint( circle );
circle_free( circle );
return( 0 );
}
/* One we can call from nip. Grr! Should be a way to wrap these
* automatically. Maybe nip could do it if it sees a RW image argument?
*/
int
im_draw_circle_copy( IMAGE *in, IMAGE *out,
int cx, int cy, int radius, gboolean fill, PEL *ink )
{
IMAGE *t;
if( !(t = im_open_local( out, "im_flood_blob_copy", "t" )) ||
im_copy( in, t ) ||
im_draw_circle( t, cx, cy, radius, fill, ink ) ||
im_copy( t, out ) )
return( -1 );
/* Check args */
if ( (im->data == NULL)||(im->BandFmt != IM_BANDFMT_UCHAR)||
(im->Bands != 1))
{
im_error("im_circle: ", "%s", _( "able to write input image") );
return(-1);
}
if ((intensity > 255)||(intensity <= 0))
{
im_error( "im_circle", "%s", _( "intensity between 0 and 255") );
return(-1);
}
/* Check if circle fits into image */
if ( ((radius+cy)> im->Ysize - 1) || ((cy-radius)< 0 ) ||
((radius+cx)> im->Xsize - 1) || ((cx-radius) < 0 ) )
{
im_error( "im_circle", "%s", _( "The circle does not fit in image") );
return(-1);
}
/* Draw the circle */
size = im->Xsize;
start = (PEL*)im->data;
offset = cy * im->Xsize + cx; /* point at the center of the circle */
x = 0;
y = radius;
d = 3 - 2 * radius;
while ( x < y )
{
*(start + offset + size * y + x) = (PEL)intensity;
*(start + offset + size * x + y) = (PEL)intensity;
*(start + offset + size * y - x) = (PEL)intensity;
*(start + offset + size * x - y) = (PEL)intensity;
*(start + offset - size * y - x) = (PEL)intensity;
*(start + offset - size * x - y) = (PEL)intensity;
*(start + offset - size * y + x) = (PEL)intensity;
*(start + offset - size * x + y) = (PEL)intensity;
if (d < 0 )
d += ( 4 * x + 6 );
else
{
d += ( 4 * ( x - y ) + 10 );
y--;
}
x++;
}
if ( x== y )
{
*(start + offset + size * y + x) = (PEL)intensity;
*(start + offset + size * x + y) = (PEL)intensity;
*(start + offset + size * y - x) = (PEL)intensity;
*(start + offset + size * x - y) = (PEL)intensity;
*(start + offset - size * y - x) = (PEL)intensity;
*(start + offset - size * x - y) = (PEL)intensity;
*(start + offset - size * y + x) = (PEL)intensity;
*(start + offset - size * x + y) = (PEL)intensity;
}
return(0);
return( 0 );
}

View File

@ -54,40 +54,6 @@
*
*/
/* Args for im_circle.
*/
static im_arg_desc circle_args[] = {
IM_RW_IMAGE( "image" ),
IM_INPUT_INT( "cx" ),
IM_INPUT_INT( "cy" ),
IM_INPUT_INT( "radius" ),
IM_INPUT_INT( "intensity" )
};
/* Call im_circle via arg vector.
*/
static int
circle_vec( im_object *argv )
{
int cx = *((int *) argv[1]);
int cy = *((int *) argv[2]);
int radius = *((int *) argv[3]);
int intensity = *((int *) argv[4]);
return( im_circle( argv[0], cx, cy, radius, intensity ) );
}
/* Description of im_circle.
*/
static im_function circle_desc = {
"im_circle", /* Name */
"plot circle on image",
0, /* Flags */
circle_vec, /* Dispatch function */
IM_NUMBER( circle_args ), /* Size of arg list */
circle_args /* Arg list */
};
/* Args for im_insertplace.
*/
static im_arg_desc insertplace_args[] = {
@ -316,6 +282,92 @@ static im_function flood_other_copy_desc = {
flood_other_copy_args /* Arg list */
};
/* Args for im_draw_circle.
*/
static im_arg_desc draw_circle_args[] = {
IM_RW_IMAGE( "image" ),
IM_INPUT_INT( "cx" ),
IM_INPUT_INT( "cy" ),
IM_INPUT_INT( "radius" ),
IM_INPUT_INT( "fill" ),
IM_INPUT_DOUBLEVEC( "ink" )
};
/* Call im_draw_circle via arg vector.
*/
static int
draw_circle_vec( im_object *argv )
{
IMAGE *in = argv[0];
int cx = *((int *) argv[1]);
int cy = *((int *) argv[2]);
int radius = *((int *) argv[3]);
int fill = *((int *) argv[4]);
im_doublevec_object *dv = (im_doublevec_object *) argv[5];
PEL *ink;
if( !(ink = vector_to_ink( in, dv->vec )) )
return( -1 );
return( im_draw_circle( in, cx, cy, radius, fill, ink ) );
}
/* Description of im_draw_circle.
*/
static im_function draw_circle_desc = {
"im_draw_circle", /* Name */
"draw circle on image",
0, /* Flags */
draw_circle_vec, /* Dispatch function */
IM_NUMBER( draw_circle_args ), /* Size of arg list */
draw_circle_args /* Arg list */
};
/* Args for im_draw_circle_copy.
*/
static im_arg_desc draw_circle_copy_args[] = {
IM_INPUT_IMAGE( "in" ),
IM_OUTPUT_IMAGE( "out" ),
IM_INPUT_INT( "cx" ),
IM_INPUT_INT( "cy" ),
IM_INPUT_INT( "radius" ),
IM_INPUT_INT( "fill" ),
IM_INPUT_DOUBLEVEC( "ink" )
};
/* Call im_draw_circle_copy via arg vector.
*/
static int
draw_circle_copy_vec( im_object *argv )
{
IMAGE *in = argv[0];
IMAGE *out = argv[1];
int cx = *((int *) argv[2]);
int cy = *((int *) argv[3]);
int radius = *((int *) argv[4]);
int fill = *((int *) argv[5]);
im_doublevec_object *dv = (im_doublevec_object *) argv[6];
PEL *ink;
if( !(ink = vector_to_ink( in, dv->vec )) )
return( -1 );
return( im_draw_circle_copy( in, out, cx, cy, radius, fill, ink ) );
}
/* Description of im_draw_circle_copy.
*/
static im_function draw_circle_copy_desc = {
"im_draw_circle_copy", /* Name */
"draw circle on image",
0, /* Flags */
draw_circle_copy_vec, /* Dispatch function */
IM_NUMBER( draw_circle_copy_args ), /* Size of arg list */
draw_circle_copy_args /* Arg list */
};
/* To do:
* these all need some kind of pel type
*
@ -331,7 +383,8 @@ static im_function flood_other_copy_desc = {
/* Package up all these functions.
*/
static im_function *inplace_list[] = {
&circle_desc,
&draw_circle_desc,
&draw_circle_copy_desc,
&flood_copy_desc,
&flood_blob_copy_desc,
&flood_other_copy_desc,