OpenCV4Android之运用手机摄像头获取Canny边缘

在图像中获取主要影响的边缘用处比较广泛,这样就用到了Canny边缘的效果

Canny边缘的提取流程

  1. 高斯模糊

  2. 梯度计算

  3. 非最大信息压制

  4. 高低阈值链接

  5. 显示

还是用我们的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-

长按下方二维码关注

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vaccae

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值