使用Opencv实现一个简单的人脸检测的Demo,是很简单的,具体的算法都是Opencv内部实现的,我们只需要调用实现就可以了。下面我们代码搞起!
重点内容
第一步:Opencv调取摄像头, implements CameraBridgeViewBase.CvCameraViewListener2,Override onCameraViewStarted(int,int)、onCameraViewStopped()和onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame)。具体详见:android中使用OpenCV之调用设备摄像头
第二步:Opencv加载脸部特征库和native方法。
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS: {
Log.i(TAG, "OpenCV loaded successfully");
// 加载回调成功时加载本地方法库
System.loadLibrary("native-lib");
try {
// 载入人脸特征文件
InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);
File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
mCascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");
FileOutputStream os = new FileOutputStream(mCascadeFile);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
is.close();
os.close();
// 载入人脸特征文件结束
//实例化java检测器
mJavaDetector = new CascadeClassifier(mCascadeFile.getAbsolutePath());
if (mJavaDetector.empty()) {
Log.e(TAG, "Failed to load cascade classifier");
mJavaDetector = null;
} else
Log.i(TAG, "Loaded cascade classifier from " + mCascadeFile.getAbsolutePath());
//实例化native检测器
mNativeDetector = new DetectionBasedTracker(mCascadeFile.getAbsolutePath(), 0);
//释放文件
cascadeDir.delete();
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "Failed to load cascade. Exception thrown: " + e);
}
//加载摄像头显示
mOpenCvCameraView.enableView();
}
break;
default: {
super.onManagerConnected(status);
}
break;
}
}
};
//检测器适配器
class CascadeDetectorAdapter : public DetectionBasedTracker::IDetector {
public:
CascadeDetectorAdapter(cv::Ptr<cv::CascadeClassifier> detector) :
IDetector(),
Detector(detector) {
LOGD("CascadeDetectorAdapter::Detect::Detect");
CV_Assert(detector);
}
void detect(const cv::Mat &Image, std::vector<cv::Rect> &objects) {
LOGD("CascadeDetectorAdapter::Detect: begin");
LOGD("CascadeDetectorAdapter::Detect: scaleFactor=%.2f, minNeighbours=%d, minObjSize=(%dx%d), maxObjSize=(%dx%d)",
scaleFactor, minNeighbours, minObjSize.width, minObjSize.height, maxObjSize.width,
maxObjSize.height);
Detector->detectMultiScale(Image, objects, scaleFactor, minNeighbours, 0, minObjSize,
maxObjSize);
LOGD("CascadeDetectorAdapter::Detect: end");
}
virtual ~CascadeDetectorAdapter() {
LOGD("CascadeDetectorAdapter::Detect::~Detect");
}
private:
CascadeDetectorAdapter();
cv::Ptr<cv::CascadeClassifier> Detector;
};
//实例化特征库检测器
extern "C"
JNIEXPORT jlong JNICALL
Java_com_example_dgxq008_faceknow_DetectionBasedTracker_nativeCreateObject
(JNIEnv *jenv, jclass, jstring jFileName, jint faceSize) {
LOGD("Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativeCreateObject enter");
const char *jnamestr = jenv->GetStringUTFChars(jFileName, NULL);
string stdFileName(jnamestr);
jlong result = 0;
LOGD("Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativeCreateObject");
try {
cv::Ptr<CascadeDetectorAdapter> mainDetector = makePtr<CascadeDetectorAdapter>(
makePtr<CascadeClassifier>(stdFileName));
cv::Ptr<CascadeDetectorAdapter> trackingDetector = makePtr<CascadeDetectorAdapter>(
makePtr<CascadeClassifier>(stdFileName));
result = (jlong) new DetectorAgregator(mainDetector, trackingDetector);
if (faceSize > 0) {
mainDetector->setMinObjectSize(Size(faceSize, faceSize));
//trackingDetector->setMinObjectSize(Size(faceSize, faceSize));
}
}
catch (cv::Exception &e) {
LOGD("nativeCreateObject caught cv::Exception: %s", e.what());
jclass je = jenv->FindClass("org/opencv/core/CvException");
if (!je)
je = jenv->FindClass("java/lang/Exception");
jenv->ThrowNew(je, e.what());
}
catch (...) {
LOGD("nativeCreateObject caught unknown exception");
jclass je = jenv->FindClass("java/lang/Exception");
jenv->ThrowNew(je,
"Unknown exception in JNI code of DetectionBasedTracker.nativeCreateObject()");
return 0;
}
LOGD("Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativeCreateObject exit");
return result;
}
第三步:特征检测,画出符合人脸特征的区域。
@Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
//针对每一帧的操作
mRgba = inputFrame.rgba();
mGray = inputFrame.gray();
//通过脸部相对尺寸计算出脸部绝对尺寸
if (mAbsoluteFaceSize == 0) {
int height = mGray.rows();
if (Math.round(height * mRelativeFaceSize) > 0) {
mAbsoluteFaceSize = Math.round(height * mRelativeFaceSize);
}
//设置脸部特征区域绝对大小
mNativeDetector.setMinFaceSize(mAbsoluteFaceSize);
}
MatOfRect faces = new MatOfRect();
if (mDetectorType == JAVA_DETECTOR) {
if (mJavaDetector != null)
//java检测处符合特征区域
mJavaDetector.detectMultiScale(mGray, faces, 1.1, 2, 2, // TODO: objdetect.CV_HAAR_SCALE_IMAGE
new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());
} else if (mDetectorType == NATIVE_DETECTOR) {
if (mNativeDetector != null)
//Native检测出符合特征区域
mNativeDetector.detect(mGray, faces);
} else {
Log.e(TAG, "Detection method is not selected!");
}
Rect[] facesArray = faces.toArray();
for (int i = 0; i < facesArray.length; I++)
//绘制识别出人脸的位置上的绿色方框
Imgproc.rectangle(mRgba, facesArray[i].tl(), facesArray[i].br(), FACE_RECT_COLOR, 3);
return mRgba;
}
//检测符合特征的区域
extern "C"
JNIEXPORT void JNICALL
Java_com_example_dgxq008_faceknow_DetectionBasedTracker_nativeDetect
(JNIEnv *jenv, jclass, jlong thiz, jlong imageGray, jlong faces) {
LOGD("Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativeDetect");
try {
vector<Rect> RectFaces;
((DetectorAgregator *) thiz)->tracker->process(*((Mat *) imageGray));
((DetectorAgregator *) thiz)->tracker->getObjects(RectFaces);
*((Mat *) faces) = Mat(RectFaces, true);
}
catch (cv::Exception &e) {
LOGD("nativeCreateObject caught cv::Exception: %s", e.what());
jclass je = jenv->FindClass("org/opencv/core/CvException");
if (!je)
je = jenv->FindClass("java/lang/Exception");
jenv->ThrowNew(je, e.what());
}
catch (...) {
LOGD("nativeDetect caught unknown exception");
jclass je = jenv->FindClass("java/lang/Exception");
jenv->ThrowNew(je, "Unknown exception in JNI code DetectionBasedTracker.nativeDetect()");
}
LOGD("Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativeDetect END");
}
//设置检测特征区域大小值
extern "C"
JNIEXPORT void JNICALL
Java_com_example_dgxq008_faceknow_DetectionBasedTracker_nativeSetFaceSize
(JNIEnv *jenv, jclass, jlong thiz, jint faceSize) {
LOGD("Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativeSetFaceSize -- BEGIN");
try {
if (faceSize > 0) {
((DetectorAgregator *) thiz)->mainDetector->setMinObjectSize(Size(faceSize, faceSize));
//((DetectorAgregator*)thiz)->trackingDetector->setMinObjectSize(Size(faceSize, faceSize));
}
}
catch (cv::Exception &e) {
LOGD("nativeStop caught cv::Exception: %s", e.what());
jclass je = jenv->FindClass("org/opencv/core/CvException");
if (!je)
je = jenv->FindClass("java/lang/Exception");
jenv->ThrowNew(je, e.what());
}
catch (...) {
LOGD("nativeSetFaceSize caught unknown exception");
jclass je = jenv->FindClass("java/lang/Exception");
jenv->ThrowNew(je,
"Unknown exception in JNI code of DetectionBasedTracker.nativeSetFaceSize()");
}
LOGD("Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativeSetFaceSize -- END");
}
效果图展示:
这里写图片描述
这里写图片描述
我的CSDN博客地址:博客地址