chernoff.cpp
Go to the documentation of this file.
1 #include "chernoff.h"
2 
3 #include <cmath>
4 
5 #include <Eigen/Core>
6 #include <Eigen/Eigenvalues>
7 
9 
11 {
12 
13  double
15  {
16  //TODO: there seems to be an error that leads to the mean vectors always having the same
17  //value, which leads to the diff being zero which leads to distance being 0/inf/nan
18  //aron::data::NDArray image1 = *p1;
19  //aron::data::NDArray image2 = *p2;
20 
21  //then normalize them to have values between 0 and 1
22  //TODO: do not rturn new array but change existing one
23  auto f = normalize_ndarray(p1, 255);
24  auto s = normalize_ndarray(p2, 255);
25  //ARMARX_INFO << VAROUT(f);
26  //ARMARX_INFO << VAROUT(s);
27  //then calculate the mean vectors
28  std::vector<double> mean_one = calculate_mean_values(f);
29  std::vector<double> mean_two = calculate_mean_values(s);
30  //ARMARX_INFO << VAROUT(mean_one);
31  //then calculate the covariance matrices
32  std::vector<std::vector<double>> cov_one = calculate_covariance_matrix(f, mean_one);
33  std::vector<std::vector<double>> cov_two = calculate_covariance_matrix(s, mean_two);
34  //then calculate the Bhattacharyya distance and return
35  double distance = calculate_bhattacharyya_distance(mean_one, mean_two, cov_one, cov_two);
36  ARMARX_INFO << "Chernoff distance: " << std::to_string(distance);
37  return distance;
38  }
39 
40  std::vector<double>
42  {
43  std::vector<double> mean(3, 0.0);
44  int width = array.getShape().at(0);
45  int height = array.getShape().at(1);
46  int colors = array.getShape().at(2);
47  auto data = array.getDataAsVector();
48 
49  for (int row = 0; row < height; row++)
50  {
51  for (int col = 0; col < width; col++)
52  {
53  double red = data.at(row * width * colors + col * colors);
54  double green = data.at(row * width * colors + col * colors + 1);
55  double blue = data.at(row * width * colors + col * colors + 2);
56  mean[0] += red;
57  mean[1] += green;
58  mean[2] += blue;
59  }
60  }
61  //ARMARX_INFO << VAROUT(mean);
62  int numPixels = width * height; //only per color
63  mean[0] /= numPixels;
64  mean[1] /= numPixels;
65  mean[2] /= numPixels;
66 
67  return mean;
68  }
69 
72  {
73  std::vector<unsigned char> data = array->getDataAsVector();
74  std::vector<unsigned char> new_data(data.size());
75 
76  for (int i = 0; i < data.size(); i++)
77  {
78  double a = data.at(i);
79  double n = a / j;
80  new_data.at(i) = n;
81  }
82 
84  array->getShape(), array->getType(), new_data, array->getPath());
85  return n;
86  }
87 
88  std::vector<std::vector<double>>
90  std::vector<double> mean = std::vector<double>())
91  {
92  int width = array.getShape().at(0);
93  int height = array.getShape().at(1);
94  int colors = array.getShape().at(2);
95  auto data = array.getDataAsVector();
96 
97  std::vector<double> mean_vec(3, 0.0);
98  if (mean.empty())
99  {
100  mean_vec = calculate_mean_values(array);
101  }
102  else
103  {
104  mean_vec = mean;
105  }
106 
107  int numPixels = width * height; //only per color
108 
109  std::vector<std::vector<double>> covariance(3, std::vector<double>(3, 0.0));
110 
111  for (int row = 0; row < height; row++)
112  {
113  for (int col = 0; col < width; col++)
114  {
115  double red = data.at(row * width * colors + col * colors);
116  double green = data.at(row * width * colors + col * colors + 1);
117  double blue = data.at(row * width * colors + col * colors + 2);
118 
119  double redDeviation = red - mean[0];
120  double greenDeviation = green - mean[1];
121  double blueDeviation = blue - mean[2];
122 
123  covariance[0][0] += redDeviation * redDeviation;
124  covariance[0][1] += redDeviation * greenDeviation;
125  covariance[0][2] += redDeviation * blueDeviation;
126  covariance[1][1] += greenDeviation * greenDeviation;
127  covariance[1][2] += greenDeviation * blueDeviation;
128  covariance[2][2] += blueDeviation * blueDeviation;
129  }
130  }
131 
132  for (int i = 0; i < 3; i++)
133  {
134  for (int j = 0; j < i; j++)
135  {
136  covariance[i][j] /= numPixels;
137  covariance[j][i] = covariance[i][j];
138  }
139  covariance[i][i] /= numPixels;
140  }
141 
142  return covariance;
143  }
144 
145  double
146  calculate_bhattacharyya_distance(std::vector<double> mean_one,
147  std::vector<double> mean_two,
148  std::vector<std::vector<double>> covariance_one,
149  std::vector<std::vector<double>> covariance_two)
150  {
151  //first make mean vectors and covariance matrices in Eigen:: objects
152  Eigen::VectorXd meanOne(3);
153  meanOne << mean_one[0], mean_one[1], mean_one[2];
154  Eigen::VectorXd meanTwo(3);
155  meanTwo << mean_two[0], mean_two[1], mean_two[2];
156 
157  //ARMARX_INFO << VAROUT(meanOne);
158  //ARMARX_INFO << VAROUT(meanTwo);
159 
160  //these are column-major instead or row-major, but we have a quadratic, symmetric matrix, so it does not matter
161  //this conversion does not work correctly!!
162  //Eigen::MatrixXd cov_one = Eigen::Map<Eigen::MatrixXd>(covariance_one[0].data(), covariance_one.size(), covariance_one[0].size());
163  //Eigen::MatrixXd cov_two = Eigen::Map<Eigen::MatrixXd>(covariance_two[0].data(), covariance_two.size(), covariance_two[0].size());
164 
165  Eigen::Matrix3d cov_one;
166  cov_one << covariance_one[0][0], covariance_one[0][1], covariance_one[0][2],
167  covariance_one[1][0], covariance_one[1][1], covariance_one[1][2], covariance_one[2][0],
168  covariance_one[2][1], covariance_one[2][2];
169 
170  Eigen::Matrix3d cov_two;
171  cov_two << covariance_two[0][0], covariance_two[0][1], covariance_two[0][2],
172  covariance_two[1][0], covariance_two[1][1], covariance_two[1][2], covariance_two[2][0],
173  covariance_two[2][1], covariance_two[2][2];
174 
175 
176  //ARMARX_INFO << VAROUT(cov_one);
177 
178  Eigen::VectorXd meanDiff = meanOne - meanTwo;
179  //ARMARX_INFO << VAROUT(meanDiff);
180 
181  Eigen::MatrixXd sigma = 0.5 * (cov_one + cov_two);
182  Eigen::MatrixXd sigma_inverse = sigma.inverse();
183 
184  double det_cov_one = cov_one.determinant();
185  double det_cov_two = cov_two.determinant();
186  double det_sigma = sigma.determinant();
187 
188  //formula from https://www.kaggle.com/code/debanga/statistical-distances
189  double bigger = meanDiff.transpose() * (sigma_inverse)*meanDiff;
190  //ARMARX_INFO << "Bigger: " << std::to_string(bigger);
191  double term_one = 0.125 * bigger;
192  double sqr = std::sqrt(det_cov_one * det_cov_two);
193  //ARMARX_INFO << "Sqr: " << std::to_string(sqr);
194  double before_log = det_sigma / (sqr);
195  //ARMARX_INFO << "Before log: " << std::to_string(before_log);
196  double term_two = 0.5 * std::log(before_log);
197 
198  double distance = term_one + term_two;
199 
200  return distance;
201  }
202 
203 
204 } // namespace armarx::aron::similarity::chernoff
armarx::aron::data::NDArray::getDataAsVector
std::vector< unsigned char > getDataAsVector() const
Definition: NDArray.cpp:141
armarx::aron::similarity::chernoff
Definition: chernoff.cpp:10
armarx::aron::data::NDArray
Definition: NDArray.h:48
armarx::aron::similarity::chernoff::calculate_mean_values
std::vector< double > calculate_mean_values(data::NDArray array)
Definition: chernoff.cpp:41
armarx::aron::similarity::chernoff::normalize_ndarray
data::NDArray normalize_ndarray(data::NDArrayPtr array, int j)
Definition: chernoff.cpp:71
armarx::aron::data::NDArrayPtr
std::shared_ptr< NDArray > NDArrayPtr
Definition: NDArray.h:46
armarx::aron::data::NDArray::getShape
std::vector< int > getShape() const
Definition: NDArray.cpp:147
armarx::aron::similarity::chernoff::calculate_bhattacharyya_distance
double calculate_bhattacharyya_distance(std::vector< double > mean_one, std::vector< double > mean_two, std::vector< std::vector< double >> covariance_one, std::vector< std::vector< double >> covariance_two)
Definition: chernoff.cpp:146
armarx::ctrlutil::a
double a(double t, double a0, double j)
Definition: CtrlUtil.h:45
armarx::mean
std::optional< float > mean(const boost::circular_buffer< NameValueMap > &buffer, const std::string &key)
Definition: KinematicUnitGuiPlugin.cpp:1620
data
uint8_t data[1]
Definition: EtherCATFrame.h:68
armarx::aron::similarity::chernoff::compute_similarity
double compute_similarity(const aron::data::NDArrayPtr p1, const aron::data::NDArrayPtr p2)
Definition: chernoff.cpp:14
armarx::to_string
const std::string & to_string(const std::string &s)
Definition: StringHelpers.h:41
armarx::red
QColor red()
Definition: StyleSheets.h:78
GfxTL::sqrt
VectorXD< D, T > sqrt(const VectorXD< D, T > &a)
Definition: VectorXD.h:704
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:181
armarx::aron::similarity::chernoff::calculate_covariance_matrix
std::vector< std::vector< double > > calculate_covariance_matrix(data::NDArray array, std::vector< double > mean=std::vector< double >())
Definition: chernoff.cpp:89
distance
double distance(const Point &a, const Point &b)
Definition: point.hpp:95
Logging.h
chernoff.h
armarx::ctrlutil::s
double s(double t, double s0, double v0, double a0, double j)
Definition: CtrlUtil.h:33
armarx::green
QColor green()
Definition: StyleSheets.h:72