16acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn/*
26acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennOpenCV for Android NDK
36acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennCopyright (c) 2006-2009 SIProp Project http://www.siprop.org/
46acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
56acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennThis software is provided 'as-is', without any express or implied warranty.
66acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennIn no event will the authors be held liable for any damages arising from the use of this software.
76acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennPermission is granted to anyone to use this software for any purpose,
86acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennincluding commercial applications, and to alter it and redistribute it freely,
96acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennsubject to the following restrictions:
106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn3. This notice may not be removed or altered from any source distribution.
146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn*/
156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include "cvjni.h"
166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include <time.h>
176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define THRESHOLD	10
206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define THRESHOLD_MAX_VALUE	255
216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define CONTOUR_MAX_LEVEL	1
236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define LINE_THICKNESS	2
246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define LINE_TYPE	8
256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define HAAR_SCALE (1.4)
276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define IMAGE_SCALE (2)
286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define MIN_NEIGHBORS (2)
296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define HAAR_FLAGS_SINGLE_FACE (0 | CV_HAAR_FIND_BIGGEST_OBJECT | CV_HAAR_DO_ROUGH_SEARCH)
306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define HAAR_FLAGS_ALL_FACES (0)
316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Other options we dropped out:
326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// CV_HAAR_DO_CANNY_PRUNING | CV_HAAR_SCALE_IMAGE
336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define MIN_SIZE_WIDTH (20)
346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define MIN_SIZE_HEIGHT (20)
356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define PAD_FACE_SIZE (10)
366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define PAD_FACE_AREA (40)
376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#define PAD_FACE_AREA_2 (PAD_FACE_AREA * 2)
386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Initialize a socket capture to grab images from a socket connection.
406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNIEXPORT
416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennjboolean
426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNICALL
436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJava_org_siprop_opencv_OpenCV_createSocketCapture(JNIEnv* env,
446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn												  jobject thiz,
456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn												  jstring address_str,
466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn												  jstring port_str,
476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn												  jint width,
486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn												  jint height) {
496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	const char *address_chars = env->GetStringUTFChars(address_str, 0);
506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (address_chars == 0) {
516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGV("Error loading socket address.");
526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return false;
536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	const char *port_chars = env->GetStringUTFChars(port_str, 0);
566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (port_chars == 0) {
576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		env->ReleaseStringUTFChars(address_str, address_chars);
586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGV("Error loading socket port.");
596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return false;
606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	m_capture = cvCreateSocketCapture(address_chars, port_chars, width, height);
636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	env->ReleaseStringUTFChars(address_str, address_chars);
646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	env->ReleaseStringUTFChars(port_str, port_chars);
656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_capture == 0)
666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	{
676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGV("Error creating socket capture.");
686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return false;
696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	return true;
726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNIEXPORT
756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennvoid
766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNICALL
776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJava_org_siprop_opencv_OpenCV_releaseSocketCapture(JNIEnv* env,
786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn												   jobject thiz) {
796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_capture) {
806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		cvReleaseCapture(&m_capture);
816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		m_capture = 0;
826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNIEXPORT
866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennjboolean
876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNICALL
886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJava_org_siprop_opencv_OpenCV_grabSourceImageFromCapture(JNIEnv* env,
896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn														 jobject thiz) {
906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_capture == 0)
916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	{
926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGE("Capture was never initialized.");
936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return false;
946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (cvGrabFrame(m_capture) == 0)
976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	{
986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGE("Failed to grab frame from the capture.");
996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return false;
1006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
1016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	IplImage *frame = cvRetrieveFrame(m_capture);
1036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (frame == 0)
1046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	{
1056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGE("Failed to retrieve frame from the capture.");
1066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return false;
1076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
1086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_sourceImage) {
1106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		cvReleaseImage(&m_sourceImage);
1116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		m_sourceImage = 0;
1126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
1136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	m_sourceImage = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U,
1156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		frame->nChannels);
1166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	// Check the origin of image. If top left, copy the image frame to frame_copy.
1186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	// Else flip and copy the image.
1196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (frame->origin == IPL_ORIGIN_TL) {
1206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	    cvCopy(frame, m_sourceImage, 0);
1216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
1226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	else {
1236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	    cvFlip(frame, m_sourceImage, 0);
1246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
1256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	return true;
1276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
1286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Generate and return a boolean array from the source image.
1306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Return 0 if a failure occurs or if the source image is undefined.
1316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNIEXPORT
1326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennjbooleanArray
1336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNICALL
1346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJava_org_siprop_opencv_OpenCV_getSourceImage(JNIEnv* env,
1356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn									    	 jobject thiz)
1366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
1376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_sourceImage == 0) {
1386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGE("Error source image was not set.");
1396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return 0;
1406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
1416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	CvMat stub;
1436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CvMat *mat_image = cvGetMat(m_sourceImage, &stub);
1446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int channels = CV_MAT_CN( mat_image->type );
1456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int ipl_depth = cvCvToIplDepth(mat_image->type);
1466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	WLNonFileByteStream *strm = new WLNonFileByteStream();
1486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    loadImageBytes(mat_image->data.ptr, mat_image->step, mat_image->width,
1496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		mat_image->height, ipl_depth, channels, strm);
1506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	int imageSize = strm->GetSize();
1526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	jbooleanArray res_array = env->NewBooleanArray(imageSize);
1536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if (res_array == 0) {
1546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGE("Unable to allocate a new boolean array for the source image.");
1556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        return 0;
1566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
1576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    env->SetBooleanArrayRegion(res_array, 0, imageSize, (jboolean*)strm->GetByte());
1586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	strm->Close();
1606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	SAFE_DELETE(strm);
1616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	return res_array;
1636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
1646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Given an integer array of image data, load an IplImage.
1666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// It is the responsibility of the caller to release the IplImage.
1676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennIplImage* getIplImageFromIntArray(JNIEnv* env, jintArray array_data,
1686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn								  jint width, jint height) {
1696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	// Load Image
1706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	int *pixels = env->GetIntArrayElements(array_data, 0);
1716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (pixels == 0) {
1726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGE("Error getting int array of pixels.");
1736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return 0;
1746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
1756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	IplImage *image = loadPixels(pixels, width, height);
1776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	env->ReleaseIntArrayElements(array_data, pixels, 0);
1786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if(image == 0) {
1796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGE("Error loading pixel array.");
1806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return 0;
1816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
1826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	return image;
1846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
1856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Set the source image and return true if successful or false otherwise.
1876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNIEXPORT
1886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennjboolean
1896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNICALL
1906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJava_org_siprop_opencv_OpenCV_setSourceImage(JNIEnv* env,
1916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn											 jobject thiz,
1926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn											 jintArray photo_data,
1936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn											 jint width,
1946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn											 jint height)
1956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
1966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	// Release the image if it hasn't already been released.
1976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_sourceImage) {
1986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		cvReleaseImage(&m_sourceImage);
1996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		m_sourceImage = 0;
2006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
2016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	m_facesFound = 0;
2026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	m_sourceImage = getIplImageFromIntArray(env, photo_data, width, height);
2046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_sourceImage == 0) {
2056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGE("Error source image could not be created.");
2066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return false;
2076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
2086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	return true;
2106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
2116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNIEXPORT
2136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennjbooleanArray
2146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNICALL
2156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJava_org_siprop_opencv_OpenCV_findContours(JNIEnv* env,
2166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn										jobject thiz,
2176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn										jint width,
2186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn										jint height) {
2196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	IplImage *grayImage = cvCreateImage( cvGetSize(m_sourceImage), IPL_DEPTH_8U, 1 );		//	�O���[�X�P�[���摜�pIplImage
2206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	IplImage *binaryImage = cvCreateImage( cvGetSize(m_sourceImage), IPL_DEPTH_8U, 1 );	//	2�l�摜�pIplImage
2216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	IplImage *contourImage = cvCreateImage( cvGetSize(m_sourceImage), IPL_DEPTH_8U, 3 );	//	�֊s�摜�pIplImage
2226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	//	BGR����O���[�X�P�[���ɕϊ�����
2246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvCvtColor( m_sourceImage, grayImage, CV_BGR2GRAY );
2256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	//	�O���[�X�P�[������2�l�ɕϊ�����
2276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvThreshold( grayImage, binaryImage, THRESHOLD, THRESHOLD_MAX_VALUE, CV_THRESH_BINARY );
2286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	//	�֊s���o�p�̃��������m�ۂ���
2306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	CvMemStorage* storage = cvCreateMemStorage( 0 );	//	���o���ꂽ�֊s��ۑ�����̈�
2316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	CvSeq* find_contour = 0;		//	�֊s�ւ̃|�C���^
2326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	//	2�l�摜���̗֊s�������A���̐���Ԃ�
2346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	int find_contour_num = cvFindContours(
2356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		binaryImage,			//	��͉摜(�W�r�b�g�V���O���`�����l���j
2366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		storage,				//	���o���ꂽ�֊s��ۑ�����̈�
2376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		&find_contour,			//	��ԊO���̗֊s�ւ̃|�C���^�ւ̃|�C���^
2386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		sizeof( CvContour ),	//	�V�[�P���X�w�b�_�̃T�C�Y
2396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		CV_RETR_LIST,			//	���o���[�h
2406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		CV_CHAIN_APPROX_NONE,	//	�����@
2416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		cvPoint( 0, 0 )			//	�I�t�Z�b�g
2426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	);
2436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	//	���̗̂֊s��ԐF�ŕ`�悷��
2456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	CvScalar red = CV_RGB( 255, 0, 0 );
2466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvDrawContours(
2476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		m_sourceImage,			//	�֊s��`�悷��摜
2486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		find_contour,			//	�ŏ��̗֊s�ւ̃|�C���^
2496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		red,					//	�O���֊s��̐F
2506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		red,					//	�����֊s��i���j�̐F
2516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		CONTOUR_MAX_LEVEL,		//	�`�悳���֊s�̍ő僌�x��
2526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LINE_THICKNESS,			//	�`�悳���֊s��̑���
2536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LINE_TYPE,				//	��̎��
2546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		cvPoint( 0, 0 )			//	�I�t�Z�b�g
2556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	);
2566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	int imageSize;
2586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	CvMat stub, *mat_image;
2596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int channels, ipl_depth;
2606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    mat_image = cvGetMat( m_sourceImage, &stub );
2616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    channels = CV_MAT_CN( mat_image->type );
2626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    ipl_depth = cvCvToIplDepth(mat_image->type);
2646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV("Load loadImageBytes.");
2666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	WLNonFileByteStream* strm = new WLNonFileByteStream();
2676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    loadImageBytes(mat_image->data.ptr, mat_image->step, mat_image->width,
2686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                             mat_image->height, ipl_depth, channels, strm);
2696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	imageSize = strm->GetSize();
2716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	jbooleanArray res_array = env->NewBooleanArray(imageSize);
2726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV("Load NewBooleanArray.");
2736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if (res_array == 0) {
2746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        return 0;
2756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
2766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    env->SetBooleanArrayRegion(res_array, 0, imageSize, (jboolean*)strm->GetByte());
2776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV("Load SetBooleanArrayRegion.");
2786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV("Release sourceImage");
2806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_sourceImage) {
2816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		cvReleaseImage(&m_sourceImage);
2826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		m_sourceImage = 0;
2836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
2846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV("Release binaryImage");
2856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvReleaseImage( &binaryImage );
2866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV("Release grayImage");
2876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvReleaseImage( &grayImage );
2886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV("Release contourImage");
2896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvReleaseImage( &contourImage );
2906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV("Release storage");
2916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvReleaseMemStorage( &storage );
2926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV("Delete strm");
2936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	strm->Close();
2946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	SAFE_DELETE(strm);
2956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	return res_array;
2976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
2986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNIEXPORT
3006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennjboolean
3016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNICALL
3026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJava_org_siprop_opencv_OpenCV_initFaceDetection(JNIEnv* env,
3036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn												jobject thiz,
3046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn												jstring cascade_path_str) {
3056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	// First call release to ensure the memory is empty.
3076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	Java_org_siprop_opencv_OpenCV_releaseFaceDetection(env, thiz);
3086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	char buffer[100];
3106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	clock_t total_time_start = clock();
3116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	m_smallestFaceSize.width = MIN_SIZE_WIDTH;
3136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	m_smallestFaceSize.height = MIN_SIZE_HEIGHT;
3146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	const char *cascade_path_chars = env->GetStringUTFChars(cascade_path_str, 0);
3166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (cascade_path_chars == 0) {
3176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGE("Error getting cascade string.");
3186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return false;
3196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
3206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	m_cascade = (CvHaarClassifierCascade*)cvLoad(cascade_path_chars);
3226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	env->ReleaseStringUTFChars(cascade_path_str, cascade_path_chars);
3236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_cascade == 0) {
3246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGE("Error loading cascade.");
3256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return false;
3266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
3276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	m_storage = cvCreateMemStorage(0);
3296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	clock_t total_time_finish = clock() - total_time_start;
3316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	sprintf(buffer, "Total Time to init: %f", (double)total_time_finish / (double)CLOCKS_PER_SEC);
3326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV(buffer);
3336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	return true;
3356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
3366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Release all of the memory used by face tracking.
3386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNIEXPORT
3396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennvoid
3406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNICALL
3416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJava_org_siprop_opencv_OpenCV_releaseFaceDetection(JNIEnv* env,
3426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn												   jobject thiz) {
3436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	m_facesFound = 0;
3456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	m_faceCropArea.width = m_faceCropArea.height = 0;
3466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_cascade) {
3486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		cvReleaseHaarClassifierCascade(&m_cascade);
3496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		m_cascade = 0;
3506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
3516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_sourceImage) {
3536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		cvReleaseImage(&m_sourceImage);
3546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		m_sourceImage = 0;
3556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
3566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_grayImage) {
3586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		cvReleaseImage(&m_grayImage);
3596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		m_grayImage = 0;
3606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
3616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_smallImage) {
3636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		cvReleaseImage(&m_smallImage);
3646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		m_smallImage = 0;
3656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
3666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_storage) {
3686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		cvReleaseMemStorage(&m_storage);
3696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		m_storage = 0;
3706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
3716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
3726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Initalize the small image and the gray image using the input source image.
3746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// If a previous face was specified, we will limit the ROI to that face.
3756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennvoid initFaceDetectionImages(IplImage *sourceImage, double scale = 1.0) {
3766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_grayImage == 0) {
3776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		m_grayImage = cvCreateImage(cvGetSize(sourceImage), IPL_DEPTH_8U, 1);
3786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
3796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_smallImage == 0) {
3816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		m_smallImage = cvCreateImage(cvSize(cvRound(sourceImage->width / scale),
3826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn			cvRound(sourceImage->height / scale)), IPL_DEPTH_8U, 1);
3836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
3846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if(m_faceCropArea.width > 0 && m_faceCropArea.height > 0) {
3866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		cvSetImageROI(m_smallImage, m_faceCropArea);
3876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		CvRect tPrev = cvRect(m_faceCropArea.x * scale, m_faceCropArea.y * scale,
3896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn			m_faceCropArea.width * scale, m_faceCropArea.height * scale);
3906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		cvSetImageROI(sourceImage, tPrev);
3916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		cvSetImageROI(m_grayImage, tPrev);
3926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	} else {
3936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		cvResetImageROI(m_smallImage);
3946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		cvResetImageROI(m_grayImage);
3956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
3966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    cvCvtColor(sourceImage, m_grayImage, CV_BGR2GRAY);
3986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    cvResize(m_grayImage, m_smallImage, CV_INTER_LINEAR);
3996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    cvEqualizeHist(m_smallImage, m_smallImage);
4006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvClearMemStorage(m_storage);
4016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvResetImageROI(sourceImage);
4036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
4046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Given a sequence of rectangles, return an array of Android Rect objects
4066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// or null if any errors occur.
4076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennjobjectArray seqRectsToAndroidRects(JNIEnv* env, CvSeq *rects) {
4086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (rects == 0 || rects->total <= 0) {
4096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGE("No rectangles were specified!");
4106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return 0;
4116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
4126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	jclass jcls = env->FindClass("android/graphics/Rect");
4146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (jcls == 0) {
4156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGE("Unable to find class android.graphics.Rect");
4166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return 0;
4176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
4186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	jmethodID jconstruct = env->GetMethodID(jcls, "<init>", "(IIII)V");
4206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (jconstruct == 0) {
4216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGE("Unable to find constructor Rect(int, int, int, int)");
4226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return 0;
4236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
4246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	jobjectArray ary = env->NewObjectArray(rects->total, jcls, 0);
4266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (ary == 0) {
4276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGE("Unable to create Rect array");
4286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return 0;
4296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
4306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	for (int i = 0; i < rects->total; i++) {
4326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		char buffer[100];
4336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		CvRect *rect = (CvRect*)cvGetSeqElem(rects, i);
4346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		if (rect == 0) {
4356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn			sprintf(buffer, "Invalid Rectangle #%d", i);
4366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn			LOGE(buffer);
4376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn			return 0;
4386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		}
4396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		jobject jrect = env->NewObject(jcls, jconstruct, rect->x, rect->y,
4416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn			rect->width, rect->height);
4426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		if (jrect == 0) {
4436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn			sprintf(buffer, "Unable to create Android Rect object for rectangle #%d", i);
4446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn			LOGE(buffer);
4456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn			return 0;
4466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		}
4476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		env->SetObjectArrayElement(ary, i, jrect);
4496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		env->DeleteLocalRef(jrect);
4506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
4516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	return ary;
4536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
4546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Identify all of the faces in the source image and return an array
4566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// of Android Rect objects with the face coordinates.  If any errors
4576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// occur, a 0 array will be returned.
4586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNIEXPORT
4596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennjobjectArray
4606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNICALL
4616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJava_org_siprop_opencv_OpenCV_findAllFaces(JNIEnv* env,
4626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn									       jobject thiz) {
4636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	char buffer[100];
4646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	clock_t total_time_start = clock();
4656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_cascade == 0 || m_storage == 0) {
4676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGE("Error find faces was not initialized.");
4686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return 0;
4696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
4706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_sourceImage == 0) {
4726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGE("Error source image was not set.");
4736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return 0;
4746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
4756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	initFaceDetectionImages(m_sourceImage, IMAGE_SCALE);
4776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	clock_t haar_detect_time_start = clock();
4796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    m_facesFound = mycvHaarDetectObjects(m_smallImage, m_cascade, m_storage, HAAR_SCALE,
4806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		MIN_NEIGHBORS, HAAR_FLAGS_ALL_FACES, cvSize(MIN_SIZE_WIDTH, MIN_SIZE_HEIGHT));
4816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	clock_t haar_detect_time_finish = clock() - haar_detect_time_start;
4836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	sprintf(buffer, "Total Time to cvHaarDetectObjects in findAllFaces: %f", (double)haar_detect_time_finish / (double)CLOCKS_PER_SEC);
4846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV(buffer);
4856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	jobjectArray faceRects = 0;
4876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_facesFound == 0 || m_facesFound->total <= 0) {
4886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGV("FACES_DETECTED 0");
4896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	} else {
4906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		sprintf(buffer, "FACES_DETECTED %d", m_facesFound->total);
4916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGV(buffer);
4926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		m_faceCropArea.width = m_faceCropArea.height = 0;
4936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		faceRects = seqRectsToAndroidRects(env, m_facesFound);
4946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
4956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
4966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	clock_t total_time_finish = clock() - total_time_start;
4976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	sprintf(buffer, "Total Time to findAllFaces: %f", (double)total_time_finish / (double)CLOCKS_PER_SEC);
4986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV(buffer);
4996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	return faceRects;
5016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
5026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Store the previous face found in the scene.
5046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennvoid storePreviousFace(CvRect* face) {
5056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	char buffer[100];
5066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_faceCropArea.width > 0 && m_faceCropArea.height > 0) {
5076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		face->x += m_faceCropArea.x;
5086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		face->y += m_faceCropArea.y;
5096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		sprintf(buffer, "Face rect + m_faceCropArea: (%d, %d) to (%d, %d)", face->x, face->y,
5106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn			face->x + face->width, face->y + face->height);
5116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGV(buffer);
5126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
5136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	int startX = MAX(face->x - PAD_FACE_AREA, 0);
5156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	int startY = MAX(face->y - PAD_FACE_AREA, 0);
5166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	int w = m_smallImage->width - startX - face->width - PAD_FACE_AREA_2;
5176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	int h = m_smallImage->height - startY - face->height - PAD_FACE_AREA_2;
5186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	int sw = face->x - PAD_FACE_AREA, sh = face->y - PAD_FACE_AREA;
5196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	m_faceCropArea = cvRect(startX, startY,
5206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		face->width + PAD_FACE_AREA_2 + ((w < 0) ? w : 0) + ((sw < 0) ? sw : 0),
5216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		face->height + PAD_FACE_AREA_2 + ((h < 0) ? h : 0) + ((sh < 0) ? sh : 0));
5226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	sprintf(buffer, "m_faceCropArea: (%d, %d) to (%d, %d)", m_faceCropArea.x, m_faceCropArea.y,
5236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		m_faceCropArea.x + m_faceCropArea.width, m_faceCropArea.y + m_faceCropArea.height);
5246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV(buffer);
5256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
5266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Given a rectangle, return an Android Rect object or null if any
5286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// errors occur.
5296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennjobject rectToAndroidRect(JNIEnv* env, CvRect *rect) {
5306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (rect == 0) {
5316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGE("No rectangle was specified!");
5326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return 0;
5336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
5346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	jclass jcls = env->FindClass("android/graphics/Rect");
5366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (jcls == 0) {
5376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGE("Unable to find class android.graphics.Rect");
5386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return 0;
5396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
5406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	jmethodID jconstruct = env->GetMethodID(jcls, "<init>", "(IIII)V");
5426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (jconstruct == 0) {
5436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGE("Unable to find constructor Rect(int, int, int, int)");
5446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return 0;
5456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
5466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	return env->NewObject(jcls, jconstruct, rect->x, rect->y,
5486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		rect->width, rect->height);
5496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
5506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Identify a single face in the source image and return an Android
5526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Android Rect object with the face coordinates.  This method is
5536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// optimized by focusing on a single face and cropping the detection
5546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// region to the area where the face is located plus some additional
5556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// padding to account for slight head movements.  If any errors occur,
5566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// a 0 array will be returned.
5576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNIEXPORT
5586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennjobject
5596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNICALL
5606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJava_org_siprop_opencv_OpenCV_findSingleFace(JNIEnv* env,
5616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn											 jobject thiz) {
5626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	char buffer[100];
5636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	clock_t total_time_start = clock();
5646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_cascade == 0 || m_storage == 0) {
5666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGE("Error find faces was not initialized.");
5676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return 0;
5686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
5696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_sourceImage == 0) {
5716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGE("Error source image was not set.");
5726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return 0;
5736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
5746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	initFaceDetectionImages(m_sourceImage, IMAGE_SCALE);
5766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	clock_t haar_detect_time_start = clock();
5786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    m_facesFound = mycvHaarDetectObjects(m_smallImage, m_cascade, m_storage, HAAR_SCALE,
5796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		MIN_NEIGHBORS, HAAR_FLAGS_SINGLE_FACE, m_smallestFaceSize);
5806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	clock_t haar_detect_time_finish = clock() - haar_detect_time_start;
5826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	sprintf(buffer, "Total Time to cvHaarDetectObjects in findSingleFace: %f", (double)haar_detect_time_finish / (double)CLOCKS_PER_SEC);
5836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV(buffer);
5846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
5856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	jobject faceRect = 0;
5866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_facesFound == 0 || m_facesFound->total <= 0) {
5876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGV("FACES_DETECTED 0");
5886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		m_faceCropArea.width = m_faceCropArea.height = 0;
5896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		m_smallestFaceSize.width = MIN_SIZE_WIDTH;
5906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		m_smallestFaceSize.height = MIN_SIZE_HEIGHT;
5916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	} else {
5926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGV("FACES_DETECTED 1");
5936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		CvRect *face = (CvRect*)cvGetSeqElem(m_facesFound, 0);
5946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		if (face == 0) {
5956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn			LOGE("Invalid rectangle detected");
5966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn			return 0;
5976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		}
5986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		m_smallestFaceSize.width = MAX(face->width - PAD_FACE_SIZE, MIN_SIZE_WIDTH);
5996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		m_smallestFaceSize.height = MAX(face->height - PAD_FACE_SIZE, MIN_SIZE_HEIGHT);
6006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		faceRect = rectToAndroidRect(env, face);
6016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		storePreviousFace(face);
6026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
6036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
6046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	clock_t total_time_finish = clock() - total_time_start;
6056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	sprintf(buffer, "Total Time to findSingleFace: %f", (double)total_time_finish / (double)CLOCKS_PER_SEC);
6066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV(buffer);
6076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
6086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	return faceRect;
6096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
6106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
6116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Draw a rectangle on the source image around the specified face rectangle.
6126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Scale the face area to the draw area based on the specified scale.
6136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennvoid highlightFace(IplImage *sourceImage, CvRect *face, double scale = 1.0) {
6146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	char buffer[100];
6156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	sprintf(buffer, "Face Rectangle: (x: %d, y: %d) to (w: %d, h: %d)",
6166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		face->x, face->y, face->width, face->height);
6176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV(buffer);
6186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	CvPoint pt1 = cvPoint(int(face->x * scale), int(face->y * scale));
6196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	CvPoint pt2 = cvPoint(int((face->x + face->width) * scale),
6206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		int((face->y + face->height) * scale));
6216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	sprintf(buffer, "Draw Rectangle: (%d, %d) to (%d, %d)", pt1.x, pt1.y, pt2.x, pt2.y);
6226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV(buffer);
6236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    cvRectangle(sourceImage, pt1, pt2, CV_RGB(255, 0, 0), 3, 8, 0);
6246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
6256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
6266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Draw rectangles on the source image around each face that was found.
6276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Scale the face area to the draw area based on the specified scale.
6286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Return true if at least one face was highlighted and false otherwise.
6296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennbool highlightFaces(IplImage *sourceImage, CvSeq *faces, double scale = 1.0) {
6306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (faces == 0 || faces->total <= 0) {
6316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGV("No faces were highlighted!");
6326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return false;
6336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	} else {
6346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGV("Drawing rectangles on each face");
6356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		int count;
6366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		CvRect* face;
6376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		for (int i = 0; i < faces->total; i++) {
6386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn			face = (CvRect*)cvGetSeqElem(faces, i);
6396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn			highlightFace(sourceImage, face, scale);
6406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		}
6416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
6426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
6436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	return true;
6446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
6456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
6466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Highlight the faces that were detected in the source image.
6476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// Return true if one or more faces is highlighted or false otherwise.
6486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNIEXPORT
6496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennjboolean
6506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNICALL
6516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJava_org_siprop_opencv_OpenCV_highlightFaces(JNIEnv* env,
6526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn									    	 jobject thiz) {
6536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if (m_facesFound == 0 || m_facesFound->total <= 0) {
6546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGV("No faces found to highlight!");
6556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return false;
6566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	} else {
6576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		highlightFaces(m_sourceImage, m_facesFound, IMAGE_SCALE);
6586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
6596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
6606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	return true;
6616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
6626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
6636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#if 0
6646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
6656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNIEXPORT
6666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennjbooleanArray
6676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJNICALL
6686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennJava_org_siprop_opencv_OpenCV_faceDetect(JNIEnv* env,
6696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn										jobject thiz,
6706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn										jintArray photo_data1,
6716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn										jintArray photo_data2,
6726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn										jint width,
6736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn										jint height) {
6746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV("Load desp.");
6756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
6766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	int i, x, y;
6776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	int* pixels;
6786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	IplImage *frameImage;
6796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
6806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	IplImage *backgroundImage = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
6816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	IplImage *grayImage = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
6826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	IplImage *differenceImage = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
6836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
6846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	IplImage *hsvImage = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 3 );
6856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	IplImage *hueImage = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
6866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	IplImage *saturationImage = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
6876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	IplImage *valueImage = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
6886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	IplImage *thresholdImage1 = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
6896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	IplImage *thresholdImage2 = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
6906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	IplImage *thresholdImage3 = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
6916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	IplImage *faceImage = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
6926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
6936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	CvMoments moment;
6946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	double m_00;
6956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	double m_10;
6966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	double m_01;
6976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	int gravityX;
6986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	int gravityY;
6996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	jbooleanArray res_array;
7016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	int imageSize;
7026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	// Load Image
7066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	pixels = env->GetIntArrayElements(photo_data1, 0);
7076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	frameImage = loadPixels(pixels, width, height);
7086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if(frameImage == 0) {
7096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGV("Error loadPixels.");
7106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return 0;
7116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
7126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvCvtColor( frameImage, backgroundImage, CV_BGR2GRAY );
7156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	pixels = env->GetIntArrayElements(photo_data2, 0);
7186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	frameImage = loadPixels(pixels, width, height);
7196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	if(frameImage == 0) {
7206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		LOGV("Error loadPixels.");
7216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		return 0;
7226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	}
7236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvCvtColor( frameImage, grayImage, CV_BGR2GRAY );
7246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvAbsDiff( grayImage, backgroundImage, differenceImage );
7256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvCvtColor( frameImage, hsvImage, CV_BGR2HSV );
7276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV("Load cvCvtColor.");
7286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvSplit( hsvImage, hueImage, saturationImage, valueImage, 0 );
7296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV("Load cvSplit.");
7306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvThreshold( hueImage, thresholdImage1, THRESH_BOTTOM, THRESHOLD_MAX_VALUE, CV_THRESH_BINARY );
7316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvThreshold( hueImage, thresholdImage2, THRESH_TOP, THRESHOLD_MAX_VALUE, CV_THRESH_BINARY_INV );
7326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvAnd( thresholdImage1, thresholdImage2, thresholdImage3, 0 );
7336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV("Load cvAnd.");
7346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvAnd( differenceImage, thresholdImage3, faceImage, 0 );
7366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvMoments( faceImage, &moment, 0 );
7386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	m_00 = cvGetSpatialMoment( &moment, 0, 0 );
7396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	m_10 = cvGetSpatialMoment( &moment, 1, 0 );
7406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	m_01 = cvGetSpatialMoment( &moment, 0, 1 );
7416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	gravityX = m_10 / m_00;
7426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	gravityY = m_01 / m_00;
7436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV("Load cvMoments.");
7446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvCircle( frameImage, cvPoint( gravityX, gravityY ), CIRCLE_RADIUS,
7476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		 CV_RGB( 255, 0, 0 ), LINE_THICKNESS, LINE_TYPE, 0 );
7486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	CvMat stub, *mat_image;
7536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int channels, ipl_depth;
7546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    mat_image = cvGetMat( frameImage, &stub );
7556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    channels = CV_MAT_CN( mat_image->type );
7566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    ipl_depth = cvCvToIplDepth(mat_image->type);
7586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	WLNonFileByteStream* m_strm = new WLNonFileByteStream();
7606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    loadImageBytes(mat_image->data.ptr, mat_image->step, mat_image->width,
7616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                             mat_image->height, ipl_depth, channels, m_strm);
7626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV("Load loadImageBytes.");
7636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	imageSize = m_strm->GetSize();
7666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	res_array = env->NewBooleanArray(imageSize);
7676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV("Load NewByteArray.");
7686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if (res_array == 0) {
7696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        return 0;
7706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
7716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    env->SetBooleanArrayRegion(res_array, 0, imageSize, (jboolean*)m_strm->GetByte());
7726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	LOGV("Load SetBooleanArrayRegion.");
7736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvReleaseImage( &backgroundImage );
7786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvReleaseImage( &grayImage );
7796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvReleaseImage( &differenceImage );
7806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvReleaseImage( &hsvImage );
7816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvReleaseImage( &hueImage );
7826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvReleaseImage( &saturationImage );
7836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvReleaseImage( &valueImage );
7846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvReleaseImage( &thresholdImage1 );
7856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvReleaseImage( &thresholdImage2 );
7866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvReleaseImage( &thresholdImage3 );
7876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvReleaseImage( &faceImage );
7886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	cvReleaseImage( &frameImage );
7896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	m_strm->Close();
7906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	SAFE_DELETE(m_strm);
7916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	return res_array;
7936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
7946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
7956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#endif
7966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
797