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