Convert YUV_420_888 to RGB in Android

2022. 6. 25.
#OpenCV#Android

๋ฌธ์ œ

Android jni๋ฅผ ์ด์šฉํ•ด์„œ ์นด๋ฉ”๋ผ ๋ฐ์ดํ„ฐ๋ฅผ C++ OpenCV๋กœ ์ฒ˜๋ฆฌํ•ด์ฃผ๋Š” ์ž‘์—…์„ ํ•˜๋Š”๋ฐ ์ด๋ฏธ์ง€๊ฐ€ ์•„๋ž˜์™€ ๊ฐ™์ด ์ดˆ๋ก์ƒ‰ ํ™”๋ฉด์œผ๋กœ ๋‚˜์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ๋‹ค. YUV Error Image

์›๋ž˜ ์‚ฌ์šฉํ•œ ๋ฐฉ๋ฒ•

์›๋ž˜๋Š” ์•„๋ž˜์˜ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ๋ณ€ํ™˜ํ•˜์˜€๋‹ค.

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

  1. https://developer.android.com/reference/android/graphics/ImageFormat#YUV_420_888
  2. https://stackoverflow.com/questions/40885602/yuv-420-888-to-rgb-conversion
  3. https://stackoverflow.com/questions/30510928/convert-android-camera2-api-yuv-420-888-to-rgb
  4. https://stackoverflow.com/questions/60992469how-to-correctly-pass-yuv-420-888-image-buffer-from-java-through-jni-to-opencv
  5. https://blog.minhazav.dev/how-to-convert-yuv-420-sp-android.media.Image-to-Bitmap-or-jpeg/