Применить эффект серого к изображению с помощью NDK (C/С++) в Android

Я хочу применить эффект серого к изображению с помощью NDK.

Для этого я много googled, но нашел тот же результат, который возвращает изображение в несколько негативном (это то, что я считаю).

Что мне нужно:

Например:

У меня есть это оригинальное изображение

enter image description here

После применения эффекта оттенков серого это должно выглядеть так:

enter image description here

Что я пробовал::

Я хочу достичь этой функции с помощью NDK, так что я создал одну функцию в файле .cpp

JNIEXPORT void JNICALL Java_com_example_ndksampleproject_MainActivity_jniConvertToGray(JNIEnv * env, jobject  obj, jobject bitmapcolor,jobject bitmapgray)
{
    AndroidBitmapInfo  infocolor;
    void*              pixelscolor;
    AndroidBitmapInfo  infogray;
    void*              pixelsgray;
    int                ret;
    int             y;
    int             x;

    LOGI("convertToGray");
    if ((ret = AndroidBitmap_getInfo(env, bitmapcolor, &infocolor)) < 0) {
        LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
        return;
    }

    if ((ret = AndroidBitmap_getInfo(env, bitmapgray, &infogray)) < 0) {
        LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
        return;
    }

    LOGI("color image :: width is %d; height is %d; stride is %d; format is %d;flags is %d",infocolor.width,infocolor.height,infocolor.stride,infocolor.format,infocolor.flags);
    if (infocolor.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
        LOGE("Bitmap format is not RGBA_8888 !");
        return;
    }

    LOGI("gray image :: width is %d; height is %d; stride is %d; format is %d;flags is %d",infogray.width,infogray.height,infogray.stride,infogray.format,infogray.flags);
    if (infogray.format != ANDROID_BITMAP_FORMAT_A_8) {
        LOGE("Bitmap format is not A_8 !");
        return;
    }

    if ((ret = AndroidBitmap_lockPixels(env, bitmapcolor, &pixelscolor)) < 0) {
        LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
    }

    if ((ret = AndroidBitmap_lockPixels(env, bitmapgray, &pixelsgray)) < 0) {
        LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
    }

    LOGI("unlocking pixels height = %d",infocolor.height);

    // modify pixels with image processing algorithm

    for (y=0;y<infocolor.height;y++) {
        argb * line = (argb *) pixelscolor;
        uint8_t * grayline = (uint8_t *) pixelsgray;
        for (x=0;x<infocolor.width;x++) {
            grayline[x] = 0.3 * line[x].red + 0.59 * line[x].green + 0.11*line[x].blue;
        }

        pixelscolor = (char *)pixelscolor + infocolor.stride;
        pixelsgray = (char *) pixelsgray + infogray.stride;
    }

    LOGI("unlocking pixels");
    AndroidBitmap_unlockPixels(env, bitmapcolor);
    AndroidBitmap_unlockPixels(env, bitmapgray);
}

Вышеуказанная функция возвращает мне результат следующим образом:

enter image description here

Этот эффект выглядит как нечто вроде негатива изображения.

Позвольте мне знать, если вам что-то нужно с моей стороны.. Пожалуйста, помогите мне решить эту проблему, поскольку я застрял в этом с многих часов.

Большое спасибо в Advance...

EDIT::

floppy12 Предложение::

for (y=0;y<infocolor.height;y++) {
        argb * line = (argb *) pixelscolor;
        uint8_t * grayline = (uint8_t *) pixelsgray;
        for (x=0;x<infocolor.width;x++) {
            grayline[x] = (255-0.3 * line[x].red) + (255-0.59 * line[x].green) + (255-0.11*line[x].blue)/3;
        }

        pixelscolor = (char *)pixelscolor + infocolor.stride;
        pixelsgray = (char *) pixelsgray + infogray.stride;
    }

Выход::

enter image description here

EDIT 2::

Я сделал некоторую простую модификацию изображения, и он возвращает мне изображение, которое я хотел, но изображение потеряло свою яркость.

Это изменения, которые я сделал в собственной функции.

for (y=0;y<infocolor.height;y++) {
        argb * line = (argb *) pixelscolor;
        uint8_t * grayline = (uint8_t *) pixelsgray;
        for (x=0;x<infocolor.width;x++) {
            grayline[x] = ((255-0.3 * line[x].red) + (255-0.59 * line[x].green) + (255-0.11*line[x].blue))/3;
        }

        pixelscolor = (char *)pixelscolor + infocolor.stride;
        pixelsgray = (char *) pixelsgray + infogray.stride;
    }

Результат (изображение серого цвета, но потеряло его яркость)::

enter image description here

Ответы

Ответ 1

Чтобы получить изображение в оттенках серого, каждый пиксель должен иметь одинаковое количество красного, зеленого и синего

Возможно, используйте красный компонент и примените его как к зеленому, так и к синему в вычислении серых линий.

или используйте формулу (R + G + B)/3 = Серый

Отрицательные изображения обычно получаются путем сдвига каждого компонента:

NegR = 255 - серыйR

и т.д.

Итак, вы можете попытаться вычислить grayscal [x] = (255 - 0.3 * line [x]) +...

Изменить яркость: Чтобы получить лучшую яркость, попробуйте добавить фиксированную сумму к вычислению оттенков серого:

G += Bness;

Здесь кажется, что Bness должен быть отрицательным, если вы переходите от 255 (черный) к 0 (белый) по какой-то странной причине. Вы хотите поставить нижний предел, чтобы он не попадал под 0 для вашего значения в гране, а затем попробуйте:

G = max(0, G+Bness);

Я рекомендую что-то вроде Bness = -25

Изменить яркость реализации:

// Declare a global variable for your brightness - outside your class
static uint8_t bness = -25;

// In your grayscale computation function
for y...
 for x...
  grayscale[x] = ( (255-0.3*line[x].red) + ..... ) /3 ;
  int16_t gBright = grayscale[x] + bness;
  grayscale[x] = MAX( 0, gBright );