Yalantis/uCrop · error · CImgArgumentException

operator*(): Invalid multiplication of instance by specified

Error message

operator*(): Invalid multiplication of instance by specified matrix (%u,%u,%u,%u,%p).

What it means

CImg's operator* between two CImg instances is matrix multiplication: instance (treated as a column vector) times img (treated as a matrix). It requires this image to be a single-column vector (_height==1, _depth==1, _spectrum==1) and img to be a 2D matrix (_depth==1, _spectrum==1) whose row count (_height) equals the vector's _width. Any deviation throws this argument exception.

Source

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

    /**
       Similar to operator*=(const char*), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary.
    **/
    CImg<Tfloat> operator*(const char *const expression) const {
      return CImg<Tfloat>(*this,false)*=expression;
    }

    //! Multiplication operator.
    /**
       Similar to operator*=(const CImg<t>&), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary.
    **/
    template<typename t>
    CImg<_cimg_Tt> operator*(const CImg<t>& img) const {
      typedef _cimg_Ttdouble Ttdouble;
      typedef _cimg_Tt Tt;
      if (_width!=img._height || _depth!=1 || _spectrum!=1 || img._depth!=1 || img._spectrum!=1)
        throw CImgArgumentException(_cimg_instance
                                    "operator*(): Invalid multiplication of instance by specified "
                                    "matrix (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    img._width,img._height,img._depth,img._spectrum,img._data);
      CImg<Tt> res(img._width,_height);

      // Check for common cases to optimize.
      if (img._width==1) { // Matrix * Vector
        if (_height==1) switch (_width) { // Vector^T * Vector
          case 1 :
            res[0] = (Tt)((Ttdouble)_data[0]*img[0]);
            return res;
          case 2 :
            res[0] = (Tt)((Ttdouble)_data[0]*img[0] + (Ttdouble)_data[1]*img[1]);
            return res;
          case 3 :
            res[0] = (Tt)((Ttdouble)_data[0]*img[0] + (Ttdouble)_data[1]*img[1] +
                          (Ttdouble)_data[2]*img[2]);

View on GitHub (pinned to f788b534b4)

Solutions

  1. Ensure the left operand is a true column vector: height==1, depth==1, spectrum==1, with width == img._height.
  2. Ensure the right operand is 2D: img._depth==1 and img._spectrum==1.
  3. For element-wise pixel multiplication use img.mul(other) instead of operator*.
  4. get_transpose() or reshape the operand so dimensions satisfy vec(w,1,1,1) * mat(w,h,1,1).

Example fix

// before
CImg<float> v(3,3);        // actually a 3x3, not a vector
CImg<float> m(3,3);
CImg<float> r = v * m;     // throws
// after
CImg<float> v(3,1);        // column vector 3x1
CImg<float> m(3,3);
CImg<float> r = v * m;     // OK
Defensive patterns

Strategy: validation

Validate before calling

if (vec._height == 1 && vec._depth == 1 && vec._spectrum == 1 &&
    m._depth == 1 && m._spectrum == 1 && vec._width == m._height) {
  CImg<Tt> r = vec * m;
}

Type guard

bool isColumnVector = img.height() == 1 && img.depth() == 1 && img.spectrum() == 1;
bool isMatrix = m.depth() == 1 && m.spectrum() == 1;

Try / catch

try {
  CImg<float> r = vec * m;
} catch (CImgArgumentException& e) {
  // fall back to mul() or fix dimensions
}

Prevention

When it happens

Trigger: Calling vec * matrix when vec has height != 1, either image has depth or spectrum != 1, or vec._width != matrix._height; also element-wise '*' confusion where users expected per-pixel multiplication (which is mul()).

Common situations: Linear-algebra code with transposed vectors (row vector instead of column vector); RGB images (spectrum=3) or volumes (depth>1) passed as operands; dimension mismatch after resizing one operand.

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/6e097f3172600edb. Report an issue: GitHub.