25 #include <Image/ImageProcessor.h>
40 m_nImageWidth = nWidth;
41 m_nImageHeight = nHeight;
43 m_pBackgroundRGB =
new CByteImage(nWidth, nHeight, CByteImage::eRGB24);
50 delete m_pPixelProbabilityDistributions;
51 delete m_pBackgroundRGB;
58 return m.r1 * m.r4 - m.r3 * m.r2;
65 CByteImage** pHSVImages =
new CByteImage*[nNumImages];
66 CByteImage* pSmoothedImage =
new CByteImage(m_nImageWidth, m_nImageHeight, CByteImage::eRGB24);
68 for (
int i = 0; i < nNumImages; i++)
70 pHSVImages[i] =
new CByteImage(m_nImageWidth, m_nImageHeight, CByteImage::eRGB24);
71 ImageProcessor::GaussianSmooth3x3(pRGBImages[i], pSmoothedImage);
72 ImageProcessor::CalculateHSVImage(pSmoothedImage, pHSVImages[i]);
77 ImageProcessor::CopyImage(pRGBImages[0], m_pBackgroundRGB);
79 for (
int i = 0; i < nNumImages; i++)
85 delete pSmoothedImage;
92 if ((pHSVImages[0]->width != m_nImageWidth) || (pHSVImages[0]->height != m_nImageHeight))
94 ARMARX_WARNING_S <<
"CGaussBackground::LearnBackground: Image dimensions do not fit!";
100 ARMARX_WARNING_S <<
"CGaussBackground::LearnBackground: Need at least one image!";
108 for (
int j = 0; j < m_nImageWidth * m_nImageHeight; j++)
110 Math2d::SetVec(pPPD[j].vMean, 0, 0);
116 Math2d::SetVec(pShPPD[j].vMean, 0, 0);
128 for (
int i = 0; i < nNumImages; i++)
131 for (
int j = 0; j < m_nImageWidth * m_nImageHeight; j++)
133 pPPD[j].
vMean.x += pHSVImages[i]->pixels[3 * j];
134 pPPD[j].
vMean.y += pHSVImages[i]->pixels[3 * j + 1];
136 pShPPD[j].
vMean.x += (pHSVImages[i]->pixels[3 * j] + 128) % 256;
137 pShPPD[j].
vMean.y += pHSVImages[i]->pixels[3 * j + 1];
141 for (
int j = 0; j < m_nImageWidth * m_nImageHeight; j++)
143 pPPD[j].
vMean.x /= nNumImages;
144 pPPD[j].
vMean.y /= nNumImages;
146 pShPPD[j].
vMean.x /= nNumImages;
147 pShPPD[j].
vMean.y /= nNumImages;
156 for (
int i = 0; i < nNumImages; i++)
159 for (
int j = 0; j < m_nImageWidth * m_nImageHeight; j++)
161 pPPD[j].
mCovariance.r1 += (pHSVImages[i]->pixels[3 * j] - pPPD[j].
vMean.x) * (pHSVImages[i]->pixels[3 * j] - pPPD[j].vMean.x);
162 pPPD[j].
mCovariance.r2 += (pHSVImages[i]->pixels[3 * j] - pPPD[j].
vMean.x) * (pHSVImages[i]->pixels[3 * j + 1] - pPPD[j].vMean.y);
163 pPPD[j].
mCovariance.r3 += (pHSVImages[i]->pixels[3 * j + 1] - pPPD[j].
vMean.y) * (pHSVImages[i]->pixels[3 * j] - pPPD[j].vMean.x);
164 pPPD[j].
mCovariance.r4 += (pHSVImages[i]->pixels[3 * j + 1] - pPPD[j].
vMean.y) * (pHSVImages[i]->pixels[3 * j + 1] - pPPD[j].vMean.y);
166 pShPPD[j].
mCovariance.r1 += (((pHSVImages[i]->pixels[3 * j] + 128) % 256) - pShPPD[j].
vMean.x) * (((pHSVImages[i]->pixels[3 * j] + 128) % 256) - pShPPD[j].vMean.x);
167 pShPPD[j].
mCovariance.r2 += (((pHSVImages[i]->pixels[3 * j] + 128) % 256) - pShPPD[j].
vMean.x) * (pHSVImages[i]->pixels[3 * j + 1] - pShPPD[j].vMean.y);
168 pShPPD[j].
mCovariance.r3 += (pHSVImages[i]->pixels[3 * j + 1] - pShPPD[j].
vMean.y) * (((pHSVImages[i]->pixels[3 * j] + 128) % 256) - pShPPD[j].vMean.x);
169 pShPPD[j].
mCovariance.r4 += (pHSVImages[i]->pixels[3 * j + 1] - pShPPD[j].
vMean.y) * (pHSVImages[i]->pixels[3 * j + 1] - pShPPD[j].vMean.y);
173 const float fFactor = 1.0f / (
float)(nNumImages - 1);
175 for (
int j = 0; j < m_nImageWidth * m_nImageHeight; j++)
213 Math2d::Invert(pPPD[j].mCovariance, pPPD[j].mCovariance);
220 for (
int j = 0; j < m_nImageWidth * m_nImageHeight; j++)
229 if (pPPD[j].vMean.x < 64 || pPPD[j].
vMean.x > 192)
231 pPPD[j].
vMean.x = ((int)pPPD[j].vMean.x + 128) % 256;
247 inline double CGaussBackground::CalcProbOfPixel(
const int nIndex,
const Vec2d vHS_Value)
250 Vec2d vTemp1, vTemp2;
253 Math2d::SubtractVecVec(vHS_Value, m_pPixelProbabilityDistributions[nIndex].vMean, vTemp1);
255 Math2d::MulMatVec(m_pPixelProbabilityDistributions[nIndex].mCovariance, vTemp1, vTemp2);
256 dTemp0 = Math2d::ScalarProduct(vTemp1, vTemp2);
258 return exp(-0.03 * (m_pPixelProbabilityDistributions[nIndex].fSatWeight * (vTemp1.y * vTemp1.y) * m_pPixelProbabilityDistributions[nIndex].mCovariance.r4
259 + (1 - m_pPixelProbabilityDistributions[nIndex].fSatWeight) * dTemp0));
271 for (
int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
278 CByteImage* pTempImage =
new CByteImage(m_nImageWidth, m_nImageHeight, CByteImage::eGrayScale);
279 ImageProcessor::Dilate(pProbabilityImage, pTempImage);
280 ImageProcessor::Erode(pTempImage, pProbabilityImage);
281 ImageProcessor::Erode(pProbabilityImage, pTempImage);
282 ImageProcessor::Erode(pTempImage, pProbabilityImage);
283 ImageProcessor::Erode(pProbabilityImage, pTempImage);
284 ImageProcessor::Dilate(pTempImage, pProbabilityImage);
285 ImageProcessor::Dilate(pProbabilityImage, pTempImage);
286 ImageProcessor::Dilate(pTempImage, pProbabilityImage);
287 ImageProcessor::Dilate(pProbabilityImage, pTempImage);
288 ImageProcessor::Dilate(pTempImage, pProbabilityImage);
292 for (
int i = 0; i < 1; i++)
294 FillHolesHorVertDiag(pProbabilityImage, pTempImage);
295 FillHolesHorVertDiag(pTempImage, pProbabilityImage);
300 for (
int i = 0; i < 2; i++)
302 FillHolesHorVert(pProbabilityImage, pTempImage);
303 FillHolesDiag(pTempImage, pProbabilityImage);
309 for (
int i = 0; i < 0; i++)
311 ImageProcessor::Dilate(pProbabilityImage, pTempImage);
312 ImageProcessor::Dilate(pTempImage, pProbabilityImage);
320 inline void CGaussBackground::FillHolesHorVert(
const CByteImage* pInputImage, CByteImage* pOutputImage,
const int nRadius)
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]*nPixelSumsInDirections[3] != 0)
373 pOutputImage->pixels[i] = 255;
381 inline void CGaussBackground::FillHolesDiag(
const CByteImage* pInputImage, CByteImage* pOutputImage,
const int nRadius)
383 for (
int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
385 pOutputImage->pixels[i] = pInputImage->pixels[i];
388 #pragma omp parallel for schedule (static, 100)
389 for (
int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
391 if (pOutputImage->pixels[i] == 0)
394 int nPixelSumsInDirections[4] = {0, 0, 0, 0};
397 for (
int j = 1; j <= nRadius; j++)
400 nIndex = i - j * m_nImageWidth - j;
404 nPixelSumsInDirections[0] += pInputImage->pixels[nIndex];
408 nIndex = i - j * m_nImageWidth + j;
412 nPixelSumsInDirections[1] += pInputImage->pixels[nIndex];
416 nIndex = i + j * m_nImageWidth - j;
418 if (nIndex < m_nImageWidth * m_nImageHeight)
420 nPixelSumsInDirections[2] += pInputImage->pixels[nIndex];
424 nIndex = i + j * m_nImageWidth + j;
426 if (nIndex < m_nImageWidth * m_nImageHeight)
428 nPixelSumsInDirections[3] += pInputImage->pixels[nIndex];
432 if (nPixelSumsInDirections[0]*nPixelSumsInDirections[1]*nPixelSumsInDirections[2]*nPixelSumsInDirections[3] != 0)
434 pOutputImage->pixels[i] = 255;
442 inline void CGaussBackground::FillHolesHorVertDiag(
const CByteImage* pInputImage, CByteImage* pOutputImage,
const int nRadius)
444 for (
int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
446 pOutputImage->pixels[i] = pInputImage->pixels[i];
449 #pragma omp parallel for schedule (static, 100)
450 for (
int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
452 if (pOutputImage->pixels[i] == 0)
455 int nPixelSumsInDirections[8] = {0, 0, 0, 0, 0, 0, 0, 0};
458 for (
int j = 1; j <= nRadius; j++)
465 nPixelSumsInDirections[0] += pInputImage->pixels[nIndex];
471 if (nIndex < m_nImageWidth * m_nImageHeight)
473 nPixelSumsInDirections[1] += pInputImage->pixels[nIndex];
477 nIndex = i - j * m_nImageWidth;
481 nPixelSumsInDirections[2] += pInputImage->pixels[nIndex];
485 nIndex = i + j * m_nImageWidth;
487 if (nIndex < m_nImageWidth * m_nImageHeight)
489 nPixelSumsInDirections[3] += pInputImage->pixels[nIndex];
493 nIndex = i - j * m_nImageWidth - j;
497 nPixelSumsInDirections[4] += pInputImage->pixels[nIndex];
501 nIndex = i - j * m_nImageWidth + j;
505 nPixelSumsInDirections[5] += pInputImage->pixels[nIndex];
509 nIndex = i + j * m_nImageWidth - j;
511 if (nIndex < m_nImageWidth * m_nImageHeight)
513 nPixelSumsInDirections[6] += pInputImage->pixels[nIndex];
517 nIndex = i + j * m_nImageWidth + j;
519 if (nIndex < m_nImageWidth * m_nImageHeight)
521 nPixelSumsInDirections[7] += pInputImage->pixels[nIndex];
525 if (nPixelSumsInDirections[0]*nPixelSumsInDirections[1]*nPixelSumsInDirections[2]*nPixelSumsInDirections[3]
526 *nPixelSumsInDirections[4]*nPixelSumsInDirections[5]*nPixelSumsInDirections[6]*nPixelSumsInDirections[7] != 0)
528 pOutputImage->pixels[i] = 255;
547 CByteImage* pHSVImage =
new CByteImage(m_nImageWidth, m_nImageHeight, CByteImage::eRGB24);
548 CByteImage* pSmoothedImage =
new CByteImage(m_nImageWidth, m_nImageHeight, CByteImage::eRGB24);
550 ImageProcessor::GaussianSmooth3x3(pInputImageRGB, pSmoothedImage);
551 ImageProcessor::CalculateHSVImage(pSmoothedImage, pHSVImage);
553 SegmentImage(pInputImageRGB, pHSVImage, pProbabilityImage);
556 delete pSmoothedImage;
563 CByteImage* pHSVImage =
new CByteImage(m_nImageWidth, m_nImageHeight, CByteImage::eRGB24);
564 CByteImage* pSmoothedImage =
new CByteImage(m_nImageWidth, m_nImageHeight, CByteImage::eRGB24);
566 ImageProcessor::GaussianSmooth3x3(pInputImageRGB, pSmoothedImage);
567 ImageProcessor::CalculateHSVImage(pSmoothedImage, pHSVImage);
569 SegmentImage(pInputImageRGB, pHSVImage, pProbabilityImage);
572 delete pSmoothedImage;
579 if ((pInputImageHSV->width != m_nImageWidth) || (pInputImageHSV->height != m_nImageHeight))
581 ARMARX_WARNING_S <<
"CGaussBackground::SegmentImage: Image dimensions do not fit!";
585 float* pProbabilities =
new float[m_nImageWidth * m_nImageHeight];
586 SegmentImage(pInputImageRGB, pInputImageHSV, pProbabilities);
588 for (
int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
590 pProbabilityImage->pixels[i] = (int)(255 * pProbabilities[i]);
593 delete[] pProbabilities;
599 if ((pInputImageHSV->width != m_nImageWidth) || (pInputImageHSV->height != m_nImageHeight))
601 ARMARX_WARNING_S <<
"CGaussBackground::SegmentImage: Image dimensions do not fit!";
605 const int nNumShifts = 21;
606 int nImageShiftValuesX[nNumShifts] = { -1, 1, -2, 0, 2, -3, -1, 1, 3, -2, 0, 2, -3, -1, 1, 3, -2, 0, 2, -1, 1};
607 int nImageShiftValuesY[nNumShifts] = { -3, -3, -2, -2, -2, -1, -1, -1, -1, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3};
608 float fProbSums[nNumShifts] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
609 float* pProbabilityImages =
new float[nNumShifts * m_nImageWidth * m_nImageHeight];
612 for (
int i = 0; i < nNumShifts * m_nImageWidth * m_nImageHeight; i++)
614 pProbabilityImages[i] = 0;
618 #pragma omp parallel for schedule(static, 1)
619 for (
int n = 0; n < nNumShifts; n++)
621 for (
int i = 3; i < m_nImageHeight - 3; i++)
623 for (
int j = 3; j < m_nImageWidth - 3; j++)
625 const int nIndex = i * m_nImageWidth + j;
626 const int nIndexSh = (i + nImageShiftValuesY[n]) * m_nImageWidth + j + nImageShiftValuesX[n];
631 if (m_pPixelProbabilityDistributions[nIndexSh].bShifted)
633 vTemp1.x = (pInputImageHSV->pixels[3 * nIndex] + 128) % 256;
637 vTemp1.x = pInputImageHSV->pixels[3 * nIndex];
640 vTemp1.y = pInputImageHSV->pixels[3 * nIndex + 1];
641 const float fProbHSV = 1 - CalcProbOfPixel(nIndexSh, vTemp1);
644 const Vec3d vRGBfromImage = {(
float)pInputImageRGB->pixels[3 * nIndex], (
float)pInputImageRGB->pixels[3 * nIndex + 1], (
float)pInputImageRGB->pixels[3 * nIndex + 2]};
645 const Vec3d vRGBfromBackground = {(
float)m_pBackgroundRGB->pixels[3 * nIndexSh], (
float)m_pBackgroundRGB->pixels[3 * nIndexSh + 1], (
float)m_pBackgroundRGB->pixels[3 * nIndexSh + 2]};
646 const float fDistance = Math3d::Distance(vRGBfromImage, vRGBfromBackground);
647 const float fProbRGB = 1 - exp(-0.01f * fDistance);
650 const float fProb = 0.33f * (fProbRGB + 2 * fProbHSV);
651 pProbabilityImages[n * m_nImageWidth * m_nImageHeight + nIndex] = fProb;
652 fProbSums[n] += fProb;
657 float fMinProb = fProbSums[0];
660 for (
int i = 1; i < nNumShifts; i++)
662 if (fProbSums[i] < fMinProb)
664 fMinProb = fProbSums[i];
669 ARMARX_VERBOSE_S <<
"Best background shift: (" << nImageShiftValuesX[nBestIndex] <<
", " << nImageShiftValuesY[nBestIndex] <<
")";
671 for (
int i = 0; i < m_nImageWidth * m_nImageHeight; i++)
673 pProbabilityImage[i] = pProbabilityImages[nBestIndex * m_nImageWidth * m_nImageHeight + i];
676 delete[] pProbabilityImages;