BGR格式的图像转YUV格式

 BGR转YUV(YUV420SP_NV21)代码实现

//BGR2YUV(YUV420SP_NV21)
void enCodeYUV420SP(unsigned  char* yuv420sp, unsigned char* rgb, int width, int height)
{
    if (yuv420sp == NULL || rgb == NULL)
        return;
    int frameSize = width*height;
    int yIndex = 0;
    int uvIndex = frameSize;
  
    int R, G, B, Y, U, V;
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            B = rgb[(i * width + j) * 3 + 0];
            G = rgb[(i * width + j) * 3 + 1];
            R = rgb[(i * width + j) * 3 + 2];
  
            //RGB to YUV
            Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
            U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
            V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;
  
            yuv420sp[yIndex++] = (unsigned char)((Y < 0) ? 0 : ((Y > 255) ? 255 : Y));
            if (i % 2 == 0 && j % 2 == 0)
            {
                yuv420sp[uvIndex++] = (unsigned char)((V < 0) ? 0 : ((V > 255) ? 255 : V));//UV交替排列
                yuv420sp[uvIndex++] = (unsigned char)((U < 0) ? 0 : ((U > 255) ? 255 : U));
            }
        }
    }
}

主函数main

        cv::Mat img = cv::imread(imgPath);
         
  
        int height = img.rows;
        int width = img.cols;
      
        unsigned char* img_bgr_data = (unsigned char*)malloc(height*width * 3 * sizeof(unsigned char));
        for (int i = 0; i < height; i++)
        {
            unsigned char* current_row = img.ptr<uchar>(i);
            for (int j = 0; j < width; j++)
            {
                img_bgr_data[(i * width + j) * 3 + 0] = current_row[j * 3 + 0];//B
                img_bgr_data[(i * width + j) * 3 + 1] = current_row[j * 3 + 1];//G
                img_bgr_data[(i * width + j) * 3 + 2] = current_row[j * 3 + 2];//R
            }
        }
      
        //RGB->NV21(YUV420SP)
        unsigned char* img_nv21_data = (unsigned char*)malloc(height*width * 3 / 2 * sizeof(unsigned char));
         
         
 
         
        enCodeYUV420SP(img_nv21_data, img_bgr_data, width, height);
//Mat img_BGR(height, width, CV_8UC3);
        //cvtColor(img_nv21, img_BGR, CV_YUV2BGR_NV21);//YUV420sp->BGR
        //cv::cvtColor(img_nv21, img_BGR, cv::COLOR_YUV420sp2BGR);
        //cv::imwrite("./img_BGR.jpg", img_BGR);       

 

void test_bgr2yuv(Mat &src, unsigned char** yuv_buf) {
	//创建yuv二维的数组
	size_t src_w = src.cols;
	size_t src_h = src.rows;
	yuv_buf[0] = (unsigned char*)malloc(src_w * src_h * sizeof(unsigned char));
	yuv_buf[1] = (unsigned char*)malloc(src_w * src_h * sizeof(unsigned char)/4);
	yuv_buf[2] = (unsigned char*)malloc(src_w * src_h * sizeof(unsigned char)/4);
	if (yuv_buf == nullptr || yuv_buf[0] == nullptr || yuv_buf[1] == nullptr || yuv_buf[2] == nullptr) {
		std::cout << " malloc failed" << std::endl;
	}
	Mat temp_yuv;
	cvtColor(src, temp_yuv, COLOR_BGR2YUV_I420);
	imshow("yuvi420", temp_yuv);
	memcpy(yuv_buf[0], temp_yuv.data, src_w * src_h);
	memcpy(yuv_buf[1], temp_yuv.data + src_w * src_h, src_w * src_h/4);
	memcpy(yuv_buf[2], temp_yuv.data + src_w * src_h*5/4, src_w * src_h / 4);
}
void test_yuv2bgr_i420(unsigned char **yuv_buf, size_t planner, size_t yuv_w, size_t yuv_h) {
	unsigned char* temp_data = (unsigned char*)malloc(yuv_w * yuv_h * sizeof(unsigned char*));
	memcpy(temp_data, yuv_buf[0], yuv_w * yuv_h * 2 / 3);
	memcpy(temp_data+ yuv_w * yuv_h * 2 / 3, yuv_buf[1], yuv_w * yuv_h  / 6);
	memcpy(temp_data + yuv_w * yuv_h * 2 / 3 + yuv_w * yuv_h / 6, yuv_buf[2], yuv_w * yuv_h / 6);
	Mat temp_yuv(yuv_h, yuv_w, CV_8UC1, temp_data);
 
	Mat bgr;
	cvtColor(temp_yuv, bgr, COLOR_YUV2BGRA_I420);
	imshow("yuvi420 to bgr", bgr);
	free(temp_data);
	temp_data = nullptr;
}
int main(int argc, char** argv) {
	Mat src = imread("xx.jpg"); // BGR
	if (src.empty()) {
		cout << " read images error" << endl;
		return -1;
	}
 
	unsigned char** yuv_buf = (unsigned char**)malloc(3 * sizeof(unsigned char*));
	test_bgr2yuv(src, yuv_buf);
	size_t yuv_h = src.rows * 3 / 2;
	size_t yuv_w = src.cols;
	test_yuv2bgr_i420(yuv_buf, 3, yuv_w, yuv_h);
	//验证我们的yuv_buf数据是否正确
 
 
	//释放资源
	for (size_t i = 0; i < 3; i++) {
		if (yuv_buf[i] != nullptr) {
			free(yuv_buf[i]);
			yuv_buf[i] = nullptr;
		}
	}
	if (yuv_buf != nullptr) {
		free(yuv_buf);
		yuv_buf = nullptr;
	}
	namedWindow("input", WINDOW_AUTOSIZE);
	imshow("input", src);
	waitKey(0);
	destroyAllWindows();
	return 0;
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序小K

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值