BGRtoNV12与NV12toBGR互转函数

rt

主要是用于输入输出图像数据的转换

cpp 复制代码
#include <stdbool.h>
#include <string.h>
#include <thread>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <signal.h>
#include <fstream>
#include <iostream>
#include <opencv2/opencv.hpp>

cv::Mat NV12ToBGRUnified(const unsigned char* nv12_data, int width, int height, int input_channels) {
    if (!nv12_data || width <= 0 || height <= 0) 
	{
        std::cerr << "[mw]Error: Invalid NV12 input data or dimensions.\n";
        return cv::Mat(); // Return empty Mat on error
    }
    if (width % 2 != 0 || height % 2 != 0) 
	{
        std::cerr << "[mw]Error: NV12 input dimensions must be even. width=" << width << ", height=" << height << "\n";
        return cv::Mat();
    }
    if (input_channels != 1 && input_channels != 3) 
	{
        std::cerr << "[mw]Error: input_channels must be 1 (grayscale) or 3 (color). Got " << input_channels << "\n";
        return cv::Mat();
    }

    int y_size = width * height;
    int uv_size = y_size / 2;

    cv::Mat bgr_mat(height, width, CV_8UC3);

    const unsigned char* y_plane = nv12_data;
    const unsigned char* uv_plane = nv12_data + y_size;

    const int SCALE_FACTOR = 1000;
    const int R_V_COEFF = static_cast<int>(1.402 * SCALE_FACTOR);      // ~1402
    const int G_U_COEFF = static_cast<int>(0.344136 * SCALE_FACTOR);  // ~344
    const int G_V_COEFF = static_cast<int>(0.714136 * SCALE_FACTOR);  // ~714
    const int B_U_COEFF = static_cast<int>(1.772 * SCALE_FACTOR);     // ~1772

    for (int y = 0; y < height; ++y) {
        unsigned char* bgr_row = bgr_mat.ptr<unsigned char>(y);
        for (int x = 0; x < width; ++x) {
            // Get Y value for current pixel (Always present)
            unsigned char Y = y_plane[y * width + x];

            unsigned char U = 128; // Default U value
            unsigned char V = 128; // Default V value

            if (input_channels == 3) {
                // Calculate corresponding UV block coordinates (since UV is subsampled 2x2)
                int uv_x = x / 2;
                int uv_y = y / 2;
                int uv_offset = uv_y * (width / 2) + uv_x;

                // Get U and V values for the 2x2 block from the NV12 UV plane
                U = uv_plane[uv_offset * 2];     // U value
                V = uv_plane[uv_offset * 2 + 1]; // V value
            }
            int c = Y - 16;
            int d = U - 128;
            int e = V - 128;

            int scaled_R = (298 * c + R_V_COEFF * e) / SCALE_FACTOR;
            int scaled_G = (298 * c - G_U_COEFF * d - G_V_COEFF * e) / SCALE_FACTOR;
            int scaled_B = (298 * c + B_U_COEFF * d) / SCALE_FACTOR;

            unsigned char R = static_cast<unsigned char>(std::max(0, std::min(255, scaled_R)));
            unsigned char G = static_cast<unsigned char>(std::max(0, std::min(255, scaled_G)));
            unsigned char B = static_cast<unsigned char>(std::max(0, std::min(255, scaled_B)));

            int pixel_idx = x * 3;
            bgr_row[pixel_idx + 0] = B; // B
            bgr_row[pixel_idx + 1] = G; // G
            bgr_row[pixel_idx + 2] = R; // R
        }
    }
    return bgr_mat;
}

std::vector<unsigned char> MatBGRToNV12(const cv::Mat& bgr_mat) 
{ 
    if (bgr_mat.empty() || bgr_mat.channels() != 3 || bgr_mat.type() != CV_8UC3) {
        std::cerr << "[mw]Error: Input Mat is empty, not 3-channel, or not CV_8UC3." << std::endl;
        return {};
    }

    int width = bgr_mat.cols;
    int height = bgr_mat.rows;
    int y_plane_size = width * height;
    int uv_plane_size = width * height / 2;
    int nv12_size = y_plane_size + uv_plane_size;

    std::vector<unsigned char> nv12_buffer(nv12_size);
	log::info("[mw]step1");
    // 将 BGR 转换为 全尺寸 YUV (YUV444P-like intermediate)
    std::vector<std::vector<unsigned char>> y_full(height, std::vector<unsigned char>(width));
    std::vector<std::vector<unsigned char>> u_full(height, std::vector<unsigned char>(width));
    std::vector<std::vector<unsigned char>> v_full(height, std::vector<unsigned char>(width));

    for (int y = 0; y < height; ++y) {
        const unsigned char* bgr_row = bgr_mat.ptr<unsigned char>(y);
        for (int x = 0; x < width; ++x) {
            // Get BGR pixel values
            // Remember: OpenCV Mat stores BGR as [B, G, R]
            unsigned char b = bgr_row[x * 3 + 0];
            unsigned char g = bgr_row[x * 3 + 1];
            unsigned char r = bgr_row[x * 3 + 2];

            // Apply YUV conversion formulas
            double Y_val =  0.299 * r + 0.587 * g + 0.114 * b;
            double U_val = -0.147 * r - 0.289 * g + 0.436 * b + 128.0; // Add 128 offset
            double V_val =  0.615 * r - 0.515 * g - 0.100 * b + 128.0; // Add 128 offset

            // Clamp values to [0, 255] and store as unsigned char
            y_full[y][x] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, Y_val)));
            u_full[y][x] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, U_val)));
            v_full[y][x] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, V_val)));
        }
    }
	log::info("[mw]step2");
    // --- Copy Y plane (no downsampling needed) ---
    for (int y = 0; y < height; ++y) {
        unsigned char* dst_y_row = nv12_buffer.data() + y * width;
        for (int x = 0; x < width; ++x) {
            dst_y_row[x] = y_full[y][x];
        }
    }
	log::info("[mw]step3");
    // --- Downsample U/V planes (2x2 average) and interleave into NV12 UV plane ---
    unsigned char* dst_uv_ptr = nv12_buffer.data() + y_plane_size;
    for (int vy = 0; vy < height / 2; ++vy) {
        for (int vx = 0; vx < width / 2; ++vx) {
            int src_y_start = vy * 2;
            int src_x_start = vx * 2;

            // Average 2x2 block for U and V
            int u_sum = 0, v_sum = 0;
            for (int dy = 0; dy < 2; ++dy) {
                for (int dx = 0; dx < 2; ++dx) {
                    int src_y = src_y_start + dy;
                    int src_x = src_x_start + dx;
                    u_sum += u_full[src_y][src_x];
                    v_sum += v_full[src_y][src_x];
                }
            }
            unsigned char avg_u = static_cast<unsigned char>((u_sum + 2) / 4); // Add 2 for rounding
            unsigned char avg_v = static_cast<unsigned char>((v_sum + 2) / 4);

            int uv_index = vy * (width / 2) + vx;
            dst_uv_ptr[uv_index * 2]     = avg_u; // U
            dst_uv_ptr[uv_index * 2 + 1] = avg_v; // V
        }
    }
	log::info("[mw]step4");
    return nv12_buffer;
}

输出的nv12图像数据写入到执行程序目录下

cpp 复制代码
	std::string df_name = "./df_pic_nv12.yuv";
	std::ofstream out_file(df_name, std::ios::binary);
	if (out_file.is_open()) 
	{
		out_file.write(reinterpret_cast<const char*>(dst_img_data_nv12.get()), nv12_size);
		out_file.close();
		log::info("Saved defogged NV12 data to %s", df_name.c_str());
	} 
	else {
		log::warn("Failed to open file for writing NV12 data.");
	}

单纯是为了绕过cvtColor函数,如果遇到自己编的库和对方跑的库opencv版本不同,可以用这种方式转换。

我main这样写

cpp 复制代码
int main(int argc, char* argv[])
{
	if (argc < 2)
    {
        std::cout << "./test_client_demo inputpath Level" << std::endl;
        return -1;
    }
	log::init();
    log::debug_enable(true);
    int Level = 1;
    if (argc >= 3)
    {
        Level = atoi(argv[2]);
    }
    cv::Mat loaded_img = cv::imread(argv[1], cv::IMREAD_COLOR);
    if (loaded_img.empty())
    {
        std::cout << "img read failed!!" << std::endl;
        return -1;
    }
	api_config_t client_config;
	int ret = 0;
	client_config.com_type = COM_ETHNET;
	strcpy(client_config.config_enet.ip_addr, "127.0.0.1");
	client_config.config_enet.port = 7887;
	system_init(client_config);
	system_sync_time();
	auto retframe = 1;
	std::vector<unsigned char> nv12_vector = MatBGRToNV12(loaded_img);
	const uint8_t* nv12_src_ptr = nv12_vector.data();
	size_t nv12_size = nv12_vector.size();
	std::unique_ptr<uint8_t[]> dst_img_data_nv12 = std::make_unique<uint8_t[]>(nv12_size);
	std::unique_ptr<uint8_t[]> dst_img_data_nv12c = std::make_unique<uint8_t[]>(nv12_size);
	log::debug("input size: w = %d ,h = %d ,size = %d", loaded_img.cols, loaded_img.rows,nv12_size);
	log::debug("Buffer Info: src_ptr=%p, dst_ptr=%p", nv12_src_ptr, dst_img_data_nv12.get());

	log::debug("nv12_src_ptr address: %p, aligned: %s", nv12_src_ptr, ((uintptr_t)nv12_src_ptr % 16 == 0) ? "Yes" : "No");
	log::debug("dst_img_data_nv12 address: %p, aligned: %s", dst_img_data_nv12.get(), ((uintptr_t)dst_img_data_nv12.get() % 16 == 0) ? "Yes" : "No");
	





		std::string df_name = "./second_see_df_pic_nv12.yuv";
		std::ofstream out_file(df_name, std::ios::binary);
		if (out_file.is_open()) 
		{
			out_file.write(reinterpret_cast<const char*>(dst_img_data_nv12.get()), nv12_size);
			out_file.close();
			log::info("Saved defogged NV12 data to %s", df_name.c_str());
		} else {
			log::warn("Failed to open file for writing NV12 data.");
		}
	
	log::info("goodbye");
	system_deinit();
  log::deinit();
	return 0;
}
相关推荐
码农三叔1 小时前
(9-1)电源管理与能源系统:电池选择与安全
人工智能·嵌入式硬件·安全·机器人·能源·人形机器人
司沐_Simuoss2 小时前
Text to SQL系统的千层套路~
数据库·人工智能·sql·语言模型·系统架构
北京阿法龙科技有限公司2 小时前
工业场景下AR+AI图像识别:精准选型赋能运维与质检
运维·人工智能·ar
才兄说2 小时前
机器人租售怎么嵌?按流程节点
人工智能
logic_52 小时前
关于VIT为啥可以用卷积代替第一层嵌入层
人工智能·神经网络·cnn
小康小小涵2 小时前
改进型深度Q-网格DQN和蒙特卡洛树搜索MCTS以及模型预测控制MPC强化学习的机器人室内导航仿真
人工智能·机器人·自动驾驶
PNP机器人2 小时前
突破机器人操作瓶颈!接触感知神经动力学,让仿真与现实无缝对齐
人工智能·机器人
美狐美颜sdk2 小时前
直播美颜sdk与智能美妆技术解析:实时人脸算法如何驱动新一代互动体验
人工智能·音视频·美颜sdk·视频美颜sdk·美狐美颜sdk
hit56实验室2 小时前
【易经系列】《屯卦》:six four:乘马班如,求婚媾,往吉,无不利
人工智能