[英]ARCore's ArFrame_acquireCameraImage method returns green image
我正在嘗試使用 ARCore 從相機獲取圖像。
我正在調用ArFrame_acquireCameraImage ,它返回 YUV_420_888 格式的圖像。 我還使用ArImage_getFormat方法檢查了它。 它返回給我 640x480 圖像。 然后我獲得 U 平面的像素步長以區分 NV21 或 YV12 格式的圖像。
然后我使用memcpy
將 Y、U、V arrays 組合成單個,將其編碼為 Base64 (使用J. Malinen 的 function )並將其打印到日志。
我還嘗試使用RenderScript Intrinsics Replacement Toolkit執行 YUV420p -> RGBA 轉換。
我有這個代碼:
LOGD("take frame");
ArImage *image = nullptr;
if (mArSession != nullptr && mArFrame != nullptr &&
ArFrame_acquireCameraImage(mArSession, mArFrame, &image) == AR_SUCCESS) {
const uint8_t *y;
const uint8_t *u;
const uint8_t *v;
int planesCount = 0;
ArImage_getNumberOfPlanes(mArSession, image, &planesCount);
LOGD("%i", planesCount);
int yLength, uLength, vLength;
ArImage_getPlaneData(mArSession, image, 0, &y, &yLength);
ArImage_getPlaneData(mArSession, image, 1, &u, &uLength);
ArImage_getPlaneData(mArSession, image, 2, &v, &vLength);
auto *yuv420 = new uint8_t[yLength + uLength + vLength];
memcpy(yuv420, y, yLength);
memcpy(yuv420 + yLength, u, uLength);
memcpy(yuv420 + yLength + uLength, v, vLength);
int width, height, stride;
ArImage_getWidth(mArSession, image, &width);
ArImage_getHeight(mArSession, image, &height);
ArImage_getPlanePixelStride(mArSession, image, 1, &stride);
//auto *argb8888 = new uint8_t[width * height * 4];
renderscript::RenderScriptToolkit::YuvFormat format = renderscript::RenderScriptToolkit::YuvFormat::YV12;
if(stride != 1) {
format = renderscript::RenderScriptToolkit::YuvFormat::NV21;
}
LOGD("%i %i %i", width, height, format);
/*renderscript::RenderScriptToolkit toolkit;
toolkit.yuvToRgb(yuv420, argb8888, width, height, format);*/
LOGD("%s", base64_encode(yuv420, yLength + uLength + vLength).c_str());
// delete[](argb8888);
delete[](yuv420);
}
if (image != nullptr) {
ArImage_release(image);
}
我的手機是小米米A3。 也嘗試在模擬器上運行它,但它仍然給我同樣的畫面。
實際圖像應如下所示:
但是,我的代碼會打印此圖像(我使用RAW Pixels對其進行解碼):
如果我取消注釋 YUV420 -> ARGB 轉換的代碼並為argb8888
數組打印 Base64,我將得到這個圖像:
預設:RGB32,寬度:640,高度:480 。此圖像的Base64 。
我用取自 TensorFlow 的代碼替換了 RenderScript Intrinsics Replacement Toolkit(具有多線程和 SMID)。 我看到了這個優點:
auto *yuv420 = new uint8_t[yLength + uLength + vLength];
memcpy(yuv420, y, yLength);
memcpy(yuv420 + yLength, u, uLength);
memcpy(yuv420 + yLength + uLength, v, vLength);
renderscript::RenderScriptToolkit::YuvFormat format =
renderscript::RenderScriptToolkit::YuvFormat::YV12;
if(stride != 1) {
format = renderscript::RenderScriptToolkit::YuvFormat::NV21;
}
renderscript::RenderScriptToolkit toolkit;
toolkit.yuvToRgb(yuv420, argb8888, width, height, format);
這是我寫的使用 TensorFlow 代碼的行:
ConvertYUV420ToARGB8888(y, u, v, argb8888, width, height, yStride, uvStride, uvPixelStride);
如您所見,RSIRT 僅采用平面圖像,而 Tensorflow 代碼編寫為使用由 3 個平面分割的圖像,因此您不需要使用 memcpy。 這就是為什么這個決定不會影響性能的原因。
完整代碼:
ArImage *image = nullptr;
if (mArSession != nullptr && mArFrame != nullptr &&
ArFrame_acquireCameraImage(mArSession, mArFrame, &image) == AR_SUCCESS) {
// It's image with Android YUV 420 format https://developer.android.com/reference/android/graphics/ImageFormat#YUV_420_888
const uint8_t *y;
const uint8_t *u;
const uint8_t *v;
int planesCount = 0;
ArImage_getNumberOfPlanes(mArSession, image, &planesCount);
LOGD("%i", planesCount);
int yLength, uLength, vLength, yStride, uvStride, uvPixelStride;
ArImage_getPlaneData(mArSession, image, 0, &y, &yLength);
ArImage_getPlaneData(mArSession, image, 1, &u, &uLength);
ArImage_getPlaneData(mArSession, image, 2, &v, &vLength);
ArImage_getPlaneRowStride(mArSession, image, 0, &yStride);
ArImage_getPlaneRowStride(mArSession, image, 1, &uvStride);
ArImage_getPlanePixelStride(mArSession, image, 1, &uvPixelStride);
int width, height;
ArImage_getWidth(mArSession, image, &width);
ArImage_getHeight(mArSession, image, &height);
auto *argb8888 = new uint32_t[width * height];
ConvertYUV420ToARGB8888(y, u, v, argb8888, width, height, yStride, uvStride, uvPixelStride);
std::ofstream stream("/data/user/0/{your app package name}/cache/img", std::ios::out | std::ios::binary);
for(int i = 0; i < width * height; i++)
stream.write((char *) &argb8888[i], sizeof(uint32_t));
stream.close();
LOGD("%i %i", width, height);
delete[](argb8888);
}
if (image != nullptr) {
ArImage_release(image);
}
但是,為了我的目的,我做了另一件事來應用 Tensorflow yuv2rgb 代碼。 yuv2rgb.cc
里面的YUV2RGB有BRGA順序,而Android ARGB_8888有ARGB順序。 更簡單地說,在內聯 YUV2RGB 方法中,您需要更改此行:
return 0xff000000 | (nR << 16) | (nG << 8) | nB;
至
return 0xff000000 | nB << 16 | nG << 8 | nR;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.