30 #include <Image/ImageProcessor.h>
35 m_nImageWidth = nWidth;
36 m_nImageHeight = nHeight;
38 m_pBackgroundRGB =
new CByteImage(nWidth, nHeight, CByteImage::eRGB24);
43 delete m_pPixelProbabilityDistributions;
44 delete m_pBackgroundRGB;
50 return m.r1 * m.r4 - m.r3 * m.r2;
56 CByteImage** pHSVImages =
new CByteImage*[nNumImages];
57 CByteImage* pSmoothedImage =
new CByteImage(m_nImageWidth, m_nImageHeight, CByteImage::eRGB24);
59 for (
int i = 0; i < nNumImages; i++)
61 pHSVImages[i] =
new CByteImage(m_nImageWidth, m_nImageHeight, CByteImage::eRGB24);
62 ImageProcessor::GaussianSmooth3x3(pRGBImages[i], pSmoothedImage);
63 ImageProcessor::CalculateHSVImage(pSmoothedImage, pHSVImages[i]);
68 ImageProcessor::CopyImage(pRGBImages[0], m_pBackgroundRGB);
70 for (
int i = 0; i < nNumImages; i++)
76 delete pSmoothedImage;
82 if ((pHSVImages[0]->width != m_nImageWidth) || (pHSVImages[0]->height != m_nImageHeight))
84 ARMARX_WARNING_S <<
"CGaussBackground::LearnBackground: Image dimensions do not fit!";
90 ARMARX_WARNING_S <<
"CGaussBackground::LearnBackground: Need at least one image!";
99 for (
int j = 0; j < m_nImageWidth * m_nImageHeight; j++)
101 Math2d::SetVec(pPPD[j].vMean, 0, 0);
107 Math2d::SetVec(pShPPD[j].vMean, 0, 0);
117 for (
int i = 0; i < nNumImages; i++)
120 for (
int j = 0; j < m_nImageWidth * m_nImageHeight; j++)
122 pPPD[j].
vMean.x += pHSVImages[i]->pixels[3 * j];
123 pPPD[j].
vMean.y += pHSVImages[i]->pixels[3 * j + 1];
125 pShPPD[j].
vMean.x += (pHSVImages[i]->pixels[3 * j] + 128) % 256;
126 pShPPD[j].
vMean.y += pHSVImages[i]->pixels[3 * j + 1];
130 for (
int j = 0; j < m_nImageWidth * m_nImageHeight; j++)
132 pPPD[j].
vMean.x /= nNumImages;
133 pPPD[j].
vMean.y /= nNumImages;
135 pShPPD[j].
vMean.x /= nNumImages;
136 pShPPD[j].
vMean.y /= nNumImages;
144 for (
int i = 0; i < nNumImages; i++)
147 for (
int j = 0; j < m_nImageWidth * m_nImageHeight; j++)
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);
159 (((pHSVImages[i]->pixels[3 * j] + 128) % 256) - pShPPD[j].
vMean.x) *
160 (((pHSVImages[i]->pixels[3 * j] + 128) % 256) - pShPPD[j].vMean.x);
162 (((pHSVImages[i]->pixels[3 * j] + 128) % 256) - pShPPD[j].
vMean.x) *
163 (pHSVImages[i]->pixels[3 * j + 1] - pShPPD[j].vMean.y);
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);
172 const float fFactor = 1.0f / (
float)(nNumImages - 1);
174 for (
int j = 0; j < m_nImageWidth * m_nImageHeight; j++)
212 Math2d::Invert(pPPD[j].mCovariance, pPPD[j].mCovariance);
219 for (
int j = 0; j < m_nImageWidth * m_nImageHeight; j++)
228 if (pPPD[j].vMean.x < 64 || pPPD[j].
vMean.x > 192)
230 pPPD[j].
vMean.x = ((int)pPPD[j].vMean.x + 128) % 256;
244 CGaussBackground::CalcProbOfPixel(
const int nIndex,
const Vec2d vHS_Value)
247 Vec2d vTemp1, vTemp2;
250 Math2d::SubtractVecVec(vHS_Value, m_pPixelProbabilityDistributions[nIndex].vMean, vTemp1);
252 Math2d::MulMatVec(m_pPixelProbabilityDistributions[nIndex].mCovariance, vTemp1, vTemp2);
253 dTemp0 = Math2d::ScalarProduct(vTemp1, vTemp2);
256 (m_pPixelProbabilityDistributions[nIndex].fSatWeight * (vTemp1.y * vTemp1.y) *
257 m_pPixelProbabilityDistributions[nIndex].mCovariance.r4 +
258 (1 - m_pPixelProbabilityDistributions[nIndex].fSatWeight) * dTemp0));
269 for (
int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
271 pProbabilityImage->pixels[i] =
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);
291 for (
int i = 0; i < 1; i++)
293 FillHolesHorVertDiag(pProbabilityImage, pTempImage);
294 FillHolesHorVertDiag(pTempImage, pProbabilityImage);
299 for (
int i = 0; i < 2; i++)
301 FillHolesHorVert(pProbabilityImage, pTempImage);
302 FillHolesDiag(pTempImage, pProbabilityImage);
308 for (
int i = 0; i < 0; i++)
310 ImageProcessor::Dilate(pProbabilityImage, pTempImage);
311 ImageProcessor::Dilate(pTempImage, pProbabilityImage);
318 CGaussBackground::FillHolesHorVert(
const CByteImage* pInputImage,
319 CByteImage* pOutputImage,
322 for (
int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
324 pOutputImage->pixels[i] = pInputImage->pixels[i];
327 #pragma omp parallel for schedule(static, 100)
328 for (
int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
330 if (pOutputImage->pixels[i] == 0)
333 int nPixelSumsInDirections[4] = {0, 0, 0, 0};
336 for (
int j = 1; j <= nRadius; j++)
343 nPixelSumsInDirections[0] += pInputImage->pixels[nIndex];
349 if (nIndex < m_nImageWidth * m_nImageHeight)
351 nPixelSumsInDirections[1] += pInputImage->pixels[nIndex];
355 nIndex = i - j * m_nImageWidth;
359 nPixelSumsInDirections[2] += pInputImage->pixels[nIndex];
363 nIndex = i + j * m_nImageWidth;
365 if (nIndex < m_nImageWidth * m_nImageHeight)
367 nPixelSumsInDirections[3] += pInputImage->pixels[nIndex];
371 if (nPixelSumsInDirections[0] * nPixelSumsInDirections[1] * nPixelSumsInDirections[2] *
372 nPixelSumsInDirections[3] !=
375 pOutputImage->pixels[i] = 255;
382 CGaussBackground::FillHolesDiag(
const CByteImage* pInputImage,
383 CByteImage* pOutputImage,
386 for (
int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
388 pOutputImage->pixels[i] = pInputImage->pixels[i];
391 #pragma omp parallel for schedule(static, 100)
392 for (
int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
394 if (pOutputImage->pixels[i] == 0)
397 int nPixelSumsInDirections[4] = {0, 0, 0, 0};
400 for (
int j = 1; j <= nRadius; j++)
403 nIndex = i - j * m_nImageWidth - j;
407 nPixelSumsInDirections[0] += pInputImage->pixels[nIndex];
411 nIndex = i - j * m_nImageWidth + j;
415 nPixelSumsInDirections[1] += pInputImage->pixels[nIndex];
419 nIndex = i + j * m_nImageWidth - j;
421 if (nIndex < m_nImageWidth * m_nImageHeight)
423 nPixelSumsInDirections[2] += pInputImage->pixels[nIndex];
427 nIndex = i + j * m_nImageWidth + j;
429 if (nIndex < m_nImageWidth * m_nImageHeight)
431 nPixelSumsInDirections[3] += pInputImage->pixels[nIndex];
435 if (nPixelSumsInDirections[0] * nPixelSumsInDirections[1] * nPixelSumsInDirections[2] *
436 nPixelSumsInDirections[3] !=
439 pOutputImage->pixels[i] = 255;
446 CGaussBackground::FillHolesHorVertDiag(
const CByteImage* pInputImage,
447 CByteImage* pOutputImage,
450 for (
int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
452 pOutputImage->pixels[i] = pInputImage->pixels[i];
455 #pragma omp parallel for schedule(static, 100)
456 for (
int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
458 if (pOutputImage->pixels[i] == 0)
461 int nPixelSumsInDirections[8] = {0, 0, 0, 0, 0, 0, 0, 0};
464 for (
int j = 1; j <= nRadius; j++)
471 nPixelSumsInDirections[0] += pInputImage->pixels[nIndex];
477 if (nIndex < m_nImageWidth * m_nImageHeight)
479 nPixelSumsInDirections[1] += pInputImage->pixels[nIndex];
483 nIndex = i - j * m_nImageWidth;
487 nPixelSumsInDirections[2] += pInputImage->pixels[nIndex];
491 nIndex = i + j * m_nImageWidth;
493 if (nIndex < m_nImageWidth * m_nImageHeight)
495 nPixelSumsInDirections[3] += pInputImage->pixels[nIndex];
499 nIndex = i - j * m_nImageWidth - j;
503 nPixelSumsInDirections[4] += pInputImage->pixels[nIndex];
507 nIndex = i - j * m_nImageWidth + j;
511 nPixelSumsInDirections[5] += pInputImage->pixels[nIndex];
515 nIndex = i + j * m_nImageWidth - j;
517 if (nIndex < m_nImageWidth * m_nImageHeight)
519 nPixelSumsInDirections[6] += pInputImage->pixels[nIndex];
523 nIndex = i + j * m_nImageWidth + j;
525 if (nIndex < m_nImageWidth * m_nImageHeight)
527 nPixelSumsInDirections[7] += pInputImage->pixels[nIndex];
531 if (nPixelSumsInDirections[0] * nPixelSumsInDirections[1] * nPixelSumsInDirections[2] *
532 nPixelSumsInDirections[3] * nPixelSumsInDirections[4] *
533 nPixelSumsInDirections[5] * nPixelSumsInDirections[6] *
534 nPixelSumsInDirections[7] !=
537 pOutputImage->pixels[i] = 255;
545 CByteImage* pForegroundImage)
555 CByteImage* pHSVImage =
new CByteImage(m_nImageWidth, m_nImageHeight, CByteImage::eRGB24);
556 CByteImage* pSmoothedImage =
new CByteImage(m_nImageWidth, m_nImageHeight, CByteImage::eRGB24);
558 ImageProcessor::GaussianSmooth3x3(pInputImageRGB, pSmoothedImage);
559 ImageProcessor::CalculateHSVImage(pSmoothedImage, pHSVImage);
561 SegmentImage(pInputImageRGB, pHSVImage, pProbabilityImage);
564 delete pSmoothedImage;
570 CByteImage* pHSVImage =
new CByteImage(m_nImageWidth, m_nImageHeight, CByteImage::eRGB24);
571 CByteImage* pSmoothedImage =
new CByteImage(m_nImageWidth, m_nImageHeight, CByteImage::eRGB24);
573 ImageProcessor::GaussianSmooth3x3(pInputImageRGB, pSmoothedImage);
574 ImageProcessor::CalculateHSVImage(pSmoothedImage, pHSVImage);
576 SegmentImage(pInputImageRGB, pHSVImage, pProbabilityImage);
579 delete pSmoothedImage;
584 const CByteImage* pInputImageHSV,
585 CByteImage* pProbabilityImage)
587 if ((pInputImageHSV->width != m_nImageWidth) || (pInputImageHSV->height != m_nImageHeight))
589 ARMARX_WARNING_S <<
"CGaussBackground::SegmentImage: Image dimensions do not fit!";
593 float* pProbabilities =
new float[m_nImageWidth * m_nImageHeight];
594 SegmentImage(pInputImageRGB, pInputImageHSV, pProbabilities);
596 for (
int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
598 pProbabilityImage->pixels[i] = (int)(255 * pProbabilities[i]);
601 delete[] pProbabilities;
606 const CByteImage* pInputImageHSV,
607 float* pProbabilityImage)
609 if ((pInputImageHSV->width != m_nImageWidth) || (pInputImageHSV->height != m_nImageHeight))
611 ARMARX_WARNING_S <<
"CGaussBackground::SegmentImage: Image dimensions do not fit!";
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];
624 for (
int i = 0; i < nNumShifts * m_nImageWidth * m_nImageHeight; i++)
626 pProbabilityImages[i] = 0;
630 #pragma omp parallel for schedule(static, 1)
631 for (
int n = 0; n < nNumShifts; n++)
633 for (
int i = 3; i < m_nImageHeight - 3; i++)
635 for (
int j = 3; j < m_nImageWidth - 3; j++)
637 const int nIndex = i * m_nImageWidth + j;
639 (i + nImageShiftValuesY[n]) * m_nImageWidth + j + nImageShiftValuesX[n];
644 if (m_pPixelProbabilityDistributions[nIndexSh].bShifted)
646 vTemp1.x = (pInputImageHSV->pixels[3 * nIndex] + 128) %
651 vTemp1.x = pInputImageHSV->pixels[3 * nIndex];
654 vTemp1.y = pInputImageHSV->pixels[3 * nIndex + 1];
655 const float fProbHSV = 1 - CalcProbOfPixel(nIndexSh, vTemp1);
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);
673 pProbabilityImages[n * m_nImageWidth * m_nImageHeight + nIndex] = fProb;
674 fProbSums[n] += fProb;
679 float fMinProb = fProbSums[0];
682 for (
int i = 1; i < nNumShifts; i++)
684 if (fProbSums[i] < fMinProb)
686 fMinProb = fProbSums[i];
691 ARMARX_VERBOSE_S <<
"Best background shift: (" << nImageShiftValuesX[nBestIndex] <<
", "
692 << nImageShiftValuesY[nBestIndex] <<
")";
694 for (
int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
696 pProbabilityImage[i] = pProbabilityImages[nBestIndex * m_nImageWidth * m_nImageHeight + i];
699 delete[] pProbabilityImages;