hog.cpp
Go to the documentation of this file.
1#include "hog.h"
2
3#include <filesystem>
4
5#include "choughcirclesdemo.h"
6
7HoG::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
23void
24HoG::loadTrainingData(std::string path)
25{
26
27 doLoadTrainingData(path + "t_training/", trainingHistTable, 6);
28 doLoadTrainingData(path + "n_training/", trainingHistTableNegative, 12);
29}
30
31void
32HoG::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
92void
93HoG::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
231bool
232HoG::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
260void
261HoG::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
284void
285HoG::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
302bool
303HoG::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
363void
364HoG::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
377float
378HoG::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)
439void
440HoG::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
489void
490HoG::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
526void
527HoG::setParameters(bool useHough, bool useHoG)
528{
529 useHoughDetector = useHough;
530 useHoGDetector = useHoG;
531}
#define float
Definition 16_Level.h:22
uint8_t index
#define M_PI
Definition MathTools.h:17
void openCVHoughSaliency(CByteImage *origin, CByteImage *saliencyImage, int sampleWindowsize, int width, int height, int windowCenterX, int windowCenterY)
HoG(int numOfBing=16, int sampleTime=500, int numOfHistory=2, int minRandomWindow=20, int randomWindowScaleFloor=1, int randomWindowScaleCeil=2)
Definition hog.cpp:7
void loadTrainingData(std::string path)
Definition hog.cpp:24
void setParameters(bool useHough, bool useHoG)
Definition hog.cpp:527
void findSalientRegions(const CByteImage *origin, CFloatImage *saliencyImage)
Definition hog.cpp:93
T max(T t1, T t2)
Definition gdiam.h:51
VectorXD< D, T > sqrt(const VectorXD< D, T > &a)
Definition VectorXD.h:704
double distance(const Point &a, const Point &b)
Definition point.hpp:95