Yalantis/uCrop · error · CImgInstanceException

_cimg2cvmat() : Invalid number of channels (should be '1' or

Error message

_cimg2cvmat() : Invalid number of channels (should be '1' or '3+').

What it means

_cimg2cvmat() cannot represent a CImg with exactly 2 channels (spectrum == 2), since cv::Mat has no 2-channel mapping in this bridge; it accepts 1 (gray) or 3+ (color/multi-channel) channel images. The image is otherwise valid, so this is a shape-incompatibility error between CImg and OpenCV.

Source

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

      if (src.channels()==1) return CImg<ucharT>(src.ptr(),src.cols,src.rows,1,1);
      else if (src.channels()==3) { // BGR
        CImg<ucharT> res(src.cols,src.rows,1,src.channels());
        const unsigned char *ptrs = src.ptr();
        unsigned char *pR = res.data(), *pG = res.data(0,0,0,1), *pB = res.data(0,0,0,2);
        cimg_forXY(res,x,y) { *(pB++) = *(ptrs++); *(pG++) = *(ptrs++); *(pR++) = *(ptrs++); }
        return res;
      }
      return CImg<ucharT>(src.ptr(),src.channels(),src.cols,src.rows,1,true).get_permute_axes("yzcx");
    }

    // Convert a CImg<T> to a cv::Mat.
    cv::Mat _cimg2cvmat() const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "_cimg2cvmat() : Instance image is empty.",
                                    cimg_instance);
      if (_spectrum==2)
        throw CImgInstanceException(_cimg_instance
                                    "_cimg2cvmat() : Invalid number of channels (should be '1' or '3+').",
                                    cimg_instance);
      if (_depth!=1)
        throw CImgInstanceException(_cimg_instance
                                    "_cimg2cvmat() : Invalid number of slices (should be '1').",
                                    cimg_instance);
      int mat_type = -1;
      if (pixel_type()==cimg::type<unsigned char>::string()) mat_type = CV_8UC1;
      if (pixel_type()==cimg::type<char>::string()) mat_type = CV_8SC1;
      if (pixel_type()==cimg::type<unsigned short>::string()) mat_type = CV_16UC1;
      if (pixel_type()==cimg::type<short>::string()) mat_type = CV_16SC1;
      if (pixel_type()==cimg::type<int>::string()) mat_type = CV_32SC1;
      if (pixel_type()==cimg::type<float>::string()) mat_type = CV_32FC1;
      if (pixel_type()==cimg::type<double>::string()) mat_type = CV_64FC1;
      if (mat_type<0)
        throw CImgInstanceException(_cimg_instance
                                    "_cvmat2cimg() : pixel type '%s' is not supported.",
                                    cimg_instance,pixel_type());

View on GitHub (pinned to f788b534b4)

Solutions

  1. Pad the image to 3 channels (e.g. duplicate or add a zero channel) before conversion.
  2. Split the two channels and convert each as a single-channel cv::Mat.
  3. Fix upstream construction so the image has 1, 3, or 4 channels.

Example fix

// before: 2-channel image
cv::Mat m = img2ch.get_cvmat(); // throws
// after
cimg_forXY(img2ch,x,y) img2ch(x,y,0,2) = 0; // pad to 3 channels
CImg<unsigned char> img3(img2ch, "xyzc", 3); // or append_channel
cv::Mat m = img3.get_cvmat();
Defensive patterns

Strategy: validation

Validate before calling

if (img.spectrum() == 2) throw std::runtime_error("2-channel image not convertible to cv::Mat; pad or split channels");

Try / catch

try { cv::Mat m = img.get_cvmat(); }
catch (CImgInstanceException& e) { /* pad/split channels and retry */ }

Prevention

When it happens

Trigger: Converting a CImg whose _spectrum was set to 2 — e.g. an image constructed with spectrum=2, a two-band multispectral image, or after slicing channel ranges that yield exactly two channels.

Common situations: Working with two-channel data (e.g. L+a, depth+mask pairs, dual-band scientific imagery) and calling get_cvmat() directly; accidentally computing channels=2 in a constructor call.

Related errors


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