Digital2Slave / ncnn-android-yolov8-seg

a sample yolov8 object segment android project based on ncnn and opencv.
68 stars 8 forks source link

Help to process static images the way camera frames are processed. #8

Open chinmayanandValtech opened 7 months ago

chinmayanandValtech commented 7 months ago

Hi all, I have application where user will take picture from camera and process it. So I'm using this repo its working fine for camera frames, I need help to process and segment the static images. Please provide any docs, code snippets.

Thank you

Digital2Slave commented 6 months ago

@chinmayanandValtech you need to create your custom jni function in yolov8ncnn.cpp like the following code snippet:

JNIEXPORT jobject JNICALL Java_cn_epbox_cv_1segx_CvSegx_getPicSegmentResult(
        JNIEnv *env,
        jobject p_this,
        jobject assetManager,
        jobject bmp,
        jstring image_name) {

    // convert jstring to string
    const char *text = env->GetStringUTFChars(image_name, JNI_FALSE);
    std::string img_name = text;

    // get image info
    jclass java_bitmap_class = (jclass) env->FindClass("android/graphics/Bitmap");
    jmethodID mid = env->GetMethodID(java_bitmap_class, "getConfig", "()Landroid/graphics/Bitmap$Config;");
    jobject bitmap_config = env->CallObjectMethod(bmp, mid);

    // generate opencv mat object
    cv::Mat src;
    bitmapToMat(env, bmp, src, JNI_FALSE);
    cv::cvtColor(src, src, cv::COLOR_RGBA2RGB);

    // load model
    AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
......
}
void bitmapToMat(JNIEnv *env, jobject bitmap, cv::Mat& dst, jboolean needUnPremultiplyAlpha) {
    AndroidBitmapInfo  info;
    void*              pixels = 0;

    try {
        assert( AndroidBitmap_getInfo(env, bitmap, &info) >= 0 );
        assert( info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 ||
                info.format == ANDROID_BITMAP_FORMAT_RGB_565 );
        assert( AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0 );
        assert( pixels );
        dst.create(info.height, info.width, CV_8UC4);
        LOGI("bitmapToMat bitmap info.format:%d", info.format);
        if( info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 )
        {
            cv::Mat tmp(info.height, info.width, CV_8UC4, pixels);
            if(needUnPremultiplyAlpha) cvtColor(tmp, dst, cv::COLOR_mRGBA2RGBA);
            else tmp.copyTo(dst);
        } else {
            // info.format == ANDROID_BITMAP_FORMAT_RGB_565
            cv::Mat tmp(info.height, info.width, CV_8UC2, pixels);
            cvtColor(tmp, dst, cv::COLOR_BGR5652RGBA);
        }
        AndroidBitmap_unlockPixels(env, bitmap);
        return;
    } catch(const cv::Exception& e) {
        AndroidBitmap_unlockPixels(env, bitmap);
        jclass je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, e.what());
        return;
    } catch (...) {
        AndroidBitmap_unlockPixels(env, bitmap);
        jclass je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, "Unknown exception in JNI code {nBitmapToMat}");
        return;
    }
}
mengxizeng commented 3 months ago

@chinmayanandValtech you need to create your custom jni function in yolov8ncnn.cpp like the following code snippet:

JNIEXPORT jobject JNICALL Java_cn_epbox_cv_1segx_CvSegx_getPicSegmentResult(
        JNIEnv *env,
        jobject p_this,
        jobject assetManager,
        jobject bmp,
        jstring image_name) {

    // convert jstring to string
    const char *text = env->GetStringUTFChars(image_name, JNI_FALSE);
    std::string img_name = text;

    // get image info
    jclass java_bitmap_class = (jclass) env->FindClass("android/graphics/Bitmap");
    jmethodID mid = env->GetMethodID(java_bitmap_class, "getConfig", "()Landroid/graphics/Bitmap$Config;");
    jobject bitmap_config = env->CallObjectMethod(bmp, mid);

    // generate opencv mat object
    cv::Mat src;
    bitmapToMat(env, bmp, src, JNI_FALSE);
    cv::cvtColor(src, src, cv::COLOR_RGBA2RGB);

    // load model
    AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
......
}
  • bitmapToMat
void bitmapToMat(JNIEnv *env, jobject bitmap, cv::Mat& dst, jboolean needUnPremultiplyAlpha) {
    AndroidBitmapInfo  info;
    void*              pixels = 0;

    try {
        assert( AndroidBitmap_getInfo(env, bitmap, &info) >= 0 );
        assert( info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 ||
                info.format == ANDROID_BITMAP_FORMAT_RGB_565 );
        assert( AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0 );
        assert( pixels );
        dst.create(info.height, info.width, CV_8UC4);
        LOGI("bitmapToMat bitmap info.format:%d", info.format);
        if( info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 )
        {
            cv::Mat tmp(info.height, info.width, CV_8UC4, pixels);
            if(needUnPremultiplyAlpha) cvtColor(tmp, dst, cv::COLOR_mRGBA2RGBA);
            else tmp.copyTo(dst);
        } else {
            // info.format == ANDROID_BITMAP_FORMAT_RGB_565
            cv::Mat tmp(info.height, info.width, CV_8UC2, pixels);
            cvtColor(tmp, dst, cv::COLOR_BGR5652RGBA);
        }
        AndroidBitmap_unlockPixels(env, bitmap);
        return;
    } catch(const cv::Exception& e) {
        AndroidBitmap_unlockPixels(env, bitmap);
        jclass je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, e.what());
        return;
    } catch (...) {
        AndroidBitmap_unlockPixels(env, bitmap);
        jclass je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, "Unknown exception in JNI code {nBitmapToMat}");
        return;
    }
}

hi,The answer given by Chatgpt 4: @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 1 && resultCode == RESULT_OK && data != null) { Uri imageUri = data.getData(); try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
if (!bitmap.isMutable()) { bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true); } ImageView imageView = (ImageView) findViewById(R.id.cameraview); Bitmap detectedImage = yolov8ncnn.detectImage(bitmap); imageView.setImageBitmap(detectedImage); } catch (IOException e) { e.printStackTrace(); } } }

JNIEXPORT jobject JNICALL Java_com_tencent_yolov8ncnn_Yolov8Ncnn_detectImage(JNIEnv env, jobject thiz, jobject bitmap) { AndroidBitmapInfo info; void bitmapPixels; cv::Mat img;

if (AndroidBitmap_getInfo(env, bitmap, &info) < 0) {
    return NULL;
}

if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
    return NULL;
}

if (AndroidBitmap_lockPixels(env, bitmap, &bitmapPixels) < 0) {
    return NULL;
}

img = cv::Mat(info.height, info.width, CV_8UC4, bitmapPixels);
cv::cvtColor(img, img, cv::COLOR_RGBA2BGR);
std::vector<Object> objects;
g_yolo->detect(img, objects);
__android_log_print(ANDROID_LOG_INFO, "YoloV8Ncnn", "Detected %d objects.", objects.size());
g_yolo->draw(img, objects);
__android_log_print(ANDROID_LOG_INFO, "YoloV8Ncnn", "draw %d objects",objects.size());
//cv::cvtColor(img, img, cv::COLOR_BGR2RGBA);
AndroidBitmap_unlockPixels(env, bitmap);
return bitmap;

} In this way, the main activity is achieved by passing in the bitmap and jni functions to perform image segmentation. After detection, there are also results, but no borders are drawn.