OpenCV for Android——实时图像处理之表格切割_Android

 






灰化、
Canny边缘检测、
Hist直方图计算、
Sobel边缘检测、
SEPIA(色调变换)、
ZOOM放大镜、
PIXELIZE像素化





》图像信息获取保存、处理和显示:

1.在OpenCV中一般都是使用Mat类型来存储图像等矩阵信息,
所以我们可以声明一个Mat对象用来作为实时帧图像的缓存对象:

 //缓存相机每帧输入的数据  
private Mat mRgba; 

对象实例化以及基本属性的设置,包括:长度、宽度和图像类型标志:

 public void onCameraViewStarted(int width, int height) {  
    // TODO Auto-generated method stub  
    mRgba = new Mat(height, width, CvType.CV_8UC4);  
}  

对象赋值

 
 /** 
 * 图像处理都写在此处 
 */  
@Override  
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {  
    switch (Cur_State) {  
    case 1:  
        //灰化处理  
        Imgproc.cvtColor(inputFrame.gray(), mRgba, Imgproc.COLOR_GRAY2RGBA,4);  
        break;  
    default:  
        //显示原图  
        mRgba = inputFrame.rgba();  
        break;  
    }  
    //返回处理后的结果数据  
    return mRgba;  
}  

由于用对象存储图像数据的话,
数据会保存到内存中,所以结束的时候需要进行数据释放,
不然可能导致崩溃:

  @Override  
public void onCameraViewStopped() {  
    // TODO Auto-generated method stub  
    mRgba.release();  
}  
 private Mat mRgba,mTmp;  ;


//对象实例化及基本属性的设置,包括长度、宽度和图像类型标志
    public void onCameraViewStarted(int width, int height) {
        Log.e("Mat","...............4...............");
        mRgba = new Mat(height, width, CvType.CV_8UC4);


        ///
        mTmp = new Mat(height, width, CvType.CV_8UC4);
    }



 //Canny边缘检测  ///二值化
        mRgba = inputFrame.rgba();
        Imgproc.Canny(inputFrame.gray(), mTmp, 80, 100);
        Imgproc.cvtColor(mTmp, mRgba, Imgproc.COLOR_GRAY2RGBA, 4);


OpenCV for Android——实时图像处理之表格切割_Android_02

 package com.e.opcv;
import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraActivity;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.Utils;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

import java.io.File;
import java.util.Collections;
import java.util.Date;
import java.util.List;


public class MainActivity extends  CameraActivity implements CvCameraViewListener2{
    private static final String TAG = "OCVSample::Activity";
    //opencv接口标志


    /**
     * CV相机
     */
    private CameraBridgeViewBase mOpenCvCameraView;
    //缓存相机每帧输入的数据



    private Mat mRgba,mTmp;  ;
    private Button button;

    private boolean              mIsJavaCamera = true;
    private MenuItem             mItemSwitchCamera = null;


/**
 * 加载OpenCV的回调
 * 通过OpenCV管理Android服务,初始化OpenCV
 */
    private BaseLoaderCallback mLoaderCallback ;



    public MainActivity() {
        Log.i(TAG, "Instantiated new " + this.getClass());
    }


    Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg){
            super.handleMessage(msg);
            if(msg.what == 1){
                button.performClick();
            }
        }
    };


    /** Called when the activity is first created. */
    @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.activity_main);


        // //初始化并设置预览部件  // 初始化CV相机
        mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.tutorial1_activity_java_surface_view);

        mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
        // 设置相机监听
        mOpenCvCameraView.setCvCameraViewListener(this);




        //拍照按键
        button = (Button) findViewById(R.id.deal_btn);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mRgba != null) {
                    if(!mRgba.empty()) {
                        Mat inter = new Mat(mRgba.width(), mRgba.height(), CvType.CV_8UC4);
                        Log.e("Mat","...............1...............");
                        //将四通道的RGBA转为三通道的BGR,重要!!
                        Imgproc.cvtColor(mRgba, inter, Imgproc.COLOR_RGBA2BGR);
                        Log.e("Mat","...............2...............");
                        File sdDir = null;
                        //判断是否存在机身内存
                        boolean sdCardExist = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
                        if(sdCardExist) {
                            //获得机身储存根目录
                            sdDir = Environment.getExternalStorageDirectory();
                            Log.e("Mat","...............3...............");
                        }
                        //将拍摄准确时间作为文件名
                        java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
                        String filename = sdf.format(new Date());
                        String savepath=sdDir + "/Pictures/OpenCV/";
                        File f=new File(savepath);
                        if(!f.exists()){
                            f.mkdirs();
                        }
                        String filePath = sdDir + "/Pictures/OpenCV/" + filename + ".png";
                        Log.e("Mat","..............."+filePath+"...............");
                        //将转化后的BGR矩阵内容写入到文件中
                        Imgcodecs.imwrite(filePath, inter);
                        Toast.makeText(MainActivity.this, "图片保存到: "+ filePath, Toast.LENGTH_SHORT).show();
                    }
                }
            }
        });

        // moveTaskToBack(true);
//        new test().start();



        // 连接到OpenCV的回调
        mLoaderCallback   = new BaseLoaderCallback(this){
            @Override
            public void onManagerConnected(int status) {
                switch (status) {
                    case LoaderCallbackInterface.SUCCESS:
                    {
                        Log.i(TAG, "OpenCV loaded successfully");
                        mOpenCvCameraView.enableView();
                    } break;
                    default:
                    {
                        super.onManagerConnected(status);
                    } break;
                }
            }
        };




    }



    private class test extends Thread{
        @Override
        public void run() {
            super.run();
            while (true){
                try {
                    Thread.sleep(2000);
                    Log.e("begin","kaishi.........");

                    Message message = new Message();
                    message.what = 1;
                    handler.sendMessage(message);
                }catch (Exception e){
                    Log.e("error",e.getMessage());
                }
            }
        }
    }






    @Override
    public void onPause()
    {
        super.onPause();
        if (mOpenCvCameraView != null)
            mOpenCvCameraView.disableView();
    }

    @Override
    public void onResume()
    {




        // 界面加载完成的时候向OpenCV的连接回调发送连接成功的信号
        if (!OpenCVLoader.initDebug()) {
            Log.d(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization");
            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback);
        } else {
            Log.d(TAG, "OpenCV library found inside package. Using it!");
            mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
        }

        super.onResume();
    }

    @Override
    public List<? extends CameraBridgeViewBase> getCameraViewList() {
        return Collections.singletonList(mOpenCvCameraView);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return false;
    }

    public void onDestroy() {
        super.onDestroy();
        if (mOpenCvCameraView != null)
            mOpenCvCameraView.disableView();
    }


    //对象实例化及基本属性的设置,包括长度、宽度和图像类型标志
    public void onCameraViewStarted(int width, int height) {
        Log.e("Mat","...............4...............");
        mRgba = new Mat(height, width, CvType.CV_8UC4);


        ///
        mTmp = new Mat(height, width, CvType.CV_8UC4);
    }




    /**图像处理都写在这里!!!**/
    public Mat onCameraFrame(CvCameraViewFrame inputFrame) {


       //灰度
        Imgproc.cvtColor(inputFrame.gray(), mRgba, Imgproc.COLOR_GRAY2RGBA,4);

        //Canny边缘检测  ///二值化
        mRgba = inputFrame.rgba();
        Imgproc.Canny(inputFrame.gray(), mTmp, 80, 100);
        Imgproc.cvtColor(mTmp, mRgba, Imgproc.COLOR_GRAY2RGBA, 4);


//        mRgba = inputFrame.rgba();  //一定要有!!!不然数据保存不进MAT中!!!
        //直接返回输入视频预览图的RGB数据并存放在Mat数据中
        Log.e("Mat","...............5...............");
        return mRgba;

    }

    @Override
    public void onPointerCaptureChanged(boolean hasCapture) {

    }


    //结束时释放
    public void onCameraViewStopped() {

        Log.e("Mat","...............6...............");
        mRgba.release();
        // mTmp.release();
    }







    }

https://pqpo.me/2017/09/11/opencv-border-recognition/

》》形态学处理保留直线 霍夫直线检测

  • 霍夫直线检测的作用——计算得到输入图像
    (一般是二值化的边缘检测结果图像)中包含的所有直线的数目与位置
 在取得图像边缘的基础上,
对一些特定的几何形状边缘,
如直线、圆,通过图像霍夫变换把图像从平面坐标空间变换到霍夫坐标空间,
就可以通过求取霍夫空间的局部极大值方法
(其实就是霍夫空间中的曲线交集点),
得到极坐标空间对应参数方程中直线的两个参数(r,θ),
从而计算得到边缘图像中的所有直线(基于平面坐标)的数目与位置。
 

https://vimsky.com/examples/detail/java-method-org.opencv.imgproc.Imgproc.HoughLinesP.html
(…霍夫直线检测 Imgproc.HoughLinesP )

http://www.what21.com/sys/view/media_img_1536741795822.html
( 图形图像上的拉普拉斯平滑(Imgproc.line) )

数学形态学中运算

有 膨胀(或扩张)、腐蚀(或侵蚀)、开启、闭合、骨架抽取、极线腐蚀、击中击不中变换、Top-hat变换、颗粒分析、流域变换、形态学梯度等,
其中腐蚀与扩张就是我们今天所有讲的要点。
opencv中对腐蚀和扩张有相对的函数去实现,多用于图像的取噪、分割出独立的图像元素,在图像中连接相邻的元素、寻找图像中明显的极大值或极小值区、求图像的梯度。
————————————————( android使用opencv图片腐蚀与扩张 )
(膨胀与腐蚀)

OpenCV for Android——实时图像处理之表格切割_Android_03

 package com.e.opcv;
import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraActivity;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.Utils;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

import java.io.File;
import java.util.Collections;
import java.util.Date;
import java.util.List;


public class MainActivity extends  CameraActivity implements CvCameraViewListener2{
    private static final String TAG = "OCVSample::Activity";
    //opencv接口标志


    /**
     * CV相机
     */
    private CameraBridgeViewBase mOpenCvCameraView;
    //缓存相机每帧输入的数据



    private Mat mRgba,mTmp;
    private Button button;

    private boolean              mIsJavaCamera = true;
    private MenuItem             mItemSwitchCamera = null;


/**
 * 加载OpenCV的回调
 * 通过OpenCV管理Android服务,初始化OpenCV
 */
    private BaseLoaderCallback mLoaderCallback ;



    public MainActivity() {
        Log.i(TAG, "Instantiated new " + this.getClass());
    }


    Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg){
            super.handleMessage(msg);
            if(msg.what == 1){
                button.performClick();
            }
        }
    };


    /** Called when the activity is first created. */
    @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.activity_main);


        // //初始化并设置预览部件  // 初始化CV相机
        mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.tutorial1_activity_java_surface_view);

        mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
        // 设置相机监听
        mOpenCvCameraView.setCvCameraViewListener(this);




        //拍照按键
        button = (Button) findViewById(R.id.deal_btn);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mRgba != null) {
                    if(!mRgba.empty()) {
                        Mat inter = new Mat(mRgba.width(), mRgba.height(), CvType.CV_8UC4);
                        Log.e("Mat","...............1...............");
                        //将四通道的RGBA转为三通道的BGR,重要!!
                        Imgproc.cvtColor(mRgba, inter, Imgproc.COLOR_RGBA2BGR);
                        Log.e("Mat","...............2...............");
                        File sdDir = null;
                        //判断是否存在机身内存
                        boolean sdCardExist = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
                        if(sdCardExist) {
                            //获得机身储存根目录
                            sdDir = Environment.getExternalStorageDirectory();
                            Log.e("Mat","...............3...............");
                        }
                        //将拍摄准确时间作为文件名
                        java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
                        String filename = sdf.format(new Date());
                        String savepath=sdDir + "/Pictures/OpenCV/";
                        File f=new File(savepath);
                        if(!f.exists()){
                            f.mkdirs();
                        }
                        String filePath = sdDir + "/Pictures/OpenCV/" + filename + ".png";
                        Log.e("Mat","..............."+filePath+"...............");
                        //将转化后的BGR矩阵内容写入到文件中
                        Imgcodecs.imwrite(filePath, inter);
                        Toast.makeText(MainActivity.this, "图片保存到: "+ filePath, Toast.LENGTH_SHORT).show();
                    }
                }
            }
        });

        // moveTaskToBack(true);
//        new test().start();



        // 连接到OpenCV的回调
        mLoaderCallback   = new BaseLoaderCallback(this){
            @Override
            public void onManagerConnected(int status) {
                switch (status) {
                    case LoaderCallbackInterface.SUCCESS:
                    {
                        Log.i(TAG, "OpenCV loaded successfully");
                        mOpenCvCameraView.enableView();
                    } break;
                    default:
                    {
                        super.onManagerConnected(status);
                    } break;
                }
            }
        };




    }



    private class test extends Thread{
        @Override
        public void run() {
            super.run();
            while (true){
                try {
                    Thread.sleep(2000);
                    Log.e("begin","kaishi.........");

                    Message message = new Message();
                    message.what = 1;
                    handler.sendMessage(message);
                }catch (Exception e){
                    Log.e("error",e.getMessage());
                }
            }
        }
    }






    @Override
    public void onPause()
    {
        super.onPause();
        if (mOpenCvCameraView != null)
            mOpenCvCameraView.disableView();
    }

    @Override
    public void onResume()
    {




        // 界面加载完成的时候向OpenCV的连接回调发送连接成功的信号
        if (!OpenCVLoader.initDebug()) {
            Log.d(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization");
            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback);
        } else {
            Log.d(TAG, "OpenCV library found inside package. Using it!");
            mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
        }

        super.onResume();
    }

    @Override
    public List<? extends CameraBridgeViewBase> getCameraViewList() {
        return Collections.singletonList(mOpenCvCameraView);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return false;
    }

    public void onDestroy() {
        super.onDestroy();
        if (mOpenCvCameraView != null)
            mOpenCvCameraView.disableView();
    }


    //对象实例化及基本属性的设置,包括长度、宽度和图像类型标志
    public void onCameraViewStarted(int width, int height) {
        Log.e("Mat","...............4...............");
        mRgba = new Mat(height, width, CvType.CV_8UC4);


        ///
        mTmp = new Mat(height, width, CvType.CV_8UC4);
    }




    /**图像处理都写在这里!!!**/
    public Mat onCameraFrame(CvCameraViewFrame inputFrame) {


       //灰度
        Imgproc.cvtColor(inputFrame.gray(), mRgba, Imgproc.COLOR_GRAY2RGBA,4);

        //Canny边缘检测  ///二值化
        mRgba = inputFrame.rgba();
        Imgproc.Canny(inputFrame.gray(), mTmp, 80, 100);
        Imgproc.cvtColor(mTmp, mRgba, Imgproc.COLOR_GRAY2RGBA, 4);



        Mat dilateImage = mRgba.clone();
        Mat erodeImage = mRgba.clone();
        Mat element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3,3));

        //膨胀
        Imgproc.dilate(mRgba, dilateImage, element, new Point(-1, -1), 1);
        //腐蚀
        Imgproc.erode(mRgba, erodeImage, element, new Point(-1, -1), 1);
        



//        mRgba = inputFrame.rgba();  //一定要有!!!不然数据保存不进MAT中!!!
        //直接返回输入视频预览图的RGB数据并存放在Mat数据中
        Log.e("Mat","...............5...............");
        return mRgba;

    }

    @Override
    public void onPointerCaptureChanged(boolean hasCapture) {

    }


    //结束时释放
    public void onCameraViewStopped() {

        Log.e("Mat","...............6...............");
        mRgba.release();
        // mTmp.release();
    }







    }