Yalantis/uCrop · error · CImgInstanceException

project_matrix(): Instance image is not a matrix.

Error message

project_matrix(): Instance image is not a matrix.

What it means

get_project_matrix() requires the instance to be a 2D matrix (_depth==1 and _spectrum==1). If it is a volume or multi-channel image, CImgInstanceException('project_matrix(): Instance image is not a matrix.') is thrown because the sparse-projection math only applies to 2D matrices.

Source

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

       \param max_iter Sets the max number of iterations processed for each signal.
                       If set to '0' (default), 'max_iter' is set to the number of dictionary columns.
                       (only meaningful for matching pursuit and its variants).
       \param max_residual Gives a stopping criterion on signal reconstruction accuracy.
                           (only meaningful for matching pursuit and its variants).
       \return A matrix W whose columns correspond to the sparse weights of associated to each input matrix column.
               Thus, the matrix product D*W is an approximation of the input matrix.
    **/
    template<typename t>
    CImg<T>& project_matrix(const CImg<t>& dictionary, const unsigned int method=0,
                            const unsigned int max_iter=0, const double max_residual=1e-6) {
      return get_project_matrix(dictionary,method,max_iter,max_residual).move_to(*this);
    }

    template<typename t>
    CImg<Tfloat> get_project_matrix(const CImg<t>& dictionary, const unsigned int method=0,
                                    const unsigned int max_iter=0, const double max_residual=1e-6) const {
      if (_depth!=1 || _spectrum!=1)
        throw CImgInstanceException(_cimg_instance
                                    "project_matrix(): Instance image is not a matrix.",
                                    cimg_instance);
      if (dictionary._height!=_height || dictionary._depth!=1 || dictionary._spectrum!=1)
        throw CImgArgumentException(_cimg_instance
                                    "project_matrix(): Specified dictionary (%u,%u,%u,%u) has an invalid size.",
                                    cimg_instance,
                                    dictionary._width,dictionary._height,dictionary._depth,dictionary._spectrum);
      if (!method) return get_solve(dictionary);

      // Compute norm of dictionary atoms.
      CImg<Tfloat> dictionary_norm(dictionary._width);
      cimg_pragma_openmp(parallel for
                         cimg_openmp_if(dictionary._width>=2 && dictionary._width*dictionary._height>=32))
      cimg_forX(dictionary_norm,atom) {
        Tfloat norm = 0;
        cimg_forY(dictionary,s) norm+=cimg::sqr(dictionary(atom,s));
        dictionary_norm[atom] = std::max((Tfloat)1e-8,std::sqrt(norm));
      }

View on GitHub (pinned to f788b534b4)

Solutions

  1. Collapse to 2D single-channel before the call: use get_channel(0) / get_slice(0)
  2. Check img.depth()==1 && img.spectrum()==1 as a guard before calling
  3. Average or convert channels to a single matrix if that matches your intent

Example fix

// before
CImg<float> P = rgb.get_project_matrix(dict);
// after
CImg<float> m = rgb.get_channel(0);
CImg<float> P = m.get_project_matrix(dict);
Defensive patterns

Strategy: validation

Validate before calling

if (img.depth() != 1 || img.spectrum() != 1) throw std::invalid_argument("get_project_matrix requires a 2D single-channel matrix");

Type guard

bool isMatrixImage(const CImg<T>& m) { return m.depth() == 1 && m.spectrum() == 1; }

Try / catch

try { P = img.get_project_matrix(dict); } catch (CImgInstanceException& e) { /* convert input to single-channel 2D and retry */ }

Prevention

When it happens

Trigger: Calling get_project_matrix(dictionary, ...) on an image with depth>1 or spectrum>1 (e.g. an RGB image or 3D volume).

Common situations: Passing a color image where a grayscale 2D signal/matrix was required; forgetting get_channel(0) after a crop; pipeline changes that made data 3D.

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