GaussBackground.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
25#include "GaussBackground.h"
26
28
30#include <Image/ImageProcessor.h>
31
32CGaussBackground::CGaussBackground(const int nWidth, const int nHeight)
33{
34 m_pPixelProbabilityDistributions = new CPixelProbabilityDistribution[nWidth * nHeight];
35 m_nImageWidth = nWidth;
36 m_nImageHeight = nHeight;
37
38 m_pBackgroundRGB = new CByteImage(nWidth, nHeight, CByteImage::eRGB24);
39}
40
42{
43 delete m_pPixelProbabilityDistributions;
44 delete m_pBackgroundRGB;
45}
46
47inline double
48DetMat2d(const Mat2d m)
49{
50 return m.r1 * m.r4 - m.r3 * m.r2;
51}
52
53void
54CGaussBackground::LearnBackgroundRGB(CByteImage** pRGBImages, const int nNumImages)
55{
56 CByteImage** pHSVImages = new CByteImage*[nNumImages];
57 CByteImage* pSmoothedImage = new CByteImage(m_nImageWidth, m_nImageHeight, CByteImage::eRGB24);
58
59 for (int i = 0; i < nNumImages; i++)
60 {
61 pHSVImages[i] = new CByteImage(m_nImageWidth, m_nImageHeight, CByteImage::eRGB24);
62 ImageProcessor::GaussianSmooth3x3(pRGBImages[i], pSmoothedImage);
63 ImageProcessor::CalculateHSVImage(pSmoothedImage, pHSVImages[i]);
64 }
65
66 LearnBackground(pHSVImages, nNumImages);
67
68 ImageProcessor::CopyImage(pRGBImages[0], m_pBackgroundRGB);
69
70 for (int i = 0; i < nNumImages; i++)
71 {
72 delete pHSVImages[i];
73 }
74
75 delete[] pHSVImages;
76 delete pSmoothedImage;
77}
78
79void
80CGaussBackground::LearnBackground(CByteImage** pHSVImages, const int nNumImages)
81{
82 if ((pHSVImages[0]->width != m_nImageWidth) || (pHSVImages[0]->height != m_nImageHeight))
83 {
84 ARMARX_WARNING_S << "CGaussBackground::LearnBackground: Image dimensions do not fit!";
85 return;
86 }
87
88 if (nNumImages < 1)
89 {
90 ARMARX_WARNING_S << "CGaussBackground::LearnBackground: Need at least one image!";
91 return;
92 }
93
94 CPixelProbabilityDistribution* pPPD = m_pPixelProbabilityDistributions;
96 new CPixelProbabilityDistribution[m_nImageWidth * m_nImageHeight];
97
98 // reset all pixels
99 for (int j = 0; j < m_nImageWidth * m_nImageHeight; j++)
100 {
101 Math2d::SetVec(pPPD[j].vMean, 0, 0);
102 pPPD[j].mCovariance.r1 = 0;
103 pPPD[j].mCovariance.r2 = 0;
104 pPPD[j].mCovariance.r3 = 0;
105 pPPD[j].mCovariance.r4 = 0;
106
107 Math2d::SetVec(pShPPD[j].vMean, 0, 0);
108 pShPPD[j].mCovariance.r1 = 0;
109 pShPPD[j].mCovariance.r2 = 0;
110 pShPPD[j].mCovariance.r3 = 0;
111 pShPPD[j].mCovariance.r4 = 0;
112 }
113
114
115 // calculate means
116 //ARMARX_VERBOSE_S << "Calculating means";
117 for (int i = 0; i < nNumImages; i++)
118 {
119 //if (i%10==0) ARMARX_VERBOSE_S << " Image %d of %d\n", i, nNumImages);
120 for (int j = 0; j < m_nImageWidth * m_nImageHeight; j++)
121 {
122 pPPD[j].vMean.x += pHSVImages[i]->pixels[3 * j];
123 pPPD[j].vMean.y += pHSVImages[i]->pixels[3 * j + 1];
124
125 pShPPD[j].vMean.x += (pHSVImages[i]->pixels[3 * j] + 128) % 256;
126 pShPPD[j].vMean.y += pHSVImages[i]->pixels[3 * j + 1];
127 }
128 }
129
130 for (int j = 0; j < m_nImageWidth * m_nImageHeight; j++)
131 {
132 pPPD[j].vMean.x /= nNumImages;
133 pPPD[j].vMean.y /= nNumImages;
134
135 pShPPD[j].vMean.x /= nNumImages;
136 pShPPD[j].vMean.y /= nNumImages;
137 }
138
139
140 // calculate covariance matrices
141 if (nNumImages > 1)
142 {
143 //ARMARX_VERBOSE_S << " -- Calculating covariance matrices --\n");
144 for (int i = 0; i < nNumImages; i++)
145 {
146 //if (i%10==0) ARMARX_VERBOSE_S << " Image %d of %d\n", i, nNumImages);
147 for (int j = 0; j < m_nImageWidth * m_nImageHeight; j++)
148 {
149 pPPD[j].mCovariance.r1 += (pHSVImages[i]->pixels[3 * j] - pPPD[j].vMean.x) *
150 (pHSVImages[i]->pixels[3 * j] - pPPD[j].vMean.x);
151 pPPD[j].mCovariance.r2 += (pHSVImages[i]->pixels[3 * j] - pPPD[j].vMean.x) *
152 (pHSVImages[i]->pixels[3 * j + 1] - pPPD[j].vMean.y);
153 pPPD[j].mCovariance.r3 += (pHSVImages[i]->pixels[3 * j + 1] - pPPD[j].vMean.y) *
154 (pHSVImages[i]->pixels[3 * j] - pPPD[j].vMean.x);
155 pPPD[j].mCovariance.r4 += (pHSVImages[i]->pixels[3 * j + 1] - pPPD[j].vMean.y) *
156 (pHSVImages[i]->pixels[3 * j + 1] - pPPD[j].vMean.y);
157
158 pShPPD[j].mCovariance.r1 +=
159 (((pHSVImages[i]->pixels[3 * j] + 128) % 256) - pShPPD[j].vMean.x) *
160 (((pHSVImages[i]->pixels[3 * j] + 128) % 256) - pShPPD[j].vMean.x);
161 pShPPD[j].mCovariance.r2 +=
162 (((pHSVImages[i]->pixels[3 * j] + 128) % 256) - pShPPD[j].vMean.x) *
163 (pHSVImages[i]->pixels[3 * j + 1] - pShPPD[j].vMean.y);
164 pShPPD[j].mCovariance.r3 +=
165 (pHSVImages[i]->pixels[3 * j + 1] - pShPPD[j].vMean.y) *
166 (((pHSVImages[i]->pixels[3 * j] + 128) % 256) - pShPPD[j].vMean.x);
167 pShPPD[j].mCovariance.r4 += (pHSVImages[i]->pixels[3 * j + 1] - pShPPD[j].vMean.y) *
168 (pHSVImages[i]->pixels[3 * j + 1] - pShPPD[j].vMean.y);
169 }
170 }
171
172 const float fFactor = 1.0f / (float)(nNumImages - 1);
173
174 for (int j = 0; j < m_nImageWidth * m_nImageHeight; j++)
175 {
176 pPPD[j].mCovariance.r1 *= fFactor;
177 pPPD[j].mCovariance.r2 *= fFactor;
178 pPPD[j].mCovariance.r3 *= fFactor;
179 pPPD[j].mCovariance.r4 *= fFactor;
180
181 pShPPD[j].mCovariance.r1 *= fFactor;
182 pShPPD[j].mCovariance.r2 *= fFactor;
183 pShPPD[j].mCovariance.r3 *= fFactor;
184 pShPPD[j].mCovariance.r4 *= fFactor;
185
186
187 // if shifted version has smaller variance, use it
188 if (DetMat2d(pPPD[j].mCovariance) > DetMat2d(pShPPD[j].mCovariance))
189 {
190 pPPD[j].vMean.x = pShPPD[j].vMean.x;
191 pPPD[j].vMean.y = pShPPD[j].vMean.y;
192
193 pPPD[j].mCovariance.r1 = pShPPD[j].mCovariance.r1;
194 pPPD[j].mCovariance.r2 = pShPPD[j].mCovariance.r2;
195 pPPD[j].mCovariance.r3 = pShPPD[j].mCovariance.r3;
196 pPPD[j].mCovariance.r4 = pShPPD[j].mCovariance.r4;
197
198 pPPD[j].bShifted = true;
199 }
200 else
201 {
202 pPPD[j].bShifted = false;
203 }
204
205 // smooth variance
206 pPPD[j].mCovariance.r1 += 1;
207 pPPD[j].mCovariance.r4 += 1;
208
209 //if (j%10000==0) ARMARX_VERBOSE_S << "Matrix: (%.2f %.2f %.2f %.2f)\n", pPPD[j].mCovariance.r1, pPPD[j].mCovariance.r2, pPPD[j].mCovariance.r3, pPPD[j].mCovariance.r4);
210
211 // invert the covariance matrix for faster evaluation
212 Math2d::Invert(pPPD[j].mCovariance, pPPD[j].mCovariance);
213
214 pPPD[j].fSatWeight = exp(-pPPD[j].vMean.y * pPPD[j].vMean.y / 6400);
215 }
216 }
217 else
218 {
219 for (int j = 0; j < m_nImageWidth * m_nImageHeight; j++)
220 {
221 pPPD[j].mCovariance.r1 = 1.0f / 264.0f;
222 pPPD[j].mCovariance.r2 = 0;
223 pPPD[j].mCovariance.r3 = 0;
224 pPPD[j].mCovariance.r4 = 1.0f / 264.0f;
225
226 pPPD[j].fSatWeight = exp(-pPPD[j].vMean.y * pPPD[j].vMean.y / 6400);
227
228 if (pPPD[j].vMean.x < 64 || pPPD[j].vMean.x > 192)
229 {
230 pPPD[j].vMean.x = ((int)pPPD[j].vMean.x + 128) % 256;
231 pPPD[j].bShifted = true;
232 }
233 else
234 {
235 pPPD[j].bShifted = false;
236 }
237 }
238 }
239
240 delete[] pShPPD;
241}
242
243inline double
244CGaussBackground::CalcProbOfPixel(const int nIndex, const Vec2d vHS_Value)
245{
246 double dTemp0;
247 Vec2d vTemp1, vTemp2;
248
249 // v = pixel value - mean
250 Math2d::SubtractVecVec(vHS_Value, m_pPixelProbabilityDistributions[nIndex].vMean, vTemp1);
251 // d = v^T*Sigma^-1*v
252 Math2d::MulMatVec(m_pPixelProbabilityDistributions[nIndex].mCovariance, vTemp1, vTemp2);
253 dTemp0 = Math2d::ScalarProduct(vTemp1, vTemp2);
254
255 return exp(-0.03 *
256 (m_pPixelProbabilityDistributions[nIndex].fSatWeight * (vTemp1.y * vTemp1.y) *
257 m_pPixelProbabilityDistributions[nIndex].mCovariance.r4 +
258 (1 - m_pPixelProbabilityDistributions[nIndex].fSatWeight) * dTemp0));
259 //return exp(-0.05 * dTemp0);
260}
261
262void
263CGaussBackground::BinarizeAndFillHoles(CByteImage* pProbabilityImage)
264{
265 //char pFileName[] = "/home/staff/schieben/datalog/bg0.bmp";
266 //pProbabilityImage->SaveToFile(pFileName);
267
268 // binarize
269 for (int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
270 {
271 pProbabilityImage->pixels[i] =
272 (pProbabilityImage->pixels[i] > OLP_FOREGROUND_THRESHOLD) ? 255 : 0;
273 }
274
275
276 // remove noise
277 CByteImage* pTempImage = new CByteImage(m_nImageWidth, m_nImageHeight, CByteImage::eGrayScale);
278 ImageProcessor::Dilate(pProbabilityImage, pTempImage);
279 ImageProcessor::Erode(pTempImage, pProbabilityImage);
280 ImageProcessor::Erode(pProbabilityImage, pTempImage);
281 ImageProcessor::Erode(pTempImage, pProbabilityImage);
282 ImageProcessor::Erode(pProbabilityImage, pTempImage);
283 ImageProcessor::Dilate(pTempImage, pProbabilityImage);
284 ImageProcessor::Dilate(pProbabilityImage, pTempImage);
285 ImageProcessor::Dilate(pTempImage, pProbabilityImage);
286 ImageProcessor::Dilate(pProbabilityImage, pTempImage);
287 ImageProcessor::Dilate(pTempImage, pProbabilityImage);
288
289
290 // fill holes
291 for (int i = 0; i < 1; i++) // 1
292 {
293 FillHolesHorVertDiag(pProbabilityImage, pTempImage);
294 FillHolesHorVertDiag(pTempImage, pProbabilityImage);
295 //pFileName[31] = '1'+i;
296 //pProbabilityImage->SaveToFile(pFileName);
297 }
298
299 for (int i = 0; i < 2; i++) // 2
300 {
301 FillHolesHorVert(pProbabilityImage, pTempImage);
302 FillHolesDiag(pTempImage, pProbabilityImage);
303 //pFileName[31] = '2'+i;
304 //pProbabilityImage->SaveToFile(pFileName);
305 }
306
307 // extend foreground regions
308 for (int i = 0; i < 0; i++) // 1
309 {
310 ImageProcessor::Dilate(pProbabilityImage, pTempImage);
311 ImageProcessor::Dilate(pTempImage, pProbabilityImage);
312 }
313
314 delete pTempImage;
315}
316
317inline void
318CGaussBackground::FillHolesHorVert(const CByteImage* pInputImage,
319 CByteImage* pOutputImage,
320 const int nRadius)
321{
322 for (int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
323 {
324 pOutputImage->pixels[i] = pInputImage->pixels[i];
325 }
326
327#pragma omp parallel for schedule(static, 100)
328 for (int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
329 {
330 if (pOutputImage->pixels[i] == 0)
331 {
332 // check for white pixels in all directions
333 int nPixelSumsInDirections[4] = {0, 0, 0, 0};
334 int nIndex;
335
336 for (int j = 1; j <= nRadius; j++)
337 {
338 // to the left
339 nIndex = i - j;
340
341 if (nIndex >= 0)
342 {
343 nPixelSumsInDirections[0] += pInputImage->pixels[nIndex];
344 }
345
346 // to the right
347 nIndex = i + j;
348
349 if (nIndex < m_nImageWidth * m_nImageHeight)
350 {
351 nPixelSumsInDirections[1] += pInputImage->pixels[nIndex];
352 }
353
354 // upwards
355 nIndex = i - j * m_nImageWidth;
356
357 if (nIndex >= 0)
358 {
359 nPixelSumsInDirections[2] += pInputImage->pixels[nIndex];
360 }
361
362 // downwards
363 nIndex = i + j * m_nImageWidth;
364
365 if (nIndex < m_nImageWidth * m_nImageHeight)
366 {
367 nPixelSumsInDirections[3] += pInputImage->pixels[nIndex];
368 }
369 }
370
371 if (nPixelSumsInDirections[0] * nPixelSumsInDirections[1] * nPixelSumsInDirections[2] *
372 nPixelSumsInDirections[3] !=
373 0)
374 {
375 pOutputImage->pixels[i] = 255;
376 }
377 }
378 }
379}
380
381inline void
382CGaussBackground::FillHolesDiag(const CByteImage* pInputImage,
383 CByteImage* pOutputImage,
384 const int nRadius)
385{
386 for (int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
387 {
388 pOutputImage->pixels[i] = pInputImage->pixels[i];
389 }
390
391#pragma omp parallel for schedule(static, 100)
392 for (int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
393 {
394 if (pOutputImage->pixels[i] == 0)
395 {
396 // check for white pixels in all directions
397 int nPixelSumsInDirections[4] = {0, 0, 0, 0};
398 int nIndex;
399
400 for (int j = 1; j <= nRadius; j++)
401 {
402 // to the left and up
403 nIndex = i - j * m_nImageWidth - j;
404
405 if (nIndex >= 0)
406 {
407 nPixelSumsInDirections[0] += pInputImage->pixels[nIndex];
408 }
409
410 // to the right and up
411 nIndex = i - j * m_nImageWidth + j;
412
413 if (nIndex >= 0)
414 {
415 nPixelSumsInDirections[1] += pInputImage->pixels[nIndex];
416 }
417
418 // to the left and down
419 nIndex = i + j * m_nImageWidth - j;
420
421 if (nIndex < m_nImageWidth * m_nImageHeight)
422 {
423 nPixelSumsInDirections[2] += pInputImage->pixels[nIndex];
424 }
425
426 // to the right and down
427 nIndex = i + j * m_nImageWidth + j;
428
429 if (nIndex < m_nImageWidth * m_nImageHeight)
430 {
431 nPixelSumsInDirections[3] += pInputImage->pixels[nIndex];
432 }
433 }
434
435 if (nPixelSumsInDirections[0] * nPixelSumsInDirections[1] * nPixelSumsInDirections[2] *
436 nPixelSumsInDirections[3] !=
437 0)
438 {
439 pOutputImage->pixels[i] = 255;
440 }
441 }
442 }
443}
444
445inline void
446CGaussBackground::FillHolesHorVertDiag(const CByteImage* pInputImage,
447 CByteImage* pOutputImage,
448 const int nRadius)
449{
450 for (int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
451 {
452 pOutputImage->pixels[i] = pInputImage->pixels[i];
453 }
454
455#pragma omp parallel for schedule(static, 100)
456 for (int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
457 {
458 if (pOutputImage->pixels[i] == 0)
459 {
460 // check for white pixels in all directions
461 int nPixelSumsInDirections[8] = {0, 0, 0, 0, 0, 0, 0, 0};
462 int nIndex;
463
464 for (int j = 1; j <= nRadius; j++)
465 {
466 // to the left
467 nIndex = i - j;
468
469 if (nIndex >= 0)
470 {
471 nPixelSumsInDirections[0] += pInputImage->pixels[nIndex];
472 }
473
474 // to the right
475 nIndex = i + j;
476
477 if (nIndex < m_nImageWidth * m_nImageHeight)
478 {
479 nPixelSumsInDirections[1] += pInputImage->pixels[nIndex];
480 }
481
482 // upwards
483 nIndex = i - j * m_nImageWidth;
484
485 if (nIndex >= 0)
486 {
487 nPixelSumsInDirections[2] += pInputImage->pixels[nIndex];
488 }
489
490 // downwards
491 nIndex = i + j * m_nImageWidth;
492
493 if (nIndex < m_nImageWidth * m_nImageHeight)
494 {
495 nPixelSumsInDirections[3] += pInputImage->pixels[nIndex];
496 }
497
498 // to the left and up
499 nIndex = i - j * m_nImageWidth - j;
500
501 if (nIndex >= 0)
502 {
503 nPixelSumsInDirections[4] += pInputImage->pixels[nIndex];
504 }
505
506 // to the right and up
507 nIndex = i - j * m_nImageWidth + j;
508
509 if (nIndex >= 0)
510 {
511 nPixelSumsInDirections[5] += pInputImage->pixels[nIndex];
512 }
513
514 // to the left and down
515 nIndex = i + j * m_nImageWidth - j;
516
517 if (nIndex < m_nImageWidth * m_nImageHeight)
518 {
519 nPixelSumsInDirections[6] += pInputImage->pixels[nIndex];
520 }
521
522 // to the right and down
523 nIndex = i + j * m_nImageWidth + j;
524
525 if (nIndex < m_nImageWidth * m_nImageHeight)
526 {
527 nPixelSumsInDirections[7] += pInputImage->pixels[nIndex];
528 }
529 }
530
531 if (nPixelSumsInDirections[0] * nPixelSumsInDirections[1] * nPixelSumsInDirections[2] *
532 nPixelSumsInDirections[3] * nPixelSumsInDirections[4] *
533 nPixelSumsInDirections[5] * nPixelSumsInDirections[6] *
534 nPixelSumsInDirections[7] !=
535 0)
536 {
537 pOutputImage->pixels[i] = 255;
538 }
539 }
540 }
541}
542
543void
544CGaussBackground::GetBinaryForegroundImageRGB(const CByteImage* pInputImageRGB,
545 CByteImage* pForegroundImage)
546{
547 SegmentImageRGB(pInputImageRGB, pForegroundImage);
548
549 BinarizeAndFillHoles(pForegroundImage);
550}
551
552void
553CGaussBackground::SegmentImageRGB(const CByteImage* pInputImageRGB, CByteImage* pProbabilityImage)
554{
555 CByteImage* pHSVImage = new CByteImage(m_nImageWidth, m_nImageHeight, CByteImage::eRGB24);
556 CByteImage* pSmoothedImage = new CByteImage(m_nImageWidth, m_nImageHeight, CByteImage::eRGB24);
557
558 ImageProcessor::GaussianSmooth3x3(pInputImageRGB, pSmoothedImage);
559 ImageProcessor::CalculateHSVImage(pSmoothedImage, pHSVImage);
560
561 SegmentImage(pInputImageRGB, pHSVImage, pProbabilityImage);
562
563 delete pHSVImage;
564 delete pSmoothedImage;
565}
566
567void
568CGaussBackground::SegmentImageRGB(const CByteImage* pInputImageRGB, float* pProbabilityImage)
569{
570 CByteImage* pHSVImage = new CByteImage(m_nImageWidth, m_nImageHeight, CByteImage::eRGB24);
571 CByteImage* pSmoothedImage = new CByteImage(m_nImageWidth, m_nImageHeight, CByteImage::eRGB24);
572
573 ImageProcessor::GaussianSmooth3x3(pInputImageRGB, pSmoothedImage);
574 ImageProcessor::CalculateHSVImage(pSmoothedImage, pHSVImage);
575
576 SegmentImage(pInputImageRGB, pHSVImage, pProbabilityImage);
577
578 delete pHSVImage;
579 delete pSmoothedImage;
580}
581
582void
583CGaussBackground::SegmentImage(const CByteImage* pInputImageRGB,
584 const CByteImage* pInputImageHSV,
585 CByteImage* pProbabilityImage)
586{
587 if ((pInputImageHSV->width != m_nImageWidth) || (pInputImageHSV->height != m_nImageHeight))
588 {
589 ARMARX_WARNING_S << "CGaussBackground::SegmentImage: Image dimensions do not fit!";
590 return;
591 }
592
593 float* pProbabilities = new float[m_nImageWidth * m_nImageHeight];
594 SegmentImage(pInputImageRGB, pInputImageHSV, pProbabilities);
595
596 for (int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
597 {
598 pProbabilityImage->pixels[i] = (int)(255 * pProbabilities[i]);
599 }
600
601 delete[] pProbabilities;
602}
603
604void
605CGaussBackground::SegmentImage(const CByteImage* pInputImageRGB,
606 const CByteImage* pInputImageHSV,
607 float* pProbabilityImage)
608{
609 if ((pInputImageHSV->width != m_nImageWidth) || (pInputImageHSV->height != m_nImageHeight))
610 {
611 ARMARX_WARNING_S << "CGaussBackground::SegmentImage: Image dimensions do not fit!";
612 return;
613 }
614
615 const int nNumShifts = 21;
616 int nImageShiftValuesX[nNumShifts] = {-1, 1, -2, 0, 2, -3, -1, 1, 3, -2, 0,
617 2, -3, -1, 1, 3, -2, 0, 2, -1, 1};
618 int nImageShiftValuesY[nNumShifts] = {-3, -3, -2, -2, -2, -1, -1, -1, -1, 0, 0,
619 0, 1, 1, 1, 1, 2, 2, 2, 3, 3};
620 float fProbSums[nNumShifts] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
621 float* pProbabilityImages = new float[nNumShifts * m_nImageWidth * m_nImageHeight];
622
623 // set to 0
624 for (int i = 0; i < nNumShifts * m_nImageWidth * m_nImageHeight; i++)
625 {
626 pProbabilityImages[i] = 0;
627 }
628
629// calc background probability for every pixel
630#pragma omp parallel for schedule(static, 1)
631 for (int n = 0; n < nNumShifts; n++)
632 {
633 for (int i = 3; i < m_nImageHeight - 3; i++)
634 {
635 for (int j = 3; j < m_nImageWidth - 3; j++)
636 {
637 const int nIndex = i * m_nImageWidth + j;
638 const int nIndexSh =
639 (i + nImageShiftValuesY[n]) * m_nImageWidth + j + nImageShiftValuesX[n];
640
641 // calculate probability using HS-distribution
642 Vec2d vTemp1;
643
644 if (m_pPixelProbabilityDistributions[nIndexSh].bShifted)
645 {
646 vTemp1.x = (pInputImageHSV->pixels[3 * nIndex] + 128) %
647 256; // adapt pixel value if the mean is shifted
648 }
649 else
650 {
651 vTemp1.x = pInputImageHSV->pixels[3 * nIndex];
652 }
653
654 vTemp1.y = pInputImageHSV->pixels[3 * nIndex + 1];
655 const float fProbHSV = 1 - CalcProbOfPixel(nIndexSh, vTemp1);
656
657 // calculate probability using the RGB image
658 const Vec3d vRGBfromImage = {(float)pInputImageRGB->pixels[3 * nIndex],
659 (float)pInputImageRGB->pixels[3 * nIndex + 1],
660 (float)pInputImageRGB->pixels[3 * nIndex + 2]};
661 const Vec3d vRGBfromBackground = {
662 (float)m_pBackgroundRGB->pixels[3 * nIndexSh],
663 (float)m_pBackgroundRGB->pixels[3 * nIndexSh + 1],
664 (float)m_pBackgroundRGB->pixels[3 * nIndexSh + 2]};
665 const float fDistance = Math3d::Distance(vRGBfromImage, vRGBfromBackground);
666 const float fProbRGB = 1 - exp(-0.01f * fDistance);
667
668
669 const float fProb =
670 0.33f *
671 (fProbRGB +
672 2 * fProbHSV); // (fProbRGB*fProbHSV) / (fProbRGB*fProbHSV + (1-fProbRGB)*(1-fProbHSV) + 0.00001f);
673 pProbabilityImages[n * m_nImageWidth * m_nImageHeight + nIndex] = fProb;
674 fProbSums[n] += fProb;
675 }
676 }
677 }
678
679 float fMinProb = fProbSums[0];
680 int nBestIndex = 0;
681
682 for (int i = 1; i < nNumShifts; i++)
683 {
684 if (fProbSums[i] < fMinProb)
685 {
686 fMinProb = fProbSums[i];
687 nBestIndex = i;
688 }
689 }
690
691 ARMARX_VERBOSE_S << "Best background shift: (" << nImageShiftValuesX[nBestIndex] << ", "
692 << nImageShiftValuesY[nBestIndex] << ")";
693
694 for (int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
695 {
696 pProbabilityImage[i] = pProbabilityImages[nBestIndex * m_nImageWidth * m_nImageHeight + i];
697 }
698
699 delete[] pProbabilityImages;
700}
#define float
Definition 16_Level.h:22
double DetMat2d(const Mat2d m)
#define OLP_FOREGROUND_THRESHOLD
void SegmentImage(const CByteImage *pInputImageRGB, const CByteImage *pInputImageHSV, CByteImage *pProbabilityImage)
CGaussBackground(const int nWidth, const int nHeight)
void LearnBackground(CByteImage **pHSVImages, const int nNumImages)
void SegmentImageRGB(const CByteImage *pInputImageRGB, CByteImage *pProbabilityImage)
void GetBinaryForegroundImageRGB(const CByteImage *pInputImageRGB, CByteImage *pForegroundImage)
void BinarizeAndFillHoles(CByteImage *pProbabilityImage)
void LearnBackgroundRGB(CByteImage **pRGBImages, const int nNumImages)
#define ARMARX_VERBOSE_S
Definition Logging.h:207
#define ARMARX_WARNING_S
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:213