Esempio n. 1
0
int
im_stdif_raw( IMAGE *in, IMAGE *out,
              double a, double m0, double b, double s0,
              int xwin, int ywin )
{
    StdifInfo *inf;

    if( xwin > in->Xsize ||
            ywin > in->Ysize ) {
        im_error( "im_stdif", "%s", _( "window too large" ) );
        return( -1 );
    }
    if( xwin <= 0 ||
            ywin <= 0 ) {
        im_error( "im_lhisteq", "%s", _( "window too small" ) );
        return( -1 );
    }
    if( m0 < 0 || m0 > 255 || a < 0 || a > 1.0 || b < 0 || b > 2 ||
            s0 < 0 || s0 > 255 ) {
        im_error( "im_stdif", "%s", _( "parameters out of range" ) );
        return( -1 );
    }
    if( im_check_format( "im_stdif", in, IM_BANDFMT_UCHAR ) ||
            im_check_uncoded( "im_stdif", in ) ||
            im_check_mono( "im_stdif", in ) ||
            im_piocheck( in, out ) )
        return( -1 );
    if( im_cp_desc( out, in ) )
        return( -1 );
    out->Xsize -= xwin;
    out->Ysize -= ywin;

    /* Save parameters.
     */
    if( !(inf = IM_NEW( out, StdifInfo )) )
        return( -1 );
    inf->xwin = xwin;
    inf->ywin = ywin;
    inf->a = a;
    inf->m0 = m0;
    inf->b = b;
    inf->s0 = s0;

    /* Set demand hints. FATSTRIP is good for us, as THINSTRIP will cause
     * too many recalculations on overlaps.
     */
    if( im_demand_hint( out, IM_FATSTRIP, in, NULL ) )
        return( -1 );

    /* Write the hist.
     */
    if( im_generate( out,
                     im_start_one, stdif_gen, im_stop_one, in, inf ) )
        return( -1 );

    return( 0 );
}
Esempio n. 2
0
/**
 * im_grad_x:
 * @in: input image
 * @out: output image
 *
 * Find horizontal differences between adjacent pixels.
 *
 * Generates an image where the value of each pixel is the difference between
 * it and the pixel to its right. The output has the same height as the input
 * and one pixel less width. One-band integer formats only. The result is
 * always %IM_BANDFMT_INT.
 *
 * This operation is much faster than (though equivalent to) im_conv() with the
 * mask [[-1, 1]].
 *
 * See also: im_grad_y(), im_conv().
 *
 * Returns: 0 on success, -1 on error
 */
int im_grad_x( IMAGE *in, IMAGE *out ){
#define FUNCTION_NAME "im_grad_x"

  if( im_piocheck( in, out ) )
    return -1;

  if( im_check_uncoded( "im_grad_x", in ) ||
	im_check_mono( "im_grad_x", in ) || 
	im_check_int( "im_grad_x", in ) )
	return( -1 );
  if( im_cp_desc( out, in ) )
    return -1;

  -- out-> Xsize;
  out-> BandFmt= IM_BANDFMT_INT; /* do not change without updating im_gradcor() */

  if( im_demand_hint( out, IM_THINSTRIP, in, NULL ) )
    return -1;

#define RETURN_GENERATE( TYPE ) return im_generate( out, im_start_one, xgrad_gen_ ## TYPE, im_stop_one, (void*) in, NULL )

  switch( in-> BandFmt ){

    case IM_BANDFMT_UCHAR:
      RETURN_GENERATE( guint8 );

    case IM_BANDFMT_CHAR:
      RETURN_GENERATE( gint8 );

    case IM_BANDFMT_USHORT:
      RETURN_GENERATE( guint16 );

    case IM_BANDFMT_SHORT:
      RETURN_GENERATE( gint16 );

    case IM_BANDFMT_UINT:
      RETURN_GENERATE( guint32 );

    case IM_BANDFMT_INT:
      RETURN_GENERATE( gint32 );
#if 0
    case IM_BANDFMT_FLOAT:
      RETURN_GENERATE( float );
    case IM_BANDFMT_DOUBLE:
      RETURN_GENERATE( double );
#endif
#undef RETURN_GENERATE
    default:
      g_assert( 0 );
  }

  /* Keep gcc happy.
   */
  return 0;
#undef FUNCTION_NAME
}
Esempio n. 3
0
int 
im__arith_binary_const( const char *domain,
	IMAGE *in, IMAGE *out, 
	int n, double *c, VipsBandFmt vfmt,
	int format_table[10], 
	im_wrapone_fn fn1, im_wrapone_fn fnn )
{
	PEL *vector;

	if( im_piocheck( in, out ) ||
		im_check_vector( domain, n, in ) ||
		im_check_uncoded( domain, in ) )
		return( -1 );
	if( im_cp_desc( out, in ) )
		return( -1 );
	out->BandFmt = format_table[in->BandFmt];

	/* Some operations need the vector in the input type (eg.
	 * im_equal_vec() where the output type is always uchar and is useless
	 * for comparisons), some need it in the output type (eg.
	 * im_andimage_vec() where we want to get the double to an int so we
	 * can do bitwise-and without having to cast for each pixel), some
	 * need a fixed type (eg. im_powtra_vec(), where we want to keep it as
	 * double).
	 *
	 * Therefore pass in the desired vector type as a param.
	 */
	if( !(vector = make_pixel( out, vfmt, n, c )) )
		return( -1 );

	/* Band-up the input image if we have a >1 vector and
	 * a 1-band image.
	 */
	if( n > 1 && out->Bands == 1 ) {
		IMAGE *t;

		if( !(t = im_open_local( out, domain, "p" )) ||
			im__bandup( domain, in, t, n ) )
			return( -1 );

		in = t;
	}

	if( n == 1 ) {
		if( im_wrapone( in, out, fn1, vector, in ) )
			return( -1 );
	}
	else {
		if( im_wrapone( in, out, fnn, vector, in ) )
			return( -1 );
	}

	return( 0 );
}
Esempio n. 4
0
int
im_contrast_surface_raw (IMAGE * in, IMAGE * out, int half_win_size,
			 int spacing)
{
#define FUNCTION_NAME "im_contrast_surface_raw"

  cont_surf_params_t *params;

  if (im_piocheck (in, out) ||
    im_check_uncoded (FUNCTION_NAME, in) ||
    im_check_mono (FUNCTION_NAME, in) ||
    im_check_format (FUNCTION_NAME, in, IM_BANDFMT_UCHAR))
    return -1;

  if (half_win_size < 1 || spacing < 1)
    {
      im_error (FUNCTION_NAME, "%s", _("bad parameters"));
      return -1;
    }

  if (DOUBLE (half_win_size) >= LESSER (in->Xsize, in->Ysize))
    {
      im_error (FUNCTION_NAME,
		"%s", _("parameters would result in zero size output image"));
      return -1;
    }

  params = IM_NEW (out, cont_surf_params_t);

  if (!params)
    return -1;

  params->half_win_size = half_win_size;
  params->spacing = spacing;

  if (im_cp_desc (out, in))
    return -1;

  out->BandFmt = IM_BANDFMT_UINT;

  out->Xsize = 1 + ((in->Xsize - DOUBLE_ADD_ONE (half_win_size)) / spacing);
  out->Ysize = 1 + ((in->Ysize - DOUBLE_ADD_ONE (half_win_size)) / spacing);

  out->Xoffset = -half_win_size;
  out->Yoffset = -half_win_size;

  if (im_demand_hint (out, IM_FATSTRIP, in, NULL))
    return -1;

  return im_generate (out, im_start_one, cont_surf_gen, im_stop_one, in,
		      params);

#undef FUNCTION_NAME
}
Esempio n. 5
0
int im_gradcor_raw( IMAGE *large, IMAGE *small, IMAGE *out ){
#define FUNCTION_NAME "im_gradcor_raw"

  if( im_piocheck( large, out ) || im_pincheck( small ) )
    return -1;

  if( im_check_uncoded( "im_gradcor", large ) ||
	im_check_mono( "im_gradcor", large ) || 
	im_check_uncoded( "im_gradcor", small ) ||
	im_check_mono( "im_gradcor", small ) || 
	im_check_format_same( "im_gradcor", large, small ) ||
	im_check_int( "im_gradcor", large ) )
	return( -1 );

  if( large-> Xsize < small-> Xsize || large-> Ysize < small-> Ysize ){
    im_error( FUNCTION_NAME, "second image must be smaller than first" );
    return -1;
  }
  if( im_cp_desc( out, large ) )
    return -1;

  out-> Xsize= 1 + large-> Xsize - small-> Xsize;
  out-> Ysize= 1 + large-> Ysize - small-> Ysize;
  out-> BandFmt= IM_BANDFMT_FLOAT;

  if( im_demand_hint( out, IM_FATSTRIP, large, NULL ) )
    return -1;

  {
    IMAGE *xgrad= im_open_local( out, FUNCTION_NAME ": xgrad", "t" );
    IMAGE *ygrad= im_open_local( out, FUNCTION_NAME ": ygrad", "t" );
    IMAGE **grads= im_allocate_input_array( out, xgrad, ygrad, NULL );

    return ! xgrad || ! ygrad || ! grads
      || im_grad_x( small, xgrad )
      || im_grad_y( small, ygrad )
      || im_generate( out, gradcor_start, gradcor_gen, gradcor_stop, (void*) large, (void*) grads );
  }
#undef FUNCTION_NAME
}
Esempio n. 6
0
/* Normalise an image using the rules noted above.
 */
static int
normalise( IMAGE *in, IMAGE *out )
{
	if( im_check_uncoded( "im_histplot", in ) ||
		im_check_noncomplex( "im_histplot", in ) )
		return( -1 );

	if( vips_bandfmt_isuint( in->BandFmt ) ) {
		if( im_copy( in, out ) )
			return( -1 );
	}
	else if( vips_bandfmt_isint( in->BandFmt ) ) {
		IMAGE *t1;
		double min;

		/* Move min up to 0. 
		 */
		if( !(t1 = im_open_local( out, "im_histplot", "p" )) ||
			im_min( in, &min ) ||
			im_lintra( 1.0, in, -min, t1 ) )
			return( -1 );
	}
	else {
		/* Float image: scale min--max to 0--any. Output square
		 * graph.
		 */
		IMAGE *t1;
		DOUBLEMASK *stats;
		double min, max;
		int any;

		if( in->Xsize == 1 )
			any = in->Ysize;
		else
			any = in->Xsize;

		if( !(stats = im_stats( in )) )
			return( -1 );
		min = VIPS_MASK( stats, 0, 0 );
		max = VIPS_MASK( stats, 1, 0 );
		im_free_dmask( stats );

		if( !(t1 = im_open_local( out, "im_histplot", "p" )) ||
			im_lintra( any / (max - min), in, 
				-min * any / (max - min), out ) )
			return( -1 );
	}

	return( 0 );
}
Esempio n. 7
0
/**
 * im_c2amph:
 * @in: input image
 * @out: output image
 *
 * Convert a complex image from rectangular to polar coordinates. Angles are
 * expressed in degrees.
 *
 * See also: im_c2rect(), im_abs().
 *
 * Returns: 0 on success, -1 on error
 */
int 
im_c2amph( IMAGE *in, IMAGE *out )
{
	if( im_check_uncoded( "im_c2amph", in ) ||
		im_check_complex( "im_c2amph", in ) ||
		im_cp_desc( out, in ) )
                return( -1 );

        if( im_wrapone( in, out,
                (im_wrapone_fn) buffer_c2amph, in, NULL ) )
                return( -1 );

	return( 0 );
}
Esempio n. 8
0
/**
 * im_abs:
 * @in: input #IMAGE
 * @out: output #IMAGE
 *
 * This operation finds the absolute value of an image. It does a copy for
 * unsigned integer types, negate for negative values in
 * signed integer types, <function>fabs(3)</function> for
 * float types, and calculate modulus for complex
 * types.
 *
 * See also: im_exp10tra(), im_sign().
 *
 * Returns: 0 on success, -1 on error
 */
int
im_abs( IMAGE *in, IMAGE *out )
{
    if( im_piocheck( in, out ) ||
            im_check_uncoded( "im_abs", in ) )
        return( -1 );

    /* Is this one of the unsigned types? Degenerate to im_copy() if it
     * is.
     */
    if( vips_bandfmt_isuint( in->BandFmt ) )
        return( im_copy( in, out ) );

    /* Prepare output header. Output type == input type, except for
     * complex.
     */
    if( im_cp_desc( out, in ) )
        return( -1 );
    switch( in->BandFmt ) {
    case IM_BANDFMT_CHAR:
    case IM_BANDFMT_SHORT:
    case IM_BANDFMT_INT:
    case IM_BANDFMT_FLOAT:
    case IM_BANDFMT_DOUBLE:
        /* No action.
         */
        break;

    case IM_BANDFMT_COMPLEX:
        out->BandFmt = IM_BANDFMT_FLOAT;
        break;

    case IM_BANDFMT_DPCOMPLEX:
        out->BandFmt = IM_BANDFMT_DOUBLE;
        break;

    default:
        im_error( "im_abs", "%s", _( "unknown input type" ) );
        return( -1 );
    }

    /* Generate!
     */
    if( im_wrapone( in, out,
                    (im_wrapone_fn) abs_gen, in, NULL ) )
        return( -1 );

    return( 0 );
}
Esempio n. 9
0
int 
im_lhisteq_raw( IMAGE *in, IMAGE *out, int xwin, int ywin )
{
	LhistInfo *inf;

	if( im_check_mono( "im_lhisteq", in ) ||
		im_check_uncoded( "im_lhisteq", in ) ||
		im_check_format( "im_lhisteq", in, IM_BANDFMT_UCHAR ) ||
		im_piocheck( in, out ) )
		return( -1 );
	if( xwin > in->Xsize || 
		ywin > in->Ysize ) {
		im_error( "im_lhisteq", "%s", _( "window too large" ) );
		return( -1 );
	}
	if( xwin <= 0 || 
		ywin <= 0 ) {
		im_error( "im_lhisteq", "%s", _( "window too small" ) );
		return( -1 );
	}

	if( im_cp_desc( out, in ) ) 
		return( -1 );
	out->Xsize -= xwin - 1;
	out->Ysize -= ywin - 1;

	/* Save parameters.
	 */
	if( !(inf = IM_NEW( out, LhistInfo )) )
		return( -1 );
	inf->xwin = xwin;
	inf->ywin = ywin;
	inf->npels = xwin * ywin;

	/* Set demand hints. FATSTRIP is good for us, as THINSTRIP will cause
	 * too many recalculations on overlaps.
	 */
	if( im_demand_hint( out, IM_FATSTRIP, in, NULL ) )
		return( -1 );

	if( im_generate( out,
		im_start_one, lhist_gen, im_stop_one, in, inf ) )
		return( -1 );

	out->Xoffset = -xwin / 2;
	out->Yoffset = -xwin / 2;

	return( 0 );
}
Esempio n. 10
0
/**
 * 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 ) );
}
Esempio n. 11
0
/**
 * im_zerox:
 * @in: input image
 * @out: output image
 * @sign: detect positive or negative zero crossings
 *
 * im_zerox() detects the positive or negative zero crossings @in, 
 * depending on @sign. If @sign is -1, negative zero crossings are returned,
 * if @sign is 1, positive zero crossings are returned.
 *
 * The output image is byte with zero crossing set to 255 and all other values
 * set to zero. Input can have any number of channels, and be any non-complex 
 * type.
 *
 * See also: im_conv(), im_rot90.
 *
 * Returns: 0 on success, -1 on error
 */
int 
im_zerox( IMAGE *in, IMAGE *out, int sign )
{
	IMAGE *t1;

	if( sign != -1 && sign != 1 ) {
		im_error( "im_zerox", "%s", _( "flag not -1 or 1" ) );
		return( -1 );
	}
	if( in->Xsize < 2 ) {
		im_error( "im_zerox", "%s", _( "image too narrow" ) );
		return( -1 );
	}
	if( !(t1 = im_open_local( out, "im_zerox" , "p" )) ||
		im_piocheck( in, t1 ) ||
		im_check_uncoded( "im_zerox", in ) ||
		im_check_noncomplex( "im_zerox", in ) )
		return( -1 );
	if( vips_bandfmt_isuint( in->BandFmt ) )
		/* Unsigned type, therefore there will be no zero-crossings.
		 */
		return( im_black( out, in->Xsize, in->Ysize, in->Bands ) );

	/* Force output to be BYTE. Output is narrower than input by 1 pixel.
	 */
	if( im_cp_desc( t1, in ) )
		return( -1 );
	t1->BandFmt = IM_BANDFMT_UCHAR;
	t1->Xsize -= 1;

	/* Set hints - THINSTRIP is ok with us.
	 */
	if( im_demand_hint( t1, IM_THINSTRIP, NULL ) )
		return( -1 );

	/* Generate image.
	 */
	if( im_generate( t1, im_start_one, zerox_gen, im_stop_one, 
		in, GINT_TO_POINTER( sign ) ) )
		return( -1 );

	/* Now embed it in a larger image.
	 */
	if( im_embed( t1, out, 0, 0, 0, in->Xsize, in->Ysize ) )
		return( -1 );

	return( 0 );
}
Esempio n. 12
0
/* Raw fastcor, with no borders.
 */
int 
im_fastcor_raw( IMAGE *in, IMAGE *ref, IMAGE *out )
{
	/* PIO between in and out; WIO from ref.
	 */
	if( im_piocheck( in, out ) || 
		im_incheck( ref ) )
		return( -1 );

	/* Check sizes.
	 */
	if( in->Xsize < ref->Xsize || in->Ysize < ref->Ysize ) {
		im_error( "im_fastcor", "%s", 
			_( "ref not smaller than or equal to in" ) );
		return( -1 );
	}

	/* Check types.
	 */
	if( im_check_uncoded( "im_fastcor", in ) ||
		im_check_mono( "im_fastcor", in ) || 
		im_check_format( "im_fastcor", in, IM_BANDFMT_UCHAR ) ||
		im_check_coding_same( "im_fastcor", in, ref ) ||
		im_check_bands_same( "im_fastcor", in, ref ) || 
		im_check_format_same( "im_fastcor", in, ref ) )
		return( -1 );

	/* Prepare the output image. 
	 */
	if( im_cp_descv( out, in, ref, NULL ) )
		return( -1 );
	out->BandFmt = IM_BANDFMT_UINT;
	out->Xsize = in->Xsize - ref->Xsize + 1;
	out->Ysize = in->Ysize - ref->Ysize + 1;

	/* FATSTRIP is good for us, as THINSTRIP will cause
	 * too many recalculations on overlaps.
	 */
	if( im_demand_hint( out, IM_FATSTRIP, in, NULL ) ||
		im_generate( out, 
			im_start_one, fastcor_gen, im_stop_one, in, ref ) )
		return( -1 );

	out->Xoffset = -ref->Xsize / 2;
	out->Yoffset = -ref->Ysize / 2;

	return( 0 );
}
Esempio n. 13
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 ) );
}
Esempio n. 14
0
/**
 * im_copy_swap:
 * @in: input image
 * @out: output image
 *
 * Copy an image, swapping byte order between little and big endian. This
 * really does change image pixels and does not just alter the header.
 *
 * See also: im_copy(), im_amiMSBfirst(), im_isMSBfirst().
 *
 * Returns: 0 on success, -1 on error.
 */
int
im_copy_swap( IMAGE *in, IMAGE *out )
{
        if( im_piocheck( in, out ) ||
		im_check_uncoded( "im_copy_swap", in ) ||
		im_cp_desc( out, in ) )
                return( -1 );

	switch( in->BandFmt ) {
        case IM_BANDFMT_CHAR:
        case IM_BANDFMT_UCHAR:
		if( im_copy( in, out ) ) 
			return( -1 );
		break;

        case IM_BANDFMT_SHORT:
        case IM_BANDFMT_USHORT:
		if( im_wrapone( in, out, 
			(im_wrapone_fn) im_copy_swap2_gen, in, NULL ) )
			return( -1 );
		break;

	case IM_BANDFMT_INT:
	case IM_BANDFMT_UINT:
	case IM_BANDFMT_FLOAT:
	case IM_BANDFMT_COMPLEX:
		if( im_wrapone( in, out, 
			(im_wrapone_fn) im_copy_swap4_gen, in, NULL ) )
			return( -1 );
		break;

        case IM_BANDFMT_DOUBLE:
        case IM_BANDFMT_DPCOMPLEX:
		if( im_wrapone( in, out, 
			(im_wrapone_fn) im_copy_swap8_gen, in, NULL ) )
			return( -1 );
		break;

	default:
		im_error( "im_copy_swap", "%s", _( "unsupported image type" ) );
		return( -1 );
	}

	return( 0 );
}
Esempio n. 15
0
/**
 * im_measure_area:
 * @im: image to measure
 * @left: area of image containing chart
 * @top: area of image containing chart
 * @width: area of image containing chart
 * @height: area of image containing chart
 * @h: patches across chart
 * @v: patches down chart
 * @sel: array of patch numbers to measure (numbered from 1 in row-major order)
 * @nsel: length of patch number array
 * @name: name to give to returned @DOUBLEMASK
 *
 * Analyse a grid of colour patches, producing a #DOUBLEMASK of patch averages.
 * The mask has a row for each measured patch, and a column for each image
 * band. The operations issues a warning if any patch has a deviation more 
 * than 20% of
 * the mean. Only the central 50% of each patch is averaged. If @sel is %NULL
 * then all patches are measured.
 *
 * Example: 6 band image of 4x2 block of colour patches.
 *
 * <tgroup cols='4' align='left' colsep='1' rowsep='1'>
 *   <tbody>
 *     <row>
 *       <entry>1</entry>
 *       <entry>2</entry>
 *       <entry>3</entry>
 *       <entry>4</entry>
 *     </row>
 *     <row>
 *       <entry>5</entry>
 *       <entry>6</entry>
 *       <entry>7</entry>
 *       <entry>8</entry>
 *     </row>
 *   </tbody>
 * </tgroup>
 *
 * Then call im_measure( im, box, 4, 2, { 2, 4 }, 2, "fred" ) makes a mask
 * "fred" which has 6 columns, two rows. The first row contains the averages
 * for patch 2, the second for patch 4.
 *
 * See also: im_avg(), im_deviate(), im_stats().
 * 
 * Returns: #DOUBLEMASK of measurements.
 */
DOUBLEMASK *
im_measure_area( IMAGE *im, 
	int left, int top, int width, int height, 
	int u, int v, 
	int *sel, int nsel, const char *name )
{	
	DOUBLEMASK *mask;

	/* Check input image.
	 */
	if( im->Coding == IM_CODING_LABQ ) {
		IMAGE *t1;
		
		if( !(t1 = im_open( "measure-temp", "p" )) )
			return( NULL );
		if( im_LabQ2Lab( im, t1 ) ||
			!(mask = im_measure_area( t1, 
				left, top, width, height,
				u, v, 
				sel, nsel, name )) ) {
			im_close( t1 );
			return( NULL );
		}

		im_close( t1 );

		return( mask );
	}

	if( im_check_uncoded( "im_measure", im ) ||
		im_check_noncomplex( "im_measure", im ) )
		return( NULL );

	/* Default to all patches if sel == NULL.
	 */
	if( sel == NULL ) {
		int i;

		nsel = u * v;
		if( !(sel = IM_ARRAY( im, nsel, int )) )
			return( NULL );
		for( i = 0; i < nsel; i++ )
			sel[i] = i + 1;
	}
Esempio n. 16
0
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 );
}
Esempio n. 17
0
/** 
 * im_maxpos_avg:
 * @im: image to scan
 * @xpos: returned X position
 * @ypos: returned Y position
 * @out: returned value
 *
 * Function to find the maximum of an image.  Returns coords and value at
 * double precision.  In the event of a draw, returns average of all 
 * drawing coords.
 *
 * See also: im_maxpos(), im_min(), im_stats().
 *
 * Returns: 0 on success, -1 on error
 */
int
im_maxpos_avg( IMAGE *in, double *xpos, double *ypos, double *out )
{
	Maxposavg *global_maxposavg;

	if( im_pincheck( in ) ||
		im_check_uncoded( "im_maxpos_avg", in ) )
		return( -1 );

	if( !(global_maxposavg = IM_NEW( in, Maxposavg )) ) 
		return( -1 );
	if( im__value( in, &global_maxposavg->max ) )
		return( -1 );
	global_maxposavg->xpos = 0;
	global_maxposavg->ypos = 0;
	global_maxposavg->occurences = 1;

	/* We use square mod for scanning, for speed.
	 */
	if( vips_band_format_iscomplex( in->BandFmt ) )
		global_maxposavg->max *= global_maxposavg->max;

	if( vips_sink( in, maxposavg_start, maxposavg_scan, maxposavg_stop, 
		in, global_maxposavg ) ) 
		return( -1 );

	/* Back to modulus.
	 */
	if( vips_band_format_iscomplex( in->BandFmt ) )
		global_maxposavg->max = sqrt( global_maxposavg->max );

	if( xpos )
		*xpos = (double) global_maxposavg->xpos / 
			global_maxposavg->occurences;
	if( ypos )
		*ypos = (double) global_maxposavg->ypos / 
			global_maxposavg->occurences;
	if( out )
		*out = global_maxposavg->max;

	return( 0 );
}
Esempio n. 18
0
/**
 * im_c2real:
 * @in: input image
 * @out: output image
 *
 * Extract the real part of a complex image.
 *
 * See also: im_c2imag().
 *
 * Returns: 0 on success, -1 on error
 */
int 
im_c2real( IMAGE *in, IMAGE *out )
{
	if( im_check_uncoded( "im_c2real", in ) ||
		im_check_complex( "im_c2real", in ) ||
		im_cp_desc( out, in ) )
                return( -1 );

	/* Output will be float or double.
	 */
	if( in->BandFmt == IM_BANDFMT_DPCOMPLEX ) 
		out->BandFmt = IM_BANDFMT_DOUBLE;
	else 
		out->BandFmt = IM_BANDFMT_FLOAT;

        if( im_wrapone( in, out,
                (im_wrapone_fn) buffer_c2real, in, NULL ) )
                return( -1 );

	return( 0 );
}
Esempio n. 19
0
/**
 * im_vips2csv:
 * @in: image to save 
 * @filename: file to write to 
 *
 * Save a CSV (comma-separated values) file. The image is written
 * one line of text per scanline. Complex numbers are written as 
 * "(real,imaginary)" and will need extra parsing I guess. The image must
 * have a single band.
 *
 * Write options can be embedded in the filename. The options can be given 
 * in any order and are:
 *
 * <itemizedlist>
 *   <listitem>
 *     <para>
 * <emphasis>sep:separator-string</emphasis> 
 * The string to use to separate numbers in the output. 
 * The default is "\\t" (tab).
 *     </para>
 *   </listitem>
 * </itemizedlist>
 *
 * For example:
 *
 * |[
 * im_csv2vips( in, "fred.csv:sep:\t" );
 * ]|
 *
 * Will write to fred.csv, separating numbers with tab characters.
 *
 * See also: #VipsFormat, im_csv2vips(), im_write_dmask(), im_vips2ppm().
 *
 * Returns: 0 on success, -1 on error.
 */
int 
im_vips2csv( IMAGE *in, const char *filename )
{
	char *separator = "\t";

	char name[FILENAME_MAX];
	char mode[FILENAME_MAX];
	FILE *fp;
	char *p, *q, *r;

	/* Parse mode string.
	 */
	im_filename_split( filename, name, mode );
	p = &mode[0];
	while( (q = im_getnextoption( &p )) ) {
		if( im_isprefix( "sep", q ) && (r = im_getsuboption( q )) )
			separator = r;
	}

	if( im_incheck( in ) ||
		im_check_mono( "im_vips2csv", in ) ||
		im_check_uncoded( "im_vips2csv", in ) )
		return( -1 );

	if( !(fp = fopen( name, "w" )) ) {
		im_error( "im_cvips2csv", _( "unable to open \"%s\"" ), 
			name );
		return( -1 );
	}

	if( vips2csv( in, fp, separator ) ) {
		fclose( fp );
		return( -1 );
	}

	fclose( fp );

	return( 0 );
}
Esempio n. 20
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 );
}
Esempio n. 21
0
static DOUBLEMASK *
internal_im_measure_area( IMAGE *im, 
	int left, int top, int width, int height, 
	int u, int v, 
	int *sel, int nsel, const char *name )
{	
	DOUBLEMASK *mask;

	if( im_check_uncoded( "im_measure", im ) ||
		im_check_noncomplex( "im_measure", im ) )
		return( NULL );

	/* Default to all patches if sel == NULL.
	 */
	if( sel == NULL ) {
		int i;

		nsel = u * v;
		if( !(sel = IM_ARRAY( im, nsel, int )) )
			return( NULL );
		for( i = 0; i < nsel; i++ )
			sel[i] = i + 1;
	}
Esempio n. 22
0
/**
 * im_profile:
 * @in: input image
 * @out: output image
 * @dir: search direction
 *
 * im_profile() searches inward from the edge of @in and finds the 
 * first non-zero pixel. It outputs an image containing a list of the offsets 
 * for each row or column.
 *
 * If @dir == 0, then im_profile() searches down from the top edge, writing an 
 * image as wide as the input image, but only 1 pixel high, containing the 
 * number of pixels down to the first non-zero pixel for each column of input 
 * pixels.
 *
 * If @dir == 1, then im_profile() searches across from the left edge, 
 * writing an image as high as the input image, but only 1 pixel wide, 
 * containing the number of pixels across to the
 * first non-zero pixel for each row of input pixels.
 *
 * See also: im_cntlines().
 *
 * Returns: 0 on success, -1 on error
 */
int 
im_profile( IMAGE *in, IMAGE *out, int dir )
{
	int sz;
	unsigned short *buf;
	int x, y, b;

	/* If in is not uchar, do (!=0) to make a uchar image.
	 */
	if( in->BandFmt != IM_BANDFMT_UCHAR ) {
		IMAGE *t;

		if( !(t = im_open_local( out, "im_profile", "p" )) ||
			im_notequalconst( in, t, 0 ) )
			return( -1 );

		in = t;
	}

	/* Check im.
	 */
	if( im_iocheck( in, out ) ||
		im_check_uncoded( "im_profile", in ) ||
		im_check_format( "im_profile", in, IM_BANDFMT_UCHAR ) )
		return( -1 );
	if( dir != 0 && 
		dir != 1 ) {
		im_error( "im_profile", "%s", _( "dir not 0 or 1" ) );
		return( -1 ); 
	}

	if( im_cp_desc( out, in ) )
		return( -1 );
	out->Type = IM_TYPE_HISTOGRAM;
	if( dir == 0 ) {
		out->Xsize = in->Xsize;
		out->Ysize = 1;
	}
	else {
		out->Xsize = 1;
		out->Ysize = in->Ysize;
	}
	out->BandFmt = IM_BANDFMT_USHORT;
	if( im_setupout( out ) )
		return( -1 );
	sz = IM_IMAGE_N_ELEMENTS( out );
	if( !(buf = IM_ARRAY( out, sz, unsigned short )) )
		return( -1 );

	if( dir == 0 ) {
		/* Find vertical lines.
		 */
		for( x = 0; x < sz; x++ ) {
			PEL *p = (PEL *) IM_IMAGE_ADDR( in, 0, 0 ) + x;
			int lsk = IM_IMAGE_SIZEOF_LINE( in );

			for( y = 0; y < in->Ysize; y++ ) {
				if( *p )
					break;
				p += lsk;
			}

			buf[x] = y;
		}

		if( im_writeline( 0, out, (PEL *) buf ) )
			return( -1 );
	}
	else {
		/* Search horizontal lines.
		 */
		for( y = 0; y < in->Ysize; y++ ) {
			PEL *p = (PEL *) IM_IMAGE_ADDR( in, 0, y );

			for( b = 0; b < in->Bands; b++ ) {
				PEL *p1;

				p1 = p + b;
				for( x = 0; x < in->Xsize; x++ ) {
					if( *p1 )
						break;
					p1 += in->Bands;
				}

				buf[b] = x;
			}

			if( im_writeline( y, out, (PEL *) buf ) )
				return( -1 );
		}
	}

	return( 0 );
}
Esempio n. 23
0
static Morph *
morph_new( IMAGE *in, IMAGE *out, INTMASK *mask, MorphOp op )
{
	const int n_mask = mask->xsize * mask->ysize; 

        Morph *morph;
        int i;

	/* If in is not uchar, do (!=0) to make a uchar image.
	 */
	if( in->BandFmt != IM_BANDFMT_UCHAR ) {
		IMAGE *t;

		if( !(t = im_open_local( out, "morph_new", "p" )) ||
			im_notequalconst( in, t, 0 ) )
			return( NULL );

		in = t;
	}

	if( im_piocheck( in, out ) ||
		im_check_uncoded( "morph", in ) ||
		im_check_format( "morph", in, IM_BANDFMT_UCHAR ) ||
		im_check_imask( "morph", mask ) ) 
		return( NULL );
	for( i = 0; i < n_mask; i++ )
		if( mask->coeff[i] != 0 && 
			mask->coeff[i] != 128 &&
			mask->coeff[i] != 255 ) {
			im_error( "morph", 
				_( "bad mask element (%d "
				"should be 0, 128 or 255)" ), 
				mask->coeff[i] );
			return( NULL );
		}

        if( !(morph = IM_NEW( out, Morph )) )
                return( NULL );

        morph->in = in;
        morph->out = out;
        morph->mask = NULL;
        morph->op = op;

        morph->n_pass = 0;
	for( i = 0; i < MAX_PASS; i++ )
		morph->pass[i].vector = NULL;

        if( im_add_close_callback( out, 
		(im_callback_fn) morph_close, morph, NULL ) ||
        	!(morph->mask = im_dup_imask( mask, "morph" )) )
                return( NULL );

	/* Generate code for this mask / image, if possible.
	 */
	if( vips_vector_isenabled() ) {
		if( pass_compile( morph ) )
			pass_free( morph );
	}

        return( morph );
}
Esempio n. 24
0
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 );
}
Esempio n. 25
0
/* Break a mask into lines.
 */
static Lines *
lines_new( IMAGE *in, IMAGE *out, DOUBLEMASK *mask, int n_layers )
{
	const int width = mask->xsize * mask->ysize;

	Lines *lines;
	double max;
	double min;
	double depth;
	double sum;
	int layers_above;
	int layers_below;
	int z, n, x;

	/* Check parameters.
	 */
	if( im_piocheck( in, out ) ||
		im_check_uncoded( "im_aconvsep", in ) ||
		vips_check_dmask_1d( "im_aconvsep", mask ) ) 
		return( NULL );

	lines = VIPS_NEW( out, Lines );
	lines->in = in;
	lines->out = out;
	if( !(lines->mask = (DOUBLEMASK *) im_local( out, 
		(im_construct_fn) im_dup_dmask,
		(im_callback_fn) im_free_dmask, mask, mask->filename, NULL )) )
		return( NULL );
	lines->n_layers = n_layers;
	lines->n_lines = 0;

	VIPS_DEBUG_MSG( "lines_new: breaking into %d layers ...\n", n_layers );

	/* Find mask range. We must always include the zero axis in the mask.
	 */
	max = 0;
	min = 0;
	for( x = 0; x < width; x++ ) {
		if( mask->coeff[x] > max )
			max = mask->coeff[x];
		if( mask->coeff[x] < min )
			min = mask->coeff[x];
	}

	/* The zero axis must fall on a layer boundary. Estimate the
	 * depth, find n-lines-above-zero, get exact depth, then calculate a
	 * fixed n-lines which includes any negative parts.
	 */
	depth = (max - min) / n_layers;
	layers_above = ceil( max / depth );
	depth = max / layers_above;
	layers_below = floor( min / depth );
	n_layers = layers_above - layers_below;

	VIPS_DEBUG_MSG( "depth = %g, n_layers = %d\n", depth, n_layers );

	/* For each layer, generate a set of lines which are inside the
	 * perimeter. Work down from the top.
	 */
	for( z = 0; z < n_layers; z++ ) {
		double y = max - (1 + z) * depth;

		/* y plus half depth ... ie. the layer midpoint.
		 */
		double y_ph = y + depth / 2;

		/* Odd, but we must avoid rounding errors that make us miss 0
		 * in the line above.
		 */
		int y_positive = z < layers_above;

		int inside;

		/* Start outside the perimeter.
		 */
		inside = 0;

		for( x = 0; x < width; x++ ) {
			/* The vertical line from mask[z] to 0 is inside. Is
			 * our current square (x, y) part of that line?
			 */
			if( (y_positive && mask->coeff[x] >= y_ph) ||
				(!y_positive && mask->coeff[x] <= y_ph) ) {
				if( !inside ) {
					lines_start( lines, x, 
						y_positive ? 1 : -1 );
					inside = 1;
				}
			}
			else {
				if( inside ) {
					if( lines_end( lines, x ) )
						return( NULL );
					inside = 0;
				}
			}
		}

		if( inside && 
			lines_end( lines, width ) )
			return( NULL );
	}

	/* Can we common up any lines? Search for lines with identical
	 * start/end.
	 */
	for( z = 0; z < lines->n_lines; z++ ) {
		for( n = z + 1; n < lines->n_lines; n++ ) {
			if( lines->start[z] == lines->start[n] &&
				lines->end[z] == lines->end[n] ) {
				lines->factor[z] += lines->factor[n];

				/* n can be deleted. Do this in a separate
				 * pass below.
				 */
				lines->factor[n] = 0;
			}
		}
	}

	/* Now we can remove all factor 0 lines.
	 */
	for( z = 0; z < lines->n_lines; z++ ) {
		if( lines->factor[z] == 0 ) {
			for( x = z; x < lines->n_lines; x++ ) {
				lines->start[x] = lines->start[x + 1];
				lines->end[x] = lines->end[x + 1];
				lines->factor[x] = lines->factor[x + 1];
			}
			lines->n_lines -= 1;
		}
	}

	/* Find the area of the lines.
	 */
	lines->area = 0;
	for( z = 0; z < lines->n_lines; z++ ) 
		lines->area += lines->factor[z] * 
			(lines->end[z] - lines->start[z]);

	/* Strength reduction: if all lines are divisible by n, we can move
	 * that n out into the ->area factor. The aim is to produce as many
	 * factor 1 lines as we can and to reduce the chance of overflow.
	 */
	x = lines->factor[0];
	for( z = 1; z < lines->n_lines; z++ ) 
		x = gcd( x, lines->factor[z] );
	for( z = 0; z < lines->n_lines; z++ ) 
		lines->factor[z] /= x;
	lines->area *= x;

	/* Find the area of the original mask.
	 */
	sum = 0;
	for( z = 0; z < width; z++ ) 
		sum += mask->coeff[z];

	lines->area = rint( sum * lines->area / mask->scale );
	lines->rounding = (lines->area + 1) / 2 + mask->offset * lines->area;

	/* ASCII-art layer drawing.
	printf( "lines:\n" );
	for( z = 0; z < lines->n_lines; z++ ) {
		printf( "%3d - %2d x ", z, lines->factor[z] );
		for( x = 0; x < 55; x++ ) {
			int rx = x * (width + 1) / 55;

			if( rx >= lines->start[z] && rx < lines->end[z] )
				printf( "#" );
			else
				printf( " " );
		}
		printf( " %3d .. %3d\n", lines->start[z], lines->end[z] );
	}
	printf( "area = %d\n", lines->area );
	printf( "rounding = %d\n", lines->rounding );
	 */

	return( lines );
}
Esempio n. 26
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 );
}
Esempio n. 27
0
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 );
}
Esempio n. 28
0
/* Break a mask into boxes.
 */
static Boxes *
boxes_new( IMAGE *in, IMAGE *out, DOUBLEMASK *mask, int n_layers, int cluster )
{
	const int size = mask->xsize * mask->ysize;

	Boxes *boxes;
	double sum;
	int x, y, z;

	/* Check parameters.
	 */
	if( im_piocheck( in, out ) ||
		im_check_uncoded( "im_aconv", in ) ||
		vips_check_dmask( "im_aconv", mask ) ) 
		return( NULL );

	boxes = VIPS_NEW( out, Boxes );
	boxes->in = in;
	boxes->out = out;
	if( !(boxes->mask = (DOUBLEMASK *) im_local( out, 
		(im_construct_fn) im_dup_dmask,
		(im_callback_fn) im_free_dmask, mask, mask->filename, NULL )) )
		return( NULL );
	boxes->n_layers = n_layers;
	boxes->cluster = cluster;

	boxes->n_hline = 0;
	boxes->n_velement = 0;
	boxes->n_vline = 0;

	/* Break into a set of hlines.
	 */
	if( boxes_break( boxes ) )
		return( NULL );

	/* Cluster to find groups of lines.
	 */
	VIPS_DEBUG_MSG( "boxes_new: clustering with thresh %d ...\n", cluster );
	while( boxes_cluster2( boxes, cluster ) )
		;

	/* Renumber to remove holes created by clustering.
	 */
	boxes_renumber( boxes );

	/* Find a set of vlines for the remaining hlines.
	 */
	boxes_vline( boxes );

	/* Find the area of the lines and the length of the longest hline.
	 */
	boxes->area = 0;
	boxes->max_line = 0;
	for( y = 0; y < boxes->n_velement; y++ ) {
		x = boxes->velement[y].band;
		z = boxes->hline[x].end - boxes->hline[x].start;

		boxes->area += boxes->velement[y].factor * z;
		if( z > boxes->max_line )
			boxes->max_line = z;
	}

	/* Strength reduction: if all lines are divisible by n, we can move
	 * that n out into the ->area factor. The aim is to produce as many
	 * factor 1 lines as we can and to reduce the chance of overflow.
	 */
	x = boxes->velement[0].factor;
	for( y = 1; y < boxes->n_velement; y++ ) 
		x = gcd( x, boxes->velement[y].factor );
	for( y = 0; y < boxes->n_velement; y++ ) 
		boxes->velement[y].factor /= x;
	boxes->area *= x;

	/* Find the area of the original mask.
	 */
	sum = 0;
	for( z = 0; z < size; z++ ) 
		sum += mask->coeff[z];

	boxes->area = rint( sum * boxes->area / mask->scale );
	boxes->rounding = (boxes->area + 1) / 2 + mask->offset * boxes->area;

#ifdef DEBUG
	boxes_hprint( boxes );
	boxes_vprint( boxes );
#endif /*DEBUG*/

	/* With 512x512 tiles, each hline requires 3mb of intermediate per
	 * thread ... 300 lines is about a gb per thread, ouch.
	 */
	if( boxes->n_hline > 150 ) {
		im_error( "im_aconv", "%s", _( "mask too complex" ) );
		return( NULL );
	}

	return( boxes );
}