Android通过OpenCV获取摄像头帧数据并在悬浮框显示
由于Android手机摄像头采集的原始帧默认是横屏格式的,所以我们需要都原始帧进行旋转等操作。有上一篇博文中的需求我们需要获取的帧数据格式为Mat类型,使用AndroidSDK自带的camera类采集我们还需要自己再转化为Mat类型,所以在这里就直接使用opencv4android 中的CameraBridgeViewBase与AndroidSDK中CameraView类结合起来采集图片帧。
图片帧旋转
图片帧旋转主要是获取手机当前的姿态,然后根据当前角度,选择旋转角度从而达到正常的显示效果。
class MyOrientationDetector extends OrientationEventListener {
public MyOrientationDetector(Context context) {
super(context);
}
@Override
public void onOrientationChanged(int orientation) {
if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
return; // 手机平放时,检测不到有效的角度
}
// 只检测是否有四个角度的改变
if (orientation > 350 || orientation < 10) { // 0度
orientation = 0;
angle = 0f;
orient = 0f;
} else if (orientation > 80 && orientation < 100) { // 90度
orientation = 90;
angle = 270f;
// angle = 90f;
orient = 90f;
} else if (orientation > 170 && orientation < 190) { // 180度
orientation = 180;
angle = 180f;
// angle = 270f;
orient = 180f;
} else if (orientation > 260 && orientation < 280) { // 270度
orientation = 270;
angle = 90f;
// angle = 90f;
orient = 270f;
} else {
return;
}
Log.d("CameraService", orientation + "," + angle + "," + orient);
}
}
frameMat = inputFrame.rgba(); // 获取摄像头前景图像
if (orient == 0) {// 竖放
org.opencv.core.Core.flip(frameMat.t(), frameMat, 0);
} else if (orient == 90) {
org.opencv.core.Core.flip(frameMat, frameMat, -1);
} else if (orient == 180) {
org.opencv.core.Core.flip(frameMat.t(), frameMat, 1);
} else if (orient == 270) {
}
mOpenCvCameraView.setRotate(angle);
悬浮窗显示
将经过旋转后的图片通过缩放尺寸大小后显示到悬浮窗中。
Size dsize = new Size(frameMat.width() * 0.25, frameMat.height() * 0.25); // 设置新图片的大小
Imgproc.resize(frameMat, frameMat,dsize);//调用Imgproc的Resize方法,进行图片缩放
创建悬浮窗
private void createFloatView()
{
wmParams = new WindowManager.LayoutParams();
//获取WindowManagerImpl.CompatModeWrapper
mWindowManager = (WindowManager)getApplication().getSystemService(getApplication().WINDOW_SERVICE);
//设置window type
wmParams.type = LayoutParams.TYPE_PHONE;
//设置图片格式,效果为背景透明
wmParams.format = PixelFormat.RGBA_8888;
//设置浮动窗口不可聚焦(实现操作除浮动窗口外的其他可见窗口的操作)
wmParams.flags = LayoutParams.FLAG_NOT_FOCUSABLE;
//调整悬浮窗显示的停靠位置为左侧置顶
wmParams.gravity = Gravity.LEFT | Gravity.TOP;
// 以屏幕左上角为原点,设置x、y初始值
wmParams.x = 300;
wmParams.y = 500;
// 设置悬浮窗口长宽数据
wmParams.width = 120;
wmParams.height = 160;
LayoutInflater inflater = LayoutInflater.from(getApplication());
//获取浮动窗口视图所在布局
mFloatLayout = (FrameLayout) inflater.inflate(R.layout.float_layout, null);
//添加mFloatLayout
mWindowManager.addView(mFloatLayout, wmParams);
mOpenCvCameraView = (BaseView) mFloatLayout.findViewById(R.id.CameraView);
mFloatLayout.measure(View.MeasureSpec.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED), View.MeasureSpec
.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
//设置监听浮动窗口的触摸移动
mFloatLayout.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
wmParams.x = (int) event.getRawX() - mFloatLayout.getMeasuredWidth()/2;
wmParams.y = (int) event.getRawY() - mFloatLayout.getMeasuredHeight()/2;
mWindowManager.updateViewLayout(mFloatLayout, wmParams);
return false;
}
});
}