SaliencyCalculation.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @package
19 * @author
20 * @date
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24#include "SaliencyCalculation.h"
25
26
27// IVT
28#include <Calibration/Calibration.h>
29#include <Image/ByteImage.h>
30#include <Image/ImageProcessor.h>
31
32// stdlib
33#include <cmath>
34
36
37#include <omp.h>
38
40{
41
42 void
43 FindLocalMaxima(const std::vector<Vec3d>& aPoints3D,
44 const std::vector<Vec2d>& aPointsInImage,
45 std::vector<Vec3d>& aMaxima,
46 const int nBinSizeInPx,
47 CByteImage* pMaximumnessImage)
48 {
49 const int nNumBinsX = OLP_IMG_WIDTH / nBinSizeInPx + 1;
50 const int nNumBinsY = OLP_IMG_HEIGHT / nBinSizeInPx + 1;
51 const int nNumBinsTotal = nNumBinsX * nNumBinsY;
52
53 float* pAverageZ = new float[nNumBinsTotal];
54
55 for (int i = 0; i < nNumBinsTotal; i++)
56 {
57 pAverageZ[i] = 0;
58 }
59
60 int* pBinPointCounters = new int[nNumBinsTotal];
61
62 for (int i = 0; i < nNumBinsTotal; i++)
63 {
64 pBinPointCounters[i] = 0;
65 }
66
67 Vec3d* pBinMaxima = new Vec3d[nNumBinsTotal];
68
69 for (int i = 0; i < nNumBinsTotal; i++)
70 {
71 Math3d::SetVec(pBinMaxima[i], 0, 0, 0);
72 }
73
74 char* pBinMaximumnessValues = new char[nNumBinsTotal];
75
76 for (int i = 0; i < nNumBinsTotal; i++)
77 {
78 pBinMaximumnessValues[i] = 0;
79 }
80
81
82 // distribute points into the grid, accumulate z values, save the maximal z value for each cell
83 int nIndexX, nIndexY, nIndex;
84 const float fBinSizeInv = 1.0f / nBinSizeInPx;
85
86 for (size_t i = 0; i < aPoints3D.size(); i++)
87 {
88 nIndexX = (int)(aPointsInImage.at(i).x * fBinSizeInv);
89 nIndexY = (int)(aPointsInImage.at(i).y * fBinSizeInv);
90 nIndex = nIndexY * nNumBinsX + nIndexX;
91
92 if (0 <= nIndex && nIndex < nNumBinsTotal)
93 {
94 pAverageZ[nIndex] += aPoints3D.at(i).z;
95 pBinPointCounters[nIndex]++;
96
97 if (pBinMaxima[nIndex].z < aPoints3D.at(i).z)
98 {
99 Math3d::SetVec(pBinMaxima[nIndex], aPoints3D.at(i));
100 }
101 }
102 }
103
104 for (int i = 0; i < nNumBinsTotal; i++)
105 {
106 if (pBinPointCounters[i] != 0)
107 {
108 pAverageZ[i] /= pBinPointCounters[i];
109 }
110 }
111
112
113 // calculate maximumness and suppress non-maximum cells
114 float* pBinMaximaTemp = new float[nNumBinsTotal];
115
116 for (int i = 0; i < nNumBinsTotal; i++)
117 {
118 pBinMaximaTemp[i] = 0;
119 }
120
121 const float fMinHeightDifference =
122 0.033 * sqrt(sqrt(nBinSizeInPx)) * OLP_TOLERANCE_CONCURRENT_MOTION;
123
124 for (int i = 1; i < nNumBinsY - 1; i++)
125 {
126 for (int j = 1; j < nNumBinsX - 1; j++)
127 {
128 const float z = pAverageZ[i * nNumBinsX + j];
129 bool bMax = true;
130 int nMaximumnessValue = 0;
131
132 for (int k = -1; k <= 1; k++)
133 {
134 for (int l = -1; l <= 1; l++)
135 {
136 const float z1 = pAverageZ[(i + k) * nNumBinsX + (j + l)];
137
138 if ((z > z1 + fMinHeightDifference) && (z1 != 0))
139 {
140 nMaximumnessValue++;
141 }
142 else if (z1 > z)
143 {
144 bMax = false;
145 }
146 }
147 }
148
149 if (bMax)
150 {
151 pBinMaximaTemp[i * nNumBinsX + j] = pAverageZ[i * nNumBinsX + j];
152 }
153 else
154 {
155 pBinMaximaTemp[i * nNumBinsX + j] = 0;
156 }
157
158 pBinMaximumnessValues[i * nNumBinsX + j] = nMaximumnessValue;
159 }
160 }
161
162 // return maxima points
163 for (int i = 0; i < nNumBinsTotal; i++)
164 {
165 if (pBinMaximaTemp[i] != 0)
166 {
167 aMaxima.push_back(pBinMaxima[i]);
168 }
169 }
170
171 ARMARX_VERBOSE_S << aMaxima.size() << " maxima";
172
173
174 // draw maximumness image
175 for (int i = 0; i < nNumBinsY; i++)
176 {
177 for (int j = 0; j < nNumBinsX; j++)
178 {
179 //const int nValue = (pBinMaximumnessValues[i*nNumBinsX+j] > 4) ? 63*(pBinMaximumnessValues[i*nNumBinsX+j]-4) : 0;
180 const int nValue = 31 * pBinMaximumnessValues[i * nNumBinsX + j];
181
182 for (int k = i * nBinSizeInPx; k < (i + 1) * nBinSizeInPx && k < OLP_IMG_HEIGHT;
183 k++)
184 {
185 for (int l = j * nBinSizeInPx; l < (j + 1) * nBinSizeInPx && l < OLP_IMG_WIDTH;
186 l++)
187 {
188 pMaximumnessImage->pixels[k * OLP_IMG_WIDTH + l] = nValue;
189 }
190 }
191 }
192 }
193
194 delete[] pAverageZ;
195 delete[] pBinPointCounters;
196 delete[] pBinMaxima;
197 delete[] pBinMaximaTemp;
198 delete[] pBinMaximumnessValues;
199 }
200
201 void
202 FindLocalMaxima(const std::vector<CHypothesisPoint*>& aPoints,
203 const Mat3d mCameraToWorldRotation,
204 const Vec3d vCameraToWorldTranslation,
205 const CCalibration* calibration,
206 std::vector<Vec3d>& aMaxima,
207 CByteImage* pMaximumnessImage,
208 const int nBinSizeInPx)
209 {
210 std::vector<Vec3d> aPointsTransformed;
211 aPointsTransformed.resize(aPoints.size());
212
213 for (size_t i = 0; i < aPoints.size(); i++)
214 {
215 Math3d::MulMatVec(mCameraToWorldRotation,
216 aPoints.at(i)->vPosition,
217 vCameraToWorldTranslation,
218 aPointsTransformed.at(i));
219 }
220
221 std::vector<Vec2d> aPointsInImage;
222 aPointsInImage.resize(aPoints.size());
223
224 for (size_t i = 0; i < aPoints.size(); i++)
225 {
226 calibration->WorldToImageCoordinates(
227 aPoints.at(i)->vPosition, aPointsInImage.at(i), false);
228 }
229
230 CByteImage* pMaximumnessImage1 =
231 new CByteImage(OLP_IMG_WIDTH, OLP_IMG_HEIGHT, CByteImage::eGrayScale);
233 aPointsTransformed, aPointsInImage, aMaxima, nBinSizeInPx, pMaximumnessImage1);
234 CByteImage* pMaximumnessImage2 =
235 new CByteImage(OLP_IMG_WIDTH, OLP_IMG_HEIGHT, CByteImage::eGrayScale);
237 aPointsTransformed, aPointsInImage, aMaxima, 2 * nBinSizeInPx, pMaximumnessImage2);
238 CByteImage* pMaximumnessImage3 =
239 new CByteImage(OLP_IMG_WIDTH, OLP_IMG_HEIGHT, CByteImage::eGrayScale);
241 aPointsTransformed, aPointsInImage, aMaxima, 4 * nBinSizeInPx, pMaximumnessImage3);
242 CByteImage* pMaximumnessImage4 =
243 new CByteImage(OLP_IMG_WIDTH, OLP_IMG_HEIGHT, CByteImage::eGrayScale);
245 aPointsTransformed, aPointsInImage, aMaxima, 8 * nBinSizeInPx, pMaximumnessImage4);
246
247 for (int i = 0; i < OLP_IMG_WIDTH * OLP_IMG_HEIGHT; i++)
248 {
249 pMaximumnessImage->pixels[i] =
250 (pMaximumnessImage1->pixels[i] + pMaximumnessImage2->pixels[i] +
251 pMaximumnessImage3->pixels[i] + pMaximumnessImage4->pixels[i]) /
252 4;
253 }
254
255 // smooth result
256 for (int i = 0; i < 10; i++)
257 {
258 ImageProcessor::GaussianSmooth3x3(pMaximumnessImage, pMaximumnessImage1);
259 ImageProcessor::GaussianSmooth3x3(pMaximumnessImage1, pMaximumnessImage);
260 }
261
262 //pMaximumnessImage->SaveToFile("/home/staff/schieben/datalog/maxness.bmp");
263
264 Mat3d mRotInv;
265 Vec3d vTemp;
266 Math3d::Transpose(mCameraToWorldRotation, mRotInv);
267
268 for (size_t i = 0; i < aMaxima.size(); i++)
269 {
270 Math3d::SubtractVecVec(aMaxima.at(i), vCameraToWorldTranslation, vTemp);
271 Math3d::MulMatVec(mRotInv, vTemp, aMaxima.at(i));
272 }
273
274 //ARMARX_VERBOSE_S << "%ld maxima\n", aMaxima.size());
275 }
276
277 CComplexNumber
279 {
280 CComplexNumber c = {a.r * b.r - a.i * b.i, a.i * b.r + a.r * b.i};
281 return c;
282 }
283
284 CComplexNumber
285 ExpComplImagOnly(const float a)
286 {
287 CComplexNumber c = {cos(a), sin(a)};
288 return c;
289 }
290
291 void
292 FourierTransformation(const CByteImage* pGrayImage, CComplexNumber* pTransformed)
293 {
296 CComplexNumber* pTempArray1 = new CComplexNumber[nWidth * nHeight];
297 CComplexNumber* pTempArray2 = new CComplexNumber[nWidth * nHeight];
298 CByteImage* pSmallerImage = new CByteImage(nWidth, nHeight, CByteImage::eGrayScale);
299 ImageProcessor::Resize(pGrayImage, pSmallerImage);
300
301 for (int i = 0; i < nWidth * nHeight; i++)
302 {
303 pTempArray1[i].r = pSmallerImage->pixels[i];
304 pTempArray1[i].i = 0;
305 }
306
307 const double fWidthInv = 1.0 / nWidth;
308 const double fHeightInv = 1.0 / nHeight;
309
310#pragma omp parallel for
311 for (int v = 0; v < nHeight; v++)
312 {
313 for (int u = 0; u < nWidth; u++)
314 {
315 CComplexNumber vTemp, vSum = {0, 0};
316
317 for (int j = 0; j < nWidth; j++)
318 {
319 vTemp = MultCompl(pTempArray1[v * nWidth + j],
320 ExpComplImagOnly(-2 * M_PI * j * u * fWidthInv));
321 vSum.r += vTemp.r;
322 vSum.i += vTemp.i;
323 }
324
325 pTempArray2[v * nWidth + u].r = fWidthInv * vSum.r;
326 pTempArray2[v * nWidth + u].i = fWidthInv * vSum.i;
327 }
328 }
329
330#pragma omp parallel for
331 for (int u = 0; u < nWidth; u++)
332 {
333 for (int v = 0; v < nHeight; v++)
334 {
335 CComplexNumber vTemp, vSum = {0, 0};
336
337 for (int j = 0; j < nHeight; j++)
338 {
339 vTemp = MultCompl(pTempArray2[j * nWidth + u],
340 ExpComplImagOnly(-2 * M_PI * v * j * fHeightInv));
341 vSum.r += vTemp.r;
342 vSum.i += vTemp.i;
343 }
344
345 pTempArray1[v * nWidth + u].r = fHeightInv * vSum.r;
346 pTempArray1[v * nWidth + u].i = fHeightInv * vSum.i;
347 }
348 }
349
350 for (int i = 0; i < nWidth * nHeight; i++)
351 {
352 pTransformed[i].r =
353 sqrt(pTempArray1[i].r * pTempArray1[i].r + pTempArray1[i].i * pTempArray1[i].i);
354 pTransformed[i].i = atan2(pTempArray1[i].i, pTempArray1[i].r);
355 //pTransformed[i].r = pTempArray1[i].r;
356 //pTransformed[i].i = pTempArray1[i].i;
357 }
358
359 float fMaxAbs = 0;
360 float fMinPhase = pTransformed[0].i;
361 float fMaxPhase = pTransformed[0].i;
362
363 for (int i = 0; i < nWidth * nHeight; i++)
364 {
365 if (pTransformed[i].r > fMaxAbs)
366 {
367 fMaxAbs = pTransformed[i].r;
368 }
369
370 if (pTransformed[i].i < fMinPhase)
371 {
372 fMinPhase = pTransformed[i].i;
373 }
374
375 if (pTransformed[i].i > fMaxPhase)
376 {
377 fMaxPhase = pTransformed[i].i;
378 }
379 }
380
381 const float fMaxAbsInv = 255.0f / logf(fMaxAbs + 1);
382 const float fPhaseDiffInv = 255.0f / (fMaxPhase - fMinPhase);
383
384 CByteImage* pOutAbs = new CByteImage(nWidth, nHeight, CByteImage::eGrayScale);
385 CByteImage* pOutPhase = new CByteImage(nWidth, nHeight, CByteImage::eGrayScale);
386
387 for (int i = 0; i < nWidth * nHeight; i++)
388 {
389 pOutAbs->pixels[i] = fMaxAbsInv * logf(pTransformed[i].r + 1);
390 pOutPhase->pixels[i] = fPhaseDiffInv * (pTransformed[i].i - fMinPhase);
391 }
392
393 //pOutAbs->SaveToFile("/home/staff/schieben/datalog/ft-abs.bmp");
394 //pOutPhase->SaveToFile("/home/staff/schieben/datalog/ft-pha.bmp");
395 //pSmallerImage->SaveToFile("/home/staff/schieben/datalog/ft-orig.bmp");
396
397 delete[] pTempArray1;
398 delete[] pTempArray2;
399 delete pOutAbs;
400 delete pOutPhase;
401 }
402
403 void
404 InverseFourierTransformation(CComplexNumber* pTransformed, CByteImage* pGrayImage)
405 {
408 CComplexNumber* pTempArray1 = new CComplexNumber[nWidth * nHeight];
409 CComplexNumber* pTempArray2 = new CComplexNumber[nWidth * nHeight];
410
411
412 for (int i = 0; i < nWidth * nHeight; i++)
413 {
414 pTempArray1[i].r = pTransformed[i].r * cosf(pTransformed[i].i);
415 pTempArray1[i].i = pTransformed[i].r * sinf(pTransformed[i].i);
416 //pTempArray1[i].r = pTransformed[i].r;
417 //pTempArray1[i].i = pTransformed[i].i;
418 }
419
420 const double fWidthInv = 1.0 / nWidth;
421 const double fHeightInv = 1.0 / nHeight;
422
423#pragma omp parallel for
424 for (int j = 0; j < nWidth; j++)
425 {
426 for (int i = 0; i < nHeight; i++)
427 {
428 CComplexNumber vTemp, vSum = {0, 0};
429
430 for (int v = 0; v < nHeight; v++)
431 {
432 vTemp = MultCompl(pTempArray1[v * nWidth + j],
433 ExpComplImagOnly(2 * M_PI * i * v * fHeightInv));
434 vSum.r += vTemp.r;
435 vSum.i += vTemp.i;
436 }
437
438 pTempArray2[i * nWidth + j].r = vSum.r;
439 pTempArray2[i * nWidth + j].i = vSum.i;
440 }
441 }
442
443#pragma omp parallel for
444 for (int i = 0; i < nHeight; i++)
445 {
446 for (int j = 0; j < nWidth; j++)
447 {
448 CComplexNumber vTemp, vSum = {0, 0};
449
450 for (int u = 0; u < nWidth; u++)
451 {
452 vTemp = MultCompl(pTempArray2[i * nWidth + u],
453 ExpComplImagOnly(2 * M_PI * j * u * fWidthInv));
454 vSum.r += vTemp.r;
455 vSum.i += vTemp.i;
456 }
457
458 pTempArray1[i * nWidth + j].r = vSum.r;
459 pTempArray1[i * nWidth + j].i = vSum.i;
460 }
461 }
462
463 CByteImage* pSmallerImage = new CByteImage(nWidth, nHeight, CByteImage::eGrayScale);
464
465 for (int i = 0; i < nWidth * nHeight; i++)
466 {
467 pSmallerImage->pixels[i] =
468 (pTempArray1[i].r < 0) ? 0 : ((pTempArray1[i].r > 255) ? 255 : pTempArray1[i].r);
469 //pSmallerImage->pixels[i] = pTempArray1[i].i;
470 }
471
472 ImageProcessor::Resize(pSmallerImage, pGrayImage);
473 //pGrayImage->SaveToFile("/home/staff/schieben/datalog/ft-restored.bmp");
474
475 delete pSmallerImage;
476 delete[] pTempArray1;
477 delete[] pTempArray2;
478 }
479
480 void
482 {
485
486 double* pTempArray1 = new double[nWidth * nHeight];
487 double* pTempArray2 = new double[nWidth * nHeight];
488
489 for (int i = 0; i < nWidth * nHeight; i++)
490 {
491 pTempArray1[i] = log(pTransformed[i].r);
492 }
493
494 // average filter
495 const double fFactor1 = 0.12;
496 const double fFactor2 = 0.11;
497 const double fFactor3 = 0.11;
498
499 for (int i = 1; i < nHeight - 1; i++)
500 {
501 for (int j = 1; j < nWidth - 1; j++)
502 {
503 pTempArray2[i * nWidth + j] = fFactor3 * pTempArray1[(i - 1) * nWidth + j - 1] +
504 fFactor2 * pTempArray1[(i - 1) * nWidth + j] +
505 fFactor3 * pTempArray1[(i - 1) * nWidth + j + 1] +
506 fFactor2 * pTempArray1[i * nWidth + j - 1] +
507 fFactor1 * pTempArray1[i * nWidth + j] +
508 fFactor2 * pTempArray1[i * nWidth + j + 1] +
509 fFactor3 * pTempArray1[(i + 1) * nWidth + j - 1] +
510 fFactor2 * pTempArray1[(i + 1) * nWidth + j] +
511 fFactor3 * pTempArray1[(i + 1) * nWidth + j + 1];
512 }
513 }
514
515 // image borders
516 for (int i = 0; i < nWidth; i++)
517 {
518 pTempArray2[i] = pTempArray1[i];
519 pTempArray2[(nHeight - 1) * nWidth + i] = pTempArray1[(nHeight - 1) * nWidth + i];
520 }
521
522 for (int i = 0; i < nHeight; i++)
523 {
524 pTempArray2[i * nWidth] = pTempArray1[i * nWidth];
525 pTempArray2[i * nWidth + nWidth - 1] = pTempArray1[i * nWidth + nWidth - 1];
526 }
527
528
529 for (int i = 0; i < nWidth * nHeight; i++)
530 {
531 pTransformed[i].r = exp(pTempArray1[i] - pTempArray2[i]);
532 }
533
534 delete[] pTempArray1;
535 delete[] pTempArray2;
536 }
537
538 void
539 FindSalientRegionsHou(const CByteImage* pImageRGB, CByteImage* pSaliencyImage)
540 {
541 CByteImage* pOneColorChannelImage =
542 new CByteImage(OLP_IMG_WIDTH, OLP_IMG_HEIGHT, CByteImage::eGrayScale);
543 int* pSaliencySum = new int[OLP_IMG_WIDTH * OLP_IMG_HEIGHT];
544
545 for (int i = 0; i < OLP_IMG_WIDTH * OLP_IMG_HEIGHT; i++)
546 {
547 pSaliencySum[i] = 0;
548 }
549
550 for (int i = 0; i < 3; i++)
551 {
552 for (int j = 0; j < OLP_IMG_WIDTH * OLP_IMG_HEIGHT; j++)
553 {
554 pOneColorChannelImage->pixels[j] = pImageRGB->pixels[3 * j + i];
555 }
556
558 FourierTransformation(pOneColorChannelImage, pResult);
560 InverseFourierTransformation(pResult, pOneColorChannelImage);
561
562 for (int j = 0; j < OLP_IMG_WIDTH * OLP_IMG_HEIGHT; j++)
563 {
564 pSaliencySum[j] +=
565 pOneColorChannelImage->pixels[j] * pOneColorChannelImage->pixels[j];
566 }
567 }
568
569 int nMin = pSaliencySum[0], nMax = pSaliencySum[0];
570
571 for (int i = 0; i < OLP_IMG_WIDTH * OLP_IMG_HEIGHT; i++)
572 {
573 if (pSaliencySum[i] < nMin)
574 {
575 nMin = pSaliencySum[i];
576 }
577
578 if (pSaliencySum[i] > nMax)
579 {
580 nMax = pSaliencySum[i];
581 }
582 }
583
584 const double fFactor = 255.0 / (nMax - nMin);
585
586 for (int i = 0; i < OLP_IMG_WIDTH * OLP_IMG_HEIGHT; i++)
587 {
588 pSaliencyImage->pixels[i] = fFactor * (pSaliencySum[i] - nMin);
589 }
590
591 const float fSigma = 3;
592 const int nKernelSize = 4 * fSigma + 2; // >= 4*fSigma+1
593 ImageProcessor::GaussianSmooth(
594 pSaliencyImage, pSaliencyImage, fSigma * fSigma, nKernelSize);
595
596 //pSaliencyImage->SaveToFile("/home/staff/schieben/datalog/ft-saliency.bmp");
597
598 delete pOneColorChannelImage;
599 delete[] pSaliencySum;
600 }
601
602 void
603 FindSalientRegionsAchanta(const CByteImage* pImageRGB, CByteImage* pSaliencyImage)
604 {
605 CByteImage* pImageLab = new CByteImage(OLP_IMG_WIDTH, OLP_IMG_HEIGHT, CByteImage::eRGB24);
606 CByteImage* pImageHSV = new CByteImage(OLP_IMG_WIDTH, OLP_IMG_HEIGHT, CByteImage::eRGB24);
607
608#pragma omp sections
609 {
610#pragma omp section
611 {
612 ConvertRGB2Lab(pImageRGB, pImageLab);
613 }
614
615#pragma omp section
616 {
617 ImageProcessor::CalculateHSVImage(pImageRGB, pImageHSV);
618 }
619 }
620
621 const int nNumChannels = 9;
622 int* pAllColorChannels = new int[nNumChannels * OLP_IMG_WIDTH * OLP_IMG_HEIGHT];
623
624#pragma omp parallel for
625 for (int i = 0; i < OLP_IMG_WIDTH * OLP_IMG_HEIGHT; i++)
626 {
627 pAllColorChannels[nNumChannels * i] = pImageRGB->pixels[3 * i];
628 pAllColorChannels[nNumChannels * i + 1] = pImageRGB->pixels[3 * i + 1];
629 pAllColorChannels[nNumChannels * i + 2] = pImageRGB->pixels[3 * i + 2];
630
631 pAllColorChannels[nNumChannels * i + 3] = pImageHSV->pixels[3 * i];
632 pAllColorChannels[nNumChannels * i + 4] = pImageHSV->pixels[3 * i + 1];
633 pAllColorChannels[nNumChannels * i + 5] = pImageHSV->pixels[3 * i + 1];
634
635 pAllColorChannels[nNumChannels * i + 6] = pImageLab->pixels[3 * i];
636 pAllColorChannels[nNumChannels * i + 7] = pImageLab->pixels[3 * i + 1];
637 pAllColorChannels[nNumChannels * i + 8] = pImageLab->pixels[3 * i + 2];
638 }
639
640 int* pSaliencySum = new int[OLP_IMG_WIDTH * OLP_IMG_HEIGHT];
641
642 for (int i = 0; i < OLP_IMG_WIDTH * OLP_IMG_HEIGHT; i++)
643 {
644 pSaliencySum[i] = 0;
645 }
646
647 const int nParallelityFactor = omp_get_num_procs();
648 omp_set_num_threads(nParallelityFactor);
649 CByteImage** pOneColorChannelImages = new CByteImage*[nParallelityFactor];
650 CByteImage** pSmoothedImages = new CByteImage*[nParallelityFactor];
651 CByteImage** pExtremelySmoothedImages = new CByteImage*[nParallelityFactor];
652
653 for (int i = 0; i < nParallelityFactor; i++)
654 {
655 pOneColorChannelImages[i] =
656 new CByteImage(OLP_IMG_WIDTH, OLP_IMG_HEIGHT, CByteImage::eGrayScale);
657 pSmoothedImages[i] =
658 new CByteImage(OLP_IMG_WIDTH, OLP_IMG_HEIGHT, CByteImage::eGrayScale);
659 pExtremelySmoothedImages[i] =
660 new CByteImage(OLP_IMG_WIDTH, OLP_IMG_HEIGHT, CByteImage::eGrayScale);
661 }
662
663 const float fSigma1 = 80; // 60
664 const float fSigma2 = 10;
665 const int nKernelSize1 = 4 * fSigma1 + 1; // >= 4*fSigma+1
666 const int nKernelSize2 = 4 * fSigma2 + 1;
667
668#pragma omp parallel for
669 for (int i = 0; i < nNumChannels; i++)
670 {
671 const int nThreadNumber = omp_get_thread_num();
672
673 //long nSum = 0;
674 for (int j = 0; j < OLP_IMG_WIDTH * OLP_IMG_HEIGHT; j++)
675 {
676 pOneColorChannelImages[nThreadNumber]->pixels[j] =
677 pAllColorChannels[nNumChannels * j + i];
678 //nSum += pImageLab->pixels[nNumChannels*j+i];
679 }
680
681 //int nAverage = nSum/(OLP_IMG_WIDTH*OLP_IMG_HEIGHT);
682
683 ImageProcessor::GaussianSmooth(pOneColorChannelImages[nThreadNumber],
684 pExtremelySmoothedImages[nThreadNumber],
685 fSigma1 * fSigma1,
686 nKernelSize1);
687
688 ImageProcessor::GaussianSmooth(pOneColorChannelImages[nThreadNumber],
689 pSmoothedImages[nThreadNumber],
690 fSigma2 * fSigma2,
691 nKernelSize2);
692
693#pragma omp critical
694 for (int j = 0; j < OLP_IMG_WIDTH * OLP_IMG_HEIGHT; j++)
695 {
696 pSaliencySum[j] += (pExtremelySmoothedImages[nThreadNumber]->pixels[j] -
697 pSmoothedImages[nThreadNumber]->pixels[j]) *
698 (pExtremelySmoothedImages[nThreadNumber]->pixels[j] -
699 pSmoothedImages[nThreadNumber]->pixels[j]);
700 //pSaliencySum[j] += (nAverage-pSmoothedImage->pixels[j])*(nAverage-pSmoothedImage->pixels[j]);
701 }
702 }
703
704#pragma omp parallel for
705 for (int j = 0; j < OLP_IMG_WIDTH * OLP_IMG_HEIGHT; j++)
706 {
707 pSaliencySum[j] = sqrt(pSaliencySum[j]);
708 }
709
710
711 // normalization
712 int nMin = pSaliencySum[0], nMax = pSaliencySum[0];
713
714 for (int i = 0; i < OLP_IMG_WIDTH * OLP_IMG_HEIGHT; i++)
715 {
716 if (pSaliencySum[i] < nMin)
717 {
718 nMin = pSaliencySum[i];
719 }
720
721 if (pSaliencySum[i] > nMax)
722 {
723 nMax = pSaliencySum[i];
724 }
725 }
726
727 const double fFactor = (nMax > nMin) ? 255.0 / (nMax - nMin) : 1.0;
728
729#pragma omp parallel for
730 for (int i = 0; i < OLP_IMG_WIDTH * OLP_IMG_HEIGHT; i++)
731 {
732 pSaliencyImage->pixels[i] = fFactor * (pSaliencySum[i] - nMin);
733 }
734
735 //ImageProcessor::GaussianSmooth5x5(pSaliencyImage, pSaliencyImage);
736
737 //pSaliencyImage->SaveToFile("/home/staff/schieben/datalog/saliency.bmp");
738
739 delete pImageLab;
740 delete pImageHSV;
741 delete[] pAllColorChannels;
742
743 for (int i = 0; i < nParallelityFactor; i++)
744 {
745 delete pOneColorChannelImages[i];
746 delete pSmoothedImages[i];
747 delete pExtremelySmoothedImages[i];
748 }
749
750 delete[] pOneColorChannelImages;
751 delete[] pSmoothedImages;
752 delete[] pExtremelySmoothedImages;
753 }
754
755 void
756 ConvertRGB2Lab(const CByteImage* pImageRGB, CByteImage* pImageLab)
757 {
758 double r, g, b;
759 double x, y, z;
760 double L, A, B;
761 const double xn = 0.95;
762 const double yn = 1;
763 const double zn = 1.09;
764 const double dOneThird = 1.0 / 3.0;
765
766 for (int i = 0; i < OLP_IMG_WIDTH * OLP_IMG_HEIGHT; i++)
767 {
768 r = pImageRGB->pixels[3 * i];
769 g = pImageRGB->pixels[3 * i + 1];
770 b = pImageRGB->pixels[3 * i + 2];
771 x = 0.4124564 * r + 0.3575761 * g + 0.1804375 * b;
772 y = 0.2126729 * r + 0.7151522 * g + 0.0721750 * b;
773 z = 0.0193339 * r + 0.1191920 * g + 0.9503041 * b;
774 L = 116 * pow(y / yn, dOneThird) - 16;
775 A = 500 * (pow(x / xn, dOneThird) - pow(y / yn, dOneThird));
776 B = 200 * (pow(y / yn, dOneThird) - pow(z / zn, dOneThird));
777 pImageLab->pixels[3 * i] = L;
778 pImageLab->pixels[3 * i + 1] = A + 150;
779 pImageLab->pixels[3 * i + 2] = B + 100;
780 }
781 }
782
783
784} // namespace CSaliencyCalculation
class A(deque< T, A >)) ARMARX_OVERLOAD_STD_HASH_FOR_ITERABLE((class T
Enables hashing of std::list.
#define M_PI
Definition MathTools.h:17
#define OLP_FOURIER_TRANSFORM_SCALING_FACTOR
#define OLP_TOLERANCE_CONCURRENT_MOTION
constexpr T c
#define ARMARX_VERBOSE_S
Definition Logging.h:207
void FindLocalMaxima(const std::vector< Vec3d > &aPoints3D, const std::vector< Vec2d > &aPointsInImage, std::vector< Vec3d > &aMaxima, const int nBinSizeInPx, CByteImage *pMaximumnessImage)
void FindSalientRegionsAchanta(const CByteImage *pImageRGB, CByteImage *pSaliencyImage)
void FourierTransformation(const CByteImage *pGrayImage, CComplexNumber *pTransformed)
void FindSalientRegionsHou(const CByteImage *pImageRGB, CByteImage *pSaliencyImage)
void ConvertRGB2Lab(const CByteImage *pImageRGB, CByteImage *pImageLab)
CComplexNumber MultCompl(const CComplexNumber a, const CComplexNumber b)
void SubstractAveragedLogPowerSpectrum(CComplexNumber *pTransformed)
void InverseFourierTransformation(CComplexNumber *pTransformed, CByteImage *pGrayImage)
CComplexNumber ExpComplImagOnly(const float a)
This file offers overloads of toIce() and fromIce() functions for STL container types.