如何正确使用 nppiYUV422ToRGB_8u_C2C3R()?
How can I properly use nppiYUV422ToRGB_8u_C2C3R()?
我正在尝试使用 CPU 和 GPU 将 YUV422 图像转换为 RGB 图像。
[在 CPU] 我尝试使用 cv::cvtColor() 如下所示:
cv::cvtColor(mat_UYVY, mat_bgr, cv::COLOR_YUV2BGR_UYVY);
而且效果很好。请参阅此处所附的图片。
[但在 GPU 上] 我尝试使用 nppiYUV422ToRGB_8u_C2C3R(),如下所示:
NppStatus status = nppiYUV422ToRGB_8u_C2C3R(gpu_buff_UYVY,
img_size.width*2,
gpu_buff_RGB,
img_size.width*3,
roi);
但它会产生一些奇怪的图像,如此处所附。
我知道 opencv 使用 BGR 图像,nppiYUV422ToRGB_8u_C2C3R() 生成的图像是 RGB 图像。正确的。但问题似乎不止于此。我尝试将 RGB 转换为 BGR,但问题仍然存在。不止于此...
有人可以给我一些建议吗?我希望对我有一些建议。谢谢!
#include <iterator>
#include <fstream>
#include <iostream>
#include "opencv2/opencv.hpp"
#include "nppdefs.h"
#include "nppi_support_functions.h"
#include "nppi_color_conversion.h"
int main()
{
cv::Size img_size(1920, 1080);
unsigned char *buff_UYVY =
new unsigned char[img_size.width * img_size.height * 2];
unsigned char *buff_RGB =
new unsigned char[img_size.width * img_size.height * 3];
//file >>> buff_UYVY
{
std::string file_uyvy("uyvy422.raw");
std::ifstream stream_uyvy;
stream_uyvy.open(file_uyvy, std::ios::in | std::ios::binary);
if (!stream_uyvy.is_open())
{
std::cerr << "[ERROR] cannot open the raw file " << file_uyvy
<< std::endl;
std::cerr << std::endl;
assert(0);
}
stream_uyvy.read((char*)buff_UYVY, img_size.width*img_size.height*2);
stream_uyvy.close();
}
//buff_UYVY >>> mat_bgr
cv::Mat mat_UYVY(img_size, CV_8UC2, buff_UYVY);
cv::Mat mat_bgr(img_size, CV_8UC3);
cv::cvtColor(mat_UYVY, mat_bgr, cv::COLOR_YUV2BGR_UYVY);
cv::imshow("BGR Image from CPU", mat_bgr);
cv::imwrite("mat_bgr.bmp", mat_bgr);
cv::imwrite("mat_bgr.jpg", mat_bgr);
//buff_UYVY >>> buff_RGB
{
Npp8u* gpu_buff_UYVY;
Npp8u* gpu_buff_RGB;
cudaError_t err_cu_api;
err_cu_api = cudaMalloc((void**)&gpu_buff_UYVY,
img_size.width*img_size.height*2);
std::cout << "cudaMalloc1 : " << err_cu_api << std::endl;
err_cu_api = cudaMemcpy((void*)gpu_buff_UYVY,
(const void*)buff_UYVY,
img_size.width*img_size.height*2,
cudaMemcpyHostToDevice);
std::cout << "cudaMemcpy2 : " << err_cu_api << std::endl;
err_cu_api = cudaMalloc((void**)&gpu_buff_RGB,
img_size.width*img_size.height*3);
std::cout << "cudaMalloc3 : " << err_cu_api << std::endl;
NppiSize roi = {img_size.width, img_size.height};
NppStatus status = nppiYUV422ToRGB_8u_C2C3R(gpu_buff_UYVY,
img_size.width*2,
gpu_buff_RGB,
img_size.width*3,
roi);
std::cout << "NppStatus : " << status << std::endl;
err_cu_api = cudaMemcpy((void*) buff_RGB,
(const void*)gpu_buff_RGB,
img_size.width*img_size.height*3,
cudaMemcpyDeviceToHost);
std::cout << "cudaMemcpy4 : " << err_cu_api << std::endl;
cudaFree(gpu_buff_UYVY);
cudaFree(gpu_buff_RGB);
}
cv::Mat mat_rgb(img_size, CV_8UC3, buff_RGB);
//cv::cvtColor(mat_rgb, mat_rgb, cv::COLOR_RGB2BGR);
std::cout << "depth : " << mat_rgb.depth() << std::endl;
std::cout << "channels : " << mat_rgb.channels() << std::endl;
std::cout << "elemSize : " << mat_rgb.elemSize() << std::endl;
std::cout << "step1 : " << mat_rgb.step1() << std::endl;
std::cout << "type : " << mat_rgb.type() << std::endl;
try {
cv::imshow("RGB Image from GPU", mat_rgb);
cv::imwrite("mat_rgb.bmp", mat_rgb);
cv::imwrite("mat_rgb.jpg", mat_rgb);
} catch( cv::Exception& e ) {
const char* err_msg = e.what();
std::cout << "exception caught #2: " << err_msg << std::endl;
}
// cv::waitKey(0);
delete[] buff_UYVY;
delete[] buff_RGB;
return 0;
}
输出信息如下图:
cudaMalloc1 : 0
cudaMemcpy2 : 0
cudaMalloc3 : 0
NppStatus : 0
cudaMemcpy4 : 0
depth : 0
channels : 3
elemSize : 3
step1 : 5760
type : 16
我认为你的主要问题是openCV UYVY格式与NPP YUV422格式的存储顺序不匹配
OpenCV UYVY存储格式为:U0 Y0 V0 Y1
NPP 格式 is: Y0 U0 Y1 V0
我无法在 Internet 上找到任何“原始”UYVY 编码图像文件,您也没有提供。所以我选择使用合成图像。这是一个测试用例:
$ cat t30.cu
#include <iterator>
#include <fstream>
#include <iostream>
#include "opencv2/opencv.hpp"
#include "nppdefs.h"
#include "nppi_support_functions.h"
#include "nppi_color_conversion.h"
int main()
{
cv::Size img_size(1920, 1080);
unsigned char *buff_UYVY =
new unsigned char[img_size.width * img_size.height * 2];
unsigned char *buff_RGB =
new unsigned char[img_size.width * img_size.height * 3];
#if 0
//file >>> buff_UYVY
{
std::string file_uyvy("uyvy422.raw");
std::ifstream stream_uyvy;
stream_uyvy.open(file_uyvy, std::ios::in | std::ios::binary);
if (!stream_uyvy.is_open())
{
std::cerr << "[ERROR] cannot open the raw file " << file_uyvy
<< std::endl;
std::cerr << std::endl;
assert(0);
}
stream_uyvy.read((char*)buff_UYVY, img_size.width*img_size.height*2);
stream_uyvy.close();
}
#endif
// create synthetic R,G,B,Black image
unsigned char r,g,b;
for (int i = 0; i < img_size.height; i++)
for (int j = 0; j < img_size.width; j+=3) {
if (j < img_size.width/3) {r = 200; g = 0; b = 0;}
else if (j < img_size.width*2/3) {r = 0; g = 200; b = 0;}
else {r = 0; g = 0; b = 200;}
buff_RGB[i*img_size.width*3+j] = r;
buff_RGB[i*img_size.width*3+j+1] = g;
buff_RGB[i*img_size.width*3+j+2] = b;}
Npp8u* gpu_buff_UYVY;
Npp8u* gpu_buff_RGB;
// use NPP to convert synthetic RGB image into NPP format YUV422
cudaError_t err_cu_api;
err_cu_api = cudaMalloc((void**)&gpu_buff_UYVY,
img_size.width*img_size.height*2);
std::cout << "cudaMalloc1 : " << err_cu_api << std::endl;
err_cu_api = cudaMalloc((void**)&gpu_buff_RGB,
img_size.width*img_size.height*3);
std::cout << "cudaMalloc3 : " << err_cu_api << std::endl;
err_cu_api = cudaMemcpy((void*)gpu_buff_RGB,
(const void*)buff_RGB,
img_size.width*img_size.height*3,
cudaMemcpyHostToDevice);
std::cout << "cudaMemcpy2 : " << err_cu_api << std::endl;
NppiSize roi = {img_size.width, img_size.height};
NppStatus status = nppiRGBToYUV422_8u_C3C2R(gpu_buff_RGB,
img_size.width*3,
gpu_buff_UYVY,
img_size.width*2,
roi);
std::cout << "NppStatus : " << status << std::endl;
err_cu_api = cudaMemcpy((void*) buff_UYVY,
(const void*)gpu_buff_UYVY,
img_size.width*img_size.height*2,
cudaMemcpyDeviceToHost);
std::cout << "cudaMemcpy4 : " << err_cu_api << std::endl;
// convert NPP format YUV422 to UYVY for use by OpenCV
for (int i = 0; i < img_size.width*img_size.height*2; i+=2){
unsigned char v1 = buff_UYVY[i];
unsigned char v2 = buff_UYVY[i+1];
buff_UYVY[i+1] = v1;
buff_UYVY[i] = v2;}
//buff_UYVY >>> mat_bgr
cv::Mat mat_UYVY(img_size, CV_8UC2, buff_UYVY);
cv::Mat mat_bgr(img_size, CV_8UC3);
cv::cvtColor(mat_UYVY, mat_bgr, cv::COLOR_YUV2BGR_UYVY);
cv::imshow("BGR Image from CPU", mat_bgr);
cv::imwrite("mat_bgr.bmp", mat_bgr);
cv::imwrite("mat_bgr.jpg", mat_bgr);
//convert UYVY OpenCV format back to NPP YUV422 format for use by NPP
for (int i = 0; i < img_size.width*img_size.height*2; i+=2){
unsigned char v1 = buff_UYVY[i];
unsigned char v2 = buff_UYVY[i+1];
buff_UYVY[i+1] = v1;
buff_UYVY[i] = v2;}
//buff_UYVY >>> buff_RGB
{
err_cu_api = cudaMemcpy((void*)gpu_buff_UYVY,
(const void*)buff_UYVY,
img_size.width*img_size.height*2,
cudaMemcpyHostToDevice);
std::cout << "cudaMemcpy4 : " << err_cu_api << std::endl;
status = nppiYUV422ToRGB_8u_C2C3R(gpu_buff_UYVY,
img_size.width*2,
gpu_buff_RGB,
img_size.width*3,
roi);
std::cout << "NppStatus : " << status << std::endl;
err_cu_api = cudaMemcpy((void*) buff_RGB,
(const void*)gpu_buff_RGB,
img_size.width*img_size.height*3,
cudaMemcpyDeviceToHost);
std::cout << "cudaMemcpy4 : " << err_cu_api << std::endl;
}
cv::Mat mat_rgb(img_size, CV_8UC3, buff_RGB);
//cv::cvtColor(mat_rgb, mat_rgb, cv::COLOR_RGB2BGR);
std::cout << "depth : " << mat_rgb.depth() << std::endl;
std::cout << "channels : " << mat_rgb.channels() << std::endl;
std::cout << "elemSize : " << mat_rgb.elemSize() << std::endl;
std::cout << "step1 : " << mat_rgb.step1() << std::endl;
std::cout << "type : " << mat_rgb.type() << std::endl;
try {
cv::imshow("RGB Image from GPU", mat_rgb);
cv::imwrite("mat_rgb.bmp", mat_rgb);
cv::imwrite("mat_rgb.jpg", mat_rgb);
} catch( cv::Exception& e ) {
const char* err_msg = e.what();
std::cout << "exception caught #2: " << err_msg << std::endl;
}
// cv::waitKey(0);
delete[] buff_UYVY;
delete[] buff_RGB;
return 0;
}
(base) [bob@localhost misc]$ nvcc -o t30 t30.cu -lnppicc -lopencv_core -lopencv_highgui -lopencv_imgcodecs -lopencv_imgproc
(base) [bob@localhost misc]$ ./t30
cudaMalloc1 : 0
cudaMalloc3 : 0
cudaMemcpy2 : 0
NppStatus : 0
cudaMemcpy4 : 0
cudaMemcpy4 : 0
NppStatus : 0
cudaMemcpy4 : 0
depth : 0
channels : 3
elemSize : 3
step1 : 5760
type : 16
输出文件是这样的:
mat_rgb.png:
mat_bgr.png:
主要区别是您已经知道的 RGB <-> BGR 不匹配。
对于剩余的颜色差异,也可能是 OpenCV 的 YUV 色彩空间与 NPP 的色彩空间不太匹配。如果您愿意,可以在 NPP 中尝试其他 YUV 函数,例如 nppiCbYCr422ToBGR_709HDTV_8u_C2C3R.
我正在尝试使用 CPU 和 GPU 将 YUV422 图像转换为 RGB 图像。
[在 CPU] 我尝试使用 cv::cvtColor() 如下所示:
cv::cvtColor(mat_UYVY, mat_bgr, cv::COLOR_YUV2BGR_UYVY);
而且效果很好。请参阅此处所附的图片。
[但在 GPU 上] 我尝试使用 nppiYUV422ToRGB_8u_C2C3R(),如下所示:
NppStatus status = nppiYUV422ToRGB_8u_C2C3R(gpu_buff_UYVY,
img_size.width*2,
gpu_buff_RGB,
img_size.width*3,
roi);
但它会产生一些奇怪的图像,如此处所附。
我知道 opencv 使用 BGR 图像,nppiYUV422ToRGB_8u_C2C3R() 生成的图像是 RGB 图像。正确的。但问题似乎不止于此。我尝试将 RGB 转换为 BGR,但问题仍然存在。不止于此...
有人可以给我一些建议吗?我希望对我有一些建议。谢谢!
#include <iterator>
#include <fstream>
#include <iostream>
#include "opencv2/opencv.hpp"
#include "nppdefs.h"
#include "nppi_support_functions.h"
#include "nppi_color_conversion.h"
int main()
{
cv::Size img_size(1920, 1080);
unsigned char *buff_UYVY =
new unsigned char[img_size.width * img_size.height * 2];
unsigned char *buff_RGB =
new unsigned char[img_size.width * img_size.height * 3];
//file >>> buff_UYVY
{
std::string file_uyvy("uyvy422.raw");
std::ifstream stream_uyvy;
stream_uyvy.open(file_uyvy, std::ios::in | std::ios::binary);
if (!stream_uyvy.is_open())
{
std::cerr << "[ERROR] cannot open the raw file " << file_uyvy
<< std::endl;
std::cerr << std::endl;
assert(0);
}
stream_uyvy.read((char*)buff_UYVY, img_size.width*img_size.height*2);
stream_uyvy.close();
}
//buff_UYVY >>> mat_bgr
cv::Mat mat_UYVY(img_size, CV_8UC2, buff_UYVY);
cv::Mat mat_bgr(img_size, CV_8UC3);
cv::cvtColor(mat_UYVY, mat_bgr, cv::COLOR_YUV2BGR_UYVY);
cv::imshow("BGR Image from CPU", mat_bgr);
cv::imwrite("mat_bgr.bmp", mat_bgr);
cv::imwrite("mat_bgr.jpg", mat_bgr);
//buff_UYVY >>> buff_RGB
{
Npp8u* gpu_buff_UYVY;
Npp8u* gpu_buff_RGB;
cudaError_t err_cu_api;
err_cu_api = cudaMalloc((void**)&gpu_buff_UYVY,
img_size.width*img_size.height*2);
std::cout << "cudaMalloc1 : " << err_cu_api << std::endl;
err_cu_api = cudaMemcpy((void*)gpu_buff_UYVY,
(const void*)buff_UYVY,
img_size.width*img_size.height*2,
cudaMemcpyHostToDevice);
std::cout << "cudaMemcpy2 : " << err_cu_api << std::endl;
err_cu_api = cudaMalloc((void**)&gpu_buff_RGB,
img_size.width*img_size.height*3);
std::cout << "cudaMalloc3 : " << err_cu_api << std::endl;
NppiSize roi = {img_size.width, img_size.height};
NppStatus status = nppiYUV422ToRGB_8u_C2C3R(gpu_buff_UYVY,
img_size.width*2,
gpu_buff_RGB,
img_size.width*3,
roi);
std::cout << "NppStatus : " << status << std::endl;
err_cu_api = cudaMemcpy((void*) buff_RGB,
(const void*)gpu_buff_RGB,
img_size.width*img_size.height*3,
cudaMemcpyDeviceToHost);
std::cout << "cudaMemcpy4 : " << err_cu_api << std::endl;
cudaFree(gpu_buff_UYVY);
cudaFree(gpu_buff_RGB);
}
cv::Mat mat_rgb(img_size, CV_8UC3, buff_RGB);
//cv::cvtColor(mat_rgb, mat_rgb, cv::COLOR_RGB2BGR);
std::cout << "depth : " << mat_rgb.depth() << std::endl;
std::cout << "channels : " << mat_rgb.channels() << std::endl;
std::cout << "elemSize : " << mat_rgb.elemSize() << std::endl;
std::cout << "step1 : " << mat_rgb.step1() << std::endl;
std::cout << "type : " << mat_rgb.type() << std::endl;
try {
cv::imshow("RGB Image from GPU", mat_rgb);
cv::imwrite("mat_rgb.bmp", mat_rgb);
cv::imwrite("mat_rgb.jpg", mat_rgb);
} catch( cv::Exception& e ) {
const char* err_msg = e.what();
std::cout << "exception caught #2: " << err_msg << std::endl;
}
// cv::waitKey(0);
delete[] buff_UYVY;
delete[] buff_RGB;
return 0;
}
输出信息如下图:
cudaMalloc1 : 0
cudaMemcpy2 : 0
cudaMalloc3 : 0
NppStatus : 0
cudaMemcpy4 : 0
depth : 0
channels : 3
elemSize : 3
step1 : 5760
type : 16
我认为你的主要问题是openCV UYVY格式与NPP YUV422格式的存储顺序不匹配
OpenCV UYVY存储格式为:U0 Y0 V0 Y1
NPP 格式 is: Y0 U0 Y1 V0
我无法在 Internet 上找到任何“原始”UYVY 编码图像文件,您也没有提供。所以我选择使用合成图像。这是一个测试用例:
$ cat t30.cu
#include <iterator>
#include <fstream>
#include <iostream>
#include "opencv2/opencv.hpp"
#include "nppdefs.h"
#include "nppi_support_functions.h"
#include "nppi_color_conversion.h"
int main()
{
cv::Size img_size(1920, 1080);
unsigned char *buff_UYVY =
new unsigned char[img_size.width * img_size.height * 2];
unsigned char *buff_RGB =
new unsigned char[img_size.width * img_size.height * 3];
#if 0
//file >>> buff_UYVY
{
std::string file_uyvy("uyvy422.raw");
std::ifstream stream_uyvy;
stream_uyvy.open(file_uyvy, std::ios::in | std::ios::binary);
if (!stream_uyvy.is_open())
{
std::cerr << "[ERROR] cannot open the raw file " << file_uyvy
<< std::endl;
std::cerr << std::endl;
assert(0);
}
stream_uyvy.read((char*)buff_UYVY, img_size.width*img_size.height*2);
stream_uyvy.close();
}
#endif
// create synthetic R,G,B,Black image
unsigned char r,g,b;
for (int i = 0; i < img_size.height; i++)
for (int j = 0; j < img_size.width; j+=3) {
if (j < img_size.width/3) {r = 200; g = 0; b = 0;}
else if (j < img_size.width*2/3) {r = 0; g = 200; b = 0;}
else {r = 0; g = 0; b = 200;}
buff_RGB[i*img_size.width*3+j] = r;
buff_RGB[i*img_size.width*3+j+1] = g;
buff_RGB[i*img_size.width*3+j+2] = b;}
Npp8u* gpu_buff_UYVY;
Npp8u* gpu_buff_RGB;
// use NPP to convert synthetic RGB image into NPP format YUV422
cudaError_t err_cu_api;
err_cu_api = cudaMalloc((void**)&gpu_buff_UYVY,
img_size.width*img_size.height*2);
std::cout << "cudaMalloc1 : " << err_cu_api << std::endl;
err_cu_api = cudaMalloc((void**)&gpu_buff_RGB,
img_size.width*img_size.height*3);
std::cout << "cudaMalloc3 : " << err_cu_api << std::endl;
err_cu_api = cudaMemcpy((void*)gpu_buff_RGB,
(const void*)buff_RGB,
img_size.width*img_size.height*3,
cudaMemcpyHostToDevice);
std::cout << "cudaMemcpy2 : " << err_cu_api << std::endl;
NppiSize roi = {img_size.width, img_size.height};
NppStatus status = nppiRGBToYUV422_8u_C3C2R(gpu_buff_RGB,
img_size.width*3,
gpu_buff_UYVY,
img_size.width*2,
roi);
std::cout << "NppStatus : " << status << std::endl;
err_cu_api = cudaMemcpy((void*) buff_UYVY,
(const void*)gpu_buff_UYVY,
img_size.width*img_size.height*2,
cudaMemcpyDeviceToHost);
std::cout << "cudaMemcpy4 : " << err_cu_api << std::endl;
// convert NPP format YUV422 to UYVY for use by OpenCV
for (int i = 0; i < img_size.width*img_size.height*2; i+=2){
unsigned char v1 = buff_UYVY[i];
unsigned char v2 = buff_UYVY[i+1];
buff_UYVY[i+1] = v1;
buff_UYVY[i] = v2;}
//buff_UYVY >>> mat_bgr
cv::Mat mat_UYVY(img_size, CV_8UC2, buff_UYVY);
cv::Mat mat_bgr(img_size, CV_8UC3);
cv::cvtColor(mat_UYVY, mat_bgr, cv::COLOR_YUV2BGR_UYVY);
cv::imshow("BGR Image from CPU", mat_bgr);
cv::imwrite("mat_bgr.bmp", mat_bgr);
cv::imwrite("mat_bgr.jpg", mat_bgr);
//convert UYVY OpenCV format back to NPP YUV422 format for use by NPP
for (int i = 0; i < img_size.width*img_size.height*2; i+=2){
unsigned char v1 = buff_UYVY[i];
unsigned char v2 = buff_UYVY[i+1];
buff_UYVY[i+1] = v1;
buff_UYVY[i] = v2;}
//buff_UYVY >>> buff_RGB
{
err_cu_api = cudaMemcpy((void*)gpu_buff_UYVY,
(const void*)buff_UYVY,
img_size.width*img_size.height*2,
cudaMemcpyHostToDevice);
std::cout << "cudaMemcpy4 : " << err_cu_api << std::endl;
status = nppiYUV422ToRGB_8u_C2C3R(gpu_buff_UYVY,
img_size.width*2,
gpu_buff_RGB,
img_size.width*3,
roi);
std::cout << "NppStatus : " << status << std::endl;
err_cu_api = cudaMemcpy((void*) buff_RGB,
(const void*)gpu_buff_RGB,
img_size.width*img_size.height*3,
cudaMemcpyDeviceToHost);
std::cout << "cudaMemcpy4 : " << err_cu_api << std::endl;
}
cv::Mat mat_rgb(img_size, CV_8UC3, buff_RGB);
//cv::cvtColor(mat_rgb, mat_rgb, cv::COLOR_RGB2BGR);
std::cout << "depth : " << mat_rgb.depth() << std::endl;
std::cout << "channels : " << mat_rgb.channels() << std::endl;
std::cout << "elemSize : " << mat_rgb.elemSize() << std::endl;
std::cout << "step1 : " << mat_rgb.step1() << std::endl;
std::cout << "type : " << mat_rgb.type() << std::endl;
try {
cv::imshow("RGB Image from GPU", mat_rgb);
cv::imwrite("mat_rgb.bmp", mat_rgb);
cv::imwrite("mat_rgb.jpg", mat_rgb);
} catch( cv::Exception& e ) {
const char* err_msg = e.what();
std::cout << "exception caught #2: " << err_msg << std::endl;
}
// cv::waitKey(0);
delete[] buff_UYVY;
delete[] buff_RGB;
return 0;
}
(base) [bob@localhost misc]$ nvcc -o t30 t30.cu -lnppicc -lopencv_core -lopencv_highgui -lopencv_imgcodecs -lopencv_imgproc
(base) [bob@localhost misc]$ ./t30
cudaMalloc1 : 0
cudaMalloc3 : 0
cudaMemcpy2 : 0
NppStatus : 0
cudaMemcpy4 : 0
cudaMemcpy4 : 0
NppStatus : 0
cudaMemcpy4 : 0
depth : 0
channels : 3
elemSize : 3
step1 : 5760
type : 16
输出文件是这样的:
mat_rgb.png:
对于剩余的颜色差异,也可能是 OpenCV 的 YUV 色彩空间与 NPP 的色彩空间不太匹配。如果您愿意,可以在 NPP 中尝试其他 YUV 函数,例如 nppiCbYCr422ToBGR_709HDTV_8u_C2C3R.