Android 识别图片亮度

<Excerpt in index | 首页摘要>

Android 识别图片亮度

<The rest of contents | 余下全文>

概要

有一个界面是文字盖在图片上面,

设计希望能够更具图片的亮度来让文字自动设置为白色或者黑色。

所以就需要识别图片的light值。

需要依赖jni开发技术

原理

java层拿到bitmap,然后丢给c++处理。

bitmap的格式通常都为rgba8888

我们将rgba8888转换为yuv,拿到Y值 y就是亮度,然后求平均值即可得到图片整体的亮度

第一版目前是这样,但是这样是有一定误差的,比如一张顶部1/3纯白 底部2/3纯黑的图片,会被认为是暗得,但是如果你的文字是盖在上部分,那么误差就会出现。

具体可以修改不求整体的平均值,求图片的局部亮度平均值更为精准。

图片的识别是一件耗时操作(虽然也很快),但是还是推荐在创建的时候去识别,服务端记录,展示的时候直接根据字段计算即可。

代码实现

AS创建JNI项目,

移动CMakeLists至app目录下

CMakeLists内容:

1
2
3
4
5
6
7
cmake_minimum_required(VERSION 3.4.1)

add_library(libimg SHARED src/main/cpp/native-lib.cpp)

find_library(log-lib log)

target_link_libraries(libimg jnigraphics ${log-lib})

build.gradle修改

1
2
3
4
5
6
externalNativeBuild {
cmake {
path "CMakeLists.txt"
version "3.10.2"
}
}

MainActivity代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.gloomyer.lightdemo;

import android.Manifest;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;

import java.io.File;

public class MainActivity extends AppCompatActivity {

private static final String TAG = "MainActivity";

static {
System.loadLibrary("libimg");
}

private ImageView iv;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 123);
iv = findViewById(R.id.iv);
}


public native int getLight(Bitmap bitmap);

public boolean isLight(Bitmap bitmap) {
return getLight(bitmap) > 128;
}

public void load(View view) {
// Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.demo);
Bitmap bitmap = BitmapFactory.decodeFile(new File(Environment.getExternalStorageDirectory(), "black.jpeg").getAbsolutePath());
if (bitmap == null) {
Log.e(TAG, "bitmap == null");
return;
}
Log.e(TAG, "is light:" + isLight(bitmap));
iv.setImageBitmap(bitmap);
}
}

native-lib.cpp代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <jni.h>
#include <string>
#include <android/log.h>
#include <android/bitmap.h>

#define LOGE(FORMAT, ...) __android_log_print(ANDROID_LOG_ERROR,"MainActivity",FORMAT,##__VA_ARGS__);

extern "C"
JNIEXPORT jint JNICALL
Java_com_gloomyer_lightdemo_MainActivity_getLight(JNIEnv *env, jobject instance, jobject bitmap) {
AndroidBitmapInfo info;
int ret = 0;
if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) >= 0) {
uint32_t width = info.height;
uint32_t height = info.width;
LOGE("width:%d, height:%d, format:%d", info.width, info.height, info.format);
void *addr = new uint32_t[width * height];
long whereToGet = 0, bright = 0;
int r, g, b;
if (AndroidBitmap_lockPixels(env, bitmap, &addr) >= 0) {
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
uint32_t pixel = ((uint32_t *) addr)[whereToGet++];
r = (pixel | 0xff00ffff) >> 16 & 0x00ff;
g = (pixel | 0xffff00ff) >> 8 & 0x0000ff;
b = (pixel | 0xffffff00) & 0x0000ff;
bright = (int) (bright + 0.299 * r + 0.587 * g + 0.114 * b);
}
}
AndroidBitmap_unlockPixels(env, bitmap);
}
LOGE("ret:%d", ret);
return bright / (whereToGet - 1);
}
return -1;
}

GitHub下载

android_distinguish_image_light