#android #android-ndk
#Android #android-ndk
Вопрос:
Я пытаюсь преобразовать изображение в оттенки серого с помощью встроенной функции, используя фрагмент кода, взятый из Android in Action (2-е изд.; Вы также можете увидеть его здесь). К сожалению, возвращаемый объект bitmap вместо оттенков серого оказывается пустым.
Вот как я загружаю изображение (.png):
Bitmap original = BitmapFactory.decodeResource(this.getResources(), R.drawable.sample, options);
Существует ряд условий безопасности, которые выполняет растровое изображение (пожалуйста, проверьте ниже). Вот определение встроенной функции в Java:
public native void convertToGray(Bitmap bitmapIn,Bitmap bitmapOut);
и вызов:
// Grayscale bitmap (initially empty)
Bitmap gray = Bitmap.createBitmap(original.getWidth(),original.getHeight(),Config.ALPHA_8);
// Native function call
convertToGray(original,gray);
И вот функция:
JNIEXPORT void JNICALL Java_com_example_Preprocessor_convertToGray(JNIEnv * env, jobject obj, jobject bitmapcolor,jobject bitmapgray)
{
AndroidBitmapInfo infocolor;
AndroidBitmapInfo infogray;
void* pixelscolor;
void* pixelsgray;
int ret;
int y;
int x;
LOGI("convertToGray");
if ((ret = AndroidBitmap_getInfo(env, bitmapcolor, amp;infocolor)) < 0) {
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
return;
}
if ((ret = AndroidBitmap_getInfo(env, bitmapgray, amp;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, amp;pixelscolor)) < 0) {
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
}
if ((ret = AndroidBitmap_lockPixels(env, bitmapgray, amp;pixelsgray)) < 0) {
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
}
// 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("Done! Unlocking pixels...");
AndroidBitmap_unlockPixels(env, bitmapcolor);
AndroidBitmap_unlockPixels(env, bitmapgray);
}
Цветное растровое изображение передается правильно, и обрабатывающая часть кода, похоже, работает нормально, но bitmapgray остается пустым. Думаю, я упускаю здесь что-то важное.
Тестовая среда: эмулятор, версия 2.2. В этой версии функция работает, когда собственный код вызывается из основного потока. В эмуляторе 2.3 функция не работает независимо от потока, который вызывает C-код, или способа загрузки растрового изображения. Android NDK: 4b и 6b.
ОБНОВЛЕНИЕ # 1: здесь вы найдете полный исходный код.
ОБНОВЛЕНИЕ # 2: RGB_565 вместо ALPHA_8 дает некоторые результаты. Похоже, что даже SetPixels() в Java не работает для ALPHA_8, и у меня возникают проблемы с поиском информации об этом типе конфигурации. Любая помощь будет высоко оценена.
Комментарии:
1. Рассматривали ли вы возможность использования ByteBuffer в качестве вывода? Если это сработает, то мы могли бы быть более уверены, что с AndroidBitmap что-то не так… Тоже есть
bitmapIn
,bitmapOrig
иoriginal
тот же объект?2. Я совершенно новичок в JNI, так что нет, я его еще не пробовал. Я попробую сделать это, а затем доложу об этом. Я все равно был бы благодарен за некоторые советы или указания, которые могли бы ускорить процесс. И, да, bitmapIn = bitmapOrig = original (извините за последние два; я должен был сделать это более понятным; исправил это).
3. @SamuelAudet: Хорошо, я попробовал это . В результате получается почти пустое растровое изображение (белая поверхность с черными артефактами (случайными черными точками)). Кто-нибудь еще был бы достаточно любезен, чтобы попробовать это?
4. И вы не получаете никаких предупреждений или чего-либо в журнале?
5. @SamuelAudet: Нет, ничего. вычисление grayline [x] определенно работает, и, следовательно, pixelsgray также должен быть заполнен правильными значениями. Однако bitmapgray остается пустым.
Ответ №1:
У меня была похожая проблема. Прежде всего, я использовал формат Android RGBA_8888 для infogray вместо A_8 (исходное растровое изображение было создано с использованием формата ARGB_8888). Затем, если вы используете argb struct для grayline вместо uint_8, вы можете заполнить пиксели следующим образом:
for (y = 0; y < infocolor.height; y) {
argb* line = (argb*) pixelscolor;
argb* grayline = (argb*) pixelsgray;
for (x = 0; x < infocolor.width; x) {
grayline[x].red = grayline[x].green = grayline[x].blue = 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;
}
Комментарии:
1. Ну, это дает некоторые результаты, но выходное изображение голубоватое. Я надеялся использовать A_8 для экономии памяти (я бы хотел попробовать обработку изображений в реальном времени).
Ответ №2:
у меня были те же проблемы. Я не очень старался заставить ALPHA_8 работать, но использование ARGB_8888 устраняет проблему.
Кстати, в ответ на комментарий @white_pawn (извините, я не могу отвечать на комментарии)
Структура argb в примере IBM находится в неправильном порядке. в моих эмуляторах или телефоне преобразование его в RGBA устраняет проблему (вероятно, это причина, по которой ваше изображение выглядит синим, потому что вы используете alpa для синего цвета). Хотя я не уверен, зависит ли этот порядок от оборудования.
typedef struct
{
uint8_t red;
uint8_t green;
uint8_t blue;
uint8_t alpha;
} argb;
Ответ №3:
У меня была такая же проблема, и я нашел, что пошло не так! При использовании APHA_8 вам необходимо изменить фон на #ffffffff,
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffffff">