Yalantis/uCrop · error · CImgInstanceException

CImg<%s>::FFT(): Specified real part (%u,%u,%u,%u,%p) and im

Error message

CImg<%s>::FFT(): Specified real part (%u,%u,%u,%u,%p) and imaginary part (%u,%u,%u,%u,%p) have different dimensions.

What it means

CImg::FFT(real, imag, axis, is_inverse) requires the imaginary buffer to have the same width, height, depth and spectrum as the real buffer. If imag was empty it is auto-sized to real, but if imag is non-empty with different XYZC dimensions, is_sameXYZC fails and CImgInstanceException is thrown with both images' dimensions and data pointers in the message.

Source

Thrown at ucrop/src/main/jni/CImg.h:47660

      CImg<Tfloat>::FFT(res[0],res[1],is_inverse);
      return res;
    }

    //! Compute 1D Fast Fourier Transform, along a specified axis.
    /**
       \param[in,out] real Real part of the pixel values.
       \param[in,out] imag Imaginary part of the pixel values.
       \param axis Axis along which the FFT is computed.
       \param is_inverse Tells if the forward (\c false) or inverse (\c true) FFT is computed.
    **/
    static void FFT(CImg<T>& real, CImg<T>& imag, const char axis, const bool is_inverse=false,
                    const unsigned int nb_threads=0) {
      if (!real)
        throw CImgInstanceException("CImg<%s>::FFT(): Specified real part is empty.",
                                    pixel_type());
      if (!imag) imag.assign(real._width,real._height,real._depth,real._spectrum,(T)0);
      if (!real.is_sameXYZC(imag))
        throw CImgInstanceException("CImg<%s>::FFT(): Specified real part (%u,%u,%u,%u,%p) and "
                                    "imaginary part (%u,%u,%u,%u,%p) have different dimensions.",
                                    pixel_type(),
                                    real._width,real._height,real._depth,real._spectrum,real._data,
                                    imag._width,imag._height,imag._depth,imag._spectrum,imag._data);
      const char _axis = cimg::lowercase(axis);
      if (_axis!='x' && _axis!='y' && _axis!='z')
        throw CImgArgumentException("CImgList<%s>::FFT(): Invalid specified axis '%c' for real and imaginary parts "
                                    "(%u,%u,%u,%u) "
                                    "(should be { x | y | z }).",
                                    pixel_type(),axis,
                                    real._width,real._height,real._depth,real._spectrum);
      cimg::unused(nb_threads);
#ifdef cimg_use_fftw3
      cimg::mutex(12);
#ifndef cimg_use_fftw3_singlethread
      fftw_plan_with_nthreads(nb_threads?nb_threads:cimg::nb_cpus());
#endif
      fftw_complex *data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*real._width*real._height*real._depth);

View on GitHub (pinned to f788b534b4)

Solutions

  1. Call real.is_sameXYZC(imag) (or compare all four dims) before FFT.
  2. Let FFT allocate the imaginary part: pass an empty CImg (imag.assign(); or default-constructed) so it auto-fills with zeros.
  3. Explicitly reassign imag to match: imag.assign(real._width, real._height, real._depth, real._spectrum, 0).
  4. In loops, re-create or re-assign scratch buffers whenever the input size changes.

Example fix

// before
CImg<float> real = imgA, imag = imgB; // imgB has different dims
CImg<float>::FFT(real, imag, 'x'); // dimension mismatch -> throws
// after
CImg<float> real = imgA;
CImg<float> imag; // empty: FFT auto-assigns to real's dims
CImg<float>::FFT(real, imag, 'x');
Defensive patterns

Strategy: validation

Validate before calling

if (!real.is_sameXYZC(imag)) imag.assign(real._width, real._height, real._depth, real._spectrum, (T)0);

Type guard

bool fftBuffersCompatible(const CImg<T>& real, const CImg<T>& imag) {
  return real.is_sameXYZC(imag);
}

Try / catch

try {
  CImg<T>::FFT(real, imag, axis);
} catch (const CImgInstanceException& e) {
  imag.assign(real._width, real._height, real._depth, real._spectrum, (T)0);
  CImg<T>::FFT(real, imag, axis);
}

Prevention

When it happens

Trigger: Reusing a persistent `imag` buffer from a previous FFT of a differently sized image; calling FFT with real and imag allocated at different resolutions; spectrum mismatch (e.g. real is 3-channel, imag is 1-channel).

Common situations: Looping over frames of varying sizes while reusing scratch FFT buffers; after an image resize only the real part was resized; passing results from two different pipelines.

Related errors


AI-assisted analysis of Yalantis/uCrop@f788b534b4 (2026-09-08). Data as JSON: /api/errors/860cd12e0561d34c. Report an issue: GitHub.