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