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
- Construct the tensor explicitly as a 2x2 image: CImg<float> tensor(2,2); tensor = sxx, sxy, sxy, syy;
- Verify dimensions before the call: if (tensor.width()!=2 || tensor.height()!=2) throw/log.
- Use the 3D draw_gaussian overload's 3x3 tensor only with the 3D overload, and vice versa.
- 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
- Always allocate the tensor with explicit 2x2 dimensions
- Unit-test tensor construction once and reuse a factory function
- Keep 2x2 and 3x3 tensors in distinctly named variables
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
- "[" cimg_appname "_math_parser] CImg<
- "[" cimg_appname "_math_parser] CImg<
- "[" cimg_appname "_math_parser] CImg<
- CImg< >::streamline(): Invalid specified integration length…
- deriche(): Invalid specified axis '%c'.
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)