void SleepDetector::operator()( cv::Mat & src )
{
	cv::Mat gray;
	cv::cvtColor(src, gray, CV_BGR2GRAY);
	cv::equalizeHist(gray, gray);

	typedef std::vector<cv::Rect> Faces;

	Faces faces;
	m_faceCascade.detectMultiScale(gray, faces, 1.1, 3, CV_HAAR_SCALE_IMAGE|CV_HAAR_FIND_BIGGEST_OBJECT, cv::Size(30, 30));

	unsigned int subjectiveAlertness = 0; // start out with the lowest alertness.
#if defined(NDEBUG)
	if (!faces.empty())
	{
		subjectiveAlertness += 1;

		const cv::Mat && faceROI = gray(faces[0]);

		typedef std::vector<cv::Rect> Eyes;
		Eyes eyes;
		m_eyesCascade.detectMultiScale(faceROI, eyes, 1.1, 3, CV_HAAR_SCALE_IMAGE, cv::Size(30, 30));

		subjectiveAlertness += eyes.size() > 1 ? 1 : 0;
	}
#else
	std::for_each(
		faces.cbegin(),
		faces.cend(),
		[&](const Faces::value_type & face)
	{
		++subjectiveAlertness;

		cv::ellipse(
			src,
			cv::Point(face.x + face.width*0.5, face.y + face.height*0.5),
			cv::Size(face.width*0.5, face.height*0.5),
			0,
			0,
			360,
			cv::Scalar(0, 255, 127),
			4,
			8,
			0);

		const cv::Mat && faceROI = gray(face);

		typedef std::vector<cv::Rect> Eyes;

		Eyes eyes;
		m_eyesCascade.detectMultiScale(faceROI, eyes, 1.1, 3, CV_HAAR_SCALE_IMAGE, cv::Size(30, 30));

		subjectiveAlertness += eyes.size() > 1 ? 1 : 0;

		std::for_each(
			eyes.cbegin(),
			eyes.cend(),
			[&](const Eyes::value_type & eye)
		{
			cv::circle(
				src,
				cv::Point((face.x + eye.x + eye.width*0.5), (face.y + eye.y + eye.height*0.5)),
				cvRound((eye.width + eye.height) * 0.25),
				cv::Scalar(127, 0, 127),
				4,
				8,
				0);
		});
	});
#endif

	switch (subjectiveAlertness)
	{
	case 2:
		m_awareness->onStaring(src);
		break;

	case 1:
		m_awareness->onBlink(src);
		break;

	default:
		m_awareness->onNotLooking(src);
		break;
	}
}