OpenCV学习笔记(七)—— OpenCV for Android实时图像处理

在上篇中我们已经实现了相机打开和实时图像信息的获取,那么接下来我们可以尝试在获取的图像信息进行一些处理,然后实时显示出来,在这里我们要完成的的几种处理:

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

一、修改布局界面:

由于这里我们需要切换不同的图像处理模式,所以这里我们需要在界面上放置一个按钮,我们可以放置很多个按钮,每个按钮对应一种处理模式,但是这里我们也可以只放置一个按钮,每次点击按钮就切换一次,循环切换模式:

activity_main.xml文件:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:opencv="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <org.opencv.android.JavaCameraView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/camera_view"
        opencv:show_fps="true"
        opencv:camera_id="any"/>

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:gravity="bottom|center_horizontal">
        <Button
            android:id="@+id/deal_btn"
            android:layout_width="100dp"
            android:layout_height="40dp"
            android:layout_marginBottom="20dp"
            android:text="处理"/>
    </RelativeLayout>

</FrameLayout>

查看预览图:

二、获取按钮组件并监听按钮点击:

1.声明一个Button对象用于绑定上面的按钮组件和一个状态标志位用于存储当前状态:

        //按钮组件
	private Button mButton;
	//当前处理状态
	private static int Cur_State = 0;

2.在OnCreate中绑定按钮和按钮点击监听:

mButton = (Button) findViewById(R.id.deal_btn);
mButton.setOnClickListener(new OnClickListener(){
	@Override
	public void onClick(View v) {
		if(Cur_State<8){
			//切换状态
			Cur_State ++;
		}else{
			//恢复初始状态
			Cur_State = 0;
		}
	}

});

这里的状态标志位Cur_State与图像处理的每个类型对应,0对应默认状态,也就是显示原图,1-7分别对应:灰化、Canny边缘检测、Hist直方图计算、Sobel边缘检测、SEPIA(色调变换)、ZOOM放大镜、PIXELIZE像素化

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

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

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

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

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

3.对象赋值,这里只对原图和灰化两种情况进行了处理,其他的处理后续再添加:

        /**
	 * 图像处理都写在此处
	 */
	@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;
	}

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

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

5.运行查看效果:

正常模式:

灰化图:

四、其他处理及结果:

在以上的例子中我们已经完成了预览图的灰化处理,那么接下来我们把其他处理都添加到代码中,查看效果。由于在2.x版本中使用到的部分方法已经发生了变化,如:在OpenCV 3.1.0中org.opencv.core.Core类中的方法line和rectangle都已失效,可以用org.opencv.imgproc.Imgproc中的line和rectangle来代替:

1.
MainActivity.java源码:

package com.linsh.opencv_test;

import java.util.Arrays;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfFloat;
import org.opencv.core.MatOfInt;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;

import android.R.string;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.view.View;
import android.view.View.OnClickListener;

public class MainActivity extends Activity implements CvCameraViewListener2{
	private String TAG = "OpenCV_Test";
	//OpenCV的相机接口
	private CameraBridgeViewBase mCVCamera;
	//缓存相机每帧输入的数据
	private Mat mRgba,mTmp;
	//按钮组件
	private Button mButton;
	//当前处理状态
	private static int Cur_State = 0;

	private Size mSize0;
    private Mat mIntermediateMat;
    private MatOfInt mChannels[];
    private MatOfInt mHistSize;
    private int mHistSizeNum = 25;
    private Mat mMat0;
    private float[] mBuff;
    private MatOfFloat mRanges;
    private Point mP1;
    private Point mP2;
    private Scalar mColorsRGB[];
    private Scalar mColorsHue[];
    private Scalar mWhilte;
    private Mat mSepiaKernel;

	/**
	 * 通过OpenCV管理Android服务,异步初始化OpenCV
	 */
	BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
		@Override
		public void onManagerConnected(int status){
			switch (status) {
			case LoaderCallbackInterface.SUCCESS:
				Log.i(TAG,"OpenCV loaded successfully");
				mCVCamera.enableView();
				break;
			default:
				break;
			}
		}
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		mCVCamera = (CameraBridgeViewBase) findViewById(R.id.camera_view);
		mCVCamera.setCvCameraViewListener(this);

		mButton = (Button) findViewById(R.id.deal_btn);
		mButton.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View v) {
				if(Cur_State<8){
					//切换状态
					Cur_State ++;
				}else{
					//恢复初始状态
					Cur_State = 0;
				}
			}

		});
	}

	@Override
	public void onResume() {
		super.onResume();
		if (!OpenCVLoader.initDebug()) {
			Log.d(TAG,"OpenCV library not found!");
		} else {
			Log.d(TAG, "OpenCV library found inside package. Using it!");
			mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
		}
	};

	@Override
	public void onDestroy() {
		if(mCVCamera!=null){
			mCVCamera.disableView();
		}
	};

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

		mIntermediateMat = new Mat();
        mSize0 = new Size();
        mChannels = new MatOfInt[] { new MatOfInt(0), new MatOfInt(1), new MatOfInt(2) };
        mBuff = new float[mHistSizeNum];
        mHistSize = new MatOfInt(mHistSizeNum);
        mRanges = new MatOfFloat(0f, 256f);
        mMat0 = new Mat();
        mColorsRGB = new Scalar[] { new Scalar(200, 0, 0, 255), new Scalar(0, 200, 0, 255), new Scalar(0, 0, 200, 255) };
        mColorsHue = new Scalar[] {
                new Scalar(255, 0, 0, 255), new Scalar(255, 60, 0, 255), new Scalar(255, 120, 0, 255), new Scalar(255, 180, 0, 255), new Scalar(255, 240, 0, 255),
                new Scalar(215, 213, 0, 255), new Scalar(150, 255, 0, 255), new Scalar(85, 255, 0, 255), new Scalar(20, 255, 0, 255), new Scalar(0, 255, 30, 255),
                new Scalar(0, 255, 85, 255), new Scalar(0, 255, 150, 255), new Scalar(0, 255, 215, 255), new Scalar(0, 234, 255, 255), new Scalar(0, 170, 255, 255),
                new Scalar(0, 120, 255, 255), new Scalar(0, 60, 255, 255), new Scalar(0, 0, 255, 255), new Scalar(64, 0, 255, 255), new Scalar(120, 0, 255, 255),
                new Scalar(180, 0, 255, 255), new Scalar(255, 0, 255, 255), new Scalar(255, 0, 215, 255), new Scalar(255, 0, 85, 255), new Scalar(255, 0, 0, 255)
        };
        mWhilte = Scalar.all(255);
        mP1 = new Point();
        mP2 = new Point();

        // Fill sepia kernel
        mSepiaKernel = new Mat(4, 4, CvType.CV_32F);
        mSepiaKernel.put(0, 0, /* R */0.189f, 0.769f, 0.393f, 0f);
        mSepiaKernel.put(1, 0, /* G */0.168f, 0.686f, 0.349f, 0f);
        mSepiaKernel.put(2, 0, /* B */0.131f, 0.534f, 0.272f, 0f);
        mSepiaKernel.put(3, 0, /* A */0.000f, 0.000f, 0.000f, 1f);
	}

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

	/**
	 * 图像处理都写在此处
	 */
	@Override
	public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
		mRgba = inputFrame.rgba();
	    Size sizeRgba = mRgba.size();
	    int rows = (int) sizeRgba.height;
	    int cols = (int) sizeRgba.width;
	    Mat rgbaInnerWindow;

	    int left = cols / 8;
	    int top = rows / 8;

	    int width = cols * 3 / 4;
	    int height = rows * 3 / 4;

		switch (Cur_State) {
		case 1:
			//灰化处理
			Imgproc.cvtColor(inputFrame.gray(), mRgba, Imgproc.COLOR_GRAY2RGBA,4);
			break;
		case 2:
			//Canny边缘检测
			mRgba = inputFrame.rgba();
			Imgproc.Canny(inputFrame.gray(), mTmp, 80, 100);
			Imgproc.cvtColor(mTmp, mRgba, Imgproc.COLOR_GRAY2RGBA, 4);
			break;
		case 3:
			//Hist直方图计算
			Mat hist = new Mat();
            int thikness = (int) (sizeRgba.width / (mHistSizeNum + 10) / 5);
            if(thikness > 5) thikness = 5;
            int offset = (int) ((sizeRgba.width - (5*mHistSizeNum + 4*10)*thikness)/2);

            // RGB
            for(int c=0; c<3; c++) {
                Imgproc.calcHist(Arrays.asList(mRgba), mChannels[c], mMat0, hist, mHistSize, mRanges);
                Core.normalize(hist, hist, sizeRgba.height/2, 0, Core.NORM_INF);
                hist.get(0, 0, mBuff);
                for(int h=0; h<mHistSizeNum; h++) {
                    mP1.x = mP2.x = offset + (c * (mHistSizeNum + 10) + h) * thikness;
                    mP1.y = sizeRgba.height-1;
                    mP2.y = mP1.y - 2 - (int)mBuff[h];
                    Imgproc.line(mRgba, mP1, mP2, mColorsRGB[c], thikness);
                }
            }
            // Value and Hue
            Imgproc.cvtColor(mRgba, mTmp, Imgproc.COLOR_RGB2HSV_FULL);
            // Value
            Imgproc.calcHist(Arrays.asList(mTmp), mChannels[2], mMat0, hist, mHistSize, mRanges);
            Core.normalize(hist, hist, sizeRgba.height/2, 0, Core.NORM_INF);
            hist.get(0, 0, mBuff);
            for(int h=0; h<mHistSizeNum; h++) {
                mP1.x = mP2.x = offset + (3 * (mHistSizeNum + 10) + h) * thikness;
                mP1.y = sizeRgba.height-1;
                mP2.y = mP1.y - 2 - (int)mBuff[h];
                Imgproc.line(mRgba, mP1, mP2, mWhilte, thikness);
            }
			break;
		case 4:
			//Sobel边缘检测
			Mat gray = inputFrame.gray();
            Mat grayInnerWindow = gray.submat(top, top + height, left, left + width);
            rgbaInnerWindow = mRgba.submat(top, top + height, left, left + width);
            Imgproc.Sobel(grayInnerWindow, mIntermediateMat, CvType.CV_8U, 1, 1);
            Core.convertScaleAbs(mIntermediateMat, mIntermediateMat, 10, 0);
            Imgproc.cvtColor(mIntermediateMat, rgbaInnerWindow, Imgproc.COLOR_GRAY2BGRA, 4);
            grayInnerWindow.release();
            rgbaInnerWindow.release();
			break;
		case 5:
			//SEPIA(色调变换)
			rgbaInnerWindow = mRgba.submat(top, top + height, left, left + width);
            Core.transform(rgbaInnerWindow, rgbaInnerWindow, mSepiaKernel);
            rgbaInnerWindow.release();
			break;
		case 6:
			//ZOOM放大镜
			Mat zoomCorner = mRgba.submat(0, rows / 2 - rows / 10, 0, cols / 2 - cols / 10);
            Mat mZoomWindow = mRgba.submat(rows / 2 - 9 * rows / 100, rows / 2 + 9 * rows / 100, cols / 2 - 9 * cols / 100, cols / 2 + 9 * cols / 100);
            Imgproc.resize(mZoomWindow, zoomCorner, zoomCorner.size());
            Size wsize = mZoomWindow.size();
            Imgproc.rectangle(mZoomWindow, new Point(1, 1), new Point(wsize.width - 2, wsize.height - 2), new Scalar(255, 0, 0, 255), 2);
            zoomCorner.release();
            mZoomWindow.release();
			break;
		case 7:
			//PIXELIZE像素化
			rgbaInnerWindow = mRgba.submat(top, top + height, left, left + width);
            Imgproc.resize(rgbaInnerWindow, mIntermediateMat, mSize0, 0.1, 0.1, Imgproc.INTER_NEAREST);
            Imgproc.resize(mIntermediateMat, rgbaInnerWindow, rgbaInnerWindow.size(), 0., 0., Imgproc.INTER_NEAREST);
            rgbaInnerWindow.release();
			break;
		default:
			//显示原图
			mRgba = inputFrame.rgba();
			break;
		}
		//返回处理后的结果数据
		return mRgba;
	}
}

2.效果图:

Canny边缘检测:

Hist直方图计算:

Sobel边缘检测:

SEPIA(色调变换):

ZOOM放大镜:

PIXELIZE像素化:

时间: 2024-08-27 09:18:46

OpenCV学习笔记(七)—— OpenCV for Android实时图像处理的相关文章

OpenCv学习笔记(七)---OpenCv中的基本绘图函数,圆,椭圆,线段,矩形,多边形的绘制(1)

(一)本节教程的目的 本节你将学到: 1--如何使用Point在图像中定义2D点 2--如何以及为何使用Scalar 3--用OpenCv的函数Line绘直线 4--用OpenCvd的函数ellipse绘制椭圆 5--用OpenCv的函数rectangle绘矩形 6--用OpenCv的函数circle绘圆 7--用OpenCv的函数fillPoly绘填充多边形 (二)原理,本节我们将大量使用Point和Scalar这两个结构: **********************************

QT+opencv学习笔记一 opencv配置及Mat浅拷贝

今天终于把Qt + opencv配置成功了,中间有一些曲折,在这里记录一下. vs2013 + opencv的方法之前记录过,但这次的不太一样,我们一开始按照这篇文章配置pro Qt5中进行OpenCV开发教程 但是,死活出不来结果,研究发现,我们用的是 mingw 不是 vs,这个方法适合vs编译器 (具体可以参考:win7下的Qt环境+OpenCV视觉库) 后来,我们找到了这篇文章 QT creator+OpenCV2.4.2+MinGW 在windows下开发环境配置 但是还是有点曲折,

OpenCv学习笔记(三)---OpenCv中基本数据类型--Point,Size,Rect,Scalar,Vec3b类类型的详细解释及其OpenCv中源代码的详细分析

/********************************************************************************************* 程序功能: OpenCv的基本数据结构源代码的解读,我们常用的OpenCv的基本数据结构有六种: 1--Point类 2--Size类 3--Rect类 4--Scalar类 5--Vec3b--向量模板类 6--Range类 编写环境: OpenCv2.4.8+VS2010 地点时间: 陕西师范大学 201

OpenCV学习笔记一 OpenCV 2.49 + Eclipse 配置教程

1.安装opencv库 1.1 双击opencv-2.4.9.exe,安装到指定目录. 1.2安装VC2010运行库,百度搜索VC2010运行库,下载安装即可.如果完成下面的所有配置之后运行程序时提示还缺少dll等文件,需要用360修复,进入人工服务,搜索提示缺少的dll文件,点击修复即可. 1.3将opencv\build\x86\vc11路径下的bin.lib.staticlib三个文件夹的路径添加到环境变量中. 2.配置Eclipse 2.1 新建一个工程file -> new -> c

OpenCv学习笔记(一)----OpenCv中Mat类源码的详细解读(2)

(一)像素存储的方法 1--本节我们讲解如何存储像素,存储像素值,需要指定: 1--颜色空间 2--数据类型 2--其中,颜色空间是指针对一个给定的颜色,如何组合颜色以其编码. 3--最简单的颜色空间是----灰度级空间----只需要处理:黑色和白色,对它们进行组合便可以产生不同程度的灰 色(256灰度级) 4--对于彩色方式---则有更多种类的颜色空间,但不论那种方式,都是把颜色分成:三个或者四个---基元素,通过 组合基元素,就可以产生所有的颜色 1--RGB颜色空间是最常用的一种颜色空间,

[OpenCV学习笔记1][OpenCV基本数据类型]

CvPoint基于二维整形坐标轴的点typedef struct CvPoint{int x; /* X 坐标, 通常以 0 为基点 */int y; /* y 坐标,通常以 0 为基点 */}CvPoint;/* 构造函数 */inline CvPoint cvPoint( int x, int y );/* 从 CvPoint2D32f 类型转换得来 */inline CvPoint cvPointFrom32f( CvPoint2D32f point ); CvPoint基于二维整形坐标轴

opencv学习笔记(七)SVM+HOG

opencv学习笔记(七)SVM+HOG 一.简介 方向梯度直方图(Histogram of Oriented Gradient,HOG)特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子.它通过计算和统计图像局部区域的梯度直方图来构成特征.Hog特征结合SVM分类器已经被广泛用于图像识别中,尤其在行人检测中获得了极大的成功.需要提醒的是,HOG+SVM进行行人检测的方法是法国研究院Dalal在2005的CVPR上提出的. 最近在做车标识别相关的研究,用到了SVM+HOG的方法进行识

Opencv学习笔记(六)SURF学习笔记

原创文章,转载请注明出处:http://blog.csdn.net/crzy_sparrow/article/details/7392345 本人挺菜的,肯定有非常多错误纰漏之处 ,希望大家不吝指正. 看了harris角点检測之后,開始研究SURF角点检測,发现挺复杂的,一时也仅仅了解了大概,把了解的东西总结下,以便下次深入学习. SURF角点检測算法是对SIFT的一种改进,主要体如今速度上,效率更高.它和SIFT的主要差别是图像多尺度空间的构建方法不同. 在计算视觉领域,尺度空间被象征性的表述

opencv学习笔记(四)投影

opencv学习笔记(四)投影 任选了一张图片用于测试,图片如下所示: 1 #include <cv.h> 2 #include <highgui.h> 3 using namespace std; 4 using namespace cv; 5 int main() 6 { 7 IplImage * src = cvLoadImage("cat.png", 0); //强制转化读取图像为灰度图 8 cvShowImage("灰度图像", s

OpenCV学习笔记(01)我的第一个OpenCV程序(环境配置)

昨天刚刚考完编译原理,私心想着可以做一些与考试无关的东西了.一直想做和图像处理相关的东西,趁这段时间有空学习一下OpenCV,搭建环境真是一件麻烦的事情,搞了近三个小时终于OK了.先来张图: 大致描述一下步骤吧: 一.安装前准备 1.VS2012(网上看到很多用的VS2010,但是基本不影响) 2.OpenCV 安装包(我下载的是最新的2.4.9) 二.安装OpenCV 1.解压OPenCV 说是安装,其实就是解压,OpenCV的Windows安装程序就是一个自解压程序: 这里我解压到C:\Pr