#include "ruby_vips.h" #include "image.h" #include "image_freq_filt.h" /* * call-seq: * im.fwfft -> image * * Transform an image to Fourier space. * * VIPS uses the fftw3 or fftw2 Fourier transform libraries if possible. If * they were not available when VIPS was built, it falls back to its own * FFT functions which are slow and only work for square images whose sides * are a power of two. */ VALUE img_fwfft(VALUE obj) { RUBY_VIPS_UNARY(im_fwfft); } /* * call-seq: * im.invfft -> image * * Transform an image from Fourier space to real space. The result is complex. * If you are OK with a real result, use Image#invfftr instead, it's quicker. * * VIPS uses the fftw3 or fftw2 Fourier transform libraries if possible. If * they were not available when VIPS was built, it falls back to its own FFT * functions which are slow and only work for square images whose sides are a * power of two. */ VALUE img_invfft(VALUE obj) { RUBY_VIPS_UNARY(im_invfft); } /* * call-seq: * im.rotquad -> image * * Rotate the quadrants of the image so that the point that was at the * top-left is now in the centre. Handy for moving Fourier images to optical * space. */ VALUE img_rotquad(VALUE obj) { RUBY_VIPS_UNARY(im_rotquad); } /* * call-seq: * im.invfftr -> image * * Transform an image from Fourier space to real space, giving a real result. * This is faster than Image#invfft, which gives a complex result. * * VIPS uses the fftw3 or fftw2 Fourier transform libraries if possible. If * they were not available when VIPS was built, it falls back to it's own * FFT functions which are slow and only work for square images whose sides * are a power of two. */ VALUE img_invfftr(VALUE obj) { RUBY_VIPS_UNARY(im_invfftr); } #if IM_MAJOR_VERSION > 7 || IM_MINOR_VERSION >= 22 /* * call-seq: * Image.fmask_ideal_lowpass(x, y, frequency_cutoff) -> image * * This operation creates a one-band float image of the size x by * y. The image must be square, and the sides must be a power of two. * The image has values in the range [0, 1] and is typically used for * multiplying against frequency domain images to filter them. * * All masks are created with the DC component at (0, 0), so you might want to * rotate the quadrants with im_rotquad() before viewing. The DC pixel always * has the value 1.0. * * Unless noted below, all parameters are expressed as percentages, scaled to * [0, 1]. * * * High-pass, low-pass masks: A high pass filter mask filters the low * frequencies while allowing the high frequencies to get through. * The reverse happens with a low pass filter mask. * * * Ring-pass, ring-reject masks: A ring filter passes or rejects a range of * frequencies. The range is specified by the frequency_cutoff and * the width. * * * Band-pass, band-reject masks: These masks are used to pass or remove * spatial frequencies around a given frequency. The position of the * frequency to pass or remove is given by frequency_cutoffx and * frequency_cutoffy. The size of the region around the point is * given by radius. * * * Ideal filters: These filters pass or reject frequencies with a sharp * cutoff at the transition. * * * Butterworth filters: These filters use a Butterworth function to separate * the frequencies (see Gonzalez and Wintz, Digital Image Processing, 1987). * The shape of the curve is controlled by order: higher values give * a sharper transition. * * * Gaussian filters: These filters have a smooth Gaussian shape, * controlled by amplitude_cutoff. */ VALUE img_s_fmask_ideal_highpass(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoff) { OutPartial(new, data, im); if (im_create_fmask(im, NUM2INT(x), NUM2INT(y), VIPS_MASK_IDEAL_HIGHPASS, NUM2DBL(frequency_cutoff))) vips_lib_error(); return new; } /* * call-seq: * Image.fmask_ideal_lowpass(x, y, frequency_cutoff) -> image * * See Image.fmask_ideal_highpass * */ VALUE img_s_fmask_ideal_lowpass(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoff) { OutPartial(new, data, im); if (im_create_fmask(im, NUM2INT(x), NUM2INT(y), VIPS_MASK_IDEAL_LOWPASS, NUM2DBL(frequency_cutoff))) vips_lib_error(); return new; } /* * call-seq: * Image.fmask_butterworth_highpass(x, y, order, frequency_cutoff, * amplitude_cutoff) -> image * * See Image.fmask_ideal_highpass */ VALUE img_s_fmask_butterworth_highpass(VALUE obj, VALUE x, VALUE y, VALUE order, VALUE frequency_cutoff, VALUE amplitude_cutoff) { OutPartial(new, data, im); if (im_create_fmask(im, NUM2INT(x), NUM2INT(y), VIPS_MASK_BUTTERWORTH_HIGHPASS, NUM2DBL(order), NUM2DBL(frequency_cutoff), NUM2DBL(amplitude_cutoff))) vips_lib_error(); return new; } /* * call-seq: * Image.fmask_butterworth_lowpass(x, y, order, frequency_cutoff, * amplitude_cutoff) * * See Image.fmask_ideal_highpass */ VALUE img_s_fmask_butterworth_lowpass(VALUE obj, VALUE x, VALUE y, VALUE order, VALUE frequency_cutoff, VALUE amplitude_cutoff) { OutPartial(new, data, im); if (im_create_fmask(im, NUM2INT(x), NUM2INT(y), VIPS_MASK_BUTTERWORTH_LOWPASS, NUM2DBL(order), NUM2DBL(frequency_cutoff), NUM2DBL(amplitude_cutoff))) vips_lib_error(); return new; } /* * call-seq: * Image.fmask_gauss_highpass(x, y, frequency_cutoff, amplitude_cutoff) -> * image * * See Image.fmask_ideal_highpass */ VALUE img_s_fmask_gauss_highpass(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoff, VALUE amplitude_cutoff) { OutPartial(new, data, im); if (im_create_fmask(im, NUM2INT(x), NUM2INT(y), VIPS_MASK_GAUSS_HIGHPASS, NUM2DBL(frequency_cutoff), NUM2DBL(amplitude_cutoff))) vips_lib_error(); return new; } /* * call-seq: * Image.fmask_gauss_lowpass(x, y, frequency_cutoff, amplitude_cutoff) -> * image * * See Image.fmask_ideal_highpass */ VALUE img_s_fmask_gauss_lowpass(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoff, VALUE amplitude_cutoff) { OutPartial(new, data, im); if (im_create_fmask(im, NUM2INT(x), NUM2INT(y), VIPS_MASK_GAUSS_LOWPASS, NUM2DBL(frequency_cutoff), NUM2DBL(amplitude_cutoff))) vips_lib_error(); return new; } /* * call-seq: * Image.fmask_ideal_ringpass(x, y, frequency_cutoff, width) -> image * * See Image.fmask_ideal_highpass */ VALUE img_s_fmask_ideal_ringpass(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoff, VALUE width) { OutPartial(new, data, im); if (im_create_fmask(im, NUM2INT(x), NUM2INT(y), VIPS_MASK_IDEAL_RINGPASS, NUM2DBL(frequency_cutoff), NUM2DBL(width))) vips_lib_error(); return new; } /* * call-seq: * Image.fmask_ideal_ringreject(x, y, frequency_cutoff, width) -> image * * See Image.fmask_ideal_highpass */ VALUE img_s_fmask_ideal_ringreject(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoff, VALUE width) { OutPartial(new, data, im); if (im_create_fmask(im, NUM2INT(x), NUM2INT(y), VIPS_MASK_IDEAL_RINGREJECT, NUM2DBL(frequency_cutoff), NUM2DBL(width))) vips_lib_error(); return new; } /* * call-seq: * Image.fmask_butterworth_ringpass(x, y, order, frequency_cutoff, * width, amplitude_cutoff) -> image * * See Image.fmask_ideal_highpass */ VALUE img_s_fmask_butterworth_ringpass(VALUE obj, VALUE x, VALUE y, VALUE order, VALUE frequency_cutoff, VALUE width, VALUE amplitude_cutoff) { OutPartial(new, data, im); if (im_create_fmask(im, NUM2INT(x), NUM2INT(y), VIPS_MASK_BUTTERWORTH_RINGPASS, NUM2DBL(order), NUM2DBL(frequency_cutoff), NUM2DBL(width), NUM2DBL(amplitude_cutoff))) vips_lib_error(); return new; } /* * call-seq: * Image.fmask_butterworth_ringreject(x, y, order, frequency_cutoff, * width, amplitude_cutoff) -> image * * See Image.fmask_ideal_highpass */ VALUE img_s_fmask_butterworth_ringreject(VALUE obj, VALUE x, VALUE y, VALUE order, VALUE frequency_cutoff, VALUE width, VALUE amplitude_cutoff) { OutPartial(new, data, im); if (im_create_fmask(im, NUM2INT(x), NUM2INT(y), VIPS_MASK_BUTTERWORTH_RINGREJECT, NUM2DBL(order), NUM2DBL(frequency_cutoff), NUM2DBL(width), NUM2DBL(amplitude_cutoff))) vips_lib_error(); return new; } /* * call-seq: * Image.fmask_gauss_ringpass(x, y, frequency_cutoff, width, * amplitude_cutoff) -> image * * See Image.fmask_ideal_highpass */ VALUE img_s_fmask_gauss_ringpass(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoff, VALUE width, VALUE amplitude_cutoff) { OutPartial(new, data, im); if (im_create_fmask(im, NUM2INT(x), NUM2INT(y), VIPS_MASK_GAUSS_RINGPASS, NUM2DBL(frequency_cutoff), NUM2DBL(width), NUM2DBL(amplitude_cutoff))) vips_lib_error(); return new; } /* * call-seq: * Image.fmask_gauss_ringreject(x, y, frequency_cutoff, width, * amplitude_cutoff) -> image * * See Image.fmask_ideal_highpass */ VALUE img_s_fmask_gauss_ringreject(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoff, VALUE width, VALUE amplitude_cutoff) { OutPartial(new, data, im); if (im_create_fmask(im, NUM2INT(x), NUM2INT(y), VIPS_MASK_GAUSS_RINGREJECT, NUM2DBL(frequency_cutoff), NUM2DBL(width), NUM2DBL(amplitude_cutoff))) vips_lib_error(); return new; } /* * call-seq: * Image.fmask_ideal_bandpass(x, y, frequency_cutoffx, frequency_cutoffy, * radius) -> image * * See Image.fmask_ideal_highpass */ VALUE img_s_fmask_ideal_bandpass(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoffx, VALUE frequency_cutoffy, VALUE radius) { OutPartial(new, data, im); if (im_create_fmask(im, NUM2INT(x), NUM2INT(y), VIPS_MASK_IDEAL_BANDPASS, NUM2DBL(frequency_cutoffx), NUM2DBL(frequency_cutoffy), NUM2DBL(radius))) vips_lib_error(); return new; } /* * call-seq: * Image.fmask_ideal_bandreject(x, y, frequency_cutoffx, frequency_cutoffy, * radius) * * See Image.fmask_ideal_highpass */ VALUE img_s_fmask_ideal_bandreject(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoffx, VALUE frequency_cutoffy, VALUE radius) { OutPartial(new, data, im); if (im_create_fmask(im, NUM2INT(x), NUM2INT(y), VIPS_MASK_IDEAL_BANDREJECT, NUM2DBL(frequency_cutoffx), NUM2DBL(frequency_cutoffy), NUM2DBL(radius))) vips_lib_error(); return new; } /* * call-seq: * Image.fmask_butterworth_bandpass(x, y, order, frequency_cutoffx, * frequency_cutoffy, radius, amplitude_cutoff) -> image * * See Image.fmask_ideal_highpass */ VALUE img_s_fmask_butterworth_bandpass(VALUE obj, VALUE x, VALUE y, VALUE order, VALUE frequency_cutoffx, VALUE frequency_cutoffy, VALUE radius, VALUE amplitude_cutoff) { OutPartial(new, data, im); if (im_create_fmask(im, NUM2INT(x), NUM2INT(y), VIPS_MASK_BUTTERWORTH_BANDPASS, NUM2DBL(order), NUM2DBL(frequency_cutoffx), NUM2DBL(frequency_cutoffy), NUM2DBL(radius), NUM2DBL(amplitude_cutoff))) vips_lib_error(); return new; } /* * call-seq: * Image.fmask_butterworth_bandreject(x, y, order, frequency_cutoffx, * frequency_cutoffy, radius, amplitude_cutoff) -> image * * See Image.fmask_ideal_highpass */ VALUE img_s_fmask_butterworth_bandreject(VALUE obj, VALUE x, VALUE y, VALUE order, VALUE frequency_cutoffx, VALUE frequency_cutoffy, VALUE radius, VALUE amplitude_cutoff) { OutPartial(new, data, im); if (im_create_fmask(im, NUM2INT(x), NUM2INT(y), VIPS_MASK_BUTTERWORTH_BANDREJECT, NUM2DBL(order), NUM2DBL(frequency_cutoffx), NUM2DBL(frequency_cutoffy), NUM2DBL(radius), NUM2DBL(amplitude_cutoff))) vips_lib_error(); return new; } /* * call-seq: * Image.fmask_gaus_bandpass(x, y, frequency_cutoffx, frequency_cutoffy, * radius, amplitude_cutoff) -> image * * See Image.fmask_ideal_highpass */ VALUE img_s_fmask_gauss_bandpass(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoffx, VALUE frequency_cutoffy, VALUE radius, VALUE amplitude_cutoff) { OutPartial(new, data, im); if (im_create_fmask(im, NUM2INT(x), NUM2INT(y), VIPS_MASK_GAUSS_BANDPASS, NUM2DBL(frequency_cutoffx), NUM2DBL(frequency_cutoffy), NUM2DBL(radius), NUM2DBL(amplitude_cutoff))) vips_lib_error(); return new; } /* * call-seq: * Image.fmask_gauss_bandreject, x, y, frequency_cutoffx, frequency_cutoffy, * radius, amplitude_cutoff) -> image * * See Image.fmask_ideal_highpass */ VALUE img_s_fmask_gauss_bandreject(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoffx, VALUE frequency_cutoffy, VALUE radius, VALUE amplitude_cutoff) { OutPartial(new, data, im); if (im_create_fmask(im, NUM2INT(x), NUM2INT(y), VIPS_MASK_GAUSS_BANDREJECT, NUM2DBL(frequency_cutoffx), NUM2DBL(frequency_cutoffy), NUM2DBL(radius), NUM2DBL(amplitude_cutoff))) vips_lib_error(); return new; } /* * call-seq: * Image.fmask_fractal_flt(x, y, fractal_dimension) -> image * * This mask is handy for filtering images of gaussian noise in order to create * surfaces of a given fractal dimension. @fractal_dimension should be between * 2 and 3. */ VALUE img_s_fmask_fractal_flt(VALUE obj, VALUE x, VALUE y, VALUE fractal_dimension) { OutPartial(new, data, im); if (im_create_fmask(im, NUM2INT(x), NUM2INT(y), VIPS_MASK_FRACTAL_FLT, NUM2DBL(fractal_dimension))) vips_lib_error(); return new; } #else VALUE img_s_fmask_ideal_highpass(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoff) { rb_raise(eVIPSError, "Operation not supported with your version of VIPS."); } VALUE img_s_fmask_ideal_lowpass(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoff) { rb_raise(eVIPSError, "Operation not supported with your version of VIPS."); } VALUE img_s_fmask_butterworth_highpass(VALUE obj, VALUE x, VALUE y, VALUE order, VALUE frequency_cutoff, VALUE amplitude_cutoff) { rb_raise(eVIPSError, "Operation not supported with your version of VIPS."); } VALUE img_s_fmask_butterworth_lowpass(VALUE obj, VALUE x, VALUE y, VALUE order, VALUE frequency_cutoff, VALUE amplitude_cutoff) { rb_raise(eVIPSError, "Operation not supported with your version of VIPS."); } VALUE img_s_fmask_gauss_highpass(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoff, VALUE amplitude_cutoff) { rb_raise(eVIPSError, "Operation not supported with your version of VIPS."); } VALUE img_s_fmask_gauss_lowpass(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoff, VALUE amplitude_cutoff) { rb_raise(eVIPSError, "Operation not supported with your version of VIPS."); } VALUE img_s_fmask_ideal_ringpass(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoff, VALUE width) { rb_raise(eVIPSError, "Operation not supported with your version of VIPS."); } VALUE img_s_fmask_ideal_ringreject(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoff, VALUE width) { rb_raise(eVIPSError, "Operation not supported with your version of VIPS."); } VALUE img_s_fmask_butterworth_ringpass(VALUE obj, VALUE x, VALUE y, VALUE order, VALUE frequency_cutoff, VALUE width, VALUE amplitude_cutoff) { rb_raise(eVIPSError, "Operation not supported with your version of VIPS."); } VALUE img_s_fmask_butterworth_ringreject(VALUE obj, VALUE x, VALUE y, VALUE order, VALUE frequency_cutoff, VALUE width, VALUE amplitude_cutoff) { rb_raise(eVIPSError, "Operation not supported with your version of VIPS."); } VALUE img_s_fmask_gauss_ringpass(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoff, VALUE width, VALUE amplitude_cutoff) { rb_raise(eVIPSError, "Operation not supported with your version of VIPS."); } VALUE img_s_fmask_gauss_ringreject(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoff, VALUE width, VALUE amplitude_cutoff) { rb_raise(eVIPSError, "Operation not supported with your version of VIPS."); } VALUE img_s_fmask_ideal_bandpass(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoffx, VALUE frequency_cutoffy, VALUE radius) { rb_raise(eVIPSError, "Operation not supported with your version of VIPS."); } VALUE img_s_fmask_ideal_bandreject(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoffx, VALUE frequency_cutoffy, VALUE radius) { rb_raise(eVIPSError, "Operation not supported with your version of VIPS."); } VALUE img_s_fmask_butterworth_bandpass(VALUE obj, VALUE x, VALUE y, VALUE order, VALUE frequency_cutoffx, VALUE frequency_cutoffy, VALUE radius, VALUE amplitude_cutoff) { rb_raise(eVIPSError, "Operation not supported with your version of VIPS."); } VALUE img_s_fmask_butterworth_bandreject(VALUE obj, VALUE x, VALUE y, VALUE order, VALUE frequency_cutoffx, VALUE frequency_cutoffy, VALUE radius, VALUE amplitude_cutoff) { rb_raise(eVIPSError, "Operation not supported with your version of VIPS."); } VALUE img_s_fmask_gauss_bandpass(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoffx, VALUE frequency_cutoffy, VALUE radius, VALUE amplitude_cutoff) { rb_raise(eVIPSError, "Operation not supported with your version of VIPS."); } VALUE img_s_fmask_gauss_bandreject(VALUE obj, VALUE x, VALUE y, VALUE frequency_cutoffx, VALUE frequency_cutoffy, VALUE radius, VALUE amplitude_cutoff) { rb_raise(eVIPSError, "Operation not supported with your version of VIPS."); } VALUE img_s_fmask_fractal_flt(VALUE obj, VALUE x, VALUE y, VALUE fractal_dimension) { rb_raise(eVIPSError, "Operation not supported with your version of VIPS."); } #endif /* * call-seq: * im.freqflt(other_image) -> image * * Filter an image in Fourier space. * * *self* is transformed to Fourier space, multipled with other_image, * then transformed back to real space. If *self* is already a complex image, * just multiply then inverse transform. */ VALUE img_freqflt(VALUE obj, VALUE obj2) { RUBY_VIPS_BINARY(im_freqflt); } /* * call-seq: * im.disp_ps -> image * * Make a displayable (ie. 8-bit unsigned int) power spectrum. * * If *self* is non-complex, it is transformed to Fourier space. Then the * absolute value is passed through Image#scaleps, and Image#rotquad. */ VALUE img_disp_ps(VALUE obj) { RUBY_VIPS_UNARY(im_disp_ps); } /* * call-seq: * im.phasecor_fft(other_image) -> image * * Convert the two input images to Fourier space, calculate phase-correlation, * back to real space. */ VALUE img_phasecor_fft(VALUE obj, VALUE obj2) { RUBY_VIPS_BINARY(im_phasecor_fft); } /* * call-seq: * Image.fractsurf(size, frd) -> image * * Generate an image of size size and fractal dimension frd. The * dimension should be between 2 and 3. */ VALUE img_s_fractsurf(VALUE obj, VALUE size, VALUE frd) { OutPartial(new, data, im); if (im_fractsurf(im, NUM2INT(size), NUM2DBL(frd))) vips_lib_error(); return new; }