前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android Studio 2.2 JNI编译及Rxjava使用初级背景

Android Studio 2.2 JNI编译及Rxjava使用初级背景

作者头像
用户1127566
发布2018-06-04 17:58:06
6640
发布2018-06-04 17:58:06
举报
文章被收录于专栏:Android 开发学习Android 开发学习

jni-2.png

背景

最近几天刚好无事由于在新公司,业务上安排不是很满。android studio 2.2以后,jni比较方便开发了。本文是使用jni进行初级的demo需求。一个图片的高斯模糊效果。算法参见(https://github.com/GankLi/Demo/tree/demo/app/src/main/java/com/gank/demo/gaussblurtest)。 上图是未模糊前原图,恩,我会把它模糊滴。

前提

请下下好ndk和cmake工具。需要环境android studio 2.2

down.jpeg

快速入门

总的工程图如图:

总的框架.png

jni配置想具体了解的可以看官方,本文仅提供一个简要的模式。先上gradle配置

代码语言:javascript
复制
apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion '23.0.2'
    defaultConfig {
        applicationId 'com.example.hellojni'
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
        externalNativeBuild {
            cmake {
                arguments '-DANDROID_TOOLCHAIN=clang'
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:23.4.0'
    compile 'com.github.bumptech.glide:glide:3.7.0'
    compile 'io.reactivex:rxjava:1.1.0'
    compile 'io.reactivex:rxandroid:1.1.0'
}

其中jni相关的

代码语言:javascript
复制
externalNativeBuild {
            cmake {
                arguments '-DANDROID_TOOLCHAIN=clang'
            }
        }

cmake,这里指明了clang来作为编译器,这里其他配置参见官方。

代码语言:javascript
复制
 externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
        }
    }

这里指明make file相关的编译文件路径。

BlurUtil.java

代码语言:javascript
复制
package com.example.nothing.blurdemo;

import android.graphics.Bitmap;

public class BlurUtil {
    //分别在x轴 和 y轴方向上进行高斯模糊
    public static Bitmap gaussBlurUseGauss(Bitmap bitmap, int radius) {
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();

        //生成一张新的图片
        Bitmap outBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);

        //定义一个临时数组存储原始图片的像素 值
        int[] pix = new int[w * h];

        //将图片像素值写入数组
        bitmap.getPixels(pix, 0, w, 0, 0, w, h);

        //进行模糊
        initCBlur1(pix, w, h, radius);

        //将数据写入到 图片
        outBitmap.setPixels(pix, 0, w, 0, 0, w, h);

        //返回结果
        return outBitmap;
    }

    //利用均值模糊 逼近 高斯模糊
    public static Bitmap gaussBlurUseAvg(Bitmap bitmap, int radius) {
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();

        //生成一张新的图片
        Bitmap outBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);

        //定义一个临时数组存储原始图片的像素 值
        int[] pix = new int[w * h];

        //将图片像素值写入数组
        bitmap.getPixels(pix, 0, w, 0, 0, w, h);

        //进行模糊
        initCBlur2(pix, w, h, radius);

        //将数据写入到 图片
        outBitmap.setPixels(pix, 0, w, 0, 0, w, h);

        //返回结果
        return outBitmap;
    }

    //原始的高斯模糊 方法
    private static native void initCBlur1(int[] pix, int w, int h, int r);

    //利用均值模糊进行拟合 高斯模糊
    private static native void initCBlur2(int[] pix, int w, int h, int r);

    //加载native模块
    static {
        System.loadLibrary("hello-jni");
    }
}

主要注意加载模块。

hello-jni.cpp jni文件

由于高斯模糊,代码不多,就写到同一个cpp文件中。

代码语言:javascript
复制
#include <jni.h>
#include <android/log.h>
#include <iostream>
#include <cmath>

#define  LOG_TAG    "blur"
#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

#define PI 3.1415926


extern "C" {

//LOGD("jni %d:  %lf", i, amplitude[i]);
void gaussBlur1(int *pix, int w, int h, int radius) {
    float sigma = 1.0 * radius / 2.57;    //2.57 * sigam半径之后基本没有贡献 所以取sigma为 r / 2.57
    float deno = 1.0 / (sigma * sqrt(2.0 * PI));
    float nume = -1.0 / (2.0 * sigma * sigma);

    //高斯分布产生的数组
    float *gaussMatrix = (float *) malloc(sizeof(float) * (radius + radius + 1));
    float gaussSum = 0.0;
    for (int i = 0, x = -radius; x <= radius; ++x, ++i) {
        float g = deno * exp(1.0 * nume * x * x);

        gaussMatrix[i] = g;
        gaussSum += g;
    }

    //归1话
    int len = radius + radius + 1;
    for (int i = 0; i < len; ++i)
        gaussMatrix[i] /= gaussSum;

    //临时存储 一行的数据
    int *rowData = (int *) malloc(w * sizeof(int));
    int *listData = (int *) malloc(h * sizeof(int));

    //x方向的模糊
    for (int y = 0; y < h; ++y) {
        //拷贝一行数据
        memcpy(rowData, pix + y * w, sizeof(int) * w);

        for (int x = 0; x < w; ++x) {
            float r = 0, g = 0, b = 0;
            gaussSum = 0;

            for (int i = -radius; i <= radius; ++i) {
                int k = x + i;

                if (0 <= k && k <= w) {
                    //得到像素点的rgb值
                    int color = rowData[k];
                    int cr = (color & 0x00ff0000) >> 16;
                    int cg = (color & 0x0000ff00) >> 8;
                    int cb = (color & 0x000000ff);

                    r += cr * gaussMatrix[i + radius];
                    g += cg * gaussMatrix[i + radius];
                    b += cb * gaussMatrix[i + radius];

                    gaussSum += gaussMatrix[i + radius];
                }
            }

            int cr = (int) (r / gaussSum);
            int cg = (int) (g / gaussSum);
            int cb = (int) (b / gaussSum);

            pix[y * w + x] = cr << 16 | cg << 8 | cb | 0xff000000;
        }
    }

    for (int x = 0; x < w; ++x) {
        //拷贝 一列 数据
        for (int y = 0; y < h; ++y)
            listData[y] = pix[y * w + x];

        for (int y = 0; y < h; ++y) {
            float r = 0, g = 0, b = 0;
            gaussSum = 0;

            for (int j = -radius; j <= radius; ++j) {
                int k = y + j;

                if (0 <= k && k <= h) {
                    int color = listData[k];
                    int cr = (color & 0x00ff0000) >> 16;
                    int cg = (color & 0x0000ff00) >> 8;
                    int cb = (color & 0x000000ff);

                    r += cr * gaussMatrix[j + radius];
                    g += cg * gaussMatrix[j + radius];
                    b += cb * gaussMatrix[j + radius];

                    gaussSum += gaussMatrix[j + radius];
                }
            }

            int cr = (int) (r / gaussSum);
            int cg = (int) (g / gaussSum);
            int cb = (int) (b / gaussSum);

            pix[y * w + x] = cr << 16 | cg << 8 | cb | 0xff000000;
        }
    }

    //清理内存
    free(gaussMatrix);
    free(rowData);
    free(listData);
}


//参考:http://blog.ivank.net/fastest-gaussian-blur.html
//横向的均值模糊 srcPix:原始的像素值 destPix将处理过的像素值放入到 destPix中
void boxBlurH(int *srcPix, int *destPix, int w, int h, int radius) {
    //用于索引
    int index;

    //r g b在遍历是 累加的色彩通道的总和
    int a = 0, r = 0, g = 0, b = 0;
    int ta, tr, tg, tb;    //临时变量

    //临时变量
    int color;
    int preColor;

    //用于计算权值 1 / num
    int num;
    float iarr;

    for (int i = 0; i < h; ++i) {
        r = 0;
        g = 0;
        b = 0;

        index = i * w;
        num = radius;

        for (int j = 0; j < radius; j++) {
            //累加0,radius-1的色彩的总和
            color = srcPix[index + j];
            //a += (color & 0xff000000) >> 24;
            r += (color & 0x00ff0000) >> 16;
            g += (color & 0x0000ff00) >> 8;
            b += (color & 0x000000ff);
        }

        //真正开始计算
        for (int j = 0; j <= radius; ++j) {
            num++;
            iarr = 1.0 / (1.0 * num);

            color = srcPix[index + j + radius];
            //a += (color & 0xff000000) >> 24;
            r += (color & 0x00ff0000) >> 16;
            g += (color & 0x0000ff00) >> 8;
            b += (color & 0x000000ff);

            //ta = (int)(1.0 * a / num);
            tr = (int) (r * iarr);
            tg = (int) (g * iarr);
            tb = (int) (b * iarr);

            destPix[index + j] = tr << 16 | tg << 8 | tb | 0xff000000;
        }

        iarr = 1.0 / (1.0 * num);
        for (int j = radius + 1; j < w - radius; ++j) {
            preColor = srcPix[index + j - 1 - radius];
            color = srcPix[index + j + radius];

            //a += (color & 0xff000000) >> 24 - (preColor & 0xff000000) >> 24;
            r = r + ((color & 0x00ff0000) >> 16) - ((preColor & 0x00ff0000) >> 16);
            g = g + ((color & 0x0000ff00) >> 8) - ((preColor & 0x0000ff00) >> 8);
            b = b + (color & 0x000000ff) - (preColor & 0x000000ff);

            //ta = (int)(1.0 * a / num);
            tr = (int) (r * iarr);
            tg = (int) (g * iarr);
            tb = (int) (b * iarr);

            destPix[index + j] = tr << 16 | tg << 8 | tb | 0xff000000;
        }

        for (int j = w - radius; j < w; ++j) {
            num--;
            iarr = 1.0 / (1.0 * num);

            preColor = srcPix[index + j - 1 - radius];

            //a -= (preColor & 0xff000000) >> 24;
            r -= (preColor & 0x00ff0000) >> 16;
            g -= (preColor & 0x0000ff00) >> 8;
            b -= (preColor & 0x000000ff);

            //ta = (int)(1.0 * a / num);
            tr = (int) (r * iarr);
            tg = (int) (g * iarr);
            tb = (int) (b * iarr);

            //
            //destPix[index + j] = (ta << 24 | tr << 16 | tg << 8 | tb);
            destPix[index + j] = tr << 16 | tg << 8 | tb | 0xff000000;
        }
    }
}


//列的均值模糊 srcPix:原始的像素值 destPix将处理过的像素值放入到 destPix中
void boxBlurV(int *srcPix, int *destPix, int w, int h, int radius) {
    //r g b在遍历是 累加的色彩通道的总和
    int a = 0, r = 0, g = 0, b = 0;
    int ta, tr, tg, tb;    //临时变量

    //临时变量
    int color;
    int preColor;

    //用于计算权值 1 / num
    int num;
    float iarr;

    for (int i = 0; i < w; ++i) {
        r = 0;
        g = 0;
        b = 0;

        num = radius;

        for (int j = 0; j < radius; ++j) {
            color = srcPix[j * w + i];
            r += (color & 0x00ff0000) >> 16;
            g += (color & 0x0000ff00) >> 8;
            b += (color & 0x000000ff);
        }

        for (int j = 0; j <= radius; ++j) {
            num++;
            iarr = 1.0 / (1.0 * num);

            color = srcPix[(j + radius) * w + i];
            r += (color & 0x00ff0000) >> 16;
            g += (color & 0x0000ff00) >> 8;
            b += (color & 0x000000ff);

            tr = (int) (r * iarr);
            tg = (int) (g * iarr);
            tb = (int) (b * iarr);

            destPix[j * w + i] = tr << 16 | tg << 8 | tb | 0xff000000;
        }

        iarr = 1.0 / (1.0 * num);
        for (int j = radius + 1; j < h - radius; ++j) {
            preColor = srcPix[(j - radius - 1) * w + i];
            color = srcPix[(j + radius) * w + i];

            r = r + ((color & 0x00ff0000) >> 16) - ((preColor & 0x00ff0000) >> 16);
            g = g + ((color & 0x0000ff00) >> 8) - ((preColor & 0x0000ff00) >> 8);
            b = b + (color & 0x000000ff) - (preColor & 0x000000ff);

            tr = (int) (r * iarr);
            tg = (int) (g * iarr);
            tb = (int) (b * iarr);

            destPix[j * w + i] = tr << 16 | tg << 8 | tb | 0xff000000;
        }

        for (int j = h - radius; j < h; ++j) {
            num--;
            iarr = 1.0 / (1.0 * num);
            preColor = srcPix[(j - radius - 1) * w + i];

            r -= (preColor & 0x00ff0000) >> 16;
            g -= (preColor & 0x0000ff00) >> 8;
            b -= (preColor & 0x000000ff);

            tr = (int) (r * iarr);
            tg = (int) (g * iarr);
            tb = (int) (b * iarr);

            destPix[j * w + i] = tr << 16 | tg << 8 | tb | 0xff000000;
        }
    }
}

void boxBlur(int *srcPix, int *destPix, int w, int h, int r) {
    if (r < 0) {
        LOGD("boxBlur r < 0: %d", r);
        return;
    }

    boxBlurH(srcPix, destPix, w, h, r);
    boxBlurV(destPix, srcPix, w, h, r);
}

//领用n 个 box 拟合 sigma的高斯函数
//参考:http://www.csse.uwa.edu.au/~pk/research/pkpapers/FastGaussianSmoothing.pdf
void boxesForGauss(float sigma, int *size, int n) {
    float wIdeal = sqrt(12.0 * sigma * sigma / n + 1.0);
    int wl = floor(wIdeal);

    if (0 == wl % 2)
        wl--;

    int wu = wl + 2;

    float mIdeal = (12.0 * sigma * sigma - n * wl * wl - 4 * n * wl - 3 * n) / (-4 * wl - 4);
    int m = round(mIdeal);

    for (int i = 0; i < n; ++i)
        size[i] = (i < m ? wl : wu);
}

void gaussBlur2(int *pix, int w, int h, int r) {
    float sigma = 1.0 * r / 2.57;    //2.57 *sigam半径之后基本没有贡献 所以取sigma为 r / 2.57

    int boxSize = 3;
    int *boxR = (int *) malloc(sizeof(int) * boxSize);    //需要的个数

    //计算拟合的半径
    boxesForGauss(sigma, boxR, boxSize);

    int *tempPix = (int *) malloc(sizeof(int) * w * h);

    boxBlur(pix, tempPix, w, h, (boxR[0] - 1) / 2);
    boxBlur(pix, tempPix, w, h, (boxR[1] - 1) / 2);
    boxBlur(pix, tempPix, w, h, (boxR[2] - 1) / 2);

    //清理内存
    free(boxR);
    free(tempPix);
}

void Java_com_example_nothing_blurdemo_BlurUtil_initCBlur1(JNIEnv *env,
                                                           jobject obj,
                                                           jintArray pix,
                                                           jint w,
                                                           jint h,
                                                           jint r) {
    gaussBlur1(env->GetIntArrayElements(pix, NULL), w, h, r);
}

void Java_com_example_nothing_blurdemo_BlurUtil_initCBlur2(JNIEnv *env,
                                                           jobject obj,
                                                           jintArray pix,
                                                           jint w,
                                                           jint h,
                                                           jint r) {
    gaussBlur2(env->GetIntArrayElements(pix, NULL), w, h, r);
}

}

注意这里: Java_com_example_nothing_blurdemo_BlurUtil 为BlurUtil类的全包路径。initCBlur1 方法名。JNIEnv 环境变量,jobject ,jintArray什么的,j代表java,去掉j就知道了。

代码语言:javascript
复制
void Java_com_example_nothing_blurdemo_BlurUtil_initCBlur1(JNIEnv *env,
                                                           jobject obj,
                                                           jintArray pix,
                                                           jint w,
                                                           jint h,
                                                           jint r) {
    gaussBlur1(env->GetIntArrayElements(pix, NULL), w, h, r);
}

CMakeLists.txt文件

代码语言:javascript
复制
cmake_minimum_required(VERSION 3.4.1)

add_library(hello-jni SHARED
            hello-jni.cpp)

# Include libraries needed for hello-jni lib
target_link_libraries(hello-jni log android)

add_library(hello-jni SHARED hello-jni.cpp) 三个参数 ,第一个为库名,第二个shared库(so)。最后一个参数是引入的文件。

MainActivity

代码语言:javascript
复制
public class MainActivity extends AppCompatActivity {

    private static final String TAG = "nothingwxq";
    ImageView mImageView;
    private Subscriber<Bitmap> mBitmapSubscriber;
    private Subscription mSubscription;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView = (ImageView) this.findViewById(R.id.image);

        mBitmapSubscriber = new Subscriber<Bitmap>() {
            @Override
            public void onCompleted() {
                Log.d(TAG,"onCompleted---");
            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(Bitmap bitmap) {
                Log.d(TAG,"onNext---");
                mImageView.setImageBitmap(bitmap);
            }
        };

        Glide.with(getApplicationContext())
                .load("http://ww2.sinaimg.cn/mw1024/005yr3jYjw1f23h3vg4waj30qo0ziwlx.jpg")
                .asBitmap()
                .into(new SimpleTarget<Bitmap>() {
                    @Override
                    public void onResourceReady(final Bitmap bitmap, GlideAnimation anim) {
                        mSubscription = Observable
                                .create(new Observable.OnSubscribe<Bitmap>() {
                                    @Override
                                    public void call(Subscriber<? super Bitmap> subscriber) {
                                        Log.d(TAG, "creat---");
                                        subscriber.onNext(bitmap);
                                        subscriber.onCompleted();
                                    }
                                })
                                .observeOn(Schedulers.io())
                                .map(new Func1<Bitmap, Bitmap>() {
                                    @Override
                                    public Bitmap call(Bitmap bitmap) {
                                        Log.d(TAG, "map---");
                                        return BlurUtil.gaussBlurUseAvg(bitmap, 0);
                                    }
                                })
                                .subscribeOn(AndroidSchedulers.mainThread())
                                .observeOn(AndroidSchedulers.mainThread())
                                .subscribe(mBitmapSubscriber);
                    }
                });

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mSubscription.unsubscribe();
    }
}

本文省略资源文件,很简单的,一张图片。这里说下逻辑,使用Glide加载网上的图片,这里涉及Glide回调的监听。下载完成后,通过rxjava 的map 操作处理,最后onNext中进行设置图片,ok,完工。看下效果:

jni-3.png

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016.09.28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
    • 前提
      • 快速入门
        • BlurUtil.java
          • hello-jni.cpp jni文件
            • CMakeLists.txt文件
              • MainActivity
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档