计算机视觉
图像处理

《Master Opencv…读书笔记》卡通化效果移植到android系统

声明

1.电脑比较坑爹,前置摄像头坏掉了。

2.卡通化效果运行比较慢,老外的书上说是,人每触摸一下屏幕,才生成一张卡通化效果的图片

因此,为了简便期间,我就只对一副图像进行卡通化效果。

原理什么的见前面的文章,本文的目的,是熟悉ndk和jni

环境需求:

eclipse juno

ndk(r9)

android sdk 4.4 api 19

opencv 2.4.7 android版本

cygwin

准备工作:

1.将E:\OpenCV-2.4.7.1-android-sdk\sdk中的Java项目导入工作空间,日后凡事java端调用opencv的函数都要用到这个类库

2.安装opencv manager.apk,目前在android上所有的opencv程序都必须依附于android manger。在DOS窗口口中执行:

adb install <OpenCV4Android SDKpath>/apk/OpenCV_2.4.7_Manager_2.14_armv7a-neon.apk

开始项目:

1.新建android application工程,取名Cartoonfiy,右击项目属性,勾选opencv类库

2.将林志玲MM的照片复制到drwabale随便哪个目录下,然后编写布局文件activity_main.xml:

  1. <LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”
  2.     xmlns:tools=“http://schemas.android.com/tools”
  3.     android:layout_width=“fill_parent”
  4.     android:layout_height=“fill_parent”
  5.     android:orientation=“vertical”
  6.     tools:context=“.MainActivity” >
  7.     <TextView
  8.         android:layout_width=“wrap_content”
  9.         android:layout_height=“wrap_content”
  10.         android:text=“@string/hello_world” />
  11.      <Button
  12.         android:id=“@+id/btn_gray_process”
  13.         android:layout_width=“fill_parent”
  14.         android:layout_height=“wrap_content”
  15.         android:text=“卡通化”
  16.         android:onClick=“click”
  17.         />
  18.     <ImageView
  19.         android:id=“@+id/image_view”
  20.         android:layout_width=“wrap_content”
  21.         android:layout_height=“wrap_content”
  22.         android:contentDescription=“@string/str_proc”/>
  23. </LinearLayout>

效果比较丑,不管了:)

4.新建ImageProc类,编写本地化方法,作为调用c语言代码的入口:

  1. package com.example.cartoonfiy;
  2. public class ImageProc {
  3.     public static native void CartoonProc(int[] pixels,int[] result, int w, int h);
  4. }

 

5.在dos窗口中,使用javah工具,自动生成c语言的头文件,具体方法就是在DOS窗口中跑到Cartoonfiy项目的bin\classes目录下:

  1. javah com.example.cartoonfiy.ImageProc

之后,在classes目录下将会有com_example_cartoonfiy_ImageProc.h文件,具体内容如下:

  1. /* DO NOT EDIT THIS FILE – it is machine generated */
  2. #include <jni.h>
  3. /* Header for class com_example_cartoonfiy_ImageProc */
  4. #ifndef _Included_com_example_cartoonfiy_ImageProc
  5. #define _Included_com_example_cartoonfiy_ImageProc
  6. #ifdef __cplusplus
  7. extern “C” {
  8. #endif
  9. /*
  10.  * Class:     com_example_cartoonfiy_ImageProc
  11.  * Method:    CartoonProc
  12.  * Signature: ([III)[I
  13.  */
  14. JNIEXPORT void JNICALL Java_com_example_cartoonfiy_ImageProc_CartoonProc
  15.   (JNIEnv *, jclass, jintArray,jintArray, jint, jint);
  16. #ifdef __cplusplus
  17. }
  18. #endif
  19. #endif

 

6.我们新建一个jni文件夹(名字就这个,不能随便改,否则ndk-build命令据说找不到的),把刚才的那个com_example_cartoonfiy_ImageProc.h文件拷贝过来。然后分别编写Android.mk:

  1. LOCAL_PATH := $(call my-dir)
  2. include $(CLEAR_VARS)
  3. include E:/OpenCV-2.4.7.1-android-sdk/sdk/native/jni/OpenCV.mk
  4. LOCAL_SRC_FILES  := ImageProc.cpp
  5. LOCAL_SRC_FILES  += Cartoon.cpp
  6. LOCAL_C_INCLUDES += $(LOCAL_PATH)
  7. LOCAL_MODULE     := image_proc
  8. include $(BUILD_SHARED_LIBRARY)

和Application.mk:

  1. APP_STL := gnustl_static
  2. APP_CPPFLAGS := -frtti -fexceptions
  3. APP_ABI := armeabi-v7a
  4. APP_PLATFORM := android-8

 

7.回到MainActivity中,编写java端主要的代码:

  1. package com.example.cartoonfiy;
  2. import org.opencv.android.BaseLoaderCallback;
  3. import org.opencv.android.LoaderCallbackInterface;
  4. import org.opencv.android.OpenCVLoader;
  5. import android.os.Bundle;
  6. import android.app.Activity;
  7. import android.graphics.Bitmap;
  8. import android.graphics.BitmapFactory;
  9. import android.graphics.Bitmap.Config;
  10. import android.view.Menu;
  11. import android.view.View;
  12. import android.widget.ImageView;
  13. public class MainActivity extends Activity {
  14.     private ImageView imageView;
  15.     private Bitmap bmp;
  16.     @Override
  17.     protected void onCreate(Bundle savedInstanceState) {
  18.         super.onCreate(savedInstanceState);
  19.         setContentView(R.layout.activity_main);
  20.         imageView = (ImageView) findViewById(R.id.image_view);
  21.          //将lena图像加载程序中并进行显示  
  22.          bmp = BitmapFactory.decodeResource(getResources(), R.drawable.lady);
  23.          imageView.setImageBitmap(bmp);
  24.     }
  25.     //OpenCV类库加载并初始化成功后的回调函数,在此我们不进行任何操作  
  26.     private BaseLoaderCallback  mLoaderCallback = new BaseLoaderCallback(this) {
  27.        @Override
  28.        public void onManagerConnected(int status) {
  29.            switch (status) {
  30.                case LoaderCallbackInterface.SUCCESS:{
  31.                    System.loadLibrary(“image_proc”);
  32.                } break;
  33.                default:{
  34.                    super.onManagerConnected(status);
  35.                } break;
  36.            }
  37.        }
  38.    };
  39.    public void click(View view){
  40.        int w = bmp.getWidth();
  41.        int h = bmp.getHeight();
  42.        int[] pixels = new int[w * h];
  43.        int[] resultInt = new int[w*h];
  44.        bmp.getPixels(pixels, 0, w, 00, w, h);
  45.        ImageProc.CartoonProc(pixels,resultInt, w, h);
  46.        Bitmap resultImg = Bitmap.createBitmap(w, h, Config.ARGB_8888);
  47.        resultImg.setPixels(resultInt, 0, w, 00, w, h);
  48.        imageView.setImageBitmap(resultImg);
  49.    }
  50.     @Override
  51.     public boolean onCreateOptionsMenu(Menu menu) {
  52.         // Inflate the menu; this adds items to the action bar if it is present.
  53.         getMenuInflater().inflate(R.menu.main, menu);
  54.         return true;
  55.     }
  56.     @Override
  57.     protected void onResume() {
  58.         // TODO Auto-generated method stub
  59.         super.onResume();
  60.           //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是  
  61.         //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存在于OpenCV安装包的apk目录中  
  62.         OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback);
  63.     }
  64. }

 

好了,现在开始主要的C语言部分。由于是针对一副图像处理,我把上次的代码修改封装成一个函数,对应头文件和源文件内容分别是(这两个文件也放在jni目录下):

Cartoon.h:

  1. #include <opencv2/core/core.hpp>  
  2. #include <opencv2/highgui/highgui.hpp>  
  3. #include <opencv2/imgproc/imgproc.hpp>  
  4. #include <iostream>
  5. using namespace cv;
  6. using namespace std;
  7. Mat image_proc(Mat src);

 

Cartoon.cpp:

  1. #include “Cartoon.h”
  2. //对一张图像进行卡通化效果处理
  3. Mat image_proc(Mat src)
  4. {
  5.     Mat smallImg,tmp,bigImg,gray,edges,masks,dst;
  6.     int repetitions = 7; // Repetitions for strong cartoon effect.
  7.     const int MEDIAN_BLUR_FILTER_SIZE = 7;
  8.     const int LAPLACIAN_FILTER_SIZE = 5;
  9.     const int EDGES_THRESHOLD = 80;
  10.     Size size = src.size();
  11.     Size smallSize;
  12.     smallSize.width = size.width/2;
  13.     smallSize.height = size.height/2;
  14.     smallImg = Mat(smallSize, CV_8UC3);
  15.     tmp = Mat(smallSize, CV_8UC3);
  16.     dst= Mat(size,CV_8UC3);
  17.     if (src.empty()) {
  18.         cerr << “ERROR: Couldn’t grab a video frame.” <<endl;
  19.         exit(1);
  20.     }
  21.     cvtColor(src,gray,CV_BGR2GRAY);
  22.     medianBlur(gray,gray,MEDIAN_BLUR_FILTER_SIZE);
  23.     Laplacian(gray, edges, CV_8U, LAPLACIAN_FILTER_SIZE);
  24.     threshold(edges, masks, EDGES_THRESHOLD, 255, THRESH_BINARY_INV);
  25.     resize(src, smallImg, smallSize, 0,0, INTER_LINEAR);
  26.     for (int i=0; i<repetitions; i++) {
  27.         int ksize = 9; // Filter size. Has a large effect on speed.
  28.         double sigmaColor = 9; // Filter color strength.
  29.         double sigmaSpace = 7; // Spatial strength. Affects speed.
  30.         bilateralFilter(smallImg, tmp, ksize, sigmaColor, sigmaSpace);
  31.         bilateralFilter(tmp, smallImg, ksize, sigmaColor, sigmaSpace);
  32.     }
  33.     resize(smallImg, bigImg, size, 0,0, INTER_LINEAR);
  34.     dst.setTo(0);
  35.     //! copies those matrix elements to “m” that are marked with non-zero mask elements.
  36.     bigImg.copyTo(dst,masks);
  37.     return dst;
  38. }

 

然后,编写我们的ImageProc.cpp:

  1. #include<com_example_cartoonfiy_ImageProc.h>
  2. #include<Cartoon.h>
  3. JNIEXPORT void JNICALL Java_com_example_cartoonfiy_ImageProc_CartoonProc
  4.   (JNIEnv *env, jclass obj, jintArray buf,jintArray res, jint w, jint h){
  5.     jint *cbuf,*bgra;
  6.     cbuf = env->GetIntArrayElements(buf, false);
  7.     bgra = env->GetIntArrayElements(res, 0);
  8.     Mat src,dst,mbgra,imgData;
  9.     Size size;
  10.     size.width = w;
  11.     size.height = h;
  12.     src = Mat(size, CV_8UC3);
  13.     dst = Mat(size, CV_8UC3);
  14.     imgData = Mat(size, CV_8UC4, (unsigned char*)cbuf);
  15.     mbgra = Mat(size, CV_8UC4, (unsigned char *)bgra);
  16.     cvtColor(imgData,src,CV_BGRA2BGR);
  17.     dst = image_proc(src);
  18.     cvtColor(dst, mbgra, CV_BGR2BGRA);
  19.     env->ReleaseIntArrayElements(buf, cbuf, 0);
  20.     env->ReleaseIntArrayElements(res, bgra, 0);
  21. }

 

最后用cygwin进行交叉编译:

打开cygwin,输入

cd /cygdrive/e/worksapce/Cartoonfiy

ndk-build

记得按F5,并clean一下工程,这是在libs目录下有个libimage_proc.so文件,

如果cygwin没有报错的话,然后运行我们的android applicatoin

运行效果:

注意:

1.老外书中说的android处理图片的color format,什么用照相机拍出来的是:YUV420s,用Bitmap读取的本地图片是:BGRA。当你的图像处理函数只能应付BGR时,你必须用cvtColor进行格式转换。老外又说什么转换格式会影响速度等等,这些先不管了。

2.关于c与java端数据传输,可以参考三个姓王的兄弟写的《android高级开发实战-UI、NDK、安全》。我这边在c 端直接把mat.data转换成int输出返回了。以后再学吧

转载注明来源:CV视觉网 » 《Master Opencv…读书笔记》卡通化效果移植到android系统

分享到:更多 ()
扫描二维码,给作者 打赏
pay_weixinpay_weixin

请选择你看完该文章的感受:

0不错 0超赞 0无聊 0扯淡 0不解 0路过

评论 3

评论前必须登录!