OpenCV4Android之运用手机摄像头获取Canny边缘
Posted 微卡智享
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV4Android之运用手机摄像头获取Canny边缘相关的知识,希望对你有一定的参考价值。
在图像中获取主要影响的边缘用处比较广泛,这样就用到了Canny边缘的效果
Canny边缘的提取流程
高斯模糊
梯度计算
非最大信息压制
高低阈值链接
显示
还是用我们的Demo
不过这次我们加上新的东西,因为正好学习了OpenCV里面调用手机里的摄像头功能获取图片信息,花了整整一天算是入了个门吧.
首先在原来的MainActivity里面增加一个按钮
对应增加的事件
照相机页面
首先我们增加了一个opencvcarema.xml页面和一个OpenCVCarema的activity
opencvcarema.xml
这里面可以直接增加org.opencv.android.JavaCameraView,然后又在下方增加了一个按钮
OpenCvCarema
这个class我们需要继承Activity并且引用了
CameraBridgeViewBase.CvCameraViewListener2
里面几个的方法
按钮获取当前图像提取边缘
里面就是根据获取的图像创建一个bitbmp的图像,然后把获取的图像mRgbaF先用高斯模糊后,再转成灰度图,然后再运用Canny边缘提取出新的Mat,再将提取完的转回为bmp图像,因为我们需要返回数据,所以返回时把bmp图像转为byte[]发送回去,原来我们的MainActivity里的onActivityResult里面增加了返回照相机数据
照相机获取图像时加入了横竖屏的判断
在OpenCV调用照相机时,默认的都是横屏,所以我们竖屏手机打开时会是个90的旋转样子,非常不友好,经常查找资料和多次测试,我自己修改了onCameraFrame这个函数
标红的这块是就是判断当前手机屏幕是横屏和竖屏,通过宽度和高度进行对比,宽度大于高度时就是横屏,小于时就是竖屏.
如果是竖屏我们就执行以下步骤:
先将水平图像转为垂直.
转完后的图像再缩放为原来的大小.
再将图像沿Y轴进行翻转(如果不翻转的话看到的图像是左右互调的)
下面的我们的视频效果,最后有OpenCVCarema.java整个类的代码
下面的整个OpenCvCarema.java的类
package dem.vaccae.opencvdemo;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Camera;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.support.annotation.Nullable;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.Utils;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import java.io.ByteArrayOutputStream;
/**
* Created by Administrator on 2018-01-01.
*/
public class OpenCvCarema extends Activity implements CameraBridgeViewBase.CvCameraViewListener2 {
private static final String TAG = "OpenCvCameraActivity";
static {
OpenCVLoader.initDebug();
}
private Mat mRgba;
private Mat mRgbaF;
private Mat mFlipRgba;
private Camera mCamera;
private CameraBridgeViewBase mOpenCvCameraView;
private Button btnCanny;
//是否按下按键
private boolean isbtn = false;
private Bitmap bmp;
public OpenCvCarema() {
Log.i(TAG, "Instantiated new " + this.getClass());
}
@Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "called onCreate");
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.opencvcarema);
mOpenCvCameraView = findViewById(R.id.opencvcaremaview);
mOpenCvCameraView.enableView();
mOpenCvCameraView.setCvCameraViewListener(this);
//后置摄像头
mOpenCvCameraView.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_BACK);
btnCanny = findViewById(R.id.btnCanny);
btnCanny.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
isbtn = true;
bmp = Bitmap.createBitmap(mRgbaF.width(), mRgbaF.height(), Bitmap.Config.ARGB_8888);
//先进行高斯模糊
Imgproc.GaussianBlur(mRgbaF, mRgbaF, new Size(3, 3), 0, 0, Imgproc.BORDER_DEFAULT);
//先改为灰度图像
Imgproc.cvtColor(mRgbaF, mRgbaF, Imgproc.COLOR_BGRA2GRAY);
//t代表低阈值,高阈值一般是低阈值的2倍,所以threshold用t*2或t*3即可,
//apertureSize这里输入3,就是代表3*3的眼膜
//L2gradient这个是对精度要求,如果是true精度会高,但是会慢,所以一般来说我们都用false就可以了
Imgproc.Canny(mRgbaF, mFlipRgba, 112, 112 * 2, 3, false);
Utils.matToBitmap(mFlipRgba, bmp);
//将图片压缩成byte[]传递回去
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] bitmapByte = baos.toByteArray();
Intent rtnintent = new Intent();
rtnintent.putExtra("bitmap", bitmapByte);
OpenCvCarema.this.setResult(Activity.RESULT_OK, rtnintent);
finish();
}
});
}
@Override
protected void onPause() {
super.onPause();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onDestroy() {
super.onDestroy();
mOpenCvCameraView.disableView();
}
@Override
public void onCameraViewStarted(int width, int height) {
mRgba = new Mat();
mRgbaF = new Mat();
mFlipRgba = new Mat();
}
@Override
public void onCameraViewStopped() {
mFlipRgba.release();
mRgbaF.release();
}
@Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
if (!isbtn) {
//注意
mRgba = inputFrame.rgba();
//获取屏幕宽和高用于判断是横屏还是竖屏
DisplayMetrics dm = getResources().getDisplayMetrics();
if (dm.widthPixels < dm.heightPixels) {
//转置函数,可以水平的图像变为垂直
Core.transpose(mRgba, mFlipRgba);
//将转置后的图像缩放为mRgbaF的大小
Imgproc.resize(mFlipRgba, mRgbaF, mRgba.size(), 0.0D, 0.0D, 0);
//flipCode>0将mRgbaF水平翻转(沿Y轴翻转)得到mRgba
Core.flip(mRgbaF, mRgbaF, 1);
} else {
mRgbaF = mRgba;
}
}
return mRgbaF;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
return true;
}
}
-END-
以上是关于OpenCV4Android之运用手机摄像头获取Canny边缘的主要内容,如果未能解决你的问题,请参考以下文章
Unity之手机键盘自定义输入栏位置适配&不同手机分辨率适配
Unity之手机键盘自定义输入栏位置适配&不同手机分辨率适配