Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> OpenCV學習筆記(七)—— OpenCV for Android實時圖像處理

OpenCV學習筆記(七)—— OpenCV for Android實時圖像處理

編輯:關於Android編程

在上篇中我們已經實現了相機打開和實時圖像信息的獲取,那麼接下來我們可以嘗試在獲取的圖像信息進行一些處理,然後實時顯示出來,在這裡我們要完成的的幾種處理:

灰化、Canny邊緣檢測、Hist直方圖計算、Sobel邊緣檢測、SEPIA(色調變換)、ZOOM放大鏡、PIXELIZE像素化

 

一、修改布局界面:

由於這裡我們需要切換不同的圖像處理模式,所以這裡我們需要在界面上放置一個按鈕,我們可以放置很多個按鈕,每個按鈕對應一種處理模式,但是這裡我們也可以只放置一個按鈕,每次點擊按鈕就切換一次,循環切換模式:

activity_main.xml文件:

 

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

    
    
    </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

 

 

2.效果圖:

Canny邊緣檢測:

\

Hist直方圖計算:

\

Sobel邊緣檢測:

\

SEPIA(色調變換):

\

ZOOM放大鏡:

\

PIXELIZE像素化: \

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved