Ask Your Question
0

difference in translation from python to C++

asked 2019-02-19 13:00:54 -0600

js4267 gravatar image

updated 2019-02-20 15:19:18 -0600

Hello

I am facing hard time to undestand the difference between two algorithm that I wrote. I following code in python:

import cv2 import numpy as np from scipy.stats import iqr

def pfs(I):
    if I.ndim == 3:
        I, _ = cv2.decolor(cv2.cvtColor(I, cv2.COLOR_BGR2Lab))

    h = cv2.calcHist([I],[0],None,[256],[0,256]).astype(np.int32).reshape((-1,))



    print(h.dtype, I.dtype, I.shape, h.min(), h.max(), I.min(), I.max())

    hd = np.abs(np.diff(h))


    thresh = np.mean(hd) + iqr(hd)

    print(thresh, np.mean(hd), iqr(hd),flush=True)

    hd = hd > thresh

    print(hd)

    idx = list()

    for i in range(254):
        if hd[i] and not hd[i+1]:
            idx.append(i)
        elif not hd[i] and hd[i+1]:
            idx.append(i+1)

    ret = np.zeros(I.shape,np.uint8)

    for i in idx:
        ret = cv2.bitwise_or(ret, cv2.compare(I,i,cv2.CMP_EQ))

    return ret

I translated that algorithm in c++ as:

cv::Mat pfd(const cv::Mat& _I)
{
    cv::Mat I = _I;

    if(I.depth())
        cv::normalize(I, I, 0., 255., cv::NORM_MINMAX, CV_8U);

    if(I.channels() == 3)
    {
        cv::Mat Lab, tmp;
        std::vector<cv::Mat> cns;
        cv::cvtColor(I, Lab, cv::COLOR_BGR2Lab);
        cv::decolor(Lab, I, tmp);

    }

    cv::Mat hist;

    cv::calcHist(std::vector<cv::Mat>(1,I),{0},cv::noArray(), hist, {256}, {0.f,256.f});


    cv::Mat hd;

    {
        cv::Mat curr = hist.rowRange(0,hist.rows-1);
        cv::Mat next = hist.rowRange(1,hist.rows);

        cv::absdiff(next,curr, hd);
    }

    hd.convertTo(hd,CV_32S);

    double thresh = (cv::mean(hd)(0) + utils::iqr(hd)(0) );
    hd = hd>thresh;

    cv::Mat1i idx;

    int i=0;
    for(auto it_current = hd.begin<uchar>(), it_next = hd.begin<uchar>() + 1; it_next != hd.end<uchar>(); it_current++, it_next++, i++)
    {
        uchar current = *it_current;
        uchar next = *it_next;

        if(current && !next)
            idx.push_back(i);
        if(!current && next)
            idx.push_back(i+1);
    }

    std::cout<<idx<<std::endl;

    cv::Mat1b ret = cv::Mat1b::zeros(I.size());

    for(const int& i : idx)
    {
        cv::Mat1b mask = I == i;
        ret |= mask;
    }

    return ret;
}

For calculate the Inter Quantile Range I wrote the following code:

namespace
{

template<class type,class wtype,bool check>
struct calculate_iqr_t
{
    calculate_iqr_t(const cv::Mat& src,
                    const float& , const float& frank25, const float& crank25,
                    const float& , const float& frank75, const float& crank75, cv::Scalar& iqr)
    {
        for(int i=0;i<src.rows;i++)
        {
            wtype v25 = ( cv::saturate_cast<wtype>(src.at<type>(i,cv::saturate_cast<int>(frank25)-1))+cv::saturate_cast<wtype>(src.at<type>(i,cv::saturate_cast<int>(crank25)-1)) )/2.f;
            wtype v75 = ( cv::saturate_cast<wtype>(src.at<type>(i,cv::saturate_cast<int>(frank75)-1))+cv::saturate_cast<wtype>(src.at<type>(i,cv::saturate_cast<int>(crank75)-1)) )/2.f;

            iqr(i) = cv::saturate_cast<double>(v75-v25);
        }
    }

};

template<class type, class wtype>
struct calculate_iqr_t<type,wtype,false>
{
    calculate_iqr_t(const cv::Mat& src,
                    const float& rank25, const float& frank25, const float& crank25,
                    const float& rank75, const float& frank75, const float& crank75, cv::Scalar& iqr)
    {
        for(int i=0;i<src.rows;i++)
        {
            wtype v25 = cv::saturate_cast<wtype>(src.at<type>(i,frank25-1)) + (rank25-frank25)*(cv::saturate_cast<wtype>(src.at<type>(i,crank25))-cv::saturate_cast<wtype>(src.at<type>(i,frank25)));
            wtype v75 ...
(more)
edit retag flag offensive close merge delete

Comments

idx where?

    if(current && !next)
        idx.push_back(i);
    if(!current && next)
        idx.push_back(i+1);

here?

LBerger gravatar imageLBerger ( 2019-02-19 13:27:19 -0600 )edit

I am not sure to understand your question. Idx is a list in python a cv::Mat1i in C++ it store the index of the boolean vector (hd after have been threshold) that represents a transition either positive (from true to false) or negative (from false to true).

js4267 gravatar imagejs4267 ( 2019-02-19 14:56:22 -0600 )edit

You said

the main difference in the variable idx that in the c++ code does contains one single value while in python it does contains 32 values in python

Do you check idx here :

    if(current && !next)
        idx.push_back(i);
    if(!current && next)
        idx.push_back(i+1);
LBerger gravatar imageLBerger ( 2019-02-19 15:48:29 -0600 )edit

During the test the main difference is after lines you refer in one case there is 32 elements in idx in python and only one in C++.

js4267 gravatar imagejs4267 ( 2019-02-19 16:10:31 -0600 )edit

Set thresh=cv::mean(hd)(0) instead of thresh = (cv::mean(hd)(0) + utils::iqr(hd)(0) ); and python and c++ results are equal

Are you sure that c++ utils version is same than scipy version ? note in scipy doc :

The IQR of an empty array is np.nan. New in version 0.18.0.

How do you read data ? Are you sure that c++ and python data are equals?

LBerger gravatar imageLBerger ( 2019-02-20 02:46:12 -0600 )edit

I'll update later the code I use in both case. There is no version of C++ utils the utils::iqr it is my IQR code that I wrote in a namespace utils. Yes there is possible slight variation between my implementation and the scipy one but it is very slight from the experiment I made. By that when I wrote it there was no variations among the few cases I evaluated it.

js4267 gravatar imagejs4267 ( 2019-02-20 05:24:39 -0600 )edit

Are you agree that if you set thresh=cv::mean(hd)(0) instead of thresh = (cv::mean(hd)(0) + utils::iqr(hd)(0) ); and python and c++ results are equal ?

LBerger gravatar imageLBerger ( 2019-02-20 05:27:05 -0600 )edit

I am not yet at my office, I'll check as soon as I'll be there. It would not very surprise me however I remember in one case the threshold was at 313 for one of the example and 315 for the other. I would be surprise if such a few difference had such huge impact on the thresholding results. It is mandatory for what I want to do that the IQR (and not standard deviation, nor the variance, nor the median) be there.

js4267 gravatar imagejs4267 ( 2019-02-20 06:50:02 -0600 )edit

Hello I restart the evaluation without using the IQR and I still do not have the same output... But I have identically the same threshold what add something to my issue.

js4267 gravatar imagejs4267 ( 2019-02-20 15:14:52 -0600 )edit

I also edited the post in with the test codes.

js4267 gravatar imagejs4267 ( 2019-02-20 15:20:36 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
0

answered 2019-02-20 17:44:07 -0600

js4267 gravatar image

The reason why I do not had the same output was related to the IQR code. Even when in the discussion with LBerger I stop using it still had an display in order to knows its value. The processing of the IQR require to sort the data. My mistake came from the Mat reference counting, I mean sorting the data inside the IQR function sorted then as well outside the function because I did not make a copy where it use to be necessary to do it.

By replacing in the IQR function:

sort(src, tmp_srt, SORT_ASCENDING | SORT_EVERY_ROW);

by:

Mat tmp_srt;
sort(src, tmp_srt, SORT_ASCENDING | SORT_EVERY_ROW);
src = tmp_srt;

makes everything working like it should :).

edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2019-02-19 13:00:54 -0600

Seen: 637 times

Last updated: Feb 20 '19