Yalantis/uCrop · error · CImgArgumentException

distance_eikonal(): image instance and metric map…

Error message

distance_eikonal(): image instance and metric map (%u,%u,%u,%u) have incompatible dimensions.

What it means

CImg::get_distance_eikonal() computes an eikonal (fast-marching) distance map to pixels equal to `value`, using `metric` as the local speed map. It requires metric to have identical width, height and depth as the image (checked via is_sameXYZ); otherwise it throws CImgArgumentException before running the fast-marching solver.

Solutions

  1. Check img.is_sameXYZ(metric) (or compare width/height/depth) before the call.
  2. Regenerate the metric from the same image instance passed as `this`, after all preprocessing.
  3. Resize/crop the metric to the image geometry, or pad the smaller one to match.
  4. Confirm depth matches: a 2D image needs a depth-1 metric.

Example fix

// before
CImg<> metric = speed.get_crop(0,0,w/2,h/2); // cropped metric
CImg<Tfloat> d = img.get_distance_eikonal(0, metric);
// after
CImg<> metric = speed.get_crop(0,0,img.width()-1,img.height()-1);
CImg<Tfloat> d = img.get_distance_eikonal(0, metric);
Defensive patterns

Strategy: validation

Validate before calling

if (!img.is_sameXYZ(metric)) throw std::invalid_argument("metric must match image XYZ dims");

Type guard

bool eikonalMetricOk(const CImg<T>& img, const CImg<t>& metric) {
  return img.is_sameXYZ(metric);
}

Try / catch

try {
  d = img.get_distance_eikonal(seedValue, metric);
} catch (const CImgArgumentException& e) {
  metric.resize(img.width(), img.height(), img.depth(), -1, 0);
  d = img.get_distance_eikonal(seedValue, metric);
}

Prevention

When it happens

Trigger: Calling get_distance_eikonal(value, metric) where the metric map's width, height, or depth differs from the calling image — e.g. a downsampled speed map, a metric for a neighboring tile, or a 3D metric used with a 2D image.

Common situations: Building the metric at a different resolution (pyramid/multiscale code), cropping one image but not the metric, video frames of varying sizes, or accidentally passing the metric of a previous iteration's image.

Related errors


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

Appendix: source

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

      return get_distance_dijkstra(value,metric,is_high_connectivity,return_path);
    }

    //! Compute distance map to one source point, according to a custom metric (use fast marching algorithm).
    /**
       \param value Reference value.
       \param metric Field of distance potentials.
     **/
    template<typename t>
    CImg<T>& distance_eikonal(const T& value, const CImg<t>& metric) {
      return get_distance_eikonal(value,metric).move_to(*this);
    }

    //! Compute distance map to one source point, according to a custom metric (use fast marching algorithm).
    template<typename t>
    CImg<Tfloat> get_distance_eikonal(const T& value, const CImg<t>& metric) const {
      if (is_empty()) return *this;
      if (!is_sameXYZ(metric))
        throw CImgArgumentException(_cimg_instance
                                    "distance_eikonal(): image instance and metric map (%u,%u,%u,%u) have "
                                    "incompatible dimensions.",
                                    cimg_instance,
                                    metric._width,metric._height,metric._depth,metric._spectrum);
      CImg<Tfloat> result(_width,_height,_depth,_spectrum,cimg::type<Tfloat>::max()), Q;
      CImg<charT> state(_width,_height,_depth); // -1=far away, 0=narrow, 1=frozen

      cimg_pragma_openmp(parallel for cimg_openmp_if(_spectrum>=2) firstprivate(Q,state))
      cimg_forC(*this,c) {
        const CImg<T> img = get_shared_channel(c);
        const CImg<t> met = metric.get_shared_channel(c%metric._spectrum);
        CImg<Tfloat> res = result.get_shared_channel(c);
        unsigned int sizeQ = 0;
        state.fill(-1);

        // Detect initial seeds.
        Tfloat *ptr1 = res._data; char *ptr2 = state._data;
        cimg_for(img,ptr0,T) { if (*ptr0==value) { *ptr1 = 0; *ptr2 = 1; } ++ptr1; ++ptr2; }

View on GitHub (pinned to f788b534b4)