Yalantis/uCrop · error · CImgInstanceException

cross(): Instance and/or specified image (%u,%u,%u,%u,%p) ar

Error message

cross(): Instance and/or specified image (%u,%u,%u,%u,%p) are not 3D vectors.

What it means

CImg::cross() computes the cross product treating the instance and the argument as 3D vectors, which requires both to be column-ish vectors of width 1 and height>=3. The library throws CImgInstanceException naming the offending image's dimensions when either operand violates this.

Source

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

        return *this;
      }
      return get_transpose().move_to(*this);
    }

    //! Transpose the image, viewed as a matrix \newinstance.
    CImg<T> get_transpose() const {
      return get_permute_axes("yxzc");
    }

    //! Compute the cross product between two \c 1x3 images, viewed as 3D vectors.
    /**
       \param img Image used as the second argument of the cross product.
       \note The first argument of the cross product is \c *this.
     **/
    template<typename t>
    CImg<T>& cross(const CImg<t>& img) {
      if (_width!=1 || _height<3 || img._width!=1 || img._height<3)
        throw CImgInstanceException(_cimg_instance
                                    "cross(): Instance and/or specified image (%u,%u,%u,%u,%p) are not 3D vectors.",
                                    cimg_instance,
                                    img._width,img._height,img._depth,img._spectrum,img._data);

      const T x = (*this)[0], y = (*this)[1], z = (*this)[2];
      (*this)[0] = (T)(y*img[2] - z*img[1]);
      (*this)[1] = (T)(z*img[0] - x*img[2]);
      (*this)[2] = (T)(x*img[1] - y*img[0]);
      return *this;
    }

    //! Compute the cross product between two \c 1x3 images, viewed as 3D vectors \newinstance.
    template<typename t>
    CImg<_cimg_Tt> get_cross(const CImg<t>& img) const {
      return CImg<_cimg_Tt>(*this).cross(img);
    }

    //! Invert the instance image, viewed as a matrix.

View on GitHub (pinned to f788b534b4)

Solutions

  1. Ensure both operands have shape (1,3): assign(w,h) as img.assign(1,3).
  2. Transpose a 1x3 row vector: a.get_transpose().cross(b).
  3. Use a 3-element constructor: CImg<float> v(1,3,1,1, x,y,z).

Example fix

// before
CImg<float> a(3,1,1,1,1,0,0), b(3,1,1,1,0,1,0); // row vectors
a.cross(b); // throws
// after
CImg<float> a(1,3,1,1,1,0,0), b(1,3,1,1,0,1,0);
a.cross(b);
Defensive patterns

Strategy: validation

Validate before calling

if (a.width()!=1 || a.height()<3 || b.width()!=1 || b.height()<3) throw std::runtime_error("cross() operands must be 1x3 vectors");

Type guard

bool isVec3(const CImg<T>& v){ return v.width()==1 && v.height()>=3; }

Try / catch

try { a.cross(b); } catch (CImgInstanceException& e) { std::cerr << e.what() << '\n'; }

Prevention

When it happens

Trigger: Calling a.cross(b) where a or b has width!=1, or height<3 (e.g. row vectors 1x3, 2D points of height 2, or full 2D matrices).

Common situations: Storing vectors as 1x3 row vectors (CImg convention is width=1, height=3 for a column vector); using 2-element 2D points; accidentally passing an image instead of a vector.

Related errors


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