天天看點

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

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

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

一、修改布局界面:

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

        activity_main.xml檔案:

[java] 

view

plain

copy print ? https://code.csdn.net/snippets/1656199 https://code.csdn.net/snippets/1656199/fork

  1. <FrameLayout   
  2.     xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:tools="http://schemas.android.com/tools"  
  4.     xmlns:opencv="http://schemas.android.com/apk/res-auto"  
  5.     android:layout_width="match_parent"  
  6.     android:layout_height="match_parent">  
  7.     <org.opencv.android.JavaCameraView   
  8.         android:layout_width="fill_parent"  
  9.         android:layout_height="fill_parent"  
  10.         android:id="@+id/camera_view"  
  11.         opencv:show_fps="true"   
  12.         opencv:camera_id="any"/>  
  13.     <RelativeLayout   
  14.         android:gravity="bottom|center_horizontal">  
  15.         <Button   
  16.             android:id="@+id/deal_btn"  
  17.             android:layout_width="100dp"  
  18.             android:layout_height="40dp"  
  19.             android:layout_marginBottom="20dp"  
  20.             android:text="處理"/>  
  21.     </RelativeLayout>  
  22. </FrameLayout>  

        檢視預覽圖:

二、擷取按鈕元件并監聽按鈕點選:

1.聲明一個Button對象用于綁定上面的按鈕元件和一個狀态标志位用于存儲目前狀态:

https://code.csdn.net/snippets/1656199 https://code.csdn.net/snippets/1656199/fork
  1.        //按鈕元件  
  2. private Button mButton;  
  3. //目前處理狀态  
  4. private static int Cur_State = 0;  

2.在OnCreate中綁定按鈕和按鈕點選監聽:

https://code.csdn.net/snippets/1656199 https://code.csdn.net/snippets/1656199/fork
  1. mButton = (Button) findViewById(R.id.deal_btn);  
  2. mButton.setOnClickListener(new OnClickListener(){  
  3.     @Override  
  4.     public void onClick(View v) {  
  5.         if(Cur_State<8){  
  6.             //切換狀态  
  7.             Cur_State ++;  
  8.         }else{  
  9.             //恢複初始狀态  
  10.             Cur_State = 0;  
  11.         }  
  12.     }  
  13. });  

        這裡的狀态标志位Cur_State與圖像處理的每個類型對應,0對應預設狀态,也就是顯示原圖,1-7分别對應:灰化、Canny邊緣檢測、Hist直方圖計算、Sobel邊緣檢測、SEPIA(色調變換)、ZOOM放大鏡、PIXELIZE像素化

三、圖像資訊擷取儲存、處理和顯示:

1.在

OpenCV

中一般都是使用Mat類型來存儲圖像等矩陣資訊,是以我們可以聲明一個Mat對象用來作為實時幀圖像的緩存對象:

https://code.csdn.net/snippets/1656199 https://code.csdn.net/snippets/1656199/fork
  1. //緩存相機每幀輸入的資料  
  2. private Mat mRgba;  

2.對象執行個體化以及基本屬性的設定,包括:長度、寬度和圖像類型标志:

https://code.csdn.net/snippets/1656199 https://code.csdn.net/snippets/1656199/fork
  1. public void onCameraViewStarted(int width, int height) {  
  2.     // TODO Auto-generated method stub  
  3.     mRgba = new Mat(height, width, CvType.CV_8UC4);  
  4. }  

3.對象指派,這裡隻對原圖和灰化兩種情況進行了處理,其他的處理後續再添加:

https://code.csdn.net/snippets/1656199 https://code.csdn.net/snippets/1656199/fork
  1.        /** 
  2.  * 圖像處理都寫在此處 
  3.  */  
  4. @Override  
  5. public Mat onCameraFrame(CvCameraViewFrame inputFrame) {  
  6.     switch (Cur_State) {  
  7.     case 1:  
  8.         //灰化處理  
  9.         Imgproc.cvtColor(inputFrame.gray(), mRgba, Imgproc.COLOR_GRAY2RGBA,4);  
  10.         break;  
  11.     default:  
  12.         //顯示原圖  
  13.         mRgba = inputFrame.rgba();  
  14.     //傳回處理後的結果資料  
  15.     return mRgba;  

4.由于用對象存儲圖像資料的話,資料會儲存到記憶體中,是以結束的時候需要進行資料釋放,不然可能導緻崩潰:

https://code.csdn.net/snippets/1656199 https://code.csdn.net/snippets/1656199/fork
  1.        @Override  
  2. public void onCameraViewStopped() {  
  3.     mRgba.release();  

5.運作檢視效果:

        正常模式:

        灰化圖:

四、其他處理及結果:

        在以上的例子中我們已經完成了預覽圖的灰化處理,那麼接下來我們把其他處理都添加到代碼中,檢視效果。由于在2.x版本中使用到的部分方法已經發生了變化,如:在OpenCV 3.1.0中

org

.

opencv core

.Core類中的方法line和rectangle都已失效,可以用

imgproc

.Imgproc中的line和rectangle來代替:

1. MainActivity.

Java

源碼:

https://code.csdn.net/snippets/1656199 https://code.csdn.net/snippets/1656199/fork
  1. package com.linsh.opencv_test;  
  2. import java.util.Arrays;  
  3. import org.opencv.android.BaseLoaderCallback;  
  4. import org.opencv.android.CameraBridgeViewBase;  
  5. import org.opencv.android.OpenCVLoader;  
  6. import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;  
  7. import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;  
  8. import org.opencv.android.LoaderCallbackInterface;  
  9. import org.opencv.core.Core;  
  10. import org.opencv.core.CvType;  
  11. import org.opencv.core.Mat;  
  12. import org.opencv.core.MatOfFloat;  
  13. import org.opencv.core.MatOfInt;  
  14. import org.opencv.core.Point;  
  15. import org.opencv.core.Scalar;  
  16. import org.opencv.core.Size;  
  17. import org.opencv.imgproc.Imgproc;  
  18. import android.R.string;  
  19. import android.app.Activity;  
  20. import android.os.Bundle;  
  21. import android.util.Log;  
  22. import android.widget.Button;  
  23. import android.view.View;  
  24. import android.view.View.OnClickListener;  
  25. public class MainActivity extends Activity implements CvCameraViewListener2{  
  26.     private String TAG = "OpenCV_Test";  
  27.     //OpenCV的相機接口  
  28.     private CameraBridgeViewBase mCVCamera;  
  29.     //緩存相機每幀輸入的資料  
  30.     private Mat mRgba,mTmp;  
  31.     //按鈕元件  
  32.     private Button mButton;  
  33.     //目前處理狀态  
  34.     private static int Cur_State = 0;  
  35.     private Size mSize0;  
  36.     private Mat mIntermediateMat;  
  37.     private MatOfInt mChannels[];  
  38.     private MatOfInt mHistSize;  
  39.     private int mHistSizeNum = 25;  
  40.     private Mat mMat0;  
  41.     private float[] mBuff;  
  42.     private MatOfFloat mRanges;  
  43.     private Point mP1;  
  44.     private Point mP2;  
  45.     private Scalar mColorsRGB[];  
  46.     private Scalar mColorsHue[];  
  47.     private Scalar mWhilte;  
  48.     private Mat mSepiaKernel;  
  49.     /** 
  50.      * 通過OpenCV管理Android服務,異步初始化OpenCV 
  51.      */  
  52.     BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {  
  53.         @Override  
  54.         public void onManagerConnected(int status){  
  55.             switch (status) {  
  56.             case LoaderCallbackInterface.SUCCESS:  
  57.                 Log.i(TAG,"OpenCV loaded successfully");  
  58.                 mCVCamera.enableView();  
  59.                 break;  
  60.             default:  
  61.             }  
  62.     };  
  63.     protected void onCreate(Bundle savedInstanceState) {  
  64.         super.onCreate(savedInstanceState);  
  65.         setContentView(R.layout.activity_main);  
  66.         mCVCamera = (CameraBridgeViewBase) findViewById(R.id.camera_view);  
  67.         mCVCamera.setCvCameraViewListener(this);  
  68.         mButton = (Button) findViewById(R.id.deal_btn);  
  69.         mButton.setOnClickListener(new OnClickListener(){  
  70.             @Override  
  71.             public void onClick(View v) {  
  72.                 if(Cur_State<8){  
  73.                     //切換狀态  
  74.                     Cur_State ++;  
  75.                 }else{  
  76.                     //恢複初始狀态  
  77.                     Cur_State = 0;  
  78.                 }  
  79.         });  
  80.     public void onResume() {  
  81.         super.onResume();  
  82.         if (!OpenCVLoader.initDebug()) {  
  83.             Log.d(TAG,"OpenCV library not found!");  
  84.         } else {  
  85.             Log.d(TAG, "OpenCV library found inside package. Using it!");  
  86.             mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);  
  87.     public void onDestroy() {  
  88.         if(mCVCamera!=null){  
  89.             mCVCamera.disableView();  
  90.     public void onCameraViewStarted(int width, int height) {  
  91.         // TODO Auto-generated method stub  
  92.         mRgba = new Mat(height, width, CvType.CV_8UC4);  
  93.         mTmp = new Mat(height, width, CvType.CV_8UC4);  
  94.         mIntermediateMat = new Mat();  
  95.         mSize0 = new Size();  
  96.         mChannels = new MatOfInt[] { new MatOfInt(0), new MatOfInt(1), new MatOfInt(2) };  
  97.         mBuff = new float[mHistSizeNum];  
  98.         mHistSize = new MatOfInt(mHistSizeNum);  
  99.         mRanges = new MatOfFloat(0f, 256f);  
  100.         mMat0 = new Mat();  
  101.         mColorsRGB = new Scalar[] { new Scalar(200, 0, 0, 255), new Scalar(0, 200, 0, 255), new Scalar(0, 0, 200, 255) };  
  102.         mColorsHue = new Scalar[] {  
  103.                 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),  
  104.                 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),  
  105.                 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),  
  106.                 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),  
  107.                 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)  
  108.         };  
  109.         mWhilte = Scalar.all(255);  
  110.         mP1 = new Point();  
  111.         mP2 = new Point();  
  112.         // Fill sepia kernel  
  113.         mSepiaKernel = new Mat(4, 4, CvType.CV_32F);  
  114.         mSepiaKernel.put(0, 0, /* R */0.189f, 0.769f, 0.393f, 0f);  
  115.         mSepiaKernel.put(1, 0, /* G */0.168f, 0.686f, 0.349f, 0f);  
  116.         mSepiaKernel.put(2, 0, /* B */0.131f, 0.534f, 0.272f, 0f);  
  117.         mSepiaKernel.put(3, 0, /* A */0.000f, 0.000f, 0.000f, 1f);  
  118.     public void onCameraViewStopped() {  
  119.         mRgba.release();  
  120.         mTmp.release();  
  121.      * 圖像處理都寫在此處 
  122.     public Mat onCameraFrame(CvCameraViewFrame inputFrame) {  
  123.         Size sizeRgba = mRgba.size();  
  124.         int rows = (int) sizeRgba.height;  
  125.         int cols = (int) sizeRgba.width;  
  126.         Mat rgbaInnerWindow;  
  127.         int left = cols / 8;  
  128.         int top = rows / 8;  
  129.         int width = cols * 3 / 4;  
  130.         int height = rows * 3 / 4;  
  131.         switch (Cur_State) {  
  132.         case 1:  
  133.             //灰化處理  
  134.             Imgproc.cvtColor(inputFrame.gray(), mRgba, Imgproc.COLOR_GRAY2RGBA,4);  
  135.             break;  
  136.         case 2:  
  137.             //Canny邊緣檢測  
  138.             mRgba = inputFrame.rgba();  
  139.             Imgproc.Canny(inputFrame.gray(), mTmp, 80, 100);  
  140.             Imgproc.cvtColor(mTmp, mRgba, Imgproc.COLOR_GRAY2RGBA, 4);  
  141.         case 3:  
  142.             //Hist直方圖計算  
  143.             Mat hist = new Mat();  
  144.             int thikness = (int) (sizeRgba.width / (mHistSizeNum + 10) / 5);  
  145.             if(thikness > 5) thikness = 5;  
  146.             int offset = (int) ((sizeRgba.width - (5*mHistSizeNum + 4*10)*thikness)/2);  
  147.             // RGB  
  148.             for(int c=0; c<3; c++) {  
  149.                 Imgproc.calcHist(Arrays.asList(mRgba), mChannels[c], mMat0, hist, mHistSize, mRanges);  
  150.                 Core.normalize(hist, hist, sizeRgba.height/2, 0, Core.NORM_INF);  
  151.                 hist.get(0, 0, mBuff);  
  152.                 for(int h=0; h<mHistSizeNum; h++) {  
  153.                     mP1.x = mP2.x = offset + (c * (mHistSizeNum + 10) + h) * thikness;  
  154.                     mP1.y = sizeRgba.height-1;  
  155.                     mP2.y = mP1.y - 2 - (int)mBuff[h];  
  156.                     Imgproc.line(mRgba, mP1, mP2, mColorsRGB[c], thikness);  
  157.             // Value and Hue  
  158.             Imgproc.cvtColor(mRgba, mTmp, Imgproc.COLOR_RGB2HSV_FULL);  
  159.             // Value  
  160.             Imgproc.calcHist(Arrays.asList(mTmp), mChannels[2], mMat0, hist, mHistSize, mRanges);  
  161.             Core.normalize(hist, hist, sizeRgba.height/2, 0, Core.NORM_INF);  
  162.             hist.get(0, 0, mBuff);  
  163.             for(int h=0; h<mHistSizeNum; h++) {  
  164.                 mP1.x = mP2.x = offset + (3 * (mHistSizeNum + 10) + h) * thikness;  
  165.                 mP1.y = sizeRgba.height-1;  
  166.                 mP2.y = mP1.y - 2 - (int)mBuff[h];  
  167.                 Imgproc.line(mRgba, mP1, mP2, mWhilte, thikness);  
  168.         case 4:  
  169.             //Sobel邊緣檢測  
  170.             Mat gray = inputFrame.gray();  
  171.             Mat grayInnerWindow = gray.submat(top, top + height, left, left + width);  
  172.             rgbaInnerWindow = mRgba.submat(top, top + height, left, left + width);  
  173.             Imgproc.Sobel(grayInnerWindow, mIntermediateMat, CvType.CV_8U, 1, 1);  
  174.             Core.convertScaleAbs(mIntermediateMat, mIntermediateMat, 10, 0);  
  175.             Imgproc.cvtColor(mIntermediateMat, rgbaInnerWindow, Imgproc.COLOR_GRAY2BGRA, 4);  
  176.             grayInnerWindow.release();  
  177.             rgbaInnerWindow.release();  
  178.         case 5:  
  179.             //SEPIA(色調變換)  
  180.             Core.transform(rgbaInnerWindow, rgbaInnerWindow, mSepiaKernel);  
  181.         case 6:  
  182.             //ZOOM放大鏡  
  183.             Mat zoomCorner = mRgba.submat(0, rows / 2 - rows / 10, 0, cols / 2 - cols / 10);  
  184.             Mat mZoomWindow = mRgba.submat(rows / 2 - 9 * rows / 100, rows / 2 + 9 * rows / 100, cols / 2 - 9 * cols / 100, cols / 2 + 9 * cols / 100);  
  185.             Imgproc.resize(mZoomWindow, zoomCorner, zoomCorner.size());  
  186.             Size wsize = mZoomWindow.size();  
  187.             Imgproc.rectangle(mZoomWindow, new Point(1, 1), new Point(wsize.width - 2, wsize.height - 2), new Scalar(255, 0, 0, 255), 2);  
  188.             zoomCorner.release();  
  189.             mZoomWindow.release();  
  190.         case 7:  
  191.             //PIXELIZE像素化  
  192.             Imgproc.resize(rgbaInnerWindow, mIntermediateMat, mSize0, 0.1, 0.1, Imgproc.INTER_NEAREST);  
  193.             Imgproc.resize(mIntermediateMat, rgbaInnerWindow, rgbaInnerWindow.size(), 0., 0., Imgproc.INTER_NEAREST);  
  194.         default:  
  195.             //顯示原圖  
  196.         //傳回處理後的結果資料  
  197.         return mRgba;  

2.效果圖:

Canny邊緣檢測:

Hist直方圖計算:

Sobel邊緣檢測:

SEPIA(色調變換):

ZOOM放大鏡:

PIXELIZE像素化: