# difference in translation from python to C++

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],,None,,[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;
}

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 ...
edit retag close merge delete

idx where?

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


here?

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).

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);


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++.

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?

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.

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 ?

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.

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.

I also edited the post in with the test codes.

Sort by » oldest newest most voted

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 :).

more

Official site

GitHub

Wiki

Documentation