Yalantis/uCrop · error · CImgArgumentException

draw_quiver(): Invalid dimensions of specified flow (%u,%u,%

Error message

draw_quiver(): Invalid dimensions of specified flow (%u,%u,%u,%u,%p).

What it means

draw_quiver() draws a vector flow field and requires the flow image to have exactly 2 values per location (spectrum==2: x and y components) and to be non-empty. When flow is empty (null data) or flow._spectrum!=2, the library cannot interpret the field as 2D vectors and throws CImgArgumentException with the flow's full dimensions.

Source

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

    //! Draw a 2D vector field, using a field of colors.
    /**
       \param flow Image of 2D vectors used as input data.
       \param color Image of spectrum()-D vectors corresponding to the color of each arrow.
       \param opacity Opacity of the drawing.
       \param sampling Length (in pixels) between each arrow.
       \param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length).
       \param is_arrow Tells if arrows must be drawn, instead of oriented segments.
       \param pattern Used pattern to draw lines.
       \note Clipping is supported.
    **/
    template<typename t1, typename t2>
    CImg<T>& draw_quiver(const CImg<t1>& flow,
                         const CImg<t2>& color, const float opacity=1,
                         const unsigned int sampling=25, const float factor=-20,
                         const bool is_arrow=true, const unsigned int pattern=~0U) {
      if (is_empty()) return *this;
      if (!flow || flow._spectrum!=2)
        throw CImgArgumentException(_cimg_instance
                                    "draw_quiver(): Invalid dimensions of specified flow (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    flow._width,flow._height,flow._depth,flow._spectrum,flow._data);
      if (sampling<=0)
        throw CImgArgumentException(_cimg_instance
                                    "draw_quiver(): Invalid sampling value %g "
                                    "(should be >0)",
                                    cimg_instance,
                                    sampling);
      const bool colorfield = (color._width==flow._width && color._height==flow._height &&
                               color._depth==1 && color._spectrum==_spectrum);
      if (is_overlapped(flow)) return draw_quiver(+flow,color,opacity,sampling,factor,is_arrow,pattern);
      float vmax,fact;
      if (factor<=0) {
        float m, M = (float)flow.get_norm(2).max_min(m);
        vmax = (float)std::max(cimg::abs(m),cimg::abs(M));
        if (!vmax) vmax = 1;
        fact = -factor;

View on GitHub (pinned to f788b534b4)

Solutions

  1. Build the flow as a CImg with spectrum 2: CImg<t> flow(w,h,1,2); flow.set_at(xy_component...).
  2. If components are separate images, merge them: flow = flowX | flowY is wrong — use flow.append(flowY,'c') after reshaping each to (w,h,1,1), giving spectrum 2.
  3. Check flow.spectrum()==2 and !flow.is_empty() before calling draw_quiver.
  4. If you loaded flow from disk, re-save/verify with the two vector components in the spectrum dimension.

Example fix

// before
CImg<float> flow = flowX.get_append(flowY,'x'); // depth stacking, spectrum stays 1
img.draw_quiver(flow,color);
// after
CImg<float> flow = flowX.get_append(flowY,'c'); // channels -> spectrum 2
img.draw_quiver(flow,color);
Defensive patterns

Strategy: validation

Validate before calling

if (flow.is_empty() || flow.spectrum()!=2)
    throw std::invalid_argument("flow must be non-empty with 2 channels (dx,dy)");
img.draw_quiver(flow,color);

Type guard

bool isFlowField(const CImg<float>& f){ return !f.is_empty() && f.spectrum()==2; }

Try / catch

try { img.draw_quiver(flow,color,sampling); }
catch (CImgArgumentException& e) { log_error("draw_quiver flow invalid: %s", e.what()); }

Prevention

When it happens

Trigger: Calling img.draw_quiver(flow,color) with a grayscale flow image (spectrum=1), an RGB flow (spectrum=3), a flow split into two separate images and passed concatenated along the wrong axis, or an unassigned/empty CImg as flow.

Common situations: Optical-flow results stored per-component in separate images and combined incorrectly; loading flow from file where channels were collapsed; constructing the flow CImg with spectrum defaulted to 1.

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