I'm studying OpenCV recently.
OpenCV for Android sample code(2.4.6) is tested.
I have some wonder.
I can detect face by sample code(OpenCV Sample - face-detection). but, can't detect face by portrait mode(vertical mode) on android device.
First, I try set Front-Camera by portrait mode.
//added code in onCameraFrame() method.
Core.flip(mRgba, mRgba, 1);
Still do not recognize face.
How to detect face by portrait mode?
Thank you.
you need to do transpose and then flip:
int height = mGray.rows();
int faceSize = Math.round(height * 0.5F);
Mat temp = mGray.clone();
Core.transpose(mGray, temp);
Core.flip(temp, temp, -1);
MatOfRect rectFaces = new MatOfRect();
// java detector fast
mCascade.detectMultiScale(temp, rectFaces, 1.1, 1, 0, new Size(faceSize, faceSize), new Size());
Set the portrait mode in android's manifest first.
android:screenOrientation="portrait"
Flip the colored and gray image(Mat) clockwise for face/feature detection to work in portrait mode.
At the end of feature detection Logic, you flip counter clockwise the colored image(mRgba Mat) . As illustrated.
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
Core.flip(inputFrame.gray().t(),mGray,1); //rotate clockwise
Core.flip(inputFrame.rgba().t(),mRgba,1);
mRgba=Feature_DetectionNATIVE(mRgba,mGray);
Core.flip(mRgba.t(),mRgba,0); //rotate counter clockwise
//this is a solution for allowing face detection in portrait view if it isn't working at all.
return mRgba;
}
public Mat Feature_DetectionNATIVE(Mat mRgba2, final Mat Gray)
{
if (mAbsoluteFaceSize == 0)
{
int height = Gray.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)
mJavaDetector.detectMultiScale(Gray, faces, 1.1, 2, 2,
new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());
}
else if (mDetectorType == NATIVE_DETECTOR)
{
if (mNativeDetector != null)
mNativeDetector.detect(Gray, faces);
}
else
{
Log.e(TAG, "Detection method is not selected!");
}
Rect[] facesArray = faces.toArray();
for (int i = 0; i < facesArray.length; i++)
{
Core.rectangle(mRgba2, facesArray[i].tl(), facesArray[i].br(), FACE_RECT_COLOR, 3);
}
return mRgba2;
}
After that the camera will show face detection in landscape orientation to fix this you rotate the canvas clockwise by 90 in opencv's CameraBridgeViewBase main class or hack it.(Note this reduces FPS but face detection is still fast)
protected void deliverAndDrawFrame(CvCameraViewFrame frame) {
Mat modified;
if (mListener != null) {
modified = mListener.onCameraFrame(frame);
} else {
modified = frame.rgba();
}
boolean bmpValid = true;
if (modified != null) {
try {
Utils.matToBitmap(modified, mCacheBitmap);
} catch(Exception e) {
Log.e(TAG, "Mat type: " + modified);
Log.e(TAG, "Bitmap type: " + mCacheBitmap.getWidth() + "*" + mCacheBitmap.getHeight());
Log.e(TAG, "Utils.matToBitmap() throws an exception: " + e.getMessage());
bmpValid = false;
}
}
if (bmpValid && mCacheBitmap != null) {
Canvas canvas = getHolder().lockCanvas();
if (canvas != null) {
canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
Log.d(TAG, "mStretch value: " + mScale);
canvas=rotateCanvas(canvas,mCacheBitmap);
getHolder().unlockCanvasAndPost(canvas);
} } }
protected Canvas rotateCanvas(final Canvas canvas, final Bitmap mCacheBitmap)
{
final CountDownLatch latch =new CountDownLatch(1);
final Mat[] mRgba=new Mat[1];
new Thread(new Runnable() {
@Override
public void run() {
try {
Bitmap bitmap = Bitmap.createScaledBitmap(mCacheBitmap, canvas.getHeight(), canvas.getWidth(), true);
canvas.rotate(90,0,0);
mScale = canvas.getWidth() / (float)bitmap.getHeight();
float scale2 = canvas.getHeight() / (float)bitmap.getWidth();
if(scale2 > mScale){
mScale = scale2;
}
if (mScale != 0) {
canvas.scale(mScale, mScale,0,0);
}
canvas.drawBitmap(bitmap, 0, -bitmap.getHeight(), null);
}
catch (CvException e) { e.printStackTrace();}
latch.countDown();//setting //release await() in this thread
}
}).start();
try { latch.await(); //waits for countDown in the Thread inorder to obtain a value from the thread
} catch (InterruptedException e) { e.printStackTrace();}
return canvas;
}
(Using OpenCV 2.4.9)