Costura panorâmica com código fonte da câmera Android

Estou tentando criar uma imagem panorâmica unindo um conjunto de bitmaps. Para esta tarefa, estou usando o código-fonte da câmera android, que possui um conjunto de classes Panorama (mosaico). Este código pode ser encontrado em muitos repositórios, mas em qualquer caso, aqui é o oficial:

https://android.googlesource.com/platform/packages/apps/Camera2/+/android-4.4.3_r1

Para usuários familiarizados com a câmera android padrão, a opção panorama funciona deslocando / movendo a câmera, que captura automaticamente os quadros para posterior processamento posterior. No meu caso, preciso costurar bitmaps estáticos e sem quadros de câmera.

Então, eu criei uma função para aceitar bitmaps com base no método da câmera padrão:

Java_com_android_camera_Mosaic_setSourceImage

Em seguida, meu método para enviar bitmaps em vez de quadros da câmera:

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;
}

E para gerar o panorama, eu faço o próximo fluxo de trabalho, também baseado no código-fonte do 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();
}

O problema que estou enfrentando é que, pelos traços, vejo que os bitmaps de teste são aceitos, passam na validação e um panorama é costurado. Mas a imagem final retornada está toda misturada. O resultado é um único quadro de imagem contendo seções / partes das 3 imagens de teste, além de alinhadas e mescladas incorretamente.

questionAnswers(0)

yourAnswerToTheQuestion