热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

OpenCVonAndroid开发(4)竖屏预览图像问题解决方法续

前一篇文章通过使用opencv官方例程的思路,初步解决了竖屏预览自动旋转的问题,但是因为要将app的方向固定为landscape,即横屏模式,这在实际的相机应用里会很奇怪,所以作为
前一篇文章通过使用opencv官方例程的思路,初步解决了竖屏预览自动旋转的问题,但是因为要将app的方向固定为landscape,即横屏模式,这在实际的相机应用里会很奇怪,所以作为强迫症患者,我想在竖屏模式下实现正常的预览检测,花了我2天的时间,在外网扒代码,终于找到了靠谱解决的方法,但是并不完美,还是存在一些小bug

解决方法的连接https://github.com/opencv/opencv/issues/4704
https://stackoverflow.com/questions/16669779/opencv-camera-orientation-issue
老外也遇到了同样的问题http://answers.opencv.org/question/20325/how-can-i-change-orientation-without-ruin-camera-settings/但是还没有人给出正确的解决办法

经过我的测试有两个方法的表现还不错

方法一

需要改opencv的库文件

首先

CameraBridgeViewBase.java 中的deliverAndDrawFrame(CVCameraViewFrame frame)方法全部替换成

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;
}
}
mFpsMeter.measure();
}

然后是

JavaCameraView.java 中的initializeCamera(int width, int height)方法,并且需要增加两个函数private void setDisplayOrientation(Camera camera, int angle)和private String getOrientation(),通过mCamera.setPreviewDisplay(getHolder());来实现竖屏全屏显示

protected boolean initializeCamera(int width, int height) {
Log.d(TAG, "Initialize java camera");
boolean result = true;
synchronized (this) {
mCamera = null;
if (mCameraIndex == CAMERA_ID_ANY) {
Log.d(TAG, "Trying to open camera with old open()");
try {
mCamera = Camera.open();
}
catch (Exception e){
Log.e(TAG, "Camera is not available (in use or does not exist): " + e.getLocalizedMessage());
}
if(mCamera == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
boolean cOnnected= false;
for (int camIdx = 0; camIdx Log.d(TAG, "Trying to open camera with new open(" + Integer.valueOf(camIdx) + ")");
try {
mCamera = Camera.open(camIdx);
cOnnected= true;
} catch (RuntimeException e) {
Log.e(TAG, "Camera #" + camIdx + "failed to open: " + e.getLocalizedMessage());
}
if (connected) break;
}
}
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
int localCameraIndex = mCameraIndex;
if (mCameraIndex == CAMERA_ID_BACK) {
Log.i(TAG, "Trying to open back camera");
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
for (int camIdx = 0; camIdx Camera.getCameraInfo( camIdx, cameraInfo );
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
localCameraIndex = camIdx;
break;
}
}
} else if (mCameraIndex == CAMERA_ID_FRONT) {
Log.i(TAG, "Trying to open front camera");
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
for (int camIdx = 0; camIdx Camera.getCameraInfo( camIdx, cameraInfo );
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
localCameraIndex = camIdx;
break;
}
}
}
if (localCameraIndex == CAMERA_ID_BACK) {
Log.e(TAG, "Back camera not found!");
} else if (localCameraIndex == CAMERA_ID_FRONT) {
Log.e(TAG, "Front camera not found!");
} else {
Log.d(TAG, "Trying to open camera with new open(" + Integer.valueOf(localCameraIndex) + ")");
try {
mCamera = Camera.open(localCameraIndex);
} catch (RuntimeException e) {
Log.e(TAG, "Camera #" + localCameraIndex + "failed to open: " + e.getLocalizedMessage());
}
}
}
}
if (mCamera == null)
return false;
/* Now set camera parameters */
try {
Camera.Parameters params = mCamera.getParameters();
Log.d(TAG, "getSupportedPreviewSizes()");
List sizes = params.getSupportedPreviewSizes();
if (sizes != null) {
/* Image format NV21 causes issues in the Android emulators */
if (Build.FINGERPRINT.startsWith("generic")
|| Build.FINGERPRINT.startsWith("unknown")
|| Build.MODEL.contains("google_sdk")
|| Build.MODEL.contains("Emulator")
|| Build.MODEL.contains("Android SDK built for x86")
|| Build.MANUFACTURER.contains("Genymotion")
|| (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
|| "google_sdk".equals(Build.PRODUCT))
params.setPreviewFormat(ImageFormat.YV12); // "generic" or "android" = android emulator
else
params.setPreviewFormat(ImageFormat.NV21);
mPreviewFormat = params.getPreviewFormat();
//从这里开始不同
if (!Build.MODEL.equals("GT-I9100")) params.setRecordingHint(true);
params.setPreviewSize(1920, 1080);
mCamera.setParameters(params);
mFrameWidth = 1920;
mFrameHeight = 1080;
if (mFpsMeter != null) {
mFpsMeter.setResolution(mFrameWidth, mFrameHeight);
}
int size = mFrameWidth * mFrameHeight;
size = size * ImageFormat.getBitsPerPixel(params.getPreviewFormat()) / 8;
mBuffer = new byte[size];
mCamera.addCallbackBuffer(mBuffer);
mCamera.setPreviewCallbackWithBuffer(this);
mFrameChain = new Mat[2];
mFrameChain[0] = new Mat(mFrameHeight + (mFrameHeight/2), mFrameWidth, CvType.CV_8UC1);
mFrameChain[1] = new Mat(mFrameHeight + (mFrameHeight/2), mFrameWidth, CvType.CV_8UC1);
AllocateCache();
mCameraFrame = new JavaCameraFrame[2];
mCameraFrame[0] = new JavaCameraFrame(mFrameChain[0], mFrameWidth, mFrameHeight);
mCameraFrame[1] = new JavaCameraFrame(mFrameChain[1], mFrameWidth, mFrameHeight);
//different
mSurfaceTexture = new SurfaceTexture(MAGIC_TEXTURE_ID);
mCamera.setPreviewTexture(mSurfaceTexture);
//主要修改
if (getOrientation().equals("portrait")) {
setDisplayOrientation(mCamera, 90);
} else if (getOrientation().equals("reverse landscape")){
setDisplayOrientation(mCamera, 180);
} else if (getOrientation().equals("reverse portrait")) {
setDisplayOrientation(mCamera, 270);
}
mCamera.setPreviewDisplay(getHolder());
//end
mCamera.startPreview();
}
else
result = false;
} catch (Exception e) {
result = false;
e.printStackTrace();
}
}
return result;
}
//add two function

private void setDisplayOrientation(Camera camera, int angle){
Method downPolymorphic;
try {
downPolymorphic = camera.getClass().getMethod("setDisplayOrientation", int.class);
if (downPolymorphic != null) {
downPolymorphic.invoke(camera, angle);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
private String getOrientation(){
int orientation = Surface.ROTATION_0;
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
if (wm != null) {
Display display = wm.getDefaultDisplay();
orientation = display.getOrientation();
}
if (orientation == Surface.ROTATION_0) {
return "portrait";
}else if (orientation == Surface.ROTATION_90) {
return "landscape";
} else if (orientation == Surface.ROTATION_180) {
return "reverse portrait";
} else return "reverse landscape";
}
//end

该方法显示的十分完美,但是存在一个无法接受的缺点
我们的onCameraFrame()方法失效了,因为我们调用了mCamera.setPreviewDisplay(getHolder());这个方法导致opencv对相机每一帧的处理无法显示出来。。。但是具体怎么解决???我也不知道,期望能有大神把解决方法分享出来23333

《OpenCV on Android 开发 (4)竖屏预览图像问题解决方法-续》

方法二

该方法只需要修改opencv的一个库文件CameraBridgeViewBase.java,相机预览的显示效果还不错,但是还是还是有问题.。。。2333。。。经我测试发现横屏时存在显示图像放大的问题,但是竖屏倒是蛮完美的,就是fps会比较显著的降低,但还在能接受的范围内。

修改如下

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);
/*
//原来的方法
if (BuildConfig.DEBUG)
Log.d(TAG, "mStretch value: " + mScale);
if (mScale != 0) {
canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
new Rect((int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2),
(int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2),
(int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2 + mScale*mCacheBitmap.getWidth()),
(int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2 + mScale*mCacheBitmap.getHeight())), null);
} else {
canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
new Rect((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,
(canvas.getHeight() - mCacheBitmap.getHeight()) / 2,
(canvas.getWidth() - mCacheBitmap.getWidth()) / 2 + mCacheBitmap.getWidth(),
(canvas.getHeight() - mCacheBitmap.getHeight()) / 2 + mCacheBitmap.getHeight()), null);
}
*///method4
Matrix matrix = new Matrix(); // I rotate it with minimal process
//matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,(canvas.getHeight() - mCacheBitmap.getHeight()) / 2);
//matrix.postRotate(90f,(canvas.getWidth()) / 2,(canvas.getHeight()) / 2);
//float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
//matrix.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
//canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
//end
if (getDisplay().getRotation() == Surface.ROTATION_0) {
matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,(canvas.getHeight() - mCacheBitmap.getHeight()) / 2);
matrix.postRotate(90f,(canvas.getWidth()) / 2,(canvas.getHeight()) / 2);
float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
matrix.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
} else if (getDisplay().getRotation() == Surface.ROTATION_90) {
float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
matrix.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
} else if (getDisplay().getRotation() == Surface.ROTATION_180) {
matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,(canvas.getHeight() - mCacheBitmap.getHeight()) / 2);
matrix.postRotate(270f,(canvas.getWidth()) / 2,(canvas.getHeight()) / 2);
float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
matrix.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
} else if (getDisplay().getRotation() == Surface.ROTATION_270) {
matrix.postRotate(180f,(canvas.getWidth()) / 2,(canvas.getHeight()) / 2);
float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
matrix.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
}
if (mFpsMeter != null) {
mFpsMeter.measure();
mFpsMeter.draw(canvas, 20, 30);
}
getHolder().unlockCanvasAndPost(canvas);
}
}
}

其实主要的修改只是
在protected void deliverAndDrawFrame(CvCameraViewFrame frame) 函数里

if (bmpValid && mCacheBitmap != null) {
Canvas canvas = getHolder().lockCanvas();
if (canvas != null) {
canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);

函数段后面把原方法替换成

Matrix matrix = new Matrix(); // I rotate it with minimal process
matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,(canvas.getHeight() - mCacheBitmap.getHeight()) / 2);
matrix.postRotate(90f,(canvas.getWidth()) / 2,(canvas.getHeight()) / 2);
float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
matrix.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
canvas.drawBitmap(mCacheBitmap, matrix, new Paint());

即可
作为个强迫症患者,我增加了个判断语句来实现横竖屏都能正常的显示。但是就是这个原因发现了这个方法的bug,横屏时显示的图像是放大的。。。2333

看来我还需要再研究下,看看能不能修复横屏会放大的bug

但是要是在AndroidManifest.xml里锁定竖屏的话

android:screenOrientation="portrait">

就不出现横屏时的bug了,但是该方法fps降低的很明显,不过显示效果还是在可以接受的范围内的。。。
方法二效果图

《OpenCV on Android 开发 (4)竖屏预览图像问题解决方法-续》

《OpenCV on Android 开发 (4)竖屏预览图像问题解决方法-续》

不过仍然还是只有在把屏幕横着时人脸检测才能得到较好的结果,竖屏时虽然也能检测到,但是很不稳定23333

总的来说,我还是决定采用方法二的方法,来实现我下一步的目标。ヾ(o・ω・)ノ
留给我的时间不多了╮(╯﹏╰)╭

更新更新

作为强迫症患者,睡觉时想到了一个解决竖屏时不能人脸检测的方法,因为opencv要在横屏时才能得到较好的结果,那么我可以先把竖屏时得到的图像顺时针旋转90度,这样就和横屏时一样了,然后我在把得到识别绿框的图像逆时针旋转90度,再输出这样就能做到竖屏时实现人脸检测了。
所以我将MainActicity.java中的onCameraViewStarted和onCameraFrame()函数修改如下

@Override
public void onCameraViewStarted(int width, int height){
rgbaImage = new Mat(width, height, CvType.CV_8UC4);
grayscaleImage = new Mat(height, width, CvType.CV_8UC4);
Matlin = new Mat(width, height, CvType.CV_8UC4);
gMatlin = new Mat(width, height, CvType.CV_8UC4);
absoluteFaceSize = (int)(height * 0.2);
}
@Override
public void onCameraViewStopped(){
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame InputFrame) {
grayscaleImage = InputFrame.gray();
rgbaImage = InputFrame.rgba();
int rotation = openCvCameraView.getDisplay().getRotation();
//使前置的图像也是正的
if (camera_scene == CAMERA_FRONT) {
Core.flip(rgbaImage, rgbaImage, 1);
Core.flip(grayscaleImage, grayscaleImage, 1);
}
//MatOfRect faces = new MatOfRect();
if (rotation == Surface.ROTATION_0) {
MatOfRect faces = new MatOfRect();
Core.rotate(grayscaleImage, gMatlin, Core.ROTATE_90_CLOCKWISE);
Core.rotate(rgbaImage, Matlin, Core.ROTATE_90_CLOCKWISE);
if (cascadeClassifier != null) {
cascadeClassifier.detectMultiScale(gMatlin, faces, 1.1, 2, 2, new Size(absoluteFaceSize, absoluteFaceSize), new Size());
}
Rect[] faceArray = faces.toArray();
for (int i = 0; i Imgproc.rectangle(Matlin, faceArray[i].tl(), faceArray[i].br(), new Scalar(0, 255, 0, 255), 2);
Core.rotate(Matlin, rgbaImage, Core.ROTATE_90_COUNTERCLOCKWISE);
} else {
MatOfRect faces = new MatOfRect();
if (cascadeClassifier != null) {
cascadeClassifier.detectMultiScale(grayscaleImage, faces, 1.1, 2, 2, new Size(absoluteFaceSize, absoluteFaceSize), new Size());
}
Rect[] faceArray = faces.toArray();
for (int i = 0; i Imgproc.rectangle(rgbaImage, faceArray[i].tl(), faceArray[i].br(), new Scalar(0, 255, 0, 255), 2);
}
return rgbaImage;
}

最后,经过我的修改显示效果如下:
竖屏后置

《OpenCV on Android 开发 (4)竖屏预览图像问题解决方法-续》

竖屏前置

《OpenCV on Android 开发 (4)竖屏预览图像问题解决方法-续》

识别效果还不错,就是侧脸的话,识别不出来。还有一个问题就是现在横屏时无法检测人脸了,我想可能是因为我锁定为了竖屏模式,导致int rotation = openCvCameraView.getDisplay().getRotation()放回的一致都是Surface.ROTATION_0使得我的其他方法不能实现。
为此,我不锁定竖屏,对AndroidManifest.xml修改

android:screenOrientation="fullSensor">

修改MainActivity.java,加入完整的if判断语句,我试过使用switch来判断但是fps会降的很低,有很明显的卡顿感

MatOfRect faces = new MatOfRect();
if (rotation == Surface.ROTATION_0) {
Core.rotate(grayscaleImage, gMatlin, Core.ROTATE_90_CLOCKWISE);
Core.rotate(rgbaImage, Matlin, Core.ROTATE_90_CLOCKWISE);
if (cascadeClassifier != null) {
cascadeClassifier.detectMultiScale(gMatlin, faces, 1.1, 2, 2, new Size(absoluteFaceSize, absoluteFaceSize), new Size());
}
Rect[] faceArray = faces.toArray();
for (int i = 0; i Imgproc.rectangle(Matlin, faceArray[i].tl(), faceArray[i].br(), new Scalar(0, 255, 0, 255), 2);
Core.rotate(Matlin, rgbaImage, Core.ROTATE_90_COUNTERCLOCKWISE);
} else if (rotation == Surface.ROTATION_90) {
if (cascadeClassifier != null) {
cascadeClassifier.detectMultiScale(grayscaleImage, faces, 1.1, 2, 2, new Size(absoluteFaceSize, absoluteFaceSize), new Size());
}
Rect[] faceArray = faces.toArray();
for (int i = 0; i Imgproc.rectangle(rgbaImage, faceArray[i].tl(), faceArray[i].br(), new Scalar(0, 255, 0, 255), 2);
} else if (rotation == Surface.ROTATION_180) {
Core.rotate(grayscaleImage, gMatlin, Core.ROTATE_90_COUNTERCLOCKWISE);
Core.rotate(rgbaImage, Matlin, Core.ROTATE_90_COUNTERCLOCKWISE);
if (cascadeClassifier != null) {
cascadeClassifier.detectMultiScale(gMatlin, faces, 1.1, 2, 2, new Size(absoluteFaceSize, absoluteFaceSize), new Size());
}
Rect[] faceArray = faces.toArray();
for (int i = 0; i Imgproc.rectangle(Matlin, faceArray[i].tl(), faceArray[i].br(), new Scalar(0, 255, 0, 255), 2);
Core.rotate(Matlin, rgbaImage, Core.ROTATE_90_CLOCKWISE);
} else if (rotation == Surface.ROTATION_270) {
Core.rotate(grayscaleImage, gMatlin, Core.ROTATE_180);
Core.rotate(rgbaImage, Matlin, Core.ROTATE_180);
if (cascadeClassifier != null) {
cascadeClassifier.detectMultiScale(gMatlin, faces, 1.1, 2, 2, new Size(absoluteFaceSize, absoluteFaceSize), new Size());
}
Rect[] faceArray = faces.toArray();
for (int i = 0; i Imgproc.rectangle(Matlin, faceArray[i].tl(), faceArray[i].br(), new Scalar(0, 255, 0, 255), 2);
Core.rotate(Matlin, rgbaImage, Core.ROTATE_180);
}

在CameraBridgeViewBase.java里的deliverAndDrawFrame()

if (bmpValid && mCacheBitmap != null) {
Canvas canvas = getHolder().lockCanvas();
if (canvas != null) {
canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);

后面的片段修改为

Matrix matrix = new Matrix(); // I rotate it with minimal process
float portraitscale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
float landscapscale = 1f;
if (getDisplay().getRotation() == Surface.ROTATION_0) {
matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,(canvas.getHeight() - mCacheBitmap.getHeight()) / 2);
matrix.postRotate(90f,(canvas.getWidth()) / 2,(canvas.getHeight()) / 2);
//float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
//matrix.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
matrix.postScale(portraitscale, portraitscale, canvas.getWidth()/2 , canvas.getHeight()/2 );
canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
} else if (getDisplay().getRotation() == Surface.ROTATION_90) {
matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,(canvas.getHeight() - mCacheBitmap.getHeight()) / 2);
//float scale = 1f;
//matrix.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
matrix.postScale(landscapscale, landscapscale, canvas.getWidth()/2 , canvas.getHeight()/2 );
canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
} else if (getDisplay().getRotation() == Surface.ROTATION_180) {
matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,(canvas.getHeight() - mCacheBitmap.getHeight()) / 2);
matrix.postRotate(270f,(canvas.getWidth()) / 2,(canvas.getHeight()) / 2);
//float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
//matrix.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
matrix.postScale(portraitscale, portraitscale, canvas.getWidth()/2 , canvas.getHeight()/2 );
canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
} else if (getDisplay().getRotation() == Surface.ROTATION_270) {
matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,(canvas.getHeight() - mCacheBitmap.getHeight()) / 2);
matrix.postRotate(180f,(canvas.getWidth()) / 2,(canvas.getHeight()) / 2);
//float scale = 1f;
//matrix.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
matrix.postScale(landscapscale, landscapscale, canvas.getWidth()/2 , canvas.getHeight()/2 );
canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
}

将横屏时的float scale 设置为1就能解决前面出现的横屏放大的比例不对的问题,该段我也尝试过换成switch语句但是同样会有很卡顿的感觉,原因不明,可能这个是编译switch时自身的问题???
做完上述修改后,横竖屏就都能进行人脸检测了,但是当旋转270度时,即倒着横屏时会有很明显的卡顿感。。。
不管了,反正一般锁定竖屏模式使用就好了。。。
剩下的工作就是提高检测的准确率,实现侧脸检测和人眼检测了


推荐阅读
  • 本文介绍了在CentOS 6.4系统中更新源地址的方法,包括备份现有源文件、下载163源、修改文件名、更新列表和系统,并提供了相应的命令。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • imx6ull开发板驱动MT7601U无线网卡的方法和步骤详解
    本文详细介绍了在imx6ull开发板上驱动MT7601U无线网卡的方法和步骤。首先介绍了开发环境和硬件平台,然后说明了MT7601U驱动已经集成在linux内核的linux-4.x.x/drivers/net/wireless/mediatek/mt7601u文件中。接着介绍了移植mt7601u驱动的过程,包括编译内核和配置设备驱动。最后,列举了关键词和相关信息供读者参考。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • 本文讨论了如何使用Web.Config进行自定义配置节的配置转换。作者提到,他将msbuild设置为详细模式,但转换却忽略了带有替换转换的自定义部分的存在。 ... [详细]
  • 如何利用 Myflash 解析 binlog ?
    本文主要介绍了对Myflash的测试,从准备测试环境到利用Myflash解析binl ... [详细]
  • 本文整理了Java中com.evernote.android.job.JobRequest.getTransientExtras()方法的一些代码示例,展示了 ... [详细]
  • 本文介绍了在Ubuntu系统中清理残余配置文件和无用内容的方法,包括清理残余配置文件、清理下载缓存包、清理不再需要的包、清理无用的语言文件和清理无用的翻译内容。通过这些清理操作可以节省硬盘空间,提高系统的运行效率。 ... [详细]
  • 本文详细介绍了GetModuleFileName函数的用法,该函数可以用于获取当前模块所在的路径,方便进行文件操作和读取配置信息。文章通过示例代码和详细的解释,帮助读者理解和使用该函数。同时,还提供了相关的API函数声明和说明。 ... [详细]
  • 本文介绍了5个基本Linux命令行工具的现代化替代品,包括du、top和ncdu。这些替代品在功能上进行了改进,提高了可用性,并且适用于现代化系统。其中,ncdu是du的替代品,它提供了与du类似的结果,但在一个基于curses的交互式界面中,重点关注占用磁盘空间较多的目录。 ... [详细]
  • Spring框架《一》简介
    Spring框架《一》1.Spring概述1.1简介1.2Spring模板二、IOC容器和Bean1.IOC和DI简介2.三种通过类型获取bean3.给bean的属性赋值3.1依赖 ... [详细]
  • php缓存ri,浅析ThinkPHP缓存之快速缓存(F方法)和动态缓存(S方法)(日常整理)
    thinkPHP的F方法只能用于缓存简单数据类型,不支持有效期和缓存对象。S()缓存方法支持有效期,又称动态缓存方法。本文是小编日常整理有关thinkp ... [详细]
  • 本文介绍了在PostgreSQL中批量导入数据时的优化方法。包括使用unlogged表、删除重建索引、删除重建外键、禁用触发器、使用COPY方法、批量插入等。同时还提到了一些参数优化的注意事项,如设置effective_cache_size、shared_buffer等,并强调了在导入大量数据后使用analyze命令重新收集统计信息的重要性。 ... [详细]
  • 本文分享了一位Android开发者多年来对于Android开发所需掌握的技能的笔记,包括架构师基础、高级UI开源框架、Android Framework开发、性能优化、音视频精编源码解析、Flutter学习进阶、微信小程序开发以及百大框架源码解读等方面的知识。文章强调了技术栈和布局的重要性,鼓励开发者做好学习规划和技术布局,以提升自己的竞争力和市场价值。 ... [详细]
  • 程序员如何选择机械键盘轴体?红轴和茶轴对比
    本文介绍了程序员如何选择机械键盘轴体,特别是红轴和茶轴的对比。同时还介绍了U盘安装Linux镜像的步骤,以及在Linux系统中安装软件的命令行操作。此外,还介绍了nodejs和npm的安装方法,以及在VSCode中安装和配置常用插件的方法。最后,还介绍了如何在GitHub上配置SSH密钥和git的基本配置。 ... [详细]
author-avatar
一粒小小无名砂_741
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有