編輯:關於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(); }
正常模式:
灰化圖:
四、其他處理及結果:
在以上的例子中我們已經完成了預覽圖的灰化處理,那麼接下來我們把其他處理都添加到代碼中,查看效果。由於在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 背景最近因為一些個人私事導致好久沒寫博客了,多事之年總算要過去了,突然沒了動力,所以趕緊先拿個最近項目中重構的一個小知識點充下數,老題重談。在我們App開發中大家可能
WiFi萬能鑰匙手機版是一款搜索連接管理Wi-Fi熱點的工具。WiFi萬能鑰匙已經內置逾千萬條的Wi-Fi熱點數據,用戶可分享使用已知的Wi-Fi熱點信息。
緊接著上一篇博客,上一篇博客中,我們已經能夠分別移動角色,並且控制他射擊了,而且還稍微區分了一下不同的角色。這篇博客中我們繼續講解後面的內容。既然角色都已經可以射擊了,那
Android本身自帶的SQLite,大家一定都用過,然而在使用它時,我們往往需要做許多額外的工作,像編寫 SQL 語句與解析查詢結果等。所以,適用於 Android 的