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

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

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

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


一、修改布局界面:

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

        activity_main.xml文件:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  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.   
  8.     <org.opencv.android.JavaCameraView   
  9.         android:layout_width="fill_parent"  
  10.         android:layout_height="fill_parent"  
  11.         android:id="@+id/camera_view"  
  12.         opencv:show_fps="true"   
  13.         opencv:camera_id="any"/>  
  14.       
  15.     <RelativeLayout   
  16.         android:layout_width="fill_parent"  
  17.         android:layout_height="fill_parent"  
  18.         android:gravity="bottom|center_horizontal">  
  19.         <Button   
  20.             android:id="@+id/deal_btn"  
  21.             android:layout_width="100dp"  
  22.             android:layout_height="40dp"  
  23.             android:layout_marginBottom="20dp"  
  24.             android:text="处理"/>  
  25.     </RelativeLayout>  
  26.   
  27. </FrameLayout>  
        查看预览图:
        

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

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

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1.        //按钮组件  
  2. private Button mButton;  
  3. //当前处理状态  
  4. private static int Cur_State = 0;  


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

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  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.               
  14. });  
        这里的状态标志位Cur_State与图像处理的每个类型对应,0对应默认状态,也就是显示原图,1-7分别对应: 灰化、Canny边缘检测、Hist直方图计算、Sobel边缘检测、SEPIA(色调变换)、ZOOM放大镜、PIXELIZE像素化

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

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

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. //缓存相机每帧输入的数据  
  2. private Mat mRgba;  


2.对象实例化以及基本属性的设置,包括:长度、宽度和图像类型标志:
[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  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.对象赋值,这里只对原图和灰化两种情况进行了处理,其他的处理后续再添加:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  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.         break;  
  15.     }  
  16.     //返回处理后的结果数据  
  17.     return mRgba;  
  18. }  


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

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1.        @Override  
  2. public void onCameraViewStopped() {  
  3.     // TODO Auto-generated method stub  
  4.     mRgba.release();  
  5. }  

5.运行查看效果:

        正常模式:

        
        灰化图:

        


四、其他处理及结果:

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

1. MainActivity.Java源码:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.linsh.opencv_test;  
  2.   
  3. import java.util.Arrays;  
  4.   
  5. import org.opencv.android.BaseLoaderCallback;  
  6. import org.opencv.android.CameraBridgeViewBase;  
  7. import org.opencv.android.OpenCVLoader;  
  8. import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;  
  9. import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;  
  10. import org.opencv.android.LoaderCallbackInterface;  
  11. import org.opencv.core.Core;  
  12. import org.opencv.core.CvType;  
  13. import org.opencv.core.Mat;  
  14. import org.opencv.core.MatOfFloat;  
  15. import org.opencv.core.MatOfInt;  
  16. import org.opencv.core.Point;  
  17. import org.opencv.core.Scalar;  
  18. import org.opencv.core.Size;  
  19. import org.opencv.imgproc.Imgproc;  
  20.   
  21. import android.R.string;  
  22. import android.app.Activity;  
  23. import android.os.Bundle;  
  24. import android.util.Log;  
  25. import android.widget.Button;  
  26. import android.view.View;  
  27. import android.view.View.OnClickListener;  
  28.   
  29. public class MainActivity extends Activity implements CvCameraViewListener2{  
  30.     private String TAG = "OpenCV_Test";  
  31.     //OpenCV的相机接口  
  32.     private CameraBridgeViewBase mCVCamera;  
  33.     //缓存相机每帧输入的数据  
  34.     private Mat mRgba,mTmp;  
  35.     //按钮组件  
  36.     private Button mButton;  
  37.     //当前处理状态  
  38.     private static int Cur_State = 0;  
  39.       
  40.     private Size mSize0;  
  41.     private Mat mIntermediateMat;  
  42.     private MatOfInt mChannels[];  
  43.     private MatOfInt mHistSize;  
  44.     private int mHistSizeNum = 25;  
  45.     private Mat mMat0;  
  46.     private float[] mBuff;  
  47.     private MatOfFloat mRanges;  
  48.     private Point mP1;  
  49.     private Point mP2;  
  50.     private Scalar mColorsRGB[];  
  51.     private Scalar mColorsHue[];  
  52.     private Scalar mWhilte;  
  53.     private Mat mSepiaKernel;  
  54.       
  55.     /** 
  56.      * 通过OpenCV管理Android服务,异步初始化OpenCV 
  57.      */  
  58.     BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {  
  59.         @Override  
  60.         public void onManagerConnected(int status){  
  61.             switch (status) {  
  62.             case LoaderCallbackInterface.SUCCESS:  
  63.                 Log.i(TAG,"OpenCV loaded successfully");  
  64.                 mCVCamera.enableView();  
  65.                 break;  
  66.             default:  
  67.                 break;  
  68.             }  
  69.         }  
  70.     };  
  71.       
  72.     @Override  
  73.     protected void onCreate(Bundle savedInstanceState) {  
  74.         super.onCreate(savedInstanceState);  
  75.         setContentView(R.layout.activity_main);  
  76.           
  77.         mCVCamera = (CameraBridgeViewBase) findViewById(R.id.camera_view);  
  78.         mCVCamera.setCvCameraViewListener(this);  
  79.           
  80.         mButton = (Button) findViewById(R.id.deal_btn);  
  81.         mButton.setOnClickListener(new OnClickListener(){  
  82.             @Override  
  83.             public void onClick(View v) {  
  84.                 if(Cur_State<8){  
  85.                     //切换状态  
  86.                     Cur_State ++;  
  87.                 }else{  
  88.                     //恢复初始状态  
  89.                     Cur_State = 0;  
  90.                 }  
  91.             }  
  92.               
  93.         });  
  94.     }  
  95.       
  96.     @Override  
  97.     public void onResume() {  
  98.         super.onResume();  
  99.         if (!OpenCVLoader.initDebug()) {  
  100.             Log.d(TAG,"OpenCV library not found!");  
  101.         } else {  
  102.             Log.d(TAG, "OpenCV library found inside package. Using it!");  
  103.             mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);  
  104.         }  
  105.     };  
  106.       
  107.     @Override  
  108.     public void onDestroy() {  
  109.         if(mCVCamera!=null){  
  110.             mCVCamera.disableView();  
  111.         }  
  112.     };  
  113.   
  114.     @Override  
  115.     public void onCameraViewStarted(int width, int height) {  
  116.         // TODO Auto-generated method stub  
  117.         mRgba = new Mat(height, width, CvType.CV_8UC4);  
  118.         mTmp = new Mat(height, width, CvType.CV_8UC4);  
  119.           
  120.         mIntermediateMat = new Mat();  
  121.         mSize0 = new Size();  
  122.         mChannels = new MatOfInt[] { new MatOfInt(0), new MatOfInt(1), new MatOfInt(2) };  
  123.         mBuff = new float[mHistSizeNum];  
  124.         mHistSize = new MatOfInt(mHistSizeNum);  
  125.         mRanges = new MatOfFloat(0f, 256f);  
  126.         mMat0 = new Mat();  
  127.         mColorsRGB = new Scalar[] { new Scalar(20000255), new Scalar(02000255), new Scalar(00200255) };  
  128.         mColorsHue = new Scalar[] {  
  129.                 new Scalar(25500255), new Scalar(255600255), new Scalar(2551200255), new Scalar(2551800255), new Scalar(2552400255),  
  130.                 new Scalar(2152130255), new Scalar(1502550255), new Scalar(852550255), new Scalar(202550255), new Scalar(025530255),  
  131.                 new Scalar(025585255), new Scalar(0255150255), new Scalar(0255215255), new Scalar(0234255255), new Scalar(0170255255),  
  132.                 new Scalar(0120255255), new Scalar(060255255), new Scalar(00255255), new Scalar(640255255), new Scalar(1200255255),  
  133.                 new Scalar(1800255255), new Scalar(2550255255), new Scalar(2550215255), new Scalar(255085255), new Scalar(25500255)  
  134.         };  
  135.         mWhilte = Scalar.all(255);  
  136.         mP1 = new Point();  
  137.         mP2 = new Point();  
  138.   
  139.         // Fill sepia kernel  
  140.         mSepiaKernel = new Mat(44, CvType.CV_32F);  
  141.         mSepiaKernel.put(00/* R */0.189f, 0.769f, 0.393f, 0f);  
  142.         mSepiaKernel.put(10/* G */0.168f, 0.686f, 0.349f, 0f);  
  143.         mSepiaKernel.put(20/* B */0.131f, 0.534f, 0.272f, 0f);  
  144.         mSepiaKernel.put(30/* A */0.000f, 0.000f, 0.000f, 1f);  
  145.     }  
  146.       
  147.     @Override  
  148.     public void onCameraViewStopped() {  
  149.         // TODO Auto-generated method stub  
  150.         mRgba.release();  
  151.         mTmp.release();  
  152.     }  
  153.       
  154.     /** 
  155.      * 图像处理都写在此处 
  156.      */  
  157.     @Override  
  158.     public Mat onCameraFrame(CvCameraViewFrame inputFrame) {  
  159.         mRgba = inputFrame.rgba();  
  160.         Size sizeRgba = mRgba.size();  
  161.         int rows = (int) sizeRgba.height;  
  162.         int cols = (int) sizeRgba.width;  
  163.         Mat rgbaInnerWindow;  
  164.               
  165.         int left = cols / 8;  
  166.         int top = rows / 8;  
  167.   
  168.         int width = cols * 3 / 4;  
  169.         int height = rows * 3 / 4;  
  170.           
  171.         switch (Cur_State) {  
  172.         case 1:  
  173.             //灰化处理  
  174.             Imgproc.cvtColor(inputFrame.gray(), mRgba, Imgproc.COLOR_GRAY2RGBA,4);  
  175.             break;  
  176.         case 2:  
  177.             //Canny边缘检测  
  178.             mRgba = inputFrame.rgba();  
  179.             Imgproc.Canny(inputFrame.gray(), mTmp, 80100);  
  180.             Imgproc.cvtColor(mTmp, mRgba, Imgproc.COLOR_GRAY2RGBA, 4);  
  181.             break;  
  182.         case 3:  
  183.             //Hist直方图计算  
  184.             Mat hist = new Mat();  
  185.             int thikness = (int) (sizeRgba.width / (mHistSizeNum + 10) / 5);  
  186.             if(thikness > 5) thikness = 5;  
  187.             int offset = (int) ((sizeRgba.width - (5*mHistSizeNum + 4*10)*thikness)/2);  
  188.              
  189.             // RGB  
  190.             for(int c=0; c<3; c++) {  
  191.                 Imgproc.calcHist(Arrays.asList(mRgba), mChannels[c], mMat0, hist, mHistSize, mRanges);  
  192.                 Core.normalize(hist, hist, sizeRgba.height/20, Core.NORM_INF);  
  193.                 hist.get(00, mBuff);  
  194.                 for(int h=0; h<mHistSizeNum; h++) {  
  195.                     mP1.x = mP2.x = offset + (c * (mHistSizeNum + 10) + h) * thikness;  
  196.                     mP1.y = sizeRgba.height-1;  
  197.                     mP2.y = mP1.y - 2 - (int)mBuff[h];  
  198.                     Imgproc.line(mRgba, mP1, mP2, mColorsRGB[c], thikness);  
  199.                 }  
  200.             }  
  201.             // Value and Hue  
  202.             Imgproc.cvtColor(mRgba, mTmp, Imgproc.COLOR_RGB2HSV_FULL);  
  203.             // Value  
  204.             Imgproc.calcHist(Arrays.asList(mTmp), mChannels[2], mMat0, hist, mHistSize, mRanges);  
  205.             Core.normalize(hist, hist, sizeRgba.height/20, Core.NORM_INF);  
  206.             hist.get(00, mBuff);  
  207.             for(int h=0; h<mHistSizeNum; h++) {  
  208.                 mP1.x = mP2.x = offset + (3 * (mHistSizeNum + 10) + h) * thikness;  
  209.                 mP1.y = sizeRgba.height-1;  
  210.                 mP2.y = mP1.y - 2 - (int)mBuff[h];  
  211.                 Imgproc.line(mRgba, mP1, mP2, mWhilte, thikness);  
  212.             }  
  213.             break;  
  214.         case 4:  
  215.             //Sobel边缘检测  
  216.             Mat gray = inputFrame.gray();  
  217.             Mat grayInnerWindow = gray.submat(top, top + height, left, left + width);  
  218.             rgbaInnerWindow = mRgba.submat(top, top + height, left, left + width);  
  219.             Imgproc.Sobel(grayInnerWindow, mIntermediateMat, CvType.CV_8U, 11);  
  220.             Core.convertScaleAbs(mIntermediateMat, mIntermediateMat, 100);  
  221.             Imgproc.cvtColor(mIntermediateMat, rgbaInnerWindow, Imgproc.COLOR_GRAY2BGRA, 4);  
  222.             grayInnerWindow.release();  
  223.             rgbaInnerWindow.release();  
  224.             break;  
  225.         case 5:  
  226.             //SEPIA(色调变换)  
  227.             rgbaInnerWindow = mRgba.submat(top, top + height, left, left + width);  
  228.             Core.transform(rgbaInnerWindow, rgbaInnerWindow, mSepiaKernel);  
  229.             rgbaInnerWindow.release();  
  230.             break;  
  231.         case 6:  
  232.             //ZOOM放大镜  
  233.             Mat zoomCorner = mRgba.submat(0, rows / 2 - rows / 100, cols / 2 - cols / 10);  
  234.             Mat mZoomWindow = mRgba.submat(rows / 2 - 9 * rows / 100, rows / 2 + 9 * rows / 100, cols / 2 - 9 * cols / 100, cols / 2 + 9 * cols / 100);  
  235.             Imgproc.resize(mZoomWindow, zoomCorner, zoomCorner.size());  
  236.             Size wsize = mZoomWindow.size();  
  237.             Imgproc.rectangle(mZoomWindow, new Point(11), new Point(wsize.width - 2, wsize.height - 2), new Scalar(25500255), 2);  
  238.             zoomCorner.release();  
  239.             mZoomWindow.release();  
  240.             break;  
  241.         case 7:  
  242.             //PIXELIZE像素化  
  243.             rgbaInnerWindow = mRgba.submat(top, top + height, left, left + width);  
  244.             Imgproc.resize(rgbaInnerWindow, mIntermediateMat, mSize0, 0.10.1, Imgproc.INTER_NEAREST);  
  245.             Imgproc.resize(mIntermediateMat, rgbaInnerWindow, rgbaInnerWindow.size(), 0., 0., Imgproc.INTER_NEAREST);  
  246.             rgbaInnerWindow.release();  
  247.             break;  
  248.         default:  
  249.             //显示原图  
  250.             mRgba = inputFrame.rgba();  
  251.             break;  
  252.         }  
  253.         //返回处理后的结果数据  
  254.         return mRgba;  
  255.     }  
  256. }  


2.效果图:

Canny边缘检测:

        

Hist直方图计算:

        

Sobel边缘检测:

        

SEPIA(色调变换):

        

ZOOM放大镜:

        

PIXELIZE像素化:
        

目录
相关文章
|
3月前
|
计算机视觉
Opencv学习笔记(十二):图片腐蚀和膨胀操作
这篇文章介绍了图像腐蚀和膨胀的原理、作用以及使用OpenCV实现这些操作的代码示例,并深入解析了开运算和闭运算的概念及其在图像形态学处理中的应用。
208 1
Opencv学习笔记(十二):图片腐蚀和膨胀操作
|
4月前
|
算法 计算机视觉
基于qt的opencv实时图像处理框架FastCvLearn实战
本文介绍了一个基于Qt的OpenCV实时图像处理框架FastCvLearn,通过手撕代码的方式详细讲解了如何实现实时人脸马赛克等功能,并提供了结果展示和基础知识回顾。
165 7
|
3月前
|
计算机视觉 Python
Opencv学习笔记(二):如何将整个文件下的彩色图片全部转换为灰度图
使用OpenCV库将一个文件夹内的所有彩色图片批量转换为灰度图,并提供了相应的Python代码示例。
42 0
Opencv学习笔记(二):如何将整个文件下的彩色图片全部转换为灰度图
|
3月前
|
计算机视觉 Python
Opencv学习笔记(一):如何将得到的图片保存在指定目录以及如何将文件夹里所有图片以数组形式输出
这篇博客介绍了如何使用OpenCV库在Python中将图片保存到指定目录,以及如何将文件夹中的所有图片读取并以数组形式输出。
244 0
Opencv学习笔记(一):如何将得到的图片保存在指定目录以及如何将文件夹里所有图片以数组形式输出
|
5月前
|
计算机视觉 索引
OpenCV4学习笔记(2):显示相机视频流的帧率
这篇文章是OpenCV4学习笔记的第二部分,介绍了如何通过OpenCV4在显示相机视频流时计算并显示其帧率,使用`getTickCount`和`getTickFrequency`函数来测量帧时间,并用`putText`在图像上绘制帧率信息。
OpenCV4学习笔记(2):显示相机视频流的帧率
|
3月前
|
编解码 数据安全/隐私保护 计算机视觉
Opencv学习笔记(十):同步和异步(多线程)操作打开海康摄像头
如何使用OpenCV进行同步和异步操作来打开海康摄像头,并提供了相关的代码示例。
137 1
Opencv学习笔记(十):同步和异步(多线程)操作打开海康摄像头
|
3月前
|
算法 计算机视觉
Opencv学习笔记(六):cv2.resize函数的介绍
这篇文章介绍了OpenCV库中cv2.resize函数的使用方法,包括其参数、插值方式选择以及实际代码示例。
570 1
Opencv学习笔记(六):cv2.resize函数的介绍
|
3月前
|
计算机视觉
Opencv学习笔记(八):如何通过cv2读取视频和摄像头来进行人脸检测(jetson nano)
如何使用OpenCV库通过cv2模块读取视频和摄像头进行人脸检测,并提供了相应的代码示例。
144 1
|
3月前
|
计算机视觉
Opencv学习笔记(五):cv2.putText()和cv2.rectangle()详细理解
这篇文章详细介绍了OpenCV库中的`cv2.putText()`和`cv2.rectangle()`函数的使用方法,并通过一个实战例子展示了如何使用这些函数在图像上绘制文字和矩形框。
329 0
Opencv学习笔记(五):cv2.putText()和cv2.rectangle()详细理解
|
3月前
|
计算机视觉
Opencv学习笔记(三):图像二值化函数cv2.threshold函数详解
这篇文章详细介绍了OpenCV库中的图像二值化函数`cv2.threshold`,包括二值化的概念、常见的阈值类型、函数的参数说明以及通过代码实例展示了如何应用该函数进行图像二值化处理,并展示了运行结果。
721 0
Opencv学习笔记(三):图像二值化函数cv2.threshold函数详解