处理YUV420图像宽高不是8的倍数的问题

项目场景:

在视频处理中,经常会遇到 YUV420 格式图像数据的宽度或高度不是8的倍数的情况。这种情况可能会导致在编码为 JPEG 图像时出现问题,例如出现编码出来的图片错乱或其他异常。


原因分析:

YUV420 图像数据由亮度(Y)和两个色度(UV)分量组成,其中 U 和 V 分量通常按照下采样方式存储。当图像的宽度或高度不是8的倍数时,可能会影响色度分量的对齐和处理,从而导致编码后的图像出现异常。


解决方案:

为了确保 YUV420 图像数据的宽度和高度能够被8整除,可以采用两种主要的方法:填充(Padding)和裁剪(Cropping)。

方式一:填充方式

填充方式通过在图像边缘添加额外像素来增加图像的宽度和高度,使其能够被8整除:

void adjustYUV420SizeToMultipleOf8(unsigned char* &yuvData, int& width, int& height) {
    int new_width = ((width + 7) / 8) * 8;
    int new_height = ((height + 7) / 8) * 8;

    if (new_width != width || new_height != height) {
        // Calculate sizes
        int old_y_size = width * height;
        int old_uv_size = width * height / 4; // YUV420: U and V size is 1/4 of Y size
        int new_y_size = new_width * new_height;
        int new_uv_size = new_width * new_height / 4; // YUV420: U and V size is 1/4 of Y size

        // Allocate new buffers for Y, U, V
        unsigned char* newY = new unsigned char[new_y_size];
        unsigned char* newU = new unsigned char[new_uv_size];
        unsigned char* newV = new unsigned char[new_uv_size];

        // Initialize new buffers (optional: memset or copy existing data)
        memset(newY, 0, new_y_size);
        memset(newU, 0, new_uv_size);
        memset(newV, 0, new_uv_size);

        // Copy existing Y, U, V data to new buffers
        for (int y = 0; y < height; ++y) {
            memcpy(newY + y * new_width, yuvData + y * width, width);
        }
        for (int y = 0; y < height / 2; ++y) {
            // U component (even rows)
            memcpy(newU + y * (new_width / 2), yuvData + old_y_size + y * (width / 2), width / 2);
            // V component (odd rows)
            memcpy(newV + y * (new_width / 2), yuvData + old_y_size + old_uv_size + y * (width / 2), width / 2);
        }

        // Free old YUV data
        delete[] yuvData;

        // Update pointers and dimensions
        yuvData = new unsigned char[new_y_size + 2 * new_uv_size]; // Allocate new space for YUV420 data
        memcpy(yuvData, newY, new_y_size);
        memcpy(yuvData + new_y_size, newU, new_uv_size);
        memcpy(yuvData + new_y_size + new_uv_size, newV, new_uv_size);

        // Update width and height
        width = new_width;
        height = new_height;

        // Free new buffers
        delete[] newY;
        delete[] newU;
        delete[] newV;
    }
}

方式二:裁剪方式

裁剪方式通过删除图像边缘的像素来减少图像的宽度和高度,使其能够被8整除:

void cropYUV420ToMultipleOf8(unsigned char* &yuvData, int& width, int& height) {
    int new_width = (width / 8) * 8;
    int new_height = (height / 8) * 8;

    if (new_width != width || new_height != height) {
        // Calculate sizes
        int old_y_size = width * height;
        int old_uv_size = width * height / 4; // YUV420: U and V size is 1/4 of Y size
        int new_y_size = new_width * new_height;
        int new_uv_size = new_width * new_height / 4; // YUV420: U and V size is 1/4 of Y size

        // Allocate new buffers for Y, U, V
        unsigned char* newY = new unsigned char[new_y_size];
        unsigned char* newU = new unsigned char[new_uv_size];
        unsigned char* newV = new unsigned char[new_uv_size];

        // Copy cropped Y, U, V data
        for (int y = 0; y < new_height; ++y) {
            memcpy(newY + y * new_width, yuvData + y * width, new_width);
        }
        for (int y = 0; y < new_height / 2; ++y) {
            // U component (even rows)
            memcpy(newU + y * (new_width / 2), yuvData + old_y_size + y * (width / 2), new_width / 2);
            // V component (odd rows)
            memcpy(newV + y * (new_width / 2), yuvData + old_y_size + old_uv_size + y * (width / 2), new_width / 2);
        }

        // Free old YUV data
        delete[] yuvData;

        // Update pointers and dimensions
        yuvData = new unsigned char[new_y_size + 2 * new_uv_size]; // Allocate new space for YUV420 data
        memcpy(yuvData, newY, new_y_size);
        memcpy(yuvData + new_y_size, newU, new_uv_size);
        memcpy(yuvData + new_y_size + new_uv_size, newV, new_uv_size);

        // Update width and height
        width = new_width;
        height = new_height;

        // Free new buffers
        delete[] newY;
        delete[] newU;
        delete[] newV;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值