image_tools.cpp 7.17 KB
Newer Older
姜天宇's avatar
姜天宇 committed
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
//
// Created by dizi on 2024/7/12.
//

#include "include/image_tools.h"


/**
 * 生成一个空的ARGB8888的Bitmap
 * @param env
 * @param width
 * @param height
 * @return
 */
jobject generate_empty_argb8888_bitmap(JNIEnv *env, int width, int height){
    jclass bitmapClass = env->FindClass("android/graphics/Bitmap");
    jmethodID constructorID = env->GetStaticMethodID(bitmapClass, "createBitmap","(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
    jclass bitmapConfigClass = env->FindClass("android/graphics/Bitmap$Config");
    jfieldID argb8888FieldID = env->GetStaticFieldID(bitmapConfigClass, "ARGB_8888", "Landroid/graphics/Bitmap$Config;");
    jobject argb8888Value = env->GetStaticObjectField(bitmapConfigClass, argb8888FieldID);
    // 创建Bitmap对象
    return env->CallStaticObjectMethod(bitmapClass, constructorID, width, height, argb8888Value);
}

/**
 * 将Bitmap转Mat
 * @param env
 * @param bitmap
 * @return
 */
cv::Mat convert_bitmap_to_mat(JNIEnv *env, jobject bitmap){
    cv::Mat mat;
    // bitmap转mat
    // 获取Bitmap的信息
    AndroidBitmapInfo info;
    AndroidBitmap_getInfo(env, bitmap, &info);
    // 根据Bitmap的图片格式决定type
    int type;
    if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888){
40
//        LOGD("CV_8UC4");
姜天宇's avatar
姜天宇 committed
41 42 43
        type = CV_8UC4;
    }
    else if (info.format == ANDROID_BITMAP_FORMAT_RGB_565){
44
//        LOGD("CV_8UC2");
姜天宇's avatar
姜天宇 committed
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
        type = CV_8UC2;
    }
    else{
        LOGD("channel error");
        return mat;
    }
    // 获取Bitmap的像素
    void * pixels;
    AndroidBitmap_lockPixels(env, bitmap, &pixels);
    if (pixels == nullptr){
        return mat;
    }
    // Bitmap转Mat
    mat = cv::Mat(info.height, info.width, type, pixels);
    // 解锁
    AndroidBitmap_unlockPixels(env, bitmap);
    return mat;
}

/**
 * 将Mat转化为Bitmap
 * @param env
 * @param mat
 * @return
 */
jobject convert_mat_to_bitmap(JNIEnv *env, cv::Mat mat){
    AndroidBitmapInfo info;
    void *pixels = 0;
    // 生成Bitmap
    jobject bitmap = generate_empty_argb8888_bitmap(env, mat.cols, mat.rows);

    try {
        CV_Assert(AndroidBitmap_getInfo(env, bitmap, &info) >= 0);
        CV_Assert(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 ||
                  info.format == ANDROID_BITMAP_FORMAT_RGB_565);
        CV_Assert(mat.dims == 2 && info.height == (uint32_t) mat.rows && info.width == (uint32_t) mat.cols);
        CV_Assert(mat.type() == CV_8UC1 || mat.type() == CV_8UC3 || mat.type() == CV_8UC4);
        CV_Assert(AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0);
        CV_Assert(pixels);
        if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
            cv::Mat tmp(info.height, info.width, CV_8UC4, pixels);
            if (mat.type() == CV_8UC1) {
                cvtColor(mat, tmp, cv::COLOR_GRAY2RGBA);
            } else if (mat.type() == CV_8UC3) {
                cvtColor(mat, tmp, cv::COLOR_RGB2RGBA);
            } else if (mat.type() == CV_8UC4) {
                mat.copyTo(tmp);
            }
        } else {
            cv::Mat tmp(info.height, info.width, CV_8UC2, pixels);
            if (mat.type() == CV_8UC1) {
                cvtColor(mat, tmp, cv::COLOR_GRAY2BGR565);
            } else if (mat.type() == CV_8UC3) {
                cvtColor(mat, tmp, cv::COLOR_RGB2BGR565);
            } else if (mat.type() == CV_8UC4) {
                cvtColor(mat, tmp, cv::COLOR_RGBA2BGR565);
            }
        }
        AndroidBitmap_unlockPixels(env, bitmap);
    } catch (const cv::Exception &e) {
        AndroidBitmap_unlockPixels(env, bitmap);
        LOGE("nMatToBitmap catched cv::Exception: %s", e.what());
        jclass je = env->FindClass("org/opencv/core/CvException");
        if (!je) je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, e.what());
    } catch (...) {
        AndroidBitmap_unlockPixels(env, bitmap);
        LOGE("nMatToBitmap catched unknown exception (...)");
        jclass je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, "Unknown exception in JNI code {nMatToBitmap}");
    }
    return bitmap;
}

/**
 * 在MAT上绘制框
 * @param mat 三通道
 * @param left_top_x
 * @param left_top_y
 * @param right_bottom_x
 * @param right_bottom_y
 * @return
 */
cv::Mat draw_rect_on_mat(cv::Mat mat, int left_top_x, int left_top_y, int right_bottom_x, int right_bottom_y){
    // 声明左上角和右下角坐标
    cv::Point point_left_top(left_top_x, left_top_y);
    cv::Point point_right_bottom(right_bottom_x, right_bottom_y);
132
    // 定义颜色和线宽度 bgr
姜天宇's avatar
姜天宇 committed
133 134 135 136 137 138
    cv::Scalar color(0, 0, 255);
    int thickness = 2;
    // 画框
    cv::rectangle(mat, point_left_top, point_right_bottom, color, thickness);

    return mat;
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
}

cv::Mat draw_rect_text_on_mat(cv::Mat mat, int left_top_x, int left_top_y, int right_bottom_x, int right_bottom_y, char* text){
    // 声明左上角和右下角坐标
    cv::Point point_left_top(left_top_x, left_top_y);
    cv::Point point_right_bottom(right_bottom_x, right_bottom_y);
    // 定义颜色和线宽度 bgr
    cv::Scalar red  (0, 0, 255);
    cv::Scalar green(0, 255, 0);
    int thickness = 2;
    if (strcmp(text, "未知商品") == 0){
        // 画框
        cv::rectangle(mat, point_left_top, point_right_bottom, red, thickness);
        // 绘制文字
        cv::putText(mat, text, point_left_top, cv::HersheyFonts::FONT_HERSHEY_SIMPLEX, 1, red, thickness);
    }
    else{
        // 画框
        cv::rectangle(mat, point_left_top, point_right_bottom, green, thickness);
        // 绘制文字
        cv::putText(mat, text, point_left_top, cv::HersheyFonts::FONT_HERSHEY_SIMPLEX, 1, green, thickness);
    }


    return mat;
}

/**
 * 在图片上绘制框和文字
 */
extern "C"
JNIEXPORT jobject JNICALL
Java_com_wmdigit_core_opencv_OpencvRepository_drawRectAndTextOnBitmap(JNIEnv *env, jobject thiz,
                                                                      jobject bitmap,
                                                                      jobjectArray points,
                                                                      jobjectArray product_names) {
    // bitmap转mat
    cv::Mat mat = convert_bitmap_to_mat(env, bitmap);
    cv::Mat mat_bgr;
    cv::cvtColor(mat, mat_bgr, CV_RGBA2BGR);
    // jobjectarray转int**
    int ** points_array = convert_jobjectArray_to_intArrayArray(env, points);
    // jobjectArray转char**
    JStringInfo * jStringInfo = convert_jobjectArray_to_charArrayArray(env, product_names);
    // 框数量
    int count = env->GetArrayLength(points);
    LOGD("COUNT:%d", count);
    // 遍历数组,绘制框和文字
    for (int i = 0; i < count; i++) {
        LOGD("%d, %d, %d, %d, %s", points_array[i][0], points_array[i][1], points_array[i][2], points_array[i][3], jStringInfo[i].str);
        mat_bgr = draw_rect_text_on_mat(mat_bgr, points_array[i][0], points_array[i][1], points_array[i][2], points_array[i][3], jStringInfo[i].str);
    }
    // mat转Bitmap
    cv::Mat mat_rgb;
    cv::cvtColor(mat_bgr, mat_rgb, CV_BGR2RGB);
    jobject result = convert_mat_to_bitmap(env, mat_rgb);
    // 释放资源
    freeStringArray(jStringInfo, count);
    mat.release();
    mat_bgr.release();
    mat_rgb.release();
    freeIntArrayArray(points_array, count);
    return result;
姜天宇's avatar
姜天宇 committed
202
}