/* A colour difference operation. */ int im__colour_difference( const char *domain, IMAGE *in1, IMAGE *in2, IMAGE *out, im_wrapmany_fn buffer_fn, void *a, void *b ) { IMAGE *t[3]; if( im_check_uncoded( domain, in1 ) || im_check_uncoded( domain, in2 ) || im_check_bands( domain, in1, 3 ) || im_check_bands( domain, in2, 3 ) || im_check_size_same( domain, in1, in2 ) || im_open_local_array( out, t, 2, domain, "p" ) || im_clip2fmt( in1, t[0], IM_BANDFMT_FLOAT ) || im_clip2fmt( in2, t[1], IM_BANDFMT_FLOAT ) ) return( -1 ); if( im_cp_descv( out, t[0], t[1], NULL ) ) return( -1 ); out->Bands = 1; out->Type = IM_TYPE_B_W; t[2] = NULL; if( im_wrapmany( t, out, buffer_fn, a, b ) ) return( -1 ); return( 0 ); }
/** * im_LabS2LabQ: * @in: input image * @out: output image * * Convert a LabS three-band signed short image to LabQ * * See also: im_LabQ2LabS(). * * Returns: 0 on success, -1 on error. */ int im_LabS2LabQ( IMAGE *in, IMAGE *out ) { IMAGE *t[1]; if( im_check_uncoded( "im_LabS2LabQ", in ) || im_check_bands( "im_LabS2LabQ", in, 3 ) || im_open_local_array( out, t, 1, "im_LabS2LabQ", "p" ) || im_clip2fmt( in, t[0], IM_BANDFMT_SHORT ) ) return( -1 ); /* Set up output image */ if( im_cp_desc( out, in ) ) return( -1 ); out->Bands = 4; out->Type = IM_TYPE_LABQ; out->BandFmt = IM_BANDFMT_UCHAR; out->Coding = IM_CODING_LABQ; if( im_wrapone( in, out, (im_wrapone_fn) imb_LabS2LabQ, NULL, NULL ) ) return( -1 ); return( 0 ); }
/* Call im_clip2fmt via arg vector. */ static int clip2fmt_vec( im_object *argv ) { int ofmt = *((int *) argv[2]); return( im_clip2fmt( argv[0], argv[1], ofmt ) ); }
/** * im_scaleps: * @in: input image * @out: output image * * Scale a power spectrum. Transform with log10(1.0 + pow(x, 0.25)) + .5, * then scale so max == 255. * * See also: im_scale(). * * Returns: 0 on success, -1 on error */ int im_scaleps( IMAGE *in, IMAGE *out ) { IMAGE *t[4]; double mx; double scale; if( im_open_local_array( out, t, 4, "im_scaleps-1", "p" ) || im_max( in, &mx ) ) return( -1 ); if( mx <= 0.0 ) /* Range of zero: just return black. */ return( im_black( out, in->Xsize, in->Ysize, in->Bands ) ); scale = 255.0 / log10( 1.0 + pow( mx, .25 ) ); /* Transform! */ if( im_powtra( in, t[0], 0.25 ) || im_lintra( 1.0, t[0], 1.0, t[1] ) || im_log10tra( t[1], t[2] ) || im_lintra( scale, t[2], 0.0, t[3] ) || im_clip2fmt( t[3], out, IM_BANDFMT_UCHAR ) ) return( -1 ); return( 0 ); }
/** * im_maplut: * @in: input image * @out: output image * @lut: look-up table * * Map an image through another image acting as a LUT (Look Up Table). * The lut may have any type, and the output image will be that type. * * The input image will be cast to one of the unsigned integer types, that is, * IM_BANDFMT_UCHAR, IM_BANDFMT_USHORT or IM_BANDFMT_UINT. * * If @lut is too small for the input type (for example, if @in is * IM_BANDFMT_UCHAR but @lut only has 100 elements), the lut is padded out * by copying the last element. Overflows are reported at the end of * computation. * If @lut is too large, extra values are ignored. * * If @lut has one band, then all bands of @in pass through it. If @lut * has same number of bands as @in, then each band is mapped * separately. If @in has one band, then @lut may have many bands and * the output will have the same number of bands as @lut. * * See also: im_histgr(), im_identity(). * * Returns: 0 on success, -1 on error */ int im_maplut( IMAGE *in, IMAGE *out, IMAGE *lut ) { IMAGE *t; LutInfo *st; /* Check input output. Old-style IO from lut, for simplicity. */ if( im_check_hist( "im_maplut", lut ) || im_check_uncoded( "im_maplut", lut ) || im_check_uncoded( "im_maplut", in ) || im_check_bands_1orn( "im_maplut", in, lut ) || im_piocheck( in, out ) || im_incheck( lut ) ) return( -1 ); /* Cast in to u8/u16/u32. */ if( !(t = im_open_local( out, "im_maplut", "p" )) || im_clip2fmt( in, t, bandfmt_maplut[in->BandFmt] ) ) return( -1 ); /* Prepare the output header. */ if( im_cp_descv( out, t, lut, NULL ) ) return( -1 ); /* Force output to be the same type as lut. */ out->BandFmt = lut->BandFmt; /* Output has same number of bands as LUT, unless LUT has 1 band, in * which case output has same number of bands as input. */ if( lut->Bands != 1 ) out->Bands = lut->Bands; /* Make tables. */ if( !(st = build_luts( out, lut )) ) return( -1 ); /* Set demand hints. */ if( im_demand_hint( out, IM_THINSTRIP, t, NULL ) ) return( -1 ); /* Process! */ if( im_generate( out, maplut_start, maplut_gen, maplut_stop, t, st ) ) return( -1 ); return( 0 ); }
/** * im_label_regions: * @test: image to test * @mask: write labelled regions here * @segments: return number of regions here * * im_label_regions() repeatedly scans @test for regions of 4-connected pixels * with the same pixel value. 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. */ if( im_rwcheck( 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_old( t[1], test, x, y, serial ) ) */ if( im_flood_other( test, t[1], x, y, serial, NULL ) ) // if( im_flood_other_old( 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 ); }
int im_freqflt( IMAGE *in, IMAGE *mask, IMAGE *out ) { IMAGE *dummy; /* Placeholder for memory free. */ if( !(dummy = im_open( "memory-1", "p" )) ) return( -1 ); if( im_iscomplex( in ) ) { /* Easy case! Assume it has already been transformed. */ IMAGE *t1 = im_open_local( dummy, "im_freqflt-1", "p" ); if( !t1 || im_multiply( in, mask, t1 ) || im_invfftr( t1, out ) ) { im_close( dummy ); return( -1 ); } } else { /* Harder - fft first, then mult, then force back to start * type. * * Optimisation: output of im_invfft() is float buffer, we * will usually chagetype to char, so rather than keeping a * large float buffer and partial to char from that, do * changetype to a memory buffer, and copy to out from that. */ IMAGE *t[3]; IMAGE *t3; if( im_open_local_array( dummy, t, 3, "im_freqflt-1", "p" ) || !(t3 = im_open_local( out, "im_freqflt-3", "t" )) || im_fwfft( in, t[0] ) || im_multiply( t[0], mask, t[1] ) || im_invfftr( t[1], t[2] ) || im_clip2fmt( t[2], t3, in->BandFmt ) || im_copy( t3, out ) ) { im_close( dummy ); return( -1 ); } } im_close( dummy ); return( 0 ); }
/** * im_grey: * @out: output image * @xsize: image size * @ysize: image size * * Create a one-band uchar image with the left-most column zero and the * right-most 255. Intermediate pixels are a linear ramp. * * See also: im_fgrey(), im_make_xy(), im_identity(). * * Returns: 0 on success, -1 on error */ int im_grey( IMAGE *out, const int xsize, const int ysize ) { IMAGE *t[2]; /* Change range to [0,255]. */ if( im_open_local_array( out, t, 2, "im_grey", "p" ) || im_fgrey( t[0], xsize, ysize ) || im_lintra( 255.0, t[0], 0.0, t[1] ) || im_clip2fmt( t[1], out, IM_BANDFMT_UCHAR ) ) return( -1 ); return( 0 ); }
/** * im_tone_build: * @out: output image * @Lb: black-point [0-100] * @Lw: white-point [0-100] * @Ps: shadow point (eg. 0.2) * @Pm: mid-tone point (eg. 0.5) * @Ph: highlight point (eg. 0.8) * @S: shadow adjustment (+/- 30) * @M: mid-tone adjustment (+/- 30) * @H: highlight adjustment (+/- 30) * * As im_tone_build_range(), but set 32767 and 32767 as values for @in_max * and @out_max. This makes a curve suitable for correcting LABS * images, the most common case. * * See also: im_tone_build_range(). * * Returns: 0 on success, -1 on error */ int im_tone_build( IMAGE *out, double Lb, double Lw, double Ps, double Pm, double Ph, double S, double M, double H ) { IMAGE *t1; if( !(t1 = im_open_local( out, "im_tone_build", "p" )) || im_tone_build_range( t1, 32767, 32767, Lb, Lw, Ps, Pm, Ph, S, M, H ) || im_clip2fmt( t1, out, IM_BANDFMT_SHORT ) ) return( -1 ); return( 0 ); }
/* As above, but make a IM_BANDFMT_UCHAR image. */ int im_zone( IMAGE *im, int size ) { IMAGE *t1 = im_open_local( im, "im_zone:1", "p" ); IMAGE *t2 = im_open_local( im, "im_zone:2", "p" ); if( !t1 || !t2 ) return( -1 ); if( im_fzone( t1, size ) || im_lintra( 127.5, t1, 127.5, t2 ) || im_clip2fmt( t2, im, IM_BANDFMT_UCHAR ) ) return( -1 ); return( 0 ); }
/** * im_tone_analyse: * @in: input image * @out: output image * @Ps: shadow point (eg. 0.2) * @Pm: mid-tone point (eg. 0.5) * @Ph: highlight point (eg. 0.8) * @S: shadow adjustment (+/- 30) * @M: mid-tone adjustment (+/- 30) * @H: highlight adjustment (+/- 30) * * As im_tone_build(), but analyse the histogram of @in and use it to * pick the 0.1% and 99.9% points for @Lb and @Lw. * * See also: im_tone_build(). * * Returns: 0 on success, -1 on error */ int im_tone_analyse( IMAGE *in, IMAGE *out, double Ps, double Pm, double Ph, double S, double M, double H ) { IMAGE *t[4]; int low, high; double Lb, Lw; if( im_open_local_array( out, t, 4, "im_tone_map", "p" ) ) return( -1 ); /* If in is IM_CODING_LABQ, unpack. */ if( in->Coding == IM_CODING_LABQ ) { if( im_LabQ2LabS( in, t[0] ) ) return( -1 ); } else t[0] = in; /* Should now be 3-band short. */ if( im_check_uncoded( "im_tone_analyse", t[0] ) || im_check_bands( "im_tone_analyse", t[0], 3 ) || im_check_format( "im_tone_analyse", t[0], IM_BANDFMT_SHORT ) ) return( -1 ); if( im_extract_band( t[0], t[1], 0 ) || im_clip2fmt( t[1], t[2], IM_BANDFMT_USHORT ) || im_histgr( t[2], t[3], -1 ) ) return( -1 ); if( im_mpercent_hist( t[3], 0.1 / 100.0, &high ) || im_mpercent_hist( t[3], 99.9 / 100.0, &low ) ) return( -1 ); Lb = 100 * low / 32768; Lw = 100 * high / 32768; im_diag( "im_tone_analyse", "set Lb = %g, Lw = %g", Lb, Lw ); return( im_tone_build( out, Lb, Lw, Ps, Pm, Ph, S, M, H ) ); }
/* Find stats on an area of an IMAGE ... consider only pixels for which the * mask is true. */ static DOUBLEMASK * find_image_stats( IMAGE *in, IMAGE *mask, Rect *area ) { DOUBLEMASK *stats; IMAGE *t[4]; gint64 count; /* Extract area, build black image, mask out pixels we want. */ if( im_open_local_array( in, t, 4, "find_image_stats", "p" ) || extract_rect( in, t[0], area ) || im_black( t[1], t[0]->Xsize, t[0]->Ysize, t[0]->Bands ) || im_clip2fmt( t[1], t[2], t[0]->BandFmt ) || im_ifthenelse( mask, t[0], t[2], t[3] ) ) return( NULL ); /* Get stats from masked image. */ if( !(stats = local_mask( in, im_stats( t[3] ) )) ) return( NULL ); /* Number of non-zero pixels in mask. */ if( count_nonzero( mask, &count ) ) return( NULL ); /* And scale masked average to match. */ stats->coeff[4] *= (double) count / ((double) mask->Xsize * mask->Ysize); /* Yuk! Zap the deviation column with the pixel count. Used later to * determine if this is likely to be a significant overlap. */ stats->coeff[5] = count; #ifdef DEBUG if( count == 0 ) im_warn( "global_balance", _( "empty overlap!" ) ); #endif /*DEBUG*/ return( stats ); }
/* The common part of most binary inplace operators. * * Unlike im__formatalike() and friends, we can only change one of the images, * since the other is being updated. */ VipsImage * im__inplace_base( const char *domain, VipsImage *main, VipsImage *sub, VipsImage *out ) { VipsImage *t[2]; if( im_rwcheck( main ) || im_pincheck( sub ) || im_check_coding_known( domain, main ) || im_check_coding_same( domain, main, sub ) || im_check_bands_1orn_unary( domain, sub, main->Bands ) ) return( NULL ); /* Cast sub to match main in bands and format. */ if( im_open_local_array( out, t, 2, domain, "p" ) || im__bandup( domain, sub, t[0], main->Bands ) || im_clip2fmt( t[0], t[1], main->BandFmt ) ) return( NULL ); return( t[1] ); }
/** * im_gammacorrect: * @in: input image * @out: output image * @exponent: gamma factor * * Gamma-correct an 8- or 16-bit unsigned image with a lookup table. The * output format is the same as the input format. * * See also: im_identity(), im_powtra(), im_maplut() * * Returns: 0 on success, -1 on error */ int im_gammacorrect( IMAGE *in, IMAGE *out, double exponent ) { IMAGE *t[4]; double mx1, mx2; if( im_open_local_array( out, t, 4, "im_gammacorrect", "p" ) || im_check_u8or16( "im_gammacorrect", in ) || im_piocheck( in, out ) || (in->BandFmt == IM_BANDFMT_UCHAR ? im_identity( t[0], 1 ) : im_identity_ushort( t[0], 1, 65536 )) || im_powtra( t[0], t[1], exponent ) || im_max( t[0], &mx1 ) || im_max( t[1], &mx2 ) || im_lintra( mx1 / mx2, t[1], 0, t[2] ) || im_clip2fmt( t[2], t[3], in->BandFmt ) || im_maplut( in, out, t[3] ) ) return( -1 ); return( 0 ); }
int im__colour_unary( const char *domain, IMAGE *in, IMAGE *out, VipsType type, im_wrapone_fn buffer_fn, void *a, void *b ) { IMAGE *t[1]; if( im_check_uncoded( domain, in ) || im_check_bands( domain, in, 3 ) || im_open_local_array( out, t, 1, domain, "p" ) || im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) ) return( -1 ); if( im_cp_desc( out, t[0] ) ) return( -1 ); out->Type = type; if( im_wrapone( t[0], out, (im_wrapone_fn) buffer_fn, a, b ) ) return( -1 ); return( 0 ); }
int im_clip2c( IMAGE *in, IMAGE *out ) { return( im_clip2fmt( in, out, IM_BANDFMT_CHAR ) ); }
int im_clip2dcm( IMAGE *in, IMAGE *out ) { return( im_clip2fmt( in, out, IM_BANDFMT_DPCOMPLEX ) ); }
/* Convert to a saveable format. * * im__saveable_t gives the general type of image * we make: vanilla 1/3 bands (eg. PPM), with an optional alpha (eg. PNG), or * with CMYK as an option (eg. JPEG). * * format_table[] says how to convert each input format. * * Need to im_close() the result IMAGE. */ IMAGE * im__convert_saveable( IMAGE *in, im__saveable_t saveable, int format_table[10] ) { IMAGE *out; if( !(out = im_open( "convert-for-save", "p" )) ) return( NULL ); /* If this is an IM_CODING_LABQ, we can go straight to RGB. */ if( in->Coding == IM_CODING_LABQ ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); static void *table = NULL; /* Make sure fast LabQ2disp tables are built. 7 is sRGB. */ if( !table ) table = im_LabQ2disp_build_table( NULL, im_col_displays( 7 ) ); if( !t || im_LabQ2disp_table( in, t, table ) ) { im_close( out ); return( NULL ); } in = t; } /* If this is an IM_CODING_RAD, we go to float RGB or XYZ. We should * probably un-gamma-correct the RGB :( */ if( in->Coding == IM_CODING_RAD ) { IMAGE *t; if( !(t = im_open_local( out, "conv:1", "p" )) || im_rad2float( in, t ) ) { im_close( out ); return( NULL ); } in = t; } /* Get the bands right. */ if( in->Coding == IM_CODING_NONE ) { if( in->Bands == 2 && saveable != IM__RGBA ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_extract_band( in, t, 0 ) ) { im_close( out ); return( NULL ); } in = t; } else if( in->Bands > 3 && saveable == IM__RGB ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_extract_bands( in, t, 0, 3 ) ) { im_close( out ); return( NULL ); } in = t; } else if( in->Bands > 4 && (saveable == IM__RGB_CMYK || saveable == IM__RGBA) ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_extract_bands( in, t, 0, 4 ) ) { im_close( out ); return( NULL ); } in = t; } /* Else we have saveable IM__ANY and we don't chop bands down. */ } /* Interpret the Type field for colorimetric images. */ if( in->Bands == 3 && in->BandFmt == IM_BANDFMT_SHORT && in->Type == IM_TYPE_LABS ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_LabS2LabQ( in, t ) ) { im_close( out ); return( NULL ); } in = t; } if( in->Coding == IM_CODING_LABQ ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_LabQ2Lab( in, t ) ) { im_close( out ); return( NULL ); } in = t; } if( in->Coding != IM_CODING_NONE ) { im_close( out ); return( NULL ); } if( in->Bands == 3 && in->Type == IM_TYPE_LCH ) { IMAGE *t[2]; if( im_open_local_array( out, t, 2, "conv-1", "p" ) || im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || im_LCh2Lab( t[0], t[1] ) ) { im_close( out ); return( NULL ); } in = t[1]; } if( in->Bands == 3 && in->Type == IM_TYPE_YXY ) { IMAGE *t[2]; if( im_open_local_array( out, t, 2, "conv-1", "p" ) || im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || im_Yxy2XYZ( t[0], t[1] ) ) { im_close( out ); return( NULL ); } in = t[1]; } if( in->Bands == 3 && in->Type == IM_TYPE_UCS ) { IMAGE *t[2]; if( im_open_local_array( out, t, 2, "conv-1", "p" ) || im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || im_UCS2XYZ( t[0], t[1] ) ) { im_close( out ); return( NULL ); } in = t[1]; } if( in->Bands == 3 && in->Type == IM_TYPE_LAB ) { IMAGE *t[2]; if( im_open_local_array( out, t, 2, "conv-1", "p" ) || im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || im_Lab2XYZ( t[0], t[1] ) ) { im_close( out ); return( NULL ); } in = t[1]; } if( in->Bands == 3 && in->Type == IM_TYPE_XYZ ) { IMAGE *t[2]; if( im_open_local_array( out, t, 2, "conv-1", "p" ) || im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || im_XYZ2disp( t[0], t[1], im_col_displays( 7 ) ) ) { im_close( out ); return( NULL ); } in = t[1]; } /* Cast to the output format. */ { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_clip2fmt( in, t, format_table[in->BandFmt] ) ) { im_close( out ); return( NULL ); } in = t; } if( im_copy( in, out ) ) { im_close( out ); return( NULL ); } return( out ); }
int im_clip2f( IMAGE *in, IMAGE *out ) { return( im_clip2fmt( in, out, IM_BANDFMT_FLOAT ) ); }
int im_clip2d( IMAGE *in, IMAGE *out ) { return( im_clip2fmt( in, out, IM_BANDFMT_DOUBLE ) ); }
int im_clip2i( IMAGE *in, IMAGE *out ) { return( im_clip2fmt( in, out, IM_BANDFMT_INT ) ); }
static VipsFits * vips_fits_new_write( VipsImage *in, const char *filename ) { VipsImage *flip; VipsImage *type; VipsFits *fits; int status; status = 0; if( im_check_noncomplex( "im_vips2fits", in ) || im_check_uncoded( "im_vips2fits", in ) ) return( NULL ); /* Cast to a supported format. */ if( !(type = vips_image_new()) || vips_object_local( in, type ) || im_clip2fmt( in, type, vips_fits_bandfmt[in->BandFmt] ) ) return( NULL ); in = type; /* FITS has (0,0) in the bottom left, we need to flip. */ if( !(flip = vips_image_new()) || vips_object_local( in, flip ) || im_flipver( in, flip ) ) return( NULL ); in = flip; if( !(fits = VIPS_NEW( in, VipsFits )) ) return( NULL ); fits->filename = im_strdup( NULL, filename ); fits->image = in; fits->fptr = NULL; fits->lock = NULL; fits->band_select = -1; fits->buffer = NULL; g_signal_connect( in, "close", G_CALLBACK( vips_fits_close_cb ), fits ); if( !(fits->filename = im_strdup( NULL, filename )) ) return( NULL ); /* We need to be able to hold one scanline of one band. */ if( !(fits->buffer = VIPS_ARRAY( NULL, VIPS_IMAGE_SIZEOF_ELEMENT( in ) * in->Xsize, PEL )) ) return( NULL ); /* fits_create_file() will fail if there's a file of thet name, unless * we put a "!" in front ofthe filename. This breaks conventions with * the rest of vips, so just unlink explicitly. */ g_unlink( filename ); if( fits_create_file( &fits->fptr, filename, &status ) ) { im_error( "fits", _( "unable to write to \"%s\"" ), filename ); vips_fits_error( status ); return( NULL ); } fits->lock = g_mutex_new(); return( fits ); }
/* Use fftw2. */ static int invfft1( IMAGE *dummy, IMAGE *in, IMAGE *out ) { IMAGE *cmplx = im_open_local( dummy, "invfft1-1", "t" ); IMAGE *real = im_open_local( out, "invfft1-2", "t" ); const int half_width = in->Xsize / 2 + 1; /* Transform to halfcomplex here. */ double *half_complex = IM_ARRAY( dummy, in->Ysize * half_width * 2, double ); rfftwnd_plan plan; int x, y; double *q, *p; if( !cmplx || !real || !half_complex || im_pincheck( in ) || im_poutcheck( out ) ) return( -1 ); if( in->Coding != IM_CODING_NONE || in->Bands != 1 ) { im_error( "im_invfft", _( "one band uncoded only" ) ); return( -1 ); } /* Make dp complex image for input. */ if( im_clip2fmt( in, cmplx, IM_BANDFMT_DPCOMPLEX ) ) return( -1 ); /* Make mem buffer real image for output. */ if( im_cp_desc( real, in ) ) return( -1 ); real->BandFmt = IM_BANDFMT_DOUBLE; if( im_setupout( real ) ) return( -1 ); /* Build half-complex image. */ q = half_complex; for( y = 0; y < cmplx->Ysize; y++ ) { p = ((double *) cmplx->data) + y * in->Xsize * 2; for( x = 0; x < half_width; x++ ) { q[0] = p[0]; q[1] = p[1]; p += 2; q += 2; } } /* Make the plan for the transform. Yes, they really do use nx for * height and ny for width. */ if( !(plan = rfftw2d_create_plan( in->Ysize, in->Xsize, FFTW_BACKWARD, FFTW_MEASURE | FFTW_USE_WISDOM )) ) { im_error( "im_invfft", _( "unable to create transform plan" ) ); return( -1 ); } rfftwnd_one_complex_to_real( plan, (fftw_complex *) half_complex, (fftw_real *) real->data ); rfftwnd_destroy_plan( plan ); /* Copy to out. */ if( im_copy( real, out ) ) return( -1 ); return( 0 ); }
/** * im_vips2mask: * @in: input image * @filename: name for output mask * * Make a mask from an image. All images are cast to %IM_BANDFMT_DOUBLE * before processing. There are two cases for handling bands: * * If the image has a single band, im_vips2mask() will write a mask the same * size as the image. * * If the image has more than one band, it must be one pixel high or wide. In * this case the output mask uses that axis to represent band values. * * See also: im_mask2vips(), im_measure_area(). * * Returns: a #DOUBLEMASK with @outname set as the name, or NULL on error */ DOUBLEMASK * im_vips2mask( IMAGE *in, const char *filename ) { int width, height; DOUBLEMASK *out; /* double* only: cast if necessary. */ if( in->BandFmt != IM_BANDFMT_DOUBLE ) { IMAGE *t; if( !(t = im_open( "im_vips2mask", "p" )) ) return( NULL ); if( im_clip2fmt( in, t, IM_BANDFMT_DOUBLE ) || !(out = im_vips2mask( t, filename )) ) { im_close( t ); return( NULL ); } im_close( t ); return( out ); } /* Check the image. */ if( im_incheck( in ) || im_check_uncoded( "im_vips2mask", in ) ) return( NULL ); if( in->Bands == 1 ) { width = in->Xsize; height = in->Ysize; } else if( in->Xsize == 1 ) { width = in->Bands; height = in->Ysize; } else if( in->Ysize == 1 ) { width = in->Xsize; height = in->Bands; } else { im_error( "im_vips2mask", "%s", _( "one band, nx1, or 1xn images only" ) ); return( NULL ); } if( !(out = im_create_dmask( filename, width, height )) ) return( NULL ); if( in->Bands > 1 && in->Ysize == 1 ) { double *data = (double *) in->data; int x, y; /* Need to transpose: the image is RGBRGBRGB, we need RRRGGGBBB. */ for( y = 0; y < height; y++ ) for( x = 0; x < width; x++ ) out->coeff[x + y * width] = data[x * height + y]; } else memcpy( out->coeff, in->data, width * height * sizeof( double ) ); out->scale = vips_image_get_scale( in ); out->offset = vips_image_get_offset( in ); return( out ); }
INTMASK * im_vips2imask( IMAGE *in, const char *filename ) { int width, height; INTMASK *out; double *data; int x, y; double double_result; int int_result; /* double* only: cast if necessary. */ if( in->BandFmt != IM_BANDFMT_DOUBLE ) { IMAGE *t; if( !(t = im_open( "im_vips2imask", "p" )) ) return( NULL ); if( im_clip2fmt( in, t, IM_BANDFMT_DOUBLE ) || !(out = im_vips2imask( t, filename )) ) { im_close( t ); return( NULL ); } im_close( t ); return( out ); } /* Check the image. */ if( im_incheck( in ) || im_check_uncoded( "im_vips2imask", in ) ) return( NULL ); if( in->Bands == 1 ) { width = in->Xsize; height = in->Ysize; } else if( in->Xsize == 1 ) { width = in->Bands; height = in->Ysize; } else if( in->Ysize == 1 ) { width = in->Xsize; height = in->Bands; } else { im_error( "im_vips2imask", "%s", _( "one band, nx1, or 1xn images only" ) ); return( NULL ); } data = (double *) in->data; if( !(out = im_create_imask( filename, width, height )) ) return( NULL ); /* We want to make an intmask which has the same input to output ratio * as the double image. * * Imagine convolving with the double image, what's the ratio of * brightness between input and output? We want the same ratio for the * int version, if we can. * * Imaging an input image where every pixel is 1, what will the output * be? */ double_result = 0; for( y = 0; y < height; y++ ) for( x = 0; x < width; x++ ) double_result += data[x + width * y]; double_result /= vips_image_get_scale( in ); for( y = 0; y < height; y++ ) for( x = 0; x < width; x++ ) if( in->Bands > 1 && in->Ysize == 1 ) /* Need to transpose: the image is RGBRGBRGB, * we need RRRGGGBBB. */ out->coeff[x + y * width] = VIPS_RINT( data[x * height + y] ); else out->coeff[x + y * width] = VIPS_RINT( data[x + y * width] ); out->scale = VIPS_RINT( vips_image_get_scale( in ) ); if( out->scale == 0 ) out->scale = 1; out->offset = VIPS_RINT( vips_image_get_offset( in ) ); /* Now convolve a 1 everywhere image with the int version we've made, * what do we get? */ int_result = 0; for( y = 0; y < height; y++ ) for( x = 0; x < width; x++ ) int_result += out->coeff[x + width * y]; int_result /= out->scale; /* And adjust the scale to get as close to a match as we can. */ out->scale = VIPS_RINT( out->scale + (int_result - double_result) ); if( out->scale == 0 ) out->scale = 1; return( out ); }
/* Fall back to vips's built-in fft. */ static int invfft1( IMAGE *dummy, IMAGE *in, IMAGE *out ) { int bpx = im_ispoweroftwo( in->Xsize ); int bpy = im_ispoweroftwo( in->Ysize ); float *buf, *q, *p1; int x, y; /* Buffers for real and imaginary parts. */ IMAGE *real = im_open_local( dummy, "invfft1:1", "t" ); IMAGE *imag = im_open_local( dummy, "invfft1:2", "t" ); /* Temps. */ IMAGE *t1 = im_open_local( dummy, "invfft1:3", "p" ); IMAGE *t2 = im_open_local( dummy, "invfft1:4", "p" ); if( !real || !imag || !t1 ) return( -1 ); if( im_pincheck( in ) || im_outcheck( out ) ) return( -1 ); if( in->Coding != IM_CODING_NONE || in->Bands != 1 || !im_iscomplex( in ) ) { im_error( "im_invfft", "%s", _( "one band complex uncoded only" ) ); return( -1 ); } if( !bpx || !bpy ) { im_error( "im_invfft", "%s", _( "sides must be power of 2" ) ); return( -1 ); } /* Make sure we have a single-precision complex input image. */ if( im_clip2fmt( in, t1, IM_BANDFMT_COMPLEX ) ) return( -1 ); /* Extract real and imag parts. We have to complement the imaginary. */ if( im_c2real( t1, real ) ) return( -1 ); if( im_c2imag( t1, t2 ) || im_lintra( -1.0, t2, 0.0, imag ) ) return( -1 ); /* Transform! */ if( im__fft_sp( (float *) real->data, (float *) imag->data, bpx - 1, bpy - 1 ) ) { im_error( "im_invfft", "%s", _( "fft_sp failed" ) ); return( -1 ); } /* WIO to out. */ if( im_cp_desc( out, in ) ) return( -1 ); out->BandFmt = IM_BANDFMT_FLOAT; if( im_setupout( out ) ) return( -1 ); if( !(buf = (float *) IM_ARRAY( dummy, IM_IMAGE_SIZEOF_LINE( out ), PEL )) ) return( -1 ); /* Just write real part. */ for( p1 = (float *) real->data, y = 0; y < out->Ysize; y++ ) { q = buf; for( x = 0; x < out->Xsize; x++ ) { q[x] = *p1++; } if( im_writeline( y, out, (PEL *) buf ) ) return( -1 ); } return( 0 ); }
int im_clip2s( IMAGE *in, IMAGE *out ) { return( im_clip2fmt( in, out, IM_BANDFMT_SHORT ) ); }