// CvView.cpp : implementation file
//

#include "stdafx.h"
#include "Open_GL_CV.h"
#include "MainFrm.h"
#include "Open_GL_CVDoc.h"
#include "CvView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define RANGE 30
#define YCBCR_SKINVALUE 140
#define YIQ_SKINVALUE 139

static CvMemStorage* storage = 0;
static CvHaarClassifierCascade* cascade = 0;

void detect_and_draw( IplImage* image );

/////////////////////////////////////////////////////////////////////////////
// CCvView

IMPLEMENT_DYNCREATE(CCvView, CFormView)

void callbackProc(IplImage* CVCamFirst, IplImage* CVCamSecond);
void RGBToHSI(BYTE R, BYTE G, BYTE B, float* H, float* S, float* I);
void RGBToYCbCr(BYTE R, BYTE G, BYTE B, float* Y, float* Cb, float* Cr);
void RGBToYIQ(BYTE R, BYTE G, BYTE B, float* Y, float* I, float* Q);

CCvView::CCvView()
	: CFormView(CCvView::IDD)
{
	//{{AFX_DATA_INIT(CCvView)
	//}}AFX_DATA_INIT
}

CCvView::~CCvView()
{
	cvcamStop();
	cvcamExit();
}

void CCvView::DoDataExchange(CDataExchange* pDX)
{
	CFormView::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CCvView)
	DDX_Control(pDX, IDC_CVCAM_2, m_ctrlCVCam2);
	DDX_Control(pDX, IDC_CVCAM_1, m_ctrlCvCam1);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CCvView, CFormView)
	//{{AFX_MSG_MAP(CCvView)
		// NOTE - the ClassWizard will add and remove mapping macros here.
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CCvView diagnostics

#ifdef _DEBUG
void CCvView::AssertValid() const
{
	CFormView::AssertValid();
}

void CCvView::Dump(CDumpContext& dc) const
{
	CFormView::Dump(dc);
}
COpen_GL_CVDoc* CCvView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(COpen_GL_CVDoc)));
	return (COpen_GL_CVDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CCvView message handlers

void CCvView::OnDraw(CDC* pDC) 
{
	// TODO: Add your specialized code here and/or call the base class
}

void CCvView::OnInitialUpdate() 
{
	CFormView::OnInitialUpdate();
	
	// TODO: Add your specialized code here and/or call the base class
	int* out;	
	int Width = 320;
	int Height = 240;
	int nselected;
		
	nselected = cvcamSelectCamera(&out);
	cvcamSetProperty(out[0], CVCAM_PROP_ENABLE, &nselected);
	cvcamSetProperty(out[1], CVCAM_PROP_ENABLE, &nselected);
	
	cvcamSetProperty(out[0], CVCAM_PROP_WINDOW, &(m_ctrlCvCam1.m_hWnd));
	cvcamSetProperty(out[0], CVCAM_RNDWIDTH, &Width);
	cvcamSetProperty(out[0], CVCAM_RNDHEIGHT, &Height);
	

	if (nselected == 2)
	{
		cvcamSetProperty(out[1], CVCAM_PROP_WINDOW, &(m_ctrlCVCam2.m_hWnd));
		cvcamSetProperty(out[1], CVCAM_RNDWIDTH, &Width);
		cvcamSetProperty(out[1], CVCAM_RNDHEIGHT, &Height);
	}

	cvcamSetProperty(NULL, CVCAM_STEREO_CALLBACK, callbackProc);

	cvcamInit();
	cvcamStart();
}

//////////////////////////////////////////////////////////////////////////
//																		//
//																		//
//////////////////////////////////////////////////////////////////////////
																					
void callbackProc(IplImage* CVCamFirst, IplImage* CVCamSecond)
{
	COpen_GL_CVApp* pApp = (COpen_GL_CVApp*)AfxGetApp();
	CMainFrame* pFrame = (CMainFrame*)pApp->GetMainWnd();

	BYTE R, G, B, RR, GG, BB;
	float Y_CVCamFirst, Cb_CVCamFirst, Cr_CVCamFirst; 
	float YY_CVCamFirst, I_CVCamFirst, Q_CVCamFirst;
	float Y_CVCamSecond, Cb_CVCamSecond, Cr_CVCamSecond;
	float YY_CVCamSecond, I_CVCamSecond, Q_CVCamSecond;

	BYTE* pYCbCrBuff_CVCamFirst = new BYTE[CVCamFirst->imageSize];
	BYTE* pYIQBuff_CVCamFirst = new BYTE[CVCamFirst->imageSize];
	BYTE* pYCbCrBuff_CVCamSecond = new BYTE[CVCamSecond->imageSize];
	BYTE* pYIQBuff_CVCamSecond = new BYTE[CVCamSecond->imageSize];
/*	
	for(int i=0; i<CVCamFirst->height*CVCamFirst->widthStep; i+=CVCamFirst->nChannels)
	{
		B = CVCamFirst->imageData[i+0];
		G = CVCamFirst->imageData[i+1];
		R = CVCamFirst->imageData[i+2];
		
		BB = CVCamSecond->imageData[i+0];
		GG = CVCamSecond->imageData[i+1];
		RR = CVCamSecond->imageData[i+2];

		//A color model conversion of CVCamFirst
		pFrame->m_pImage->RGBToYCbCr(R, G, B, &Y_CVCamFirst, &Cb_CVCamFirst, &Cr_CVCamFirst);
		pFrame->m_pImage->RGBToYIQ(R, G, B, &YY_CVCamFirst, &I_CVCamFirst, &Q_CVCamFirst);

		///A color model conversion of CVCamSecond
		pFrame->m_pImage->RGBToYCbCr(RR, GG, BB, &Y_CVCamSecond, &Cb_CVCamSecond, &Cr_CVCamSecond);
		pFrame->m_pImage->RGBToYIQ(RR, GG, BB, &YY_CVCamSecond, &I_CVCamSecond, &Q_CVCamSecond);
		
		//Skin Color search in CVCamFirst
		if(Cr_CVCamFirst>YCBCR_SKINVALUE && Cr_CVCamFirst<YCBCR_SKINVALUE+RANGE)
		{
			pYCbCrBuff_CVCamFirst[i+0] = (BYTE)255;
			pYCbCrBuff_CVCamFirst[i+1] = (BYTE)255;
			pYCbCrBuff_CVCamFirst[i+2] = (BYTE)255;
		}
		else
		{
			pYCbCrBuff_CVCamFirst[i+0] = 0;
			pYCbCrBuff_CVCamFirst[i+1] = 0;
			pYCbCrBuff_CVCamFirst[i+2] = 0;
		}
		
		if(I_CVCamFirst>YIQ_SKINVALUE && I_CVCamFirst<YIQ_SKINVALUE+RANGE)
		{
			pYIQBuff_CVCamFirst[i+0] = (BYTE)255;
			pYIQBuff_CVCamFirst[i+1] = (BYTE)255;
			pYIQBuff_CVCamFirst[i+2] = (BYTE)255;
		}
		else
		{
			pYIQBuff_CVCamFirst[i+0] = 0;
			pYIQBuff_CVCamFirst[i+1] = 0;
			pYIQBuff_CVCamFirst[i+2] = 0;
		}

		//Skin Color search in CVCamSecond
		if(Cr_CVCamSecond>130 && Cr_CVCamSecond<130+RANGE)
		{
			pYCbCrBuff_CVCamSecond[i+0] = (BYTE)255;
			pYCbCrBuff_CVCamSecond[i+1] = (BYTE)255;
			pYCbCrBuff_CVCamSecond[i+2] = (BYTE)255;
		}
		else
		{
			pYCbCrBuff_CVCamSecond[i+0] = 0;
			pYCbCrBuff_CVCamSecond[i+1] = 0;
			pYCbCrBuff_CVCamSecond[i+2] = 0;
		}
		
		if(I_CVCamSecond>130 && I_CVCamSecond<130+RANGE)
		{
			pYIQBuff_CVCamSecond[i+0] = (BYTE)255;
			pYIQBuff_CVCamSecond[i+1] = (BYTE)255;
			pYIQBuff_CVCamSecond[i+2] = (BYTE)255;
		}
		else
		{
			pYIQBuff_CVCamSecond[i+0] = 0;
			pYIQBuff_CVCamSecond[i+1] = 0;
			pYIQBuff_CVCamSecond[i+2] = 0;
		}
		
		//multiply logical of YIQBuff and YCbCrBuff of CVCamFirst
		CVCamFirst->imageData[i+0] = (pYIQBuff_CVCamFirst[i+0] & pYCbCrBuff_CVCamFirst[i+0]); // | pYCbCrBuff[i+0];
		CVCamFirst->imageData[i+1] = (pYIQBuff_CVCamFirst[i+1] & pYCbCrBuff_CVCamFirst[i+1]); // | pYCbCrBuff[i+1];
		CVCamFirst->imageData[i+2] = (pYIQBuff_CVCamFirst[i+2] & pYCbCrBuff_CVCamFirst[i+2]); // | pYCbCrBuff[i+2];
		
		//multiply logical of YIQBuff and YCbCrBuff of CVCamSecond
		CVCamSecond->imageData[i+0] = (pYIQBuff_CVCamSecond[i+0] & pYCbCrBuff_CVCamSecond[i+0]); // | pYCbCrBuff[i+0];
		CVCamSecond->imageData[i+1] = (pYIQBuff_CVCamSecond[i+1] & pYCbCrBuff_CVCamSecond[i+1]); // | pYCbCrBuff[i+1];
		CVCamSecond->imageData[i+2] = (pYIQBuff_CVCamSecond[i+2] & pYCbCrBuff_CVCamSecond[i+2]); // | pYCbCrBuff[i+2];
	}
*/
	cascade = (CvHaarClassifierCascade*)cvLoad("haarcascade_frontalface_default.xml");
	storage = cvCreateMemStorage(0);
	detect_and_draw( CVCamFirst );

	delete [] pYCbCrBuff_CVCamFirst;
	delete [] pYIQBuff_CVCamFirst;
	delete [] pYCbCrBuff_CVCamSecond;
	delete [] pYIQBuff_CVCamSecond;
}

void detect_and_draw( IplImage* img )
{
    static CvScalar colors[] = 
    {
        {{0,0,255}},
        {{0,128,255}},
        {{0,255,255}},
        {{0,255,0}},
        {{255,128,0}},
        {{255,255,0}},
        {{255,0,0}},
        {{255,0,255}}
    };

    double scale = 1.3;
    IplImage* gray = cvCreateImage( cvSize(img->width,img->height), 8, 1 );
    IplImage* small_img = cvCreateImage( cvSize( cvRound (img->width/scale),
                         cvRound (img->height/scale)),
                     8, 1 );
    int i;

    cvCvtColor( img, gray, CV_BGR2GRAY );
    cvResize( gray, small_img, CV_INTER_LINEAR );
    cvEqualizeHist( small_img, small_img );
    cvClearMemStorage( storage );

    if( cascade )
    {
        double t = (double)cvGetTickCount();
        CvSeq* faces = cvHaarDetectObjects( small_img, cascade, storage,
                                            1.1, 2, 0/*CV_HAAR_DO_CANNY_PRUNING*/,
                                            cvSize(30, 30) );
        t = (double)cvGetTickCount() - t;
        printf( "detection time = %gms\n", t/((double)cvGetTickFrequency()*1000.) );
        for( i = 0; i < (faces ? faces->total : 0); i++ )
        {
            CvRect* r = (CvRect*)cvGetSeqElem( faces, i );
            CvPoint center;
            int radius;
            center.x = cvRound((r->x + r->width*0.5)*scale);
            center.y = cvRound((r->y + r->height*0.5)*scale);
            radius = cvRound((r->width + r->height)*0.25*scale);
            cvCircle( img, center, radius, colors[i%8], 3, 8, 0 );
        }
    }

    cvShowImage( "result", img );
    cvReleaseImage( &gray );
    cvReleaseImage( &small_img );
}