Untitled
unknown
plain_text
a year ago
7.3 kB
19
Indexable
if (pFrameData == NULL) return -1;
#ifdef MOTIONDETECTION_LOG_PERFORMANCE
shared_ptr<ReportDuration>reportDuration(new ReportDuration("SigmaDelta:"));
#endif
ResetEvent(m_DestroyClassEvent);
DBG_NM_PIPE(
if (settled == 1 && (k_size != k_size_prev || (float)*(reinterpret_cast<int*>(&m_gaussianSigma)) != gauss_sigma_prev))
{
InitDiffusionKernel();
printKernel();
}
)
const int imageSize = m_sizeImage.cx * m_sizeImage.cy * 2; // YUV = 2 bytes / pixel
if (m_pSigmaDeltaStreamData == NULL)
{
m_pSigmaDeltaStreamData = (LPBYTE)malloc(imageSize);
}
LPBYTE pStreamData = m_pSigmaDeltaStreamData;
if (m_fpCvDllBlur)
{
(*m_fpCvDllBlur)(pFrameData, pStreamData, m_sizeImage);
}
else
{
memcpy(pStreamData, pFrameData, imageSize);
}
// Previously, for simplicity these SigmaDelta variables were 2 bytes per pixel for simplicity, but we only need 1 byte per pixel
// since we're working with grayscale images. So we'll use half the size for these arrays and save some memory.
//
if (m_pSigmaDeltaM.size() != imageSize / 2)
{
// start with the "background" copied from the current image. otherwise we startup with it looking like there is
// motion everywhere until the true background emerges from averaging.
//
m_pSigmaDeltaM.resize(imageSize / 2);
m_pSigmaDeltaV.resize(imageSize / 2);
m_pSigmaDeltaVCopyForNoiseMask.resize(imageSize / 2);
m_pSigmaDeltaVDiffused.resize(imageSize / 2);
m_pSigmaDeltaE.resize(imageSize / 2);
m_pSigmaDeltaTemp.resize(imageSize / 2);
m_pSigmaDeltaNoiseMask.resize(imageSize / 2);
for (int i = 0; i < imageSize; i += 2)
{
m_pSigmaDeltaM[i / 2] = pStreamData[i];
m_pSigmaDeltaV[i / 2] = 0;
m_pSigmaDeltaVDiffused[i / 2] = 0;
m_pSigmaDeltaVCopyForNoiseMask[i / 2] = 0;
m_pSigmaDeltaE[i / 2] = BACKGROUND_PIXEL;
}
InitDiffusionKernel();
//printKernel();
}
#ifdef DEBUG_NAMED_PIPE_VIDEO
vector<BYTE> diff(imageSize);
vector<BYTE> variance(imageSize);
vector<BYTE> varianceDiffused(imageSize);
#endif
if (m_frameCounter % 5 == 0)
{
DiffuseVMask(m_pSigmaDeltaV, m_pSigmaDeltaVDiffused, m_sizeImage.cy, m_sizeImage.cx);
}
// N is the variance diff to test for diff O exceeding V.
// Make larger makes so that minor fluctations in the background brightness are ignored.
//
static int N = 6;
// iterate over the Luma bytes skipping over the Chroma bytes....
//
int count_foreground = 0;
bool has_color = false;
for (INT i = 0; i < imageSize; i += 2)
{
// reduce the number of times we access the array by index by using a local variable
BYTE M = m_pSigmaDeltaM[i / 2];
int V = m_pSigmaDeltaV[i / 2];
int Vd = m_pSigmaDeltaVDiffused[i / 2];
// O is the abs diff of current and background, range YUV_LUMA_MIN to YUV_LUMA_MAX
const int O = abs(M - pStreamData[i]);
// check for color in the image, if so then it's not purely black&white
if (!has_color && pStreamData[i + 1] != YUV_CHROMA_ZERO)
has_color = true;
// V is the dispersion background
if (V < N * O)
V++;
else if (V > N * O)
V--;
// update background M incrementally.
if (M < pStreamData[i])
M++;
else if (M > pStreamData[i])
M--;
// finally, E is the estimated motion. Although we can simply use 0/1 values for motion detect,
// I am using YUV values so that rendering the intermediate stages for visualization works well.
//
bool isForeground = O > Vd && O > 8;
count_foreground += isForeground ? 1 : 0;
m_pSigmaDeltaV[i / 2] = V;
m_pSigmaDeltaM[i / 2] = M;
m_pSigmaDeltaE[i / 2] = isForeground ? FOREGROUND_PIXEL : BACKGROUND_PIXEL;
#ifdef DEBUG_NAMED_PIPE_VIDEO
diff[i] = O + BACKGROUND_PIXEL;
diff[i + 1] = YUV_CHROMA_ZERO;
variance[i] = V;
variance[i + 1] = YUV_CHROMA_ZERO;
varianceDiffused[i] = Vd;
varianceDiffused[i + 1] = YUV_CHROMA_ZERO;
#endif
}
if (frameReceived)
*frameReceived = true;
if (m_bNoiseMaskGenEnabled)
SampleVMask();
ErodeImageMask(m_pSigmaDeltaE, m_sizeImage, BACKGROUND_PIXEL, m_pSigmaDeltaTemp);
DilateImageMask(m_pSigmaDeltaTemp, m_sizeImage, FOREGROUND_PIXEL, m_pSigmaDeltaE);
// If there is any color, then camera is not in night mode
bool nightMode = !has_color;
bool day_to_night_transition = nightMode && !m_bNightVisionMode;
m_bNightVisionMode = nightMode;
// if more than %large% of the image is foreground, then the background is not stable.
bool invalid_background = count_foreground > 0.90 * imageSize / 2;
// if the background is invalid or we are transitioning from day to night, then reset the background.
if (invalid_background || day_to_night_transition)
{
// reset the background to the current image, declare no motion
for (int i = 0; i < imageSize; i += 2)
{
m_pSigmaDeltaM[i / 2] = pStreamData[i];
m_pSigmaDeltaE[i / 2] = BACKGROUND_PIXEL;
m_pSigmaDeltaV[i / 2] = 0;
}
}
#ifdef DEBUG_NAMED_PIPE_VIDEO
if (m_nCameraID == camid)
{
prevDataSender.SendData(&pStreamData[0], imageSize);
//if(m_nCameraID == 0xff0003)
diffDataSender.SendData(diff);
varianceDataSender.SendData(variance);
vector<BYTE> E(imageSize);
for (int i = 0; i < imageSize; i += 2)
{
E[i] = m_pSigmaDeltaE[i / 2];
E[i + 1] = YUV_CHROMA_ZERO;
}
finalDataSender.SendData(E);
}
#endif
// Count up the final results YUV data on a per-motion-rectangle basis into m_apdwCompareResult
//
for (UINT i = 0; i < m_apAreaRect.size(); i++)
{
INT w = m_apAreaRect[i].right - m_apAreaRect[i].left;
INT h = m_apAreaRect[i].bottom - m_apAreaRect[i].top;
if ((0 < w) && (0 < h) && m_atMDInfo.auSensitive[i] != 255) // if valid rect and not masked out..
{
double result = CompareBinaryMask(m_pSigmaDeltaE, m_sizeImage, &m_apAreaRect[i]);
#if 0
if (result > 0 && m_nCameraType == 99 /*360 cameras*/ && max(m_sizeImage.cx, m_sizeImage.cy) >= 640)
{
// Only going to perform this boost on hi-res 360 cameras, on the assumption that they have a hi-res primary stream.
//
// Radius of the image. Note the 360 image is a circle fitted into a rect, so the diameter is just the smaller
// of the full image width or height.
//
const double max_r = min(m_sizeImage.cx, m_sizeImage.cy) / 2;
// center of the motion rectangle relative to the image center
int x = m_apAreaRect[i].left + (m_apAreaRect[i].right - m_apAreaRect[i].left) / 2 - m_sizeImage.cx / 2;
int y = m_apAreaRect[i].top + (m_apAreaRect[i].bottom - m_apAreaRect[i].top) / 2 - m_sizeImage.cy / 2;
// estimated radius of the motion rectangle center from the image center
double r = sqrt((double)(x * x + y * y));
// add compensation for the outer areas, since for a 360 camera the rim is highly compressed.
// using N^(2x) boosts exponentially, increases more rapidly as you get closer to the edge.
// N^(3x) is even more aggressive.
//
if (r / max_r > 0.5)
{
double boost = pow((double)2.0, (double)(3.0 * r / max_r));
result *= boost;
}
}
#endif
m_apdwCompareResult[i] = result;
}
else
{
m_apdwCompareResult[i] = 0;
}
}
//DilateCompareResult();
SetEvent(m_DestroyClassEvent);
return 0;
Editor is loading...
Leave a Comment