Why cv::cuda::cvtColor() not support yuv to rgb

void cv::cuda::cvtColor	(	InputArray 	src,
OutputArray 	dst,
int 	code,
int 	dcn = 0,
Stream & 	stream = Stream::Null() 
)

docs say :
src : Source image with CV_8U , CV_16U , or CV_32F depth and 1, 3, or 4 channels.
from here

Why src not support 2 channels?

Why cv::cuda::cvtColor() not support yuv to rgb

It does see https://github.com/opencv/opencv_contrib/blob/6ebb38db6d0504682d72d168c4bba13a6b70895c/modules/cudaimgproc/test/test_color.cpp#L1558

I would guess because there is no color conversion from a two channel format, e.g. NV12.

1 Like

cv::cvtColor() can convert from yuv to rgb. So I want to konw, why cv::cuda::cvtColor() can not do this. Why cv::cuda::cvtColor() not support 2 channels.

Agreed the link I posted has this as a first step.

It does see the link I posted.

See my response above, additionally YUV in OpenCV is 3 channels.

In case the link is broken the example shows the conversion from RGB to YUV on the host (cv::cvtColor()), 3 channels (RGB) to 3 channels (YUV) and then YUV to RGB on the device (cv::cuda::cvtColor()).

1 Like

Thank you for your patient help. Now, I have a YVYU image, cv::cvtColor() can convert it to rgb, but I want use cv::cuda::cvtColor(). Using cv::cuda::cvtColor() the program will report the following error:

terminate called after throwing an instance of 'cv::Exception'
  what():  OpenCV(4.7.0) opencv-4.7.0/opencv_contrib/modules/cudaimgproc/src/color.cpp:2103: error: (-206:Bad flag (parameter or structure field)) Unknown/unsupported color conversion code in function 'cvtColor'

Aborted (core dumped)

code:

char buffer[1920 * 1536 * 2];
int main(int argc, char** argv)
{
	ifstream in_file("/75907810_18.yuv", ios::in|ios::binary); 	in_file.read(buffer, sizeof(buffer));

	cv::Mat src(1536, 1920, CV_8UC2, buffer);
	cv::cuda::GpuMat g_img(src);
	cv::cuda::GpuMat dst;
	cv::cuda::cvtColor(g_img, dst, cv::COLOR_YUV2RGB_YVYU);

	cv::Mat rgb_gray;
	dst.download(rgb_gray);
    cv::imshow("rgb", rgb_gray);
    cv::waitKey(0);
    cv::destroyAllWindows();
    return 0;
}

My guess is that YUV to RGB is good enough to use function cv::cvtColor(), there is no need to use function cv::cuda::cvtColor() hardware acceleration.
Is that really the case? :thinking:
I wonder why dual channel can’t use GPU acceleration, or why GPU acceleration is not more efficient than CPU.

Not all OpenCV CPU functionality has been implemented in CUDA. This has nothing to do with performance, the CUDA color conversion routines implement some of the most commonly required conversions.

Additionaly I think, but I may be wrong, that all the compressed YUV formats are stored in a single channel in OpenCV. Have you tested

cv::cvtColor(src,dst,cv::COLOR_YUV2RGB_YVYU)

with a 2 channel source?

See modules/cudaimgproc/src/color.cpp for a list of the supported conversions in cv::cuda.

You may be able to find an NPP implementation of the conversion you require, see modules/cudacodec/src/video_reader.cpp for an example of how to call from OpenCV. If the conversion is not covered by NPP then it is again probably not that common.

Thank you for your patience, my friend. :grinning:

My data is obtained from the camera. Now I convert a frame of data into BGR color space by cv::cvtColor() function, and then encode into png picture (4K) by cv::imencode(). However, the time is too high, is there an efficient method to use hardware acceleration.

It depends, on the camera and what you are trying to achieve. If you include this + an MRE I will be able to be more specific.

My friend thank you for telling me MRE. Actually, the focus of my question is not the code, but whether opencv has a way to hardware-accelerate encoding of png or jpg images. Or is there some other technology that can do this, that uses the power of the GPU to encode images more efficiently than the CPU does?

Maybe I got my knowledge wrong, and I didn’t find an effective way to hardware-encode the picture. :thinking:

Not that I know of in OpenCV.

The reason I suggested an MRE is because I wanted to check where your bottleneck is and understand why you would want to save 4K images instead of video.

My client’s requirement is to save every frame data in png format. My camera frame format is YUV, so my job is to convert YUV to BGR and then encode the data into png format. The code is very simple, and the conversion process is as follows:

std::vector<int> compression_params;
compression_params.push_back(cv::IMWRITE_PNG_COMPRESSION);
compression_params.push_back(0);
cv::Mat yuv_img(height, width, CV_8UC2, buffers[n_buffers].start);
cv::cvtColor(yuv_img, rgb_mat, cv::COLOR_YUV2BGR_UYVY);
cv::imencode(".png", rgb_mat, png_vec, compression_params);

Please forgive me if the above code is not MRE, the last line of code takes about 500ms on my computer (picture size 3840*2160).