hog.cpp
Go to the documentation of this file.
1 #include "hog.h"
2 
3 #include <filesystem>
4 
5 #include "choughcirclesdemo.h"
6 
7 HoG::HoG(int numOfBing,
8  int sampleTime,
9  int numOfHistory,
10  int minRandomWindow,
11  int randomWindowScaleFloor,
12  int randomWindowScaleCeil)
13 {
14  std::cout << "a HoG class constructed" << std::endl;
15  numberOfBins = numOfBing;
16  sampleTimes = sampleTime;
17  numberOfHistory = numOfHistory;
18  minimumRandomWindow = minRandomWindow;
19  randomWindowScaleRateFloor = randomWindowScaleFloor;
20  randomWindowScaleRateCeil = randomWindowScaleCeil;
21 }
22 
23 void
24 HoG::loadTrainingData(std::string path)
25 {
26 
27  doLoadTrainingData(path + "t_training/", trainingHistTable, 6);
28  doLoadTrainingData(path + "n_training/", trainingHistTableNegative, 12);
29 }
30 
31 void
32 HoG::doLoadTrainingData(std::string path, std::vector<std::vector<float>>& histTable, int scaling)
33 {
34  int width, height;
35  CByteImage *origin, *greyImage;
36  CFloatImage *hogImg, *amplitude;
37  std::vector<float> trainHist(numberOfBins, 0);
38  std::vector<float> trainHistNorm(numberOfBins, 0);
39 
40  std::vector<std::string> fileNames;
41 
42  for (std::filesystem::recursive_directory_iterator end, dir(path); dir != end; ++dir)
43  {
44  if (dir->path().extension() == ".bmp")
45  {
46  fileNames.push_back(dir->path().string());
47  }
48  }
49 
50 
51  for (std::string filename : fileNames)
52  {
53  CBitmapCapture capture(filename.c_str());
54 
55  if (capture.OpenCamera() == false)
56  {
57  std::cout << "error: could not open camera. Positive examples. " << filename
58  << std::endl;
59  }
60 
61  origin = new CByteImage(capture.GetWidth(), capture.GetHeight(), CByteImage::eRGB24);
62  capture.CaptureImage(&origin);
63 
64  for (int j = 2; j < scaling; j++)
65  {
66  width = capture.GetWidth() / j;
67  height = capture.GetHeight() / j;
68 
69  CByteImage* image = new CByteImage(width, height, CByteImage::eRGB24);
70  greyImage = new CByteImage(width, height, CByteImage::eGrayScale);
71  hogImg = new CFloatImage(width, height, 1);
72  amplitude = new CFloatImage(width, height, 1);
73 
74  ImageProcessor::Resize(origin, image);
75  HoG::preprocess(image, greyImage);
76  HoG::hogDescriptor(greyImage, hogImg, amplitude);
77  HoG::calculateHist(360, numberOfBins, hogImg, &trainHist, amplitude);
78  HoG::histogramNorm(&trainHist, &trainHistNorm);
79  // HoG::histogramRotationInvariant(&trainHistNorm, &trainHistNorm);
80  histTable.push_back(trainHistNorm);
81  delete image;
82  delete greyImage;
83  delete hogImg;
84  delete amplitude;
85  }
86 
87  delete origin;
88  // std::cout << trainingHistTable.size() << std::endl;
89  }
90 }
91 
92 void
93 HoG::findSalientRegions(const CByteImage* origin, CFloatImage* saliencyImage)
94 {
95  int width = origin->width;
96  int height = origin->height;
97 
98  CByteImage tempSaliencyImage(width, height, CByteImage::eGrayScale);
99  CByteImage* saliencyImageOrigin = new CByteImage(width, height, CByteImage::eGrayScale);
100  CFloatImage* hogImg = new CFloatImage(width, height, 1);
101  CFloatImage* amplitude = new CFloatImage(width, height, 1);
102  CByteImage* greyImage = new CByteImage(width, height, CByteImage::eGrayScale);
103 
104  HoG::preprocess(origin, greyImage);
105  HoG::hogDescriptor(greyImage, hogImg, amplitude);
106  ImageProcessor::Zero(saliencyImageOrigin);
107 
108  // std::cout << "compair greyImage, hogImg, amplitude" << greyImage->width << " " << greyImage->height << std::endl;
109  // std::cout << hogImg->width << " " << hogImg->height << std::endl;
110  // std::cout << amplitude->width << " " << amplitude->height << std::endl;
111 
112 
113  // std::cout << "step into findSalienRegions Function!" << std::endl;
114  for (int i = 0; i < numberOfHistory; i++)
115  {
116  for (int i = 0; i < saliencyImageOrigin->width * saliencyImageOrigin->height; i++)
117  {
118  saliencyImageOrigin->pixels[i] /= 3;
119  }
120 
121 #pragma omp parallel for
122  for (int i = 0; i < sampleTimes; i++)
123  {
124  int sampleWindowSize, windowCenterX, windowCenterY;
125  sampleWindowSize =
126  minimumRandomWindow + rand() % (std::min(width, height) - minimumRandomWindow);
127  //sampleWindowSize = 200;
128  //sampleWindowSize = 250;
129  windowCenterX = sampleWindowSize / 2 + rand() % (width - sampleWindowSize);
130  windowCenterY = sampleWindowSize / 2 + rand() % (height - sampleWindowSize);
131  //Important: adjust fenste windows' size according to the training Images.
132  for (int j = randomWindowScaleRateFloor; j < randomWindowScaleRateCeil; j++)
133  //for (int j=2; j<3; j++)
134  {
135  sampleWindowSize /= j;
136  CByteImage* sampleWindow =
137  new CByteImage(sampleWindowSize, sampleWindowSize, CByteImage::eGrayScale);
138  CFloatImage* sampleHogImg =
139  new CFloatImage(sampleWindow->width, sampleWindow->height, 1);
140  CFloatImage* sampleAmplitude =
141  new CFloatImage(sampleWindow->width, sampleWindow->height, 1);
142  for (int wIn = windowCenterX - (sampleWindowSize / 2), wOut = 0;
143  wOut < sampleWindowSize;
144  wIn++, wOut++)
145  {
146  for (int hIn = windowCenterY - (sampleWindowSize / 2), hOut = 0;
147  hOut < sampleWindowSize;
148  hIn++, hOut++)
149  {
150  sampleWindow->pixels[hOut * sampleWindowSize + wOut] =
151  greyImage->pixels[hIn * width + wIn];
152  sampleHogImg->pixels[hOut * sampleWindowSize + wOut] =
153  hogImg->pixels[hIn * width + wIn];
154  sampleAmplitude->pixels[hOut * sampleWindowSize + wOut] =
155  amplitude->pixels[hIn * width + wIn];
156  }
157  }
158 
159  std::vector<float> sampleHist(numberOfBins, 0);
160  std::vector<float> sampleHistNorm(numberOfBins, 0);
161 
162  HoG::calculateHist(360, numberOfBins, sampleHogImg, &sampleHist, sampleAmplitude);
163  HoG::histogramNorm(&sampleHist, &sampleHistNorm);
164  // HoG::histogramRotationInvariant(&sampleHistNorm, &sampleHistNorm);
165 
166 
167  if (useHoGDetector)
168  {
169  bool predict =
170  knn(trainingHistTable, trainingHistTableNegative, sampleHistNorm);
171  if (predict)
172  {
173  // set saliencyImage
174  for (int j = -1; j <= 1; j++)
175  {
176  for (int k = -1; k <= 1; k++)
177  {
178  saliencyImageOrigin
179  ->pixels[width * (windowCenterY + j) + (windowCenterX + k)] =
180  255;
181  }
182  }
183  }
184  }
185 
186  if (useHoughDetector)
187  {
188 
189  CHoughCircles hough;
190  //hough.HoughSaliency(sampleWindow, saliencyImageOrigin, sampleWindowSize, width, height, windowCenterX, windowCenterY);
191  hough.openCVHoughSaliency(sampleWindow,
192  saliencyImageOrigin,
193  sampleWindowSize,
194  width,
195  height,
196  windowCenterX,
197  windowCenterY);
198 
199  //using hough transformation to detect circle
200  }
201 
202 
203  delete sampleHogImg;
204  delete sampleAmplitude;
205  delete sampleWindow;
206  }
207  }
208 
209  for (int j = 0; j < 3; j++)
210  {
211  //ImageProcessor::HistogramStretching(&saliencyImageOrigin, &tempSaliencyImage, 0.0, 1.0);
212  ImageProcessor::GaussianSmooth5x5(saliencyImageOrigin, &tempSaliencyImage);
213  ImageProcessor::GaussianSmooth5x5(&tempSaliencyImage, saliencyImageOrigin);
214  }
215  ImageProcessor::HistogramStretching(saliencyImageOrigin, &tempSaliencyImage, 0.0, 1.0);
216  ImageProcessor::CopyImage(&tempSaliencyImage, saliencyImageOrigin);
217 
218  for (int i = 0; i < saliencyImage->width * saliencyImage->height; i++)
219  {
220  saliencyImage->pixels[i] = (float)saliencyImageOrigin->pixels[i] / 255;
221  //std::cout << "pixel is " << saliencyImage->pixels[i] << std::endl;
222  }
223  }
224 
225  delete hogImg;
226  delete amplitude;
227  delete greyImage;
228  delete saliencyImageOrigin;
229 }
230 
231 bool
232 HoG::hogDescriptor(CByteImage* origin, CFloatImage* outImage, CFloatImage* amplitude)
233 {
234  int width, height;
235  width = origin->width;
236  height = origin->height;
237  CShortImage sobelXImage(width, height);
238  CShortImage sobelYImage(width, height);
239  // CFloatImage hogImage(width, height, 1);
240 
241  ImageProcessor::SobelX(origin, &sobelXImage, false);
242  ImageProcessor::SobelY(origin, &sobelYImage, false);
243 
244  for (int i = 0; i < width * height; i++)
245  {
246  //std::cout << (int)pImage.pixels[i] << std::endl;
247 
248  outImage->pixels[i] = atan2((float)sobelXImage.pixels[i], (float)sobelYImage.pixels[i]);
249  outImage->pixels[i] = (outImage->pixels[i] * 180) / M_PI;
250  if (outImage->pixels[i] < 0)
251  {
252  outImage->pixels[i] += 360;
253  }
254  amplitude->pixels[i] = sqrt((float)sobelXImage.pixels[i] * (float)sobelXImage.pixels[i] +
255  (float)sobelYImage.pixels[i] * (float)sobelYImage.pixels[i]);
256  }
257  return true;
258 }
259 
260 void
261 HoG::calculateHist(int range,
262  int bin,
263  CFloatImage* inputImg,
264  std::vector<float>* output,
265  CFloatImage* amplitude)
266 {
267  // std::cout << "step into the calculateHist function!" << std::endl;
268  int index, binRange;
269  std::vector<float>::iterator it;
270  binRange = ceil((float)range / (float)bin);
271 
272  for (it = output->begin(); it < output->end(); it++)
273  {
274  *it = 0;
275  }
276 
277  for (int i = 0; i < inputImg->height * inputImg->width; i++)
278  {
279  index = inputImg->pixels[i] / binRange;
280  output->at(index) = output->at(index) + amplitude->pixels[i];
281  }
282 }
283 
284 void
285 HoG::histogramNorm(std::vector<float>* input, std::vector<float>* normOutput)
286 {
287  int sum = 0;
288  for (size_t i = 0; i < normOutput->size(); i++)
289  {
290  normOutput->at(i) = 0;
291  }
292  for (size_t i = 0; i < input->size(); i++)
293  {
294  sum = sum + input->at(i);
295  }
296  for (size_t i = 0; i < input->size(); i++)
297  {
298  normOutput->at(i) = input->at(i) / sum;
299  }
300 }
301 
302 bool
303 HoG::knn(std::vector<std::vector<float>> trainingHistTable,
304  std::vector<std::vector<float>> trainingHistTableNegative,
305  std::vector<float> testWindow)
306 {
307  float nearstDistance, secondDistance, thirdDistance;
308  int sum;
309  // std::pair <std::vector<float>, int> nearstNeighbor, secondNeighbor, thirdNeighbor;
310  // nearstNeighbor.second = -1;
311  // secondNeighbor.second = -1;
312  // thirdNeighbor.second = -1;
313  nearstDistance = std::numeric_limits<int>::max();
314  secondDistance = std::numeric_limits<int>::max();
315  thirdDistance = std::numeric_limits<int>::max();
316 
317  std::pair<std::vector<float>*, int> nearstNeighborPtr, secondNeighborPtr, thirdNeighborPtr;
318  nearstNeighborPtr.second = -1;
319  secondNeighborPtr.second = -1;
320  thirdNeighborPtr.second = -1;
321 
322  // findThreeNearstNeighbors(testWindow, trainingHistTable, 1, &nearstNeighbor, &secondNeighbor, &thirdNeighbor, &nearstDistance, &secondDistance, &thirdDistance);
323  // findThreeNearstNeighbors(testWindow, trainingHistTableNegative, 0, &nearstNeighbor, &secondNeighbor, &thirdNeighbor, &nearstDistance, &secondDistance, &thirdDistance);
324 
325  findThreeNearstNeighbors(testWindow,
326  trainingHistTable,
327  1,
328  &nearstNeighborPtr,
329  &secondNeighborPtr,
330  &thirdNeighborPtr,
331  &nearstDistance,
332  &secondDistance,
333  &thirdDistance);
334  findThreeNearstNeighbors(testWindow,
335  trainingHistTableNegative,
336  0,
337  &nearstNeighborPtr,
338  &secondNeighborPtr,
339  &thirdNeighborPtr,
340  &nearstDistance,
341  &secondDistance,
342  &thirdDistance);
343 
344  // sum = thirdNeighbor.second + secondNeighbor.second + nearstNeighbor.second;
345  sum = thirdNeighborPtr.second + secondNeighborPtr.second + nearstNeighborPtr.second;
346 
347  if (sum >= 2)
348  {
349  //if (nearstNeighbor.second == 1 && secondNeighbor.second == 1 && nearstDistance < 0.15)
350  if (nearstNeighborPtr.second == 1 && secondNeighborPtr.second == 1 && nearstDistance < 0.15)
351  {
352  //std::cout << "The window includes a valve!" << std::endl;
353  return true;
354  }
355  else
356  {
357  return false;
358  }
359  }
360  return false;
361 }
362 
363 void
364 HoG::preprocess(const CByteImage* origin, CByteImage* outImage)
365 {
366  ImageProcessor::ConvertImage(origin, outImage);
367  for (int i = 0; i < 4; i++)
368  {
369  ImageProcessor::GaussianSmooth5x5(outImage, outImage);
370  }
371  // if(!ImageProcessor::HistogramStretching(outImage, outImage))
372  // {
373  // return false;
374  // }
375 }
376 
377 float
378 HoG::distanceBetweenPoints(std::vector<float> firstPoint,
379  std::vector<float> secondPoint,
380  int metrics)
381 {
382  float distance = 0;
383  float manhattanDistance = 0;
384  float multiplicationSumme = 0;
385  float squareSummeFirst = 0;
386  float squareSummeSecond = 0;
387  float result = 0;
388  float chiSquare = 0;
389  if (firstPoint.size() != secondPoint.size())
390  {
391  //std::cout << "Two points have different dimensions." << std::endl;
392  return -1;
393  }
394  for (size_t i = 0; i < firstPoint.size(); i++)
395  {
396  distance += pow(firstPoint[i] - secondPoint[i], 2);
397  manhattanDistance += fabs(firstPoint[i] - secondPoint[i]);
398  multiplicationSumme += firstPoint[i] * secondPoint[i];
399  squareSummeFirst += pow(firstPoint[i], 2);
400  squareSummeSecond += pow(secondPoint[i], 2);
401  if ((firstPoint[i] + secondPoint[i]) != 0)
402  {
403  chiSquare += (firstPoint[i] - secondPoint[i]) * (firstPoint[i] - secondPoint[i]) /
404  (firstPoint[i] + secondPoint[i]);
405  }
406  }
407 
408  //std::cout << sqrt(distance) << std::endl;
409  switch (metrics)
410  {
411  case 1:
412  //Euclidean Distance
413  result = sqrt(distance);
414  break;
415  case 2:
416  //Mean Squared Error
417  result = distance;
418  break;
419  case 3:
420  //Manhattan Distance
421  result = manhattanDistance;
422  break;
423  case 4:
424  //Cosine Distance
425  result = (1 - multiplicationSumme / (sqrt(squareSummeFirst) * sqrt(squareSummeSecond)));
426  break;
427  case 5:
428  result = chiSquare;
429  break;
430  default:
431  result = sqrt(distance);
432  break;
433  }
434  //std::cout << "The distance between two points is: " << result << std::endl;
435  return result;
436 }
437 
438 //void HoG::findThreeNearstNeighbors(std::vector<float> testWindow, std::vector<std::vector<float> > trainingHistTable, int lable, std::pair <std::vector<float>, int>* nearstNeighbor, std::pair <std::vector<float>, int>* secondNeighbor, std::pair <std::vector<float>, int>* thirdNeighbor, float* nearstDistance, float* secondDistance, float* thirdDistance)
439 void
440 HoG::findThreeNearstNeighbors(std::vector<float> testWindow,
441  std::vector<std::vector<float>> trainingHistTable,
442  int lable,
443  std::pair<std::vector<float>*, int>* nearstNeighbor,
444  std::pair<std::vector<float>*, int>* secondNeighbor,
445  std::pair<std::vector<float>*, int>* thirdNeighbor,
446  float* nearstDistance,
447  float* secondDistance,
448  float* thirdDistance)
449 {
450  float distance;
451  std::vector<std::vector<float>>::iterator hisIt;
452  for (hisIt = trainingHistTable.begin(); hisIt < trainingHistTable.end(); hisIt++)
453  {
454  distance = distanceBetweenPoints(*hisIt, testWindow, 4);
455  //std::cout << "The distance between two points is " << distance << std::endl;
456  if (distance > *thirdDistance)
457  {
458  }
459  else if (distance < *nearstDistance)
460  {
461  *thirdNeighbor = *secondNeighbor;
462  *thirdDistance = *secondDistance;
463  *secondNeighbor = *nearstNeighbor;
464  *secondDistance = *nearstDistance;
465  //nearstNeighbor->first = *hisIt;
466  nearstNeighbor->first = &(*hisIt);
467  nearstNeighbor->second = lable;
468  *nearstDistance = distance;
469  }
470  else if (distance < *secondDistance)
471  {
472  *thirdNeighbor = *secondNeighbor;
473  *thirdDistance = *secondDistance;
474  // secondNeighbor->first = *hisIt;
475  secondNeighbor->first = &(*hisIt);
476  secondNeighbor->second = lable;
477  *secondDistance = distance;
478  }
479  else
480  {
481  //thirdNeighbor->first = *hisIt;
482  thirdNeighbor->first = &(*hisIt);
483  thirdNeighbor->second = lable;
484  *thirdDistance = distance;
485  }
486  }
487 }
488 
489 void
490 HoG::histogramRotationInvariant(std::vector<float>* inputHist, std::vector<float>* outputHist)
491 {
492  std::vector<float> newHistogram;
493  float max = 0, second = 0;
494  for (size_t i = 0; i < inputHist->size(); i++)
495  {
496  if (inputHist->at(i) > inputHist->at(max))
497  {
498  max = i;
499  }
500  else if (inputHist->at(i) > inputHist->at(second))
501  {
502  second = i;
503  }
504  // std::cout << inputHist->at(i) << std::endl;
505  }
506  // std::cout << "the index of the maximum is: " << max << " , the value is: " << inputHist->at(max) << std::endl;
507  // std::cout << "the index of the second maximum is: " << second << " , the value is: " << inputHist->at(second) << std::endl;
508  // std::cout << "The difference between the first two max is: " << inputHist->at(max) - inputHist->at(second) << std::endl;
509 
510  for (size_t i = max; i < inputHist->size(); i++)
511  {
512  newHistogram.push_back(inputHist->at(i));
513  }
514  for (int i = 0; i < max; i++)
515  {
516  newHistogram.push_back(inputHist->at(i));
517  }
518 
519  for (size_t i = 0; i < newHistogram.size(); i++)
520  {
521  outputHist->at(i) = newHistogram.at(i);
522  }
523  //std::cout << "The number of bin in newHistogram is: " << newHistogram.size() << std::endl;
524 }
525 
526 void
527 HoG::setParameters(bool useHough, bool useHoG)
528 {
529  useHoughDetector = useHough;
530  useHoGDetector = useHoG;
531 }
CHoughCircles::openCVHoughSaliency
void openCVHoughSaliency(CByteImage *origin, CByteImage *saliencyImage, int sampleWindowsize, int width, int height, int windowCenterX, int windowCenterY)
Definition: choughcirclesdemo.cpp:64
index
uint8_t index
Definition: EtherCATFrame.h:59
CHoughCircles
Definition: choughcirclesdemo.h:23
HoG::HoG
HoG(int numOfBing=16, int sampleTime=500, int numOfHistory=2, int minRandomWindow=20, int randomWindowScaleFloor=1, int randomWindowScaleCeil=2)
Definition: hog.cpp:7
HoG::findSalientRegions
void findSalientRegions(const CByteImage *origin, CFloatImage *saliencyImage)
Definition: hog.cpp:93
M_PI
#define M_PI
Definition: MathTools.h:17
armarx::aron::input
ReaderT::InputType & input
Definition: rw.h:12
filename
std::string filename
Definition: VisualizationRobot.cpp:86
max
T max(T t1, T t2)
Definition: gdiam.h:51
HoG::setParameters
void setParameters(bool useHough, bool useHoG)
Definition: hog.cpp:527
GfxTL::sqrt
VectorXD< D, T > sqrt(const VectorXD< D, T > &a)
Definition: VectorXD.h:704
float
#define float
Definition: 16_Level.h:22
hog.h
distance
double distance(const Point &a, const Point &b)
Definition: point.hpp:95
choughcirclesdemo.h
min
T min(T t1, T t2)
Definition: gdiam.h:44
HoG::loadTrainingData
void loadTrainingData(std::string path)
Definition: hog.cpp:24