Repository: opencv/opencv
File: modules/imgproc/src/phasecorr_iterative.cpp (C++)

Code before:
    for (double L1ratio = 0.45; getL1size(L2U.cols, L1ratio) > 0; L1ratio -= 0.025)
    {
        Point2d L2Upeak = L2Umid;  // reset the accumulated L2U peak position
        const int L1size = getL1size(L2U.cols, L1ratio);  // calculate the current L1 size
        const Point2d L1mid(L1size / 2, L1size / 2);  // update the L1 mid position

        // perform the iterative refinement algorithm
        for (int iter = 0; iter < maxIters; ++iter)
        {
            // verify that the L1 region is within the L2U region
            if (isOutOfBounds(L2Upeak, L2U, L1size))
                break;

            // extract the L1 region from L2U
            const Mat L1 = L2U(Rect(static_cast<int>(L2Upeak.x - L1size / 2),
                                    static_cast<int>(L2Upeak.y - L1size / 2),
                                    L1size,
                                    L1size));

            // calculate the centroid location
            const Point2d L1peak = getPeakSubpixel(L1);

            // add the contribution of the current iteration to the accumulated L2U peak location
            L2Upeak += Point2d(std::round(L1peak.x - L1mid.x), std::round(L1peak.y - L1mid.y));

            // check for convergence
            if (accuracyReached(L1peak, L1mid))
                // return the refined subpixel image shift
                return Point2d(L3peak) - L3mid +
                       (L2Upeak - L2Umid + L1peak - L1mid) /
                           (static_cast<double>(L2Usize) / L2size);
        }
    }

    // iterative refinement failed to converge, return non-iterative subpixel shift
    return getSubpixelShift(L3, Point2d(L3peak), L3mid, L2size);
}


Review comment (suggestion):
std::round behaviour may change depending on global settings. I recommend to use cvRound or other round (bank rounding) with fixed behaviour. See https://en.cppreference.com/w/cpp/numeric/math/round.html

Code after:
    const double L1ratioBase = 0.45;  // empirically determined optimal constant
    const double L1ratioStep = 0.025;
    for (double L1ratio = L1ratioBase; getL1size(L2U.cols, L1ratio) > 0; L1ratio -= L1ratioStep)
    {
        Point2d L2Upeak = L2Umid;  // reset the accumulated L2U peak position
        const int L1size = getL1size(L2U.cols, L1ratio);  // calculate the current L1 size
        const Point2d L1mid(L1size / 2, L1size / 2);  // update the L1 mid position

        // perform the iterative refinement algorithm
        for (int iter = 0; iter < maxIters; ++iter)
        {
            // verify that the L1 region is within the L2U region
            if (isOutOfBounds(L2Upeak, L2U, L1size))
                break;

            // extract the L1 region from L2U
            const Mat L1 = L2U(Rect(static_cast<int>(L2Upeak.x - L1size / 2),
                                    static_cast<int>(L2Upeak.y - L1size / 2),
                                    L1size,
                                    L1size));

            // calculate the centroid location
            const Point2d L1peak = getPeakSubpixel(L1);

            // add the contribution of the current iteration to the accumulated L2U peak location
            L2Upeak += Point2d(std::round(L1peak.x - L1mid.x), std::round(L1peak.y - L1mid.y));

            // check for convergence
            if (accuracyReached(L1peak, L1mid))
                // return the refined subpixel image shift
                return Point2d(L3peak) - L3mid +
                       (L2Upeak - L2Umid + L1peak - L1mid) /
                           (static_cast<double>(L2Usize) / L2size);
        }
    }

    // iterative refinement failed to converge, return non-iterative subpixel shift
    return getSubpixelShift(L3, Point2d(L3peak), L3mid, L2size);
}