Untitled

 avatar
unknown
plain_text
10 months ago
7.3 kB
17
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