Сшивание панорамы с помощью исходного кода камеры Android
Я пытаюсь создать панорамное изображение, сшивая набор растровых изображений. Для этой задачи я использую исходный код со стоковой камеры Android, у которой есть набор классов Panorama (мозаика). Этот код можно найти во многих репозиториях, но в любом случае вот официальный:
https://android.googlesource.com/platform/packages/apps/Camera2/+/android-4.4.3_r1
Для пользователей, которые знакомы со стандартной камерой Android, опция панорамы работает путем панорамирования / перемещения камеры, которая автоматически захватывает кадры для последующей постобработки. В моем случае мне нужно на самом деле сшивать по-прежнему растровые изображения и без кадров камеры.
Поэтому я создал функцию для приема растровых изображений на основе метода стандартной камеры:
Java_com_android_camera_Mosaic_setSourceImage
Далее мой метод для добавления растровых изображений вместо рамок камеры:
JNIEXPORT jfloatArray JNICALL Java_com_android_camera_Mosaic_setSourceBitmap(JNIEnv* env, jobject thiz, jobject bitmap)
{
int ret_code = Mosaic::MOSAIC_RET_OK;
if (frame_number_HR < MAX_FRAMES && frame_number_LR < MAX_FRAMES)
{
AndroidBitmapInfo bitmapInfo;
AndroidBitmap_getInfo(env, bitmap, &bitmapInfo);
void* bitmapPixels;
AndroidBitmap_lockPixels(env, bitmap, &bitmapPixels);
ImageUtils::rgba2yvu(tImage[HR][frame_number_HR], (unsigned char*)bitmapPixels, tWidth[HR], tHeight[HR]);
AndroidBitmap_unlockPixels(env, bitmap);
GenerateQuarterResImagePlanar(tImage[HR][frame_number_HR], tWidth[HR], tHeight[HR], tImage[LR][frame_number_LR]);
decodeYUV444SP(gPreviewImage[LR], tImage[LR][frame_number_LR], gPreviewImageWidth[LR], gPreviewImageHeight[LR]);
ret_code = AddFrame(LR, frame_number_LR, gTRS);
if (ret_code == Mosaic::MOSAIC_RET_OK || ret_code == Mosaic::MOSAIC_RET_FEW_INLIERS)
{
frame_number_LR++;
frame_number_HR++;
}
}
else
{
gTRS[1] = gTRS[2] = gTRS[3] = gTRS[5] = gTRS[6] = gTRS[7] = 0.0f;
gTRS[0] = gTRS[4] = gTRS[8] = 1.0f;
}
UpdateWarpTransformation(gTRS);
gTRS[9] = frame_number_HR;
gTRS[10] = ret_code;
jfloatArray bytes = env->NewFloatArray(11);
if (bytes != 0)
{
env->SetFloatArrayRegion(bytes, 0, 11, (jfloat*)gTRS);
}
return bytes;
}
И чтобы создать панораму, я делаю следующий рабочий процесс, также основанный на исходном коде Android:
private static Bitmap loadBitmap(final String filename)
{
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmap = BitmapFactory.decodeFile(filename, options);
return bitmap;
}
public int createMosaicFromBitmaps(final boolean highRes, final List<String> images)
{
for (String file : images)
{
final Bitmap bitmap = MosaicFrameProcessor.loadBitmap(file);
this._mosaicer.setSourceBitmap(bitmap);
bitmap.recycle();
}
return this._mosaicer.createMosaic(true);
}
public void generatePanorama()
{
final MosaicFrameProcessor mosaicProcessor = new MosaicFrameProcessor(1280, 720);
final List<String> imagesList = new ArrayList<String>();
imagesList.add("storage/extSdCard/Test2/A1.jpg");
imagesList.add("storage/extSdCard/Test2/A2.jpg");
imagesList.add("storage/extSdCard/Test2/A3.jpg");
final int mosaicReturnCode = createMosaicFromBitmaps(false, imagesList);
if (mosaicReturnCode == Mosaic.MOSAIC_RET_CANCELLED || mosaicReturnCode == Mosaic.MOSAIC_RET_ERROR)
{
return;
}
int[] imageData = mosaicProcessor.getFinalMosaic();
if (imageData == null)
{
Log.e(PanoramaActivity.TAG, "getFinalMosaic() returned null.");
return;
}
final int height = imageData[imageData.length - 1];
final int width = imageData[imageData.length - 2];
final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
System.arraycopy(imageData, 0, imageData, 0, imageData.length - 2);
bitmap.setPixels(imageData, 0, width, 0, 0, width, height);
final ImageView image = (ImageView)this.findViewById(com.example.customcamera.R.id.image);
image.setImageBitmap(bitmap);
image.invalidate();
}
Проблема, с которой я сталкиваюсь, заключается в том, что по трассировкам я вижу, что тестовые растровые изображения принимаются, они проходят проверку и панораму сшивают. Но возвращенное конечное изображение все перепутано. В результате получается один кадр изображения, содержащий разделы / части 3 тестовых изображений, а также неправильно выровненные и смешанные изображения.