最近研究opencv,主要的是以Android平台的为主。废话不多说直接来干货。
一: SDK下载:https://opencv.org/ 我使用的是opencv 2.4.10的
二:IDE我是使用eclipse的,也可以使用AS进行开发,需要NDK, eclipse的opencv配置请参考:https://blog.****.net/roboman/article/details/42883399 博主的。
三:我使用的是samples文件夹的 face-detection 示例,把示例加入工程,添加 opencv libs。在detectionBasedTracker.java 中添加smile本地方法->
//smile
public float data(Mat imageGray, MatOfRect faces){
float data = 0;
data = nativateSmileData(mNativeObj, imageGray.getNativeObjAddr(), faces.getNativeObjAddr());
return data ;
}
private static native float nativateSmileData(long thiz, long inputImage, long faces);
四:再在jni文件夹中的 .h 文件中添加jni接口
/*
* smile
* */
JNIEXPORT jfloat JNICALL Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativateSmileData
(JNIEnv *, jclass, jlong, jlong, jlong);
五:修改.cpp文件 添加->
//smile 处理
JNIEXPORT jfloat JNICALL Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativateSmileData(
JNIEnv * jenv, jclass, jlong thiz, jlong imageGray, jlong facess) {
Mat img;
Mat gray, smallImg;
double scale = 1;
bool tryflip = 0;
float smile_max = 0;
vector<Rect> faces, faces2;
img = *((Mat*) imageGray);
CascadeClassifier nestedCascade, cascade;
if (!cascade.load(
"/data/data/org.opencv.samples.facedetect/app_cascade/haarcascade_frontalface_alt2.xml")) { //分类器存放的位置
return 11;
}
if (!nestedCascade.load(
"/data/data/org.opencv.samples.facedetect/app_cascade/haarcascade_smile.xml")) { //分类器存放的位置
return 11;
}
const static Scalar colors[] = { Scalar(255, 0, 0), Scalar(255, 128, 0),
Scalar(255, 255, 0), Scalar(0, 255, 0), Scalar(0, 128, 255), Scalar(
0, 255, 255), Scalar(0, 0, 255), Scalar(255, 0, 255) };
cvtColor(img, gray, COLOR_BGR2GRAY);
double fx = 1 / scale;
resize(gray, smallImg, Size(), fx, fx, INTER_LINEAR);
equalizeHist(smallImg, smallImg);
cascade.detectMultiScale(smallImg, faces, 1.1, 2, 0
| CASCADE_SCALE_IMAGE, Size(30, 30));
if (tryflip)
{
flip(smallImg, smallImg, 1);
cascade.detectMultiScale(smallImg, faces2,
1.1, 2, 0
| CASCADE_SCALE_IMAGE,
Size(30, 30));
for (vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); ++r)
{
faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));
}
}
for (size_t i = 0; i < faces.size(); i++) {
Rect r = faces[i];
Mat smallImgROI;
vector<Rect> nestedObjects; //微笑处理
Point center;
Scalar color = colors[i % 8];
int radius;
double aspect_ratio = (double) r.width / r.height;
if (0.75 < aspect_ratio && aspect_ratio < 1.3) {
center.x = cvRound((r.x + r.width * 0.5) * scale);
center.y = cvRound((r.y + r.height * 0.5) * scale);
radius = cvRound((r.width + r.height) * 0.25 * scale);
circle(img, center, radius, color, 3, 8, 0);
} else
rectangle(img, cvPoint(cvRound(r.x * scale), cvRound(r.y * scale)),
cvPoint(cvRound((r.x + r.width - 1) * scale),
cvRound((r.y + r.height - 1) * scale)), color, 3, 8,
0);
const int half_height = cvRound((float) r.height / 2);
r.y = r.y + half_height;
r.height = half_height - 1;
smallImgROI = smallImg(r);
//微笑处理&识别度
nestedCascade.detectMultiScale(smallImgROI, nestedObjects, 1.1, 0, 0
| CASCADE_SCALE_IMAGE, Size(30, 30));
// The number of detected neighbors depends on image size (and also illumination, etc.). The
// following steps use a floating minimum and maximum of neighbors. Intensity thus estimated will be
//accurate only after a first smile has been displayed by the user.
const int smile_neighbors = (int) nestedObjects.size();
static int max_neighbors = -1;
static int min_neighbors = -1;
if (min_neighbors == -1)
min_neighbors = smile_neighbors;
max_neighbors = MAX(max_neighbors, smile_neighbors);
// Draw rectangle on the left side of the image reflecting smile intensity
float intensityZeroOne = ((float) smile_neighbors - min_neighbors)
/ (max_neighbors - min_neighbors + 1);
smile_max = intensityZeroOne;
}
LOGE("jni_smile_ok_->3");
return (jfloat) smile_max;
}
六:Java调用
在 public Mat onCameraFrame(CvCameraViewFrame inputFrame){
// 这里获取相机拍摄到的原图,彩色图
mRgba = inputFrame.rgba();
// 这里获取相机拍摄到的灰度图,用来给下面检测人脸使用。
mGray = inputFrame.gray();
MatOfRect faces2 = new MatOfRect();
float sm = mNativeDetector.data(mRgba, faces2);
Log.e("微笑强度-->", ""+sm);
return mRgba;
}
总结:整个工程对smile识别还是不错的,cpp算法是结合windows工程加进去改进的,其Android 是通过jni方法,NDK 调用opencv算法,的出结果 反馈给上层应用。