YUV图片格式
OpenCV读取图片时默认都是BGR,一般需要使用cv::cvtColor转为RGB,但有些情况下需要使用YUV格式,YUV格式比较多,OpenCV并没有提供所有的转换方法,但是可以自己实现
主要使用的还是YUV420_NV12格式
// read img and convert to different format
// bgr -> argb1555
cv::Mat GetArgb(std::string& img_path) {
cv::Mat src_img = cv::imread(img_path);
cv::Mat bgr_555_img;
cv::cvtColor(src_img, bgr_555_img, cv::COLOR_BGR2BGR555);
cv::Mat rgba_img;
cv::cvtColor(bgr_555_img, rgba_img, cv::COLOR_BGR5552RGBA);
cv::Mat argb_img(rgba_img.size(), rgba_img.type());
int from_to[] = {0, 1, 1, 2, 2, 3, 3, 0};
cv::mixChannels(&rgba_img, 1, &argb_img, 1, from_to, 4);
return argb_img;
}
// bgr -> YUV420_NV12
cv::Mat GetYuv(std::string& img_path) {
cv::Mat src_img = cv::imread(img_path);
int src_h = src_img.rows;
int src_w = src_img.cols;
cv::Mat yuv_img(src_h * 1.5, src_w, CV_8UC1);
cv::cvtColor(src_img, yuv_img, cv::COLOR_BGR2YUV_I420); // YUV_I420
int n_y = src_h * src_w;
int n_uv = n_y / 2;
int n_u = n_y / 4;
std::vector<uint8_t> uv(n_uv);
std::copy(yuv_img.data + n_y, yuv_img.data + n_y + n_uv, uv.data());
for (int i = 0; i < n_u; ++i) {
yuv_img.data[n_y + 2 * i] = uv[i]; // U
yuv_img.data[n_y + 2 * i + 1] = uv[n_u + i]; // V
}
return yuv_img;
}
// YUV420_NV12 -> bgr
cv::Mat GetBgr(cv::Mat& yuv_img) {
cv::Mat bgr_img;
cv::cvtColor(yuv_img, bgr_img, cv::COLOR_YUV2BGR_NV12);
return bgr_img;
}
// YUV420_NV12 -> bgr, manual conversion
cv::Mat GetBgrManual(cv::Mat& yuv_img) {
int src_h = yuv_img.rows;
int src_w = yuv_img.cols;
int yuv_h = src_h * 2 / 3;
int yuv_w = src_w;
int n_y = yuv_h * yuv_w;
int n_uv = n_y / 2;
int n_u = n_y / 4;
std::vector<uint8_t> uv(n_uv);
std::copy(yuv_img.data + n_y, yuv_img.data + n_y + n_uv, uv.data());
for (int i = 0; i < n_u; i += 2) {
yuv_img.data[n_y + i] = uv[i]; // U
}
for (int i = 1; i < n_u; i += 2) {
yuv_img.data[n_y + i] = uv[i]; // V
}
cv::Mat bgr_img(yuv_h, yuv_w, CV_8UC3);
cvtColor(yuv_img, bgr_img, cv::COLOR_YUV2BGR_I420);
return bgr_img;
}
// YUV420 -> bgr, then save img
void SaveImg(cv::Mat& res, std::string& res_img_path) {
// std::cout << "save img. " << std::endl;
if (!res.empty()) {
cv::Mat bgr_img = GetBgr(res);
cv::imwrite(res_img_path, bgr_img);
std::cout << "Save img success. " << std::endl;
}else {
std::cout << "Save img error. " << std::endl;
}
}
// save gray img
void SaveGrayImg(cv::Mat& res, std::string& res_img_path) {
// std::cout << "save img. " << std::endl;
if (!res.empty()) {
cv::imwrite(res_img_path, res);
std::cout << "Save img success. " << std::endl;
}else {
std::cout << "Save img error. " << std::endl;
}
}
// YUV420 -> gray, then save img
void saveYUVtoGrayImg(cv::Mat& yuv_img, std::string& res_img_path) {
// std::cout << "save gray img. " << std::endl;
if (!yuv_img.empty()) {
int yuv_img_h = yuv_img.rows;
int yuv_img_w = yuv_img.cols;
int gray_img_h = yuv_img_h * 2 / 3;
int gray_img_w = yuv_img_w;
cv::Mat gray_img(gray_img_h, gray_img_w, CV_8UC1);
memcpy((void *)gray_img.data, (void *)yuv_img.data, (size_t)gray_img_h * gray_img_w);
cv::imwrite(res_img_path, gray_img);
std::cout << "Save img success. " << std::endl;
}else {
std::cout << "Save img error. " << std::endl;
}
}
// print img property
void PrintImgPro(cv::Mat &img) {
std::cout << "img.rows: " << img.rows << std::endl;
std::cout << "img.cols: " << img.cols << std::endl;
std::cout << "img.empty: " << img.empty() << std::endl;
std::cout << "img.dims: " << img.dims << std::endl;
std::cout << "img.channels: " << img.channels() << std::endl;
std::cout << "img.type: " << img.type() << std::endl;
std::cout << "img isContinuous: " << img.isContinuous() << std::endl;
std::cout << "img.depth: " << img.depth() << std::endl;
std::cout << "img.elemSize: " << img.elemSize() << std::endl;
std::cout << "img.step: " << img.step << std::endl;
// if (!img.isContinuous()) { // make img continuous
// img = img.clone();
// }
}