I have a webcam from which I read frames in NV12 format. I convert the frames to RGB, then to YV12, and my goal is to convert them back to NV12, for verification purposes. I am doing something like this:
cv::cvtColor(InputFrame, InputRGB, cv::COLOR_YUV2RGB_NV12);
cv::cvtColor(InputRGB, OutputYV12, cv::COLOR_RGB2YUV_YV12);
I wrote the following function to convert from YV12 to NV12 (similar to this post - Convert YV12 to NV21 (YUV YCrCb 4:2:0)), which doesn't seem to work. I get a grayscale image with a vague magenta copy mixed over the top half with a vague green copy mixed over the bottom half of my resulting image.
In my function below I'm assuming a layout where the V-plane is sitting next to the U-plane in the matrix. I don't know if that is correct. I first tried following the layout for YV12 as shown at https://learn.microsoft.com/en-us/windows/win32/medfound/recommended-8-bit-yuv-formats-for-video-rendering where the U/V planes sit underneath each other instead of next to each other, but that caused a crash.
void YV12toNV12(const cv::Mat& input, cv::Mat& output, int width, int height) {
input.copyTo(output);
for (int row = 0; row < height/2; row++) {
for (int col = 0; col < width/2; col++) {
output.at<uchar>(height + row, 2 * col) = input.at<uchar>(height + row, col);
output.at<uchar>(height + row, 2 * col + 1) = input.at<uchar>(height + row, width/2 + col);
}
}
}
Any hints appreciated.
Applying the conversion using indexing is confusing.
My suggestion is treating the YV12 image as 3 separate images.
According to the following documentation:
I420 is ordered as here:

BGR to I420 conversion is supported by OpenCV, and more documented format compared to YV12, so we better start testing with I420, and continue with YV12 (by switching U and V channels).
The main idea is "wrapping" V and U matrices with cv:Mat objects (setting matrix
datapointer by adding offsets to the inputdatapointer).Here is the conversion function:
Implementation and Testing:
Creating NV12 sample image using FFmpeg command line tool:
Creating YV12 sample image using MATLAB (or OCTAVE):
C++ implementation (both I420toNV12 and YV12toNV12):
Testing the output using MATLAB (or OCTAVE):
Input (YV12 as grayscale image):

Input (NV12 as grayscale image):
