Convert YUV_420_888 to RGB in Android
2022. 6. 25.๋ฌธ์
Android jni๋ฅผ ์ด์ฉํด์ ์นด๋ฉ๋ผ ๋ฐ์ดํฐ๋ฅผ C++ OpenCV๋ก ์ฒ๋ฆฌํด์ฃผ๋ ์์
์ ํ๋๋ฐ ์ด๋ฏธ์ง๊ฐ ์๋์ ๊ฐ์ด ์ด๋ก์ ํ๋ฉด์ผ๋ก ๋์ค๋ ๊ฒ์ ํ์ธํ๋ค.
์๋ ์ฌ์ฉํ ๋ฐฉ๋ฒ
์๋๋ ์๋์ ์ฝ๋๋ฅผ ์ฌ์ฉํด ๋ณํํ์๋ค.
cv::Mat mYuv(height + height / 2, width, CV_8UC1, bufferY);
cv::Mat mRgba(height, width, CV_8UC4);
cv::cvtColor(mYuv, mRgba, cv::COLOR_YUV2RGBA_NV21);
Android Developers๋ฅผ ๋ณด๋ฉด ์๋๋ก์ด๋์์ YUV_420_888๋ก ์นด๋ฉ๋ผ๋ฅผ ์ฝ์์ ๋, pixel stride์ ๊ธฐ๋ณธ ๊ฐ์ด 1์ธ ๊ฒ์ ์ ์ ์๋ค.
๊ทธ๋ฌ๋ ๋ด ํธ๋ํฐ ๊ธฐ์ข (S22)๋ก ํ ์คํธ ํด๋ดค์ ๋๋ pixel stride๊ฐ 2์ธ ๊ฒ์ ํ์ธํ ์ ์์๊ณ , ์๋ง ์ด๊ฒ ๋ฌธ์ ๊ฐ ์๋๊น ์์๋๋ค.
ํด๊ฒฐ
Minhazโs Blog์ ์ฝ๋๋ฅผ ์ฐธ๊ณ ํ์ฌ ์ง์ ๊ฐ์ ๊ณ์ฐํด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์๋ค.
cv::Mat mRgba(height, width, CV_8UC4);
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
int yIndex = (y * rowStrideY) + (x * pixelStrideY);
// Y plane should have positive values belonging to [0...255]
int yValue = (bufferY[yIndex] & 0xff);
int uvx = x / 2;
int uvy = y / 2;
// U/V Values are subsampled i.e. each pixel in U/V chanel in a
// YUV_420 image act as chroma value for 4 neighbouring pixels
int uvIndex = (uvy * rowStrideUV) + (uvx * pixelStrideUV);
// U/V values ideally fall under [-0.5, 0.5] range. To fit them into
// [0, 255] range they are scaled up and centered to 128.
// Operation below brings U/V values to [-128, 127].
int uValue = (bufferU[uvIndex] & 0xff) - 128;
int vValue = (bufferV[uvIndex] & 0xff) - 128;
// Compute RGB values per formula above.
int r = (int) (yValue + 1.370705f * vValue);
int g = (int) (yValue - (0.698001f * vValue) - (0.337633f * uValue));
int b = (int) (yValue + 1.732446f * uValue);
r = std::clamp(r, 0, 255);
g = std::clamp(g, 0, 255);
b = std::clamp(b, 0, 255);
mRgba.at<cv::Vec4b>(y, x) = cv::Vec4b(r, g, b, 255);
}
}
reference
- https://developer.android.com/reference/android/graphics/ImageFormat#YUV_420_888
- https://stackoverflow.com/questions/40885602/yuv-420-888-to-rgb-conversion
- https://stackoverflow.com/questions/30510928/convert-android-camera2-api-yuv-420-888-to-rgb
- https://stackoverflow.com/questions/60992469how-to-correctly-pass-yuv-420-888-image-buffer-from-java-through-jni-to-opencv
- https://blog.minhazav.dev/how-to-convert-yuv-420-sp-android.media.Image-to-Bitmap-or-jpeg/