/** * im_region_region: * @reg: region to operate upon * @dest: region to connect to * @r: #Rect of pixels you need to be able to address * @x: postion of @r in @dest * @y: postion of @r in @dest * * Make IM_REGION_ADDR() on @reg go to @dest instead. * * @r is the part of @reg which you want to be able to address (this * effectively becomes the valid field), (@x, @y) is the top LH corner of the * corresponding area in @dest. * * Performs all clipping necessary to ensure that @reg->valid is indeed * valid. * * If the region we attach to is modified, we can be left with dangling * pointers! If the region we attach to is on another image, the two images * must have * the same sizeof( pel ). * * Returns: 0 on success, or -1 for error. */ int im_region_region( REGION *reg, REGION *dest, Rect *r, int x, int y ) { Rect image; Rect wanted; Rect clipped; Rect clipped2; Rect final; /* Sanity check. */ if( !dest->data || IM_IMAGE_SIZEOF_PEL( dest->im ) != IM_IMAGE_SIZEOF_PEL( reg->im ) ) { im_error( "im_region_region", "%s", _( "inappropriate region type" ) ); return( -1 ); } im__region_check_ownership( reg ); /* We can't test g_assert( dest->thread == g_thread_self() ); * since we can have several threads writing to the same region in * threadgroup. */ /* Clip r against size of the image. */ image.top = 0; image.left = 0; image.width = reg->im->Xsize; image.height = reg->im->Ysize; im_rect_intersectrect( r, &image, &clipped ); /* Translate to dest's coordinate space and clip against the available * pixels. */ wanted.left = x + (clipped.left - r->left); wanted.top = y + (clipped.top - r->top); wanted.width = clipped.width; wanted.height = clipped.height; /* Test that dest->valid is large enough. */ if( !im_rect_includesrect( &dest->valid, &wanted ) ) { im_error( "im_region_region", "%s", _( "dest too small" ) ); return( -1 ); } /* Clip against the available pixels. */ im_rect_intersectrect( &wanted, &dest->valid, &clipped2 ); /* Translate back to reg's coordinate space and set as valid. */ final.left = r->left + (clipped2.left - wanted.left);
/* Like im_prepare(): fill reg with data, ready to be read from by our caller. * Unlike im_prepare(), rather than allocating memory local to reg for the * result, we guarantee that we will fill the pixels in dest at offset x, y. * In other words, we generate an extra copy operation if necessary. */ int im_prepare_to( REGION *reg, REGION *dest, Rect *r, int x, int y ) { IMAGE *im = reg->im; Rect image; Rect wanted; Rect clipped; Rect clipped2; Rect final; if( im__test_kill( im ) ) return( -1 ); /* Sanity check. */ if( !dest->data || dest->im->BandFmt != reg->im->BandFmt || dest->im->Bands != reg->im->Bands ) { im_error( "im_prepare_to", _( "inappropriate region type" ) ); return( -1 ); } /* clip r first against the size of reg->im, then again against the * memory we have available to write to on dest. Just like * im_region_region() */ image.top = 0; image.left = 0; image.width = reg->im->Xsize; image.height = reg->im->Ysize; im_rect_intersectrect( r, &image, &clipped ); assert( clipped.left == r->left ); assert( clipped.top == r->top ); wanted.left = x + (clipped.left - r->left); wanted.top = y + (clipped.top - r->top); wanted.width = clipped.width; wanted.height = clipped.height; /* Test that dest->valid is large enough. */ if( !im_rect_includesrect( &dest->valid, &wanted ) ) { im_error( "im_prepare_to", _( "dest too small" ) ); return( -1 ); } im_rect_intersectrect( &wanted, &dest->valid, &clipped2 ); /* Translate back to reg's coordinate space and set as valid. */ final.left = r->left + (clipped2.left - wanted.left);
/** * im_region_buffer: * @reg: region to operate upon * @r: #Rect of pixels you need to be able to address * * The region is transformed so that at least @r pixels are available as a * memory buffer. * * Returns: 0 on success, or -1 for error. */ int im_region_buffer( REGION *reg, Rect *r ) { IMAGE *im = reg->im; Rect image; Rect clipped; im__region_check_ownership( reg ); /* Clip against image. */ image.top = 0; image.left = 0; image.width = im->Xsize; image.height = im->Ysize; im_rect_intersectrect( r, &image, &clipped ); /* Test for empty. */ if( im_rect_isempty( &clipped ) ) { im_error( "im_region_buffer", "%s", _( "valid clipped to nothing" ) ); return( -1 ); } /* Have we been asked to drop caches? We want to throw everything * away. * * If not, try to reuse the current buffer. */ if( reg->invalid ) { im_region_reset( reg ); if( !(reg->buffer = im_buffer_new( im, &clipped )) ) return( -1 ); } else { /* Don't call im_region_reset() ... we combine buffer unref * and new buffer ref in one call to reduce malloc/free * cycling. */ IM_FREEF( im_window_unref, reg->window ); if( !(reg->buffer = im_buffer_unref_ref( reg->buffer, im, &clipped )) ) return( -1 ); } /* Init new stuff. */ reg->valid = reg->buffer->area; reg->bpl = IM_IMAGE_SIZEOF_PEL( im ) * reg->buffer->area.width; reg->type = IM_REGION_BUFFER; reg->data = reg->buffer->buf; return( 0 ); }
/* Region should be a pixel buffer. On return, check * reg->buffer->done to see if there are pixels there already. Otherwise, you * need to calculate. */ int im_region_buffer( REGION *reg, Rect *r ) { IMAGE *im = reg->im; Rect image; Rect clipped; im__region_check_ownership( reg ); /* Clip against image. */ image.top = 0; image.left = 0; image.width = im->Xsize; image.height = im->Ysize; im_rect_intersectrect( r, &image, &clipped ); /* Test for empty. */ if( im_rect_isempty( &clipped ) ) { im_error( "im_region_buffer", _( "valid clipped to nothing" ) ); return( -1 ); } /* Already have stuff? */ if( reg->type == IM_REGION_BUFFER && im_rect_includesrect( ®->valid, &clipped ) && reg->buffer && !reg->buffer->invalid ) return( 0 ); /* Don't call im_region_reset() ... we combine buffer unref and new * buffer ref in one call to reduce malloc/free cycling. */ IM_FREEF( im_window_unref, reg->window ); if( !(reg->buffer = im_buffer_unref_ref( reg->buffer, im, &clipped )) ) return( -1 ); /* Init new stuff. */ reg->valid = reg->buffer->area; reg->bpl = IM_IMAGE_SIZEOF_PEL( im ) * reg->buffer->area.width; reg->type = IM_REGION_BUFFER; reg->data = reg->buffer->buf; return( 0 ); }
/* Loop over the output region, filling with data from cache. */ static int tile_cache_fill( REGION *out, void *seq, void *a, void *b ) { REGION *in = (REGION *) seq; Read *read = (Read *) b; const int tw = read->tile_width; const int th = read->tile_height; Rect *r = &out->valid; /* Find top left of tiles we need. */ int xs = (r->left / tw) * tw; int ys = (r->top / th) * th; int x, y; g_mutex_lock( read->lock ); for( y = ys; y < IM_RECT_BOTTOM( r ); y += th ) for( x = xs; x < IM_RECT_RIGHT( r ); x += tw ) { Tile *tile; Rect tarea; Rect hit; if( !(tile = tile_find( read, in, x, y )) ) { g_mutex_unlock( read->lock ); return( -1 ); } /* The area of the tile. */ tarea.left = x; tarea.top = y; tarea.width = tw; tarea.height = th; /* The part of the tile that we need. */ im_rect_intersectrect( &tarea, r, &hit ); copy_region( tile->region, out, &hit ); } g_mutex_unlock( read->lock ); return( 0 ); }
static int im_pvmerge( Rect *tarea, Rect *barea, Rect *outarea ) { Rect overlap; /* Compute overlap. */ im_rect_intersectrect( tarea, barea, &overlap ); outarea->width = overlap.width; outarea->height = barea->top + barea->height ; outarea->left = overlap.left; outarea->top = tarea->top; return( 0 ); }
static int im_phmerge( Rect *larea, Rect *rarea, Rect *outarea ) { Rect overlap; /* Compute overlap. */ im_rect_intersectrect( larea, rarea, &overlap ); outarea->width = rarea->left + rarea->width; outarea->height = overlap.height; outarea->top = overlap.top; outarea->left = larea->left; return( 0 ); }
/* Find max and min of visible area of image. */ static gboolean conversionview_findmaxmin( Imagemodel *imagemodel, double *min, double *max ) { Conversion *conv = imagemodel->conv; Rect a, b; conversion_disp_to_im_rect( conv, &imagemodel->visible, &a ); im_rect_intersectrect( &a, &conv->image, &b ); if( findmaxmin( imageinfo_get( FALSE, conv->ii ), b.left, b.top, b.width, b.height, min, max ) ) { error_top( _( "Unable to find image range." ) ); error_sub( _( "Find image range failed." ) ); error_vips(); return( FALSE ); } return( TRUE ); }
static Mask * mask_new( VipsImage *im, int x, int y, PEL *ink, VipsImage *mask_im ) { Mask *mask; Rect area, image; if( im_check_coding_noneorlabq( "im_draw_mask", im ) || im_incheck( mask_im ) || im_check_mono( "im_draw_mask", mask_im ) || im_check_uncoded( "im_draw_mask", mask_im ) || im_check_format( "im_draw_mask", mask_im, IM_BANDFMT_UCHAR ) || !(mask = IM_NEW( NULL, Mask )) ) return( NULL ); if( !im__draw_init( DRAW( mask ), im, ink ) ) { mask_free( mask ); return( NULL ); } mask->x = x; mask->y = y; mask->mask_im = mask_im; /* Find the area we draw on the image. */ area.left = x; area.top = y; area.width = mask_im->Xsize; area.height = mask_im->Ysize; image.left = 0; image.top = 0; image.width = im->Xsize; image.height = im->Ysize; im_rect_intersectrect( &area, &image, &mask->image_clip ); /* And the area of the mask image we use. */ mask->mask_clip = mask->image_clip; mask->mask_clip.left -= x; mask->mask_clip.top -= y; return( mask ); }
/** * im_draw_image: * @image: image to draw on * @sub: image to draw * @x: position to insert * @y: position to insert * * Draw @sub on top of @image at position @x, @y. The two images must have the * same * Coding. If @sub has 1 band, the bands will be duplicated to match the * number of bands in @image. @sub will be converted to @image's format, see * im_clip2fmt(). * * See also: im_insert(). * * Returns: 0 on success, or -1 on error. */ int im_draw_image( VipsImage *image, VipsImage *sub, int x, int y ) { Rect br, sr, clip; PEL *p, *q; int z; /* Make rects for main and sub and clip. */ br.left = 0; br.top = 0; br.width = image->Xsize; br.height = image->Ysize; sr.left = x; sr.top = y; sr.width = sub->Xsize; sr.height = sub->Ysize; im_rect_intersectrect( &br, &sr, &clip ); if( im_rect_isempty( &clip ) ) return( 0 ); if( !(sub = im__inplace_base( "im_draw_image", image, sub, image )) || im_rwcheck( image ) || im_incheck( sub ) ) return( -1 ); /* Loop, memcpying sub to main. */ p = (PEL *) IM_IMAGE_ADDR( sub, clip.left - x, clip.top - y ); q = (PEL *) IM_IMAGE_ADDR( image, clip.left, clip.top ); for( z = 0; z < clip.height; z++ ) { memcpy( (char *) q, (char *) p, clip.width * IM_IMAGE_SIZEOF_PEL( sub ) ); p += IM_IMAGE_SIZEOF_LINE( sub ); q += IM_IMAGE_SIZEOF_LINE( image ); } return( 0 ); }
/** * im_draw_smudge: * @image: image to smudge * @left: area to smudge * @top: area to smudge * @width: area to smudge * @height: area to smudge * * Smudge a section of @image. Each pixel in the area @left, @top, @width, * @height is replaced by the average of the surrounding 3x3 pixels. * * This an inplace operation, so @image 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_draw_line(). * * Returns: 0 on success, or -1 on error. */ int im_draw_smudge( VipsImage *im, int left, int top, int width, int height ) { Rect area, image, clipped; IMAGE *t[2]; area.left = left; area.top = top; area.width = width; area.height = height; image.left = 0; image.top = 0; image.width = im->Xsize; image.height = im->Ysize; im_rect_intersectrect( &area, &image, &clipped ); if( im_rect_isempty( &clipped ) ) return( 0 ); if( !blur ) { blur = im_create_imaskv( "im_draw_smudge", 3, 1, 1, 4, 1 ); blur->scale = 6; } if( !(t[0] = im_open( "im_draw_smudge", "p" )) ) return( -1 ); if( !(t[1] = im_open_local( t[0], "im_draw_smudge", "p" )) || im_convsep( im, t[0], blur ) || im_extract_area( t[0], t[1], clipped.left, clipped.top, clipped.width, clipped.height ) || im_draw_image( im, t[1], clipped.left, clipped.top ) ) { im_close( t[0] ); return( -1 ); } im_close( t[0] ); return( 0 ); }
static int affinei_gen( REGION *or, void *seq, void *a, void *b ) { REGION *ir = (REGION *) seq; const IMAGE *in = (IMAGE *) a; const Affine *affine = (Affine *) b; const int window_offset = vips_interpolate_get_window_offset( affine->interpolate ); const VipsInterpolateMethod interpolate = vips_interpolate_get_method( affine->interpolate ); /* Area we generate in the output image. */ const Rect *r = &or->valid; const int le = r->left; const int ri = IM_RECT_RIGHT( r ); const int to = r->top; const int bo = IM_RECT_BOTTOM( r ); const Rect *iarea = &affine->trn.iarea; const Rect *oarea = &affine->trn.oarea; int ps = IM_IMAGE_SIZEOF_PEL( in ); int x, y, z; Rect image, want, need, clipped; #ifdef DEBUG printf( "affine: generating left=%d, top=%d, width=%d, height=%d\n", r->left, r->top, r->width, r->height ); #endif /*DEBUG*/ /* We are generating this chunk of the transformed image. */ want = *r; want.left += oarea->left; want.top += oarea->top; /* Find the area of the input image we need. */ im__transform_invert_rect( &affine->trn, &want, &need ); /* Now go to space (2) above. */ need.left += iarea->left; need.top += iarea->top; /* Add a border for interpolation. Plus one for rounding errors. */ im_rect_marginadjust( &need, window_offset + 1 ); /* Clip against the size of (2). */ image.left = 0; image.top = 0; image.width = in->Xsize; image.height = in->Ysize; im_rect_intersectrect( &need, &image, &clipped ); /* Outside input image? All black. */ if( im_rect_isempty( &clipped ) ) { im_region_black( or ); return( 0 ); } /* We do need some pixels from the input image to make our output - * ask for them. */ if( im_prepare( ir, &clipped ) ) return( -1 ); #ifdef DEBUG printf( "affine: preparing left=%d, top=%d, width=%d, height=%d\n", clipped.left, clipped.top, clipped.width, clipped.height ); #endif /*DEBUG*/ /* Resample! x/y loop over pixels in the output image (5). */ for( y = to; y < bo; y++ ) { /* Input clipping rectangle. */ const int ile = iarea->left; const int ito = iarea->top; const int iri = iarea->left + iarea->width; const int ibo = iarea->top + iarea->height; /* Derivative of matrix. */ const double ddx = affine->trn.ia; const double ddy = affine->trn.ic; /* Continuous cods in transformed space. */ const double ox = le + oarea->left - affine->trn.dx; const double oy = y + oarea->top - affine->trn.dy; /* Continuous cods in input space. */ double ix, iy; PEL *q; /* To (3). */ ix = affine->trn.ia * ox + affine->trn.ib * oy; iy = affine->trn.ic * ox + affine->trn.id * oy; /* Now move to (2). */ ix += iarea->left; iy += iarea->top; q = (PEL *) IM_REGION_ADDR( or, le, y ); for( x = le; x < ri; x++ ) { int fx, fy; fx = FLOOR( ix ); fy = FLOOR( iy ); /* Clipping! */ if( fx < ile || fx >= iri || fy < ito || fy >= ibo ) { for( z = 0; z < ps; z++ ) q[z] = 0; } else { interpolate( affine->interpolate, q, ir, ix, iy ); } ix += ddx; iy += ddy; q += ps; } } return( 0 ); }
/** * im_draw_rect: * @image: image to draw on * @left: area to paint * @top: area to paint * @width: area to paint * @height: area to paint * @fill: fill the rect * @ink: paint with this colour * * Paint pixels within @left, @top, @width, @height in @image with @ink. If * @fill is zero, just paint a 1-pixel-wide outline. * * See also: im_draw_circle(). * * Returns: 0 on success, or -1 on error. */ int im_draw_rect( IMAGE *image, int left, int top, int width, int height, int fill, VipsPel *ink ) { Rect im, rect, clipped; Draw draw; if( !fill ) return( im_draw_rect( image, left, top, width, 1, 1, ink ) || im_draw_rect( image, left + width - 1, top, 1, height, 1, ink ) || im_draw_rect( image, left, top + height - 1, width, 1, 1, ink ) || im_draw_rect( image, left, top, 1, height, 1, ink ) ); int x, y; VipsPel *to; VipsPel *q; /* Find area we plot. */ im.left = 0; im.top = 0; im.width = image->Xsize; im.height = image->Ysize; rect.left = left; rect.top = top; rect.width = width; rect.height = height; im_rect_intersectrect( &rect, &im, &clipped ); /* Any points left to plot? */ if( im_rect_isempty( &clipped ) ) return( 0 ); if( im_check_coding_known( "im_draw_rect", image ) || !im__draw_init( &draw, image, ink ) ) return( -1 ); /* We plot the first line pointwise, then memcpy() it for the * subsequent lines. */ to = IM_IMAGE_ADDR( image, clipped.left, clipped.top ); q = to; for( x = 0; x < clipped.width; x++ ) { im__draw_pel( &draw, q ); q += draw.psize; } q = to + draw.lsize; for( y = 1; y < clipped.height; y++ ) { memcpy( q, to, clipped.width * draw.psize ); q += draw.lsize; } im__draw_free( &draw ); return( 0 ); }
int im__find_tboverlap( IMAGE *ref_in, IMAGE *sec_in, IMAGE *out, int bandno_in, int xref, int yref, int xsec, int ysec, int halfcorrelation, int halfarea, int *dx0, int *dy0, double *scale1, double *angle1, double *dx1, double *dy1 ) { IMAGE *ref, *sec; TIE_POINTS points, *p_points; /* defined in mosaic.h */ TIE_POINTS newpoints, *p_newpoints; int i; int dx, dy; Rect top, bottom, overlap; /* Check ref and sec are compatible. */ if( ref_in->Bands != sec_in->Bands || ref_in->BandFmt != sec_in->BandFmt || ref_in->Coding != sec_in->Coding ) { im_errormsg( "im_tbmosaic: input images incompatible" ); return( -1 ); } /* Test cor and area. */ if( halfcorrelation < 0 || halfarea < 0 || halfarea < halfcorrelation ) { im_errormsg( "im_tbmosaic: bad area parameters" ); return( -1 ); } /* Set positions of top and bottom. */ top.left = 0; top.top = 0; top.width = ref_in->Xsize; top.height = ref_in->Ysize; bottom.left = xref - xsec; bottom.top = yref - ysec; bottom.width = sec_in->Xsize; bottom.height = sec_in->Ysize; /* Find overlap. */ im_rect_intersectrect( &top, &bottom, &overlap ); if( overlap.width < 2*halfarea + 1 || overlap.height < 2*halfarea + 1 ) { im_errormsg( "im_tbmosaic: overlap too small for search" ); return( -1 ); } /* Extract overlaps. */ ref = im_open_local( out, "temp_one", "t" ); sec = im_open_local( out, "temp_two", "t" ); if( !ref || !sec ) return( -1 ); if( ref_in->Coding == IM_CODING_LABQ ) { IMAGE *t1 = im_open_local( out, "temp:3", "p" ); IMAGE *t2 = im_open_local( out, "temp:4", "p" ); IMAGE *t3 = im_open_local( out, "temp:5", "p" ); IMAGE *t4 = im_open_local( out, "temp:6", "p" ); IMAGE *t5 = im_open_local( out, "temp:7", "p" ); IMAGE *t6 = im_open_local( out, "temp:8", "p" ); if( !t1 || !t2 || !t3 || !t4 || !t5 || !t6 ) return( -1 ); if( im_extract_area( ref_in, t1, overlap.left, overlap.top, overlap.width, overlap.height ) ) return( -1 ); if( im_extract_area( sec_in, t2, overlap.left - bottom.left, overlap.top - bottom.top, overlap.width, overlap.height ) ) return( -1 ); if( im_LabQ2Lab( t1, t3 ) || im_LabQ2Lab( t2, t4 ) || im_Lab2disp( t3, t5, im_col_displays( 1 ) ) || im_Lab2disp( t4, t6, im_col_displays( 1 ) ) ) return( -1 ); /* Extract the green. */ if( im_extract_band( t5, ref, 1 ) || im_extract_band( t6, sec, 1 ) ) return( -1 ); } else if( ref_in->Coding == IM_CODING_NONE ) { IMAGE *t1 = im_open_local( out, "temp:9", "p" ); IMAGE *t2 = im_open_local( out, "temp:10", "p" ); IMAGE *t3 = im_open_local( out, "temp:11", "p" ); IMAGE *t4 = im_open_local( out, "temp:12", "p" ); if( !t1 || !t2 || !t3 || !t4 ) return( -1 ); if( im_extract_area( ref_in, t1, overlap.left, overlap.top, overlap.width, overlap.height ) ) return( -1 ); if( im_extract_area( sec_in, t2, overlap.left - bottom.left, overlap.top - bottom.top, overlap.width, overlap.height ) ) return( -1 ); if( im_extract_band( t1, t3, bandno_in ) || im_extract_band( t2, t4, bandno_in ) ) return( -1 ); if( im_scale( t3, ref ) || im_scale( t4, sec ) ) return( -1 ); } else { im_errormsg( "im_tbmosaic: unknown Coding type" ); return( -1 ); } /* Initialise and fill TIE_POINTS */ p_points = &points; p_newpoints = &newpoints; p_points->reference = ref_in->filename; p_points->secondary = sec_in->filename; p_points->nopoints = IM_MAXPOINTS; p_points->deltax = 0; p_points->deltay = 0; p_points->halfcorsize = halfcorrelation; p_points->halfareasize = halfarea; /* Initialise the structure */ for( i = 0; i < IM_MAXPOINTS; i++ ) { p_points->x_reference[i] = 0; p_points->y_reference[i] = 0; p_points->x_secondary[i] = 0; p_points->y_secondary[i] = 0; p_points->contrast[i] = 0; p_points->correlation[i] = 0.0; p_points->dx[i] = 0.0; p_points->dy[i] = 0.0; p_points->deviation[i] = 0.0; } /* Search ref for possible tie-points. Sets: p_points->contrast, * p_points->x,y_reference. */ if( im__tbcalcon( ref, p_points ) ) return( -1 ); /* For each candidate point, correlate against corresponding part of * sec. Sets x,y_secondary and fills correlation and dx, dy. */ if( im__chkpair( ref, sec, p_points ) ) return( -1 ); /* First call to im_clinear(). */ if( im__initialize( p_points ) ) return( -1 ); /* Improve the selection of tiepoints until all abs(deviations) are * < 1.0 by deleting all wrong points. */ if( im__improve( p_points, p_newpoints ) ) return( -1 ); /* Average remaining offsets. */ if( im__avgdxdy( p_newpoints, &dx, &dy ) ) return( -1 ); /* Offset with overlap position. */ *dx0 = -bottom.left + dx; *dy0 = -bottom.top + dy; /* Write 1st order parameters too. */ *scale1 = newpoints.l_scale; *angle1 = newpoints.l_angle; *dx1 = newpoints.l_deltax; *dy1 = newpoints.l_deltay; return( 0 ); }
/** * im_region_image: * @reg: region to operate upon * @r: #Rect of pixels you need to be able to address * * The region is transformed so that at least @r pixels are available directly * from the image. The image needs to be a memory buffer or represent a file * on disc that has been mapped or can be mapped. * * Returns: 0 on success, or -1 for error. */ int im_region_image( REGION *reg, Rect *r ) { Rect image; Rect clipped; /* Sanity check. */ im__region_check_ownership( reg ); /* Clip against image. */ image.top = 0; image.left = 0; image.width = reg->im->Xsize; image.height = reg->im->Ysize; im_rect_intersectrect( r, &image, &clipped ); /* Test for empty. */ if( im_rect_isempty( &clipped ) ) { im_error( "im_region_image", "%s", _( "valid clipped to nothing" ) ); return( -1 ); } if( reg->im->data ) { /* We have the whole image available ... easy! */ im_region_reset( reg ); /* We can't just set valid = clipped, since this may be an * incompletely calculated memory buffer. Just set valid to r. */ reg->valid = clipped; reg->bpl = IM_IMAGE_SIZEOF_LINE( reg->im ); reg->data = reg->im->data + (gint64) clipped.top * IM_IMAGE_SIZEOF_LINE( reg->im ) + clipped.left * IM_IMAGE_SIZEOF_PEL( reg->im ); reg->type = IM_REGION_OTHER_IMAGE; } else if( reg->im->dtype == IM_OPENIN ) { /* No complete image data ... but we can use a rolling window. */ if( reg->type != IM_REGION_WINDOW || !reg->window || reg->window->top > clipped.top || reg->window->top + reg->window->height < clipped.top + clipped.height ) { im_region_reset( reg ); if( !(reg->window = im_window_ref( reg->im, clipped.top, clipped.height )) ) return( -1 ); reg->type = IM_REGION_WINDOW; } /* Note the area the window actually represents. */ reg->valid.left = 0; reg->valid.top = reg->window->top; reg->valid.width = reg->im->Xsize; reg->valid.height = reg->window->height; reg->bpl = IM_IMAGE_SIZEOF_LINE( reg->im ); reg->data = reg->window->data; } else { im_error( "im_region_image", "%s", _( "bad image type" ) ); return( -1 ); } return( 0 ); }
/* Smear a section of an IMAGE. As above, but shift it left a bit. */ int im_smear( IMAGE *im, int ix, int iy, Rect *r ) { int x, y, a, b, c; int ba = im->Bands; int el = ba * im->Xsize; Rect area, image, clipped; double total[ 256 ]; if( im_rwcheck( im ) ) return( -1 ); /* Don't do the margins. */ area = *r; area.left += ix; area.top += iy; image.left = 0; image.top = 0; image.width = im->Xsize; image.height = im->Ysize; im_rect_marginadjust( &image, -1 ); image.left--; im_rect_intersectrect( &area, &image, &clipped ); /* Any left? */ if( im_rect_isempty( &clipped ) ) return( 0 ); /* What we do for each type. */ #define SMEAR(TYPE) \ for( y = clipped.top; y < clipped.top + clipped.height; y++ ) \ for( x = clipped.left; \ x < clipped.left + clipped.width; x++ ) { \ TYPE *to = (TYPE *) im->data + x * ba + y * el; \ TYPE *from = to - el; \ TYPE *f; \ \ for( a = 0; a < ba; a++ ) \ total[a] = 0.0; \ \ for( a = 0; a < 3; a++ ) { \ f = from; \ for( b = 0; b < 3; b++ ) \ for( c = 0; c < ba; c++ ) \ total[c] += *f++; \ from += el; \ } \ \ for( a = 0; a < ba; a++ ) \ to[a] = (40 * (double) to[a+ba] + total[a]) \ / 49.0; \ } /* Loop through the remaining pixels. */ switch( im->BandFmt ) { case IM_BANDFMT_UCHAR: SMEAR(unsigned char); break; case IM_BANDFMT_CHAR: SMEAR(char); break; case IM_BANDFMT_USHORT: SMEAR(unsigned short); break; case IM_BANDFMT_SHORT: SMEAR(short); break; case IM_BANDFMT_UINT: SMEAR(unsigned int); break; case IM_BANDFMT_INT: SMEAR(int); break; case IM_BANDFMT_FLOAT: SMEAR(float); break; case IM_BANDFMT_DOUBLE: SMEAR(double); break; /* Do complex types too. Just treat as float and double, but with * twice the number of bands. */ case IM_BANDFMT_COMPLEX: /* Twice number of bands: double size and bands. */ ba *= 2; el *= 2; SMEAR(float); break; case IM_BANDFMT_DPCOMPLEX: /* Twice number of bands: double size and bands. */ ba *= 2; el *= 2; SMEAR(double); break; default: im_error( "im_smear", "%s", _( "unknown band format" ) ); return( -1 ); } return( 0 ); }
static int replicate_gen( REGION *or, void *seq, void *a, void *b ) { REGION *ir = (REGION *) seq; IMAGE *in = (IMAGE *) a; Rect *r = &or->valid; int twidth = in->Xsize; int theight = in->Ysize; int x, y; Rect tile; /* Find top left of tiles we need. */ int xs = (r->left / twidth) * twidth; int ys = (r->top / theight) * theight; /* The tile enclosing the top-left corner of the requested area. */ tile.left = xs; tile.top = ys; tile.width = twidth; tile.height = theight; /* If the request fits inside a single tile, we can just pointer-copy. */ if( im_rect_includesrect( &tile, r ) ) { Rect irect; /* Translate request to input space. */ irect = *r; irect.left -= xs; irect.top -= ys; if( im_prepare( ir, &irect ) ) return( -1 ); if( im_region_region( or, ir, r, irect.left, irect.top ) ) return( -1 ); return( 0 ); } for( y = ys; y < IM_RECT_BOTTOM( r ); y += theight ) for( x = xs; x < IM_RECT_RIGHT( r ); x += twidth ) { Rect paint; /* Whole tile at x, y */ tile.left = x; tile.top = y; tile.width = twidth; tile.height = theight; /* Which parts touch the area of the output we are * building. */ im_rect_intersectrect( &tile, r, &paint ); /* Translate back to ir coordinates. */ paint.left -= x; paint.top -= y; g_assert( !im_rect_isempty( &paint ) ); /* Render into or. */ if( im_prepare_to( ir, or, &paint, paint.left + x, paint.top + y ) ) return( -1 ); } return( 0 ); }
/* Make REGION reg ready for input of area r. For most image types, we can * just im_attach, for PARTIAL though we may need to generate. */ int im_prepare( REGION *reg, Rect *r ) { IMAGE *im = reg->im; Rect save = *r; im__region_check_ownership( reg ); if( im__test_kill( im ) ) return( -1 ); /* We use save for sanity checking valid: we test at the end that the * pixels we have generated are indeed all the ones that were asked * for. * * However, r may be clipped by the image size, so we need to clip * save as well to make sure we don't fail the assert due to that. */ { Rect image; image.left = 0; image.top = 0; image.width = reg->im->Xsize; image.height = reg->im->Ysize; im_rect_intersectrect( &save, &image, &save ); } #ifdef DEBUG printf( "im_prepare: left = %d, top = %d, width = %d, height = %d\n", r->left, r->top, r->width, r->height ); #endif /*DEBUG*/ switch( im->dtype ) { case IM_PARTIAL: if( im_region_fill( reg, r, (im_region_fill_fn) fill_region, NULL ) ) return( -1 ); break; case IM_SETBUF: case IM_SETBUF_FOREIGN: case IM_MMAPIN: case IM_MMAPINRW: case IM_OPENIN: /* Attach to existing buffer. */ if( im_region_image( reg, r ) ) return( -1 ); break; default: im_error( "im_prepare", _( "unable to input from a %s image" ), im_dtype2char( im->dtype ) ); return( -1 ); } /* valid should now include all the pixels that were asked for. */ assert( im_rect_includesrect( ®->valid, &save ) ); return( 0 ); }
/** * im_correl: * @ref: reference image * @sec: secondary image * @xref: position in reference image * @yref: position in reference image * @xsec: position in secondary image * @ysec: position in secondary image * @hwindowsize: half window size * @hsearchsize: half search size * @correlation: return detected correlation * @x: return found position * @y: return found position * * This operation finds the position of @sec within @ref. * * The area around * (@xsec, @ysec) is searched for the best match to the area around (@xref, * @yref). It searches an area of size @hsearchsize for a * match of size @hwindowsize. The position of the best match is * returned, together with the correlation at that point. * * Only the first band of each image is correlated. @ref and @sec may be * very large --- the function extracts and generates just the * parts needed. Correlation is done with im_spcor(); the position of * the maximum is found with im_maxpos(). * * See also: im_match_linear(), im_match_linear_search(), im_lrmosaic(). * * Returns: 0 on success, -1 on error */ int im_correl( IMAGE *ref, IMAGE *sec, int xref, int yref, int xsec, int ysec, int hwindowsize, int hsearchsize, double *correlation, int *x, int *y ) { IMAGE *surface = im_open( "surface", "t" ); IMAGE *t1, *t2, *t3, *t4; Rect refr, secr; Rect winr, srhr; Rect wincr, srhcr; if( !surface || !(t1 = im_open_local( surface, "correlate:1", "p" )) || !(t2 = im_open_local( surface, "correlate:1", "p" )) || !(t3 = im_open_local( surface, "correlate:1", "p" )) || !(t4 = im_open_local( surface, "correlate:1", "p" )) ) return( -1 ); /* Find position of window and search area, and clip against image * size. */ refr.left = 0; refr.top = 0; refr.width = ref->Xsize; refr.height = ref->Ysize; winr.left = xref - hwindowsize; winr.top = yref - hwindowsize; winr.width = hwindowsize*2 + 1; winr.height = hwindowsize*2 + 1; im_rect_intersectrect( &refr, &winr, &wincr ); secr.left = 0; secr.top = 0; secr.width = sec->Xsize; secr.height = sec->Ysize; srhr.left = xsec - hsearchsize; srhr.top = ysec - hsearchsize; srhr.width = hsearchsize*2 + 1; srhr.height = hsearchsize*2 + 1; im_rect_intersectrect( &secr, &srhr, &srhcr ); /* Extract window and search area. */ if( im_extract_area( ref, t1, wincr.left, wincr.top, wincr.width, wincr.height ) || im_extract_area( sec, t2, srhcr.left, srhcr.top, srhcr.width, srhcr.height ) ) { im_close( surface ); return( -1 ); } /* Make sure we have just one band. From im_*mosaic() we will, but * from im_match_linear_search() etc. we may not. */ if( t1->Bands != 1 ) { if( im_extract_band( t1, t3, 0 ) ) { im_close( surface ); return( -1 ); } t1 = t3; } if( t2->Bands != 1 ) { if( im_extract_band( t2, t4, 0 ) ) { im_close( surface ); return( -1 ); } t2 = t4; } /* Search! */ if( im_spcor( t2, t1, surface ) ) { im_close( surface ); return( -1 ); } /* Find maximum of correlation surface. */ if( im_maxpos( surface, x, y, correlation ) ) { im_close( surface ); return( -1 ); } im_close( surface ); /* Translate back to position within sec. */ *x += srhcr.left; *y += srhcr.top; return( 0 ); }
int im__find_lroverlap( IMAGE *ref_in, IMAGE *sec_in, IMAGE *out, int bandno_in, int xref, int yref, int xsec, int ysec, int halfcorrelation, int halfarea, int *dx0, int *dy0, double *scale1, double *angle1, double *dx1, double *dy1 ) { Rect left, right, overlap; IMAGE *ref, *sec; IMAGE *t[6]; TIE_POINTS points, *p_points; TIE_POINTS newpoints, *p_newpoints; int dx, dy; int i; /* Test cor and area. */ if( halfcorrelation < 0 || halfarea < 0 || halfarea < halfcorrelation ) { im_error( "im_lrmosaic", "%s", _( "bad area parameters" ) ); return( -1 ); } /* Set positions of left and right. */ left.left = 0; left.top = 0; left.width = ref_in->Xsize; left.height = ref_in->Ysize; right.left = xref - xsec; right.top = yref - ysec; right.width = sec_in->Xsize; right.height = sec_in->Ysize; /* Find overlap. */ im_rect_intersectrect( &left, &right, &overlap ); if( overlap.width < 2 * halfarea + 1 || overlap.height < 2 * halfarea + 1 ) { im_error( "im_lrmosaic", "%s", _( "overlap too small for search" ) ); return( -1 ); } /* Extract overlaps as 8-bit, 1 band. */ if( !(ref = im_open_local( out, "temp_one", "t" )) || !(sec = im_open_local( out, "temp_two", "t" )) || im_open_local_array( out, t, 6, "im_lrmosaic", "p" ) || im_extract_area( ref_in, t[0], overlap.left, overlap.top, overlap.width, overlap.height ) || im_extract_area( sec_in, t[1], overlap.left - right.left, overlap.top - right.top, overlap.width, overlap.height ) ) return( -1 ); if( ref_in->Coding == IM_CODING_LABQ ) { if( im_LabQ2Lab( t[0], t[2] ) || im_LabQ2Lab( t[1], t[3] ) || im_Lab2disp( t[2], t[4], im_col_displays( 1 ) ) || im_Lab2disp( t[3], t[5], im_col_displays( 1 ) ) || im_extract_band( t[4], ref, 1 ) || im_extract_band( t[5], sec, 1 ) ) return( -1 ); } else if( ref_in->Coding == IM_CODING_NONE ) { if( im_extract_band( t[0], t[2], bandno_in ) || im_extract_band( t[1], t[3], bandno_in ) || im_scale( t[2], ref ) || im_scale( t[3], sec ) ) return( -1 ); } else { im_error( "im_lrmosaic", "%s", _( "unknown Coding type" ) ); return( -1 ); } /* Initialise and fill TIE_POINTS */ p_points = &points; p_newpoints = &newpoints; p_points->reference = ref_in->filename; p_points->secondary = sec_in->filename; p_points->nopoints = IM_MAXPOINTS; p_points->deltax = 0; p_points->deltay = 0; p_points->halfcorsize = halfcorrelation; p_points->halfareasize = halfarea; /* Initialise the structure */ for( i = 0; i < IM_MAXPOINTS; i++ ) { p_points->x_reference[i] = 0; p_points->y_reference[i] = 0; p_points->x_secondary[i] = 0; p_points->y_secondary[i] = 0; p_points->contrast[i] = 0; p_points->correlation[i] = 0.0; p_points->dx[i] = 0.0; p_points->dy[i] = 0.0; p_points->deviation[i] = 0.0; } /* Search ref for possible tie-points. Sets: p_points->contrast, * p_points->x,y_reference. */ if( im__lrcalcon( ref, p_points ) ) return( -1 ); /* For each candidate point, correlate against corresponding part of * sec. Sets x,y_secondary and fills correlation and dx, dy. */ if( im__chkpair( ref, sec, p_points ) ) return( -1 ); /* First call to im_clinear(). */ if( im__initialize( p_points ) ) return( -1 ); /* Improve the selection of tiepoints until all abs(deviations) are * < 1.0 by deleting all wrong points. */ if( im__improve( p_points, p_newpoints ) ) return( -1 ); /* Average remaining offsets. */ if( im__avgdxdy( p_newpoints, &dx, &dy ) ) return( -1 ); /* Offset with overlap position. */ *dx0 = -right.left + dx; *dy0 = -right.top + dy; /* Write 1st order parameters too. */ *scale1 = newpoints.l_scale; *angle1 = newpoints.l_angle; *dx1 = newpoints.l_deltax; *dy1 = newpoints.l_deltay; return( 0 ); }
/* Loop over a big region, filling it in many small pieces with threads. */ static int eval_to_region( REGION *or, im_threadgroup_t *tg ) { Rect *r = &or->valid; Rect image; int x, y; image.left = 0; image.top = 0; image.width = or->im->Xsize; image.height = or->im->Ysize; /* Note we'll be working to fill a contigious area. */ tg->inplace = 1; /* Loop over or, attaching to all sub-parts in turn. */ for( y = r->top; y < IM_RECT_BOTTOM( r ); y += tg->ph ) for( x = r->left; x < IM_RECT_RIGHT( r ); x += tg->pw ) { im_thread_t *thr; Rect pos; Rect clipped; /* thrs appear on idle when the child thread does * threadgroup_idle_add and hits the 'go' semaphore. */ thr = im_threadgroup_get( tg ); /* Set the position we want to generate with this * thread. Clip against the size of the image and the * space available in or. */ pos.left = x; pos.top = y; pos.width = tg->pw; pos.height = tg->ph; im_rect_intersectrect( &pos, &image, &clipped ); im_rect_intersectrect( &clipped, r, &clipped ); /* Note params and start work. */ thr->oreg = or; thr->pos = clipped; thr->x = clipped.left; thr->y = clipped.top; im_threadgroup_trigger( thr ); /* Check for errors. */ if( im_threadgroup_iserror( tg ) ) { /* Don't kill threads yet ... we may want to * get some error stuff out of them. */ im_threadgroup_wait( tg ); return( -1 ); } } /* Wait for all threads to hit 'go' again. */ im_threadgroup_wait( tg ); if( im_threadgroup_iserror( tg ) ) return( -1 ); return( 0 ); }