Yalantis/uCrop · error · CImgArgumentException

draw_gaussian(): Specified tensor (%u,%u,%u,%u,%p) is not a…

Error message

draw_gaussian(): Specified tensor (%u,%u,%u,%u,%p) is not a 2x2 matrix.

What it means

CImg's draw_gaussian() 2D variant draws a 2D Gaussian bump whose shape is defined by a symmetric 2x2 tensor (covariance) matrix. The library validates that the tensor image has width=2, height=2, depth=1, spectrum=1, and throws CImgArgumentException when it does not. This is an argument-shape validation, thrown before any drawing occurs.

Solutions

  1. Construct the tensor explicitly as a 2x2 image: CImg<float> tensor(2,2); tensor = sxx, sxy, sxy, syy;
  2. Verify dimensions before the call: if (tensor.width()!=2 || tensor.height()!=2) throw/log.
  3. Use the 3D draw_gaussian overload's 3x3 tensor only with the 3D overload, and vice versa.
  4. Check that intermediate operations (get_invert, multiplication) did not resize the tensor.

Example fix

// before
CImg<float> tensor(3,3); // wrong shape
img.draw_gaussian(xc, yc, tensor, color);
// after
CImg<float> tensor(2,2);
tensor(0,0)=sxx; tensor(1,0)=sxy; tensor(0,1)=sxy; tensor(1,1)=syy;
img.draw_gaussian(xc, yc, tensor, color);
Defensive patterns

Strategy: validation

Validate before calling

if (tensor.width()!=2 || tensor.height()!=2 || tensor.depth()!=1 || tensor.spectrum()!=1) {
  throw std::invalid_argument("draw_gaussian tensor must be a 2x2 matrix");
}

Type guard

bool is2x2Tensor(const CImg<float>& t) {
  return t.width()==2 && t.height()==2 && t.depth()==1 && t.spectrum()==1;
}

Try / catch

try {
  img.draw_gaussian(xc, yc, tensor, color);
} catch (const cimg_library::CImgArgumentException& e) {
  std::cerr << "Bad gaussian tensor: " << e.what() << std::endl;
}

Prevention

When it happens

Trigger: Calling draw_gaussian(xc,yc,tensor,color) with a tensor CImg that is not exactly 2x2x1x1 — e.g. passing a 1x1 matrix, a 3x3 tensor, an image with multiple spectrum channels, or a wrong-sized intermediate result from get_invert/multiplication.

Common situations: Building the covariance tensor programmatically and computing its size wrong (e.g. appending rows/columns, accidentally using the full 3x3 tensor of the 3D overload); reusing an image variable that was earlier resized; loading a tensor from a file with extra channels.

Understand the failure class

Background: Tensor shape mismatch errors ("must have shape", "expected shape ... got ..."): when tensor dimensions disagree with what an op or layer was told to expect — this error's family across 6 libraries.

Related errors


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

Appendix: source

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

        col-=_spectrum;
      }
      return *this;
    }

    //! Draw a 2D gaussian function.
    /**
       \param xc X-coordinate of the gaussian center.
       \param yc Y-coordinate of the gaussian center.
       \param tensor Covariance matrix (must be 2x2).
       \param color Pointer to \c spectrum() consecutive values, defining the drawing color.
       \param opacity Drawing opacity.
    **/
    template<typename t, typename tc>
    CImg<T>& draw_gaussian(const float xc, const float yc, const CImg<t>& tensor,
                           const tc *const color, const float opacity=1) {
      if (is_empty()) return *this;
      if (tensor._width!=2 || tensor._height!=2 || tensor._depth!=1 || tensor._spectrum!=1)
        throw CImgArgumentException(_cimg_instance
                                    "draw_gaussian(): Specified tensor (%u,%u,%u,%u,%p) is not a 2x2 matrix.",
                                    cimg_instance,
                                    tensor._width,tensor._height,tensor._depth,tensor._spectrum,tensor._data);
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_gaussian(): Specified color is (null).",
                                    cimg_instance);
      typedef typename CImg<t>::Tfloat tfloat;
      const CImg<tfloat> invT = tensor.get_invert(), invT2 = (invT*invT)/=-2.;
      const tfloat a = invT2(0,0), b = 2*invT2(1,0), c = invT2(1,1);
      const float nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.f);
      const ulongT whd = (ulongT)_width*_height*_depth;
      const tc *col = color;
      float dy = -yc;
      cimg_forY(*this,y) {
        float dx = -xc;
        cimg_forX(*this,x) {
          const float val = (float)std::exp(a*dx*dx + b*dx*dy + c*dy*dy);

View on GitHub (pinned to f788b534b4)