{"record":{"id":"1ad5c6a85ed0861f","repo":"Yalantis/uCrop","slug":"draw-quiver-invalid-dimensions-of-specified-flo","errorCode":null,"errorMessage":"draw_quiver(): Invalid dimensions of specified flow (%u,%u,%u,%u,%p).","messagePattern":"draw_quiver\\(\\): Invalid dimensions of specified flow \\(%u,%u,%u,%u,%p\\)\\.","errorType":"validation","errorClass":"CImgArgumentException","httpStatus":null,"severity":"error","filePath":"ucrop/src/main/jni/CImg.h","lineNumber":53103,"sourceCode":"    //! Draw a 2D vector field, using a field of colors.\n    /**\n       \\param flow Image of 2D vectors used as input data.\n       \\param color Image of spectrum()-D vectors corresponding to the color of each arrow.\n       \\param opacity Opacity of the drawing.\n       \\param sampling Length (in pixels) between each arrow.\n       \\param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length).\n       \\param is_arrow Tells if arrows must be drawn, instead of oriented segments.\n       \\param pattern Used pattern to draw lines.\n       \\note Clipping is supported.\n    **/\n    template<typename t1, typename t2>\n    CImg<T>& draw_quiver(const CImg<t1>& flow,\n                         const CImg<t2>& color, const float opacity=1,\n                         const unsigned int sampling=25, const float factor=-20,\n                         const bool is_arrow=true, const unsigned int pattern=~0U) {\n      if (is_empty()) return *this;\n      if (!flow || flow._spectrum!=2)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_quiver(): Invalid dimensions of specified flow (%u,%u,%u,%u,%p).\",\n                                    cimg_instance,\n                                    flow._width,flow._height,flow._depth,flow._spectrum,flow._data);\n      if (sampling<=0)\n        throw CImgArgumentException(_cimg_instance\n                                    \"draw_quiver(): Invalid sampling value %g \"\n                                    \"(should be >0)\",\n                                    cimg_instance,\n                                    sampling);\n      const bool colorfield = (color._width==flow._width && color._height==flow._height &&\n                               color._depth==1 && color._spectrum==_spectrum);\n      if (is_overlapped(flow)) return draw_quiver(+flow,color,opacity,sampling,factor,is_arrow,pattern);\n      float vmax,fact;\n      if (factor<=0) {\n        float m, M = (float)flow.get_norm(2).max_min(m);\n        vmax = (float)std::max(cimg::abs(m),cimg::abs(M));\n        if (!vmax) vmax = 1;\n        fact = -factor;","sourceCodeStart":53085,"sourceCodeEnd":53121,"githubUrl":"https://github.com/Yalantis/uCrop/blob/f788b534b48c144edf786c8cddbf0e029e637804/ucrop/src/main/jni/CImg.h#L53085-L53121","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Build the flow as a CImg with spectrum 2: CImg<t> flow(w,h,1,2); flow.set_at(xy_component...).","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.","Check flow.spectrum()==2 and !flow.is_empty() before calling draw_quiver.","If you loaded flow from disk, re-save/verify with the two vector components in the spectrum dimension."],"exampleFix":"// before\nCImg<float> flow = flowX.get_append(flowY,'x'); // depth stacking, spectrum stays 1\nimg.draw_quiver(flow,color);\n// after\nCImg<float> flow = flowX.get_append(flowY,'c'); // channels -> spectrum 2\nimg.draw_quiver(flow,color);","handlingStrategy":"validation","validationCode":"if (flow.is_empty() || flow.spectrum()!=2)\n    throw std::invalid_argument(\"flow must be non-empty with 2 channels (dx,dy)\");\nimg.draw_quiver(flow,color);","typeGuard":"bool isFlowField(const CImg<float>& f){ return !f.is_empty() && f.spectrum()==2; }","tryCatchPattern":"try { img.draw_quiver(flow,color,sampling); }\ncatch (CImgArgumentException& e) { log_error(\"draw_quiver flow invalid: %s\", e.what()); }","preventionTips":["Store flow fields with spectrum=2 (dx,dy in channels), not as stacked volumes.","Merge per-component flow images with append(...,'c').","Validate channel count right after loading flow data from disk/network.","Document the (w,h,1,2) layout in your flow-producing APIs."],"tags":["cimg","image-processing","shape-mismatch"],"backgroundTag":"tensor-shape-mismatch","analyzedSha":"f788b534b48c144edf786c8cddbf0e029e637804","analyzedAt":"2026-09-08T08:36:04.887Z","contentChangedAt":"2026-09-08T08:36:04.887Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}