图像处理 yuyv转rgb,rgb转jpeg,yuyv转yuv420, yuyv转jpeg

本文详细介绍了从YUYV格式图像数据转换至RGB,再到JPEG格式的完整过程,包括所需库的安装配置,以及具体的转换算法实现,适用于嵌入式系统或图像处理软件的开发人员。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

说明:将图片转到jpeg(我用的是jpegsrc.v9d.tar.gz),需要用到libjpeg库,下载目录http://www.ijg.org/,

安装方法:

1.  ./configure   --prefix=目录

2. make

3. make install

 

yuyv转rgb:

void yuv_to_rgb(unsigned char *yuv, unsigned char *rgb)
{
    unsigned int i;
    unsigned char* y0 = yuv + 0;
    unsigned char* u0 = yuv + 1;
    unsigned char* y1 = yuv + 2;
    unsigned char* v0 = yuv + 3;

    unsigned  char* r0 = rgb + 0;
    unsigned  char* g0 = rgb + 1;
    unsigned  char* b0 = rgb + 2;
    unsigned  char* r1 = rgb + 3;
    unsigned  char* g1 = rgb + 4;
    unsigned  char* b1 = rgb + 5;

    float rt0 = 0, gt0 = 0, bt0 = 0, rt1 = 0, gt1 = 0, bt1 = 0;

    for(i = 0; i <= (IMAGE_W * IMAGE_H) / 2 ;i++)
    {
        bt0 = 1.164 * (*y0 - 16) + 2.018 * (*u0 - 128);
        gt0 = 1.164 * (*y0 - 16) - 0.813 * (*v0 - 128) - 0.394 * (*u0 - 128);
        rt0 = 1.164 * (*y0 - 16) + 1.596 * (*v0 - 128);

        bt1 = 1.164 * (*y1 - 16) + 2.018 * (*u0 - 128);
        gt1 = 1.164 * (*y1 - 16) - 0.813 * (*v0 - 128) - 0.394 * (*u0 - 128);
        rt1 = 1.164 * (*y1 - 16) + 1.596 * (*v0 - 128);


        if(rt0 > 250)      rt0 = 255;
        if(rt0< 0)        rt0 = 0;

        if(gt0 > 250)     gt0 = 255;
        if(gt0 < 0)    gt0 = 0;

        if(bt0 > 250)    bt0 = 255;
        if(bt0 < 0)    bt0 = 0;

        if(rt1 > 250)    rt1 = 255;
        if(rt1 < 0)    rt1 = 0;

        if(gt1 > 250)    gt1 = 255;
        if(gt1 < 0)    gt1 = 0;

        if(bt1 > 250)    bt1 = 255;
        if(bt1 < 0)    bt1 = 0;

        *r0 = (unsigned char)rt0;
        *g0 = (unsigned char)gt0;
        *b0 = (unsigned char)bt0;

        *r1 = (unsigned char)rt1;
        *g1 = (unsigned char)gt1;
        *b1 = (unsigned char)bt1;

        yuv = yuv + 4;
        rgb = rgb + 6;
        if(yuv == NULL)
            break;

        y0 = yuv;
        u0 = yuv + 1;
        y1 = yuv + 2;
        v0 = yuv + 3;

        r0 = rgb + 0;
        g0 = rgb + 1;
        b0 = rgb + 2;
        r1 = rgb + 3;
        g1 = rgb + 4;
        b1 = rgb + 5;
    }
}

rgb转jpeg:

long rgb_to_jpeg(unsigned char *rgb, unsigned char *jpeg)
{
    size_t jpeg_size;
    struct jpeg_compress_struct jcs;
    struct jpeg_error_mgr jem;
    JSAMPROW row_pointer[1];
    int row_stride;

    jcs.err = jpeg_std_error(&jem);
    jpeg_create_compress(&jcs);

    jpeg_mem_dest(&jcs, &jpeg, &jpeg_size);//就是这个函数!!!!!!!

    jcs.image_width = IMAGE_W;
    jcs.image_height = IMAGE_H;

    jcs.input_components = 3;//1;
    jcs.in_color_space = JCS_RGB;//JCS_GRAYSCALE;

    jpeg_set_defaults(&jcs);
    jpeg_set_quality(&jcs, 180, TRUE);

    jpeg_start_compress(&jcs, TRUE);
    row_stride =jcs.image_width * 3;

    while(jcs.next_scanline < jcs.image_height){//对每一行进行压缩
        row_pointer[0] = &rgb[jcs.next_scanline * row_stride];
        (void)jpeg_write_scanlines(&jcs, row_pointer, 1);
    }
    jpeg_finish_compress(&jcs);
    jpeg_destroy_compress(&jcs);

#ifdef JPEG    //jpeg 保存,测试用
    FILE *jpeg_fd;

    jpeg_fd = fopen("./jpeg.jpg","w");
    if(jpeg_fd < 0 ){
        perror("open jpeg.jpg failed!\n");
        exit(-1);
    }

    fwrite(jpeg, jpeg_size, 1, jpeg_fd);
    fclose(jpeg_fd);
#endif
    return jpeg_size;
}

yuyv转yuv420:

int YUV422To420(unsigned char *yuv422, unsigned char *yuv420, int width, int height)
{

       int ynum=width*height;
       int i,j,k=0;
    //得到Y分量
       for(i=0;i<ynum;i++){
           yuv420[i]=yuv422[i*2];
       }
    //得到U分量
       for(i=0;i<height;i++){
           if((i%2)!=0)continue;
           for(j=0;j<(width/2);j++){
               if((4*j+1)>(2*width))break;
               yuv420[ynum+k*2*width/4+j]=yuv422[i*2*width+4*j+1];
                       }
            k++;
       }
       k=0;
    //得到V分量
       for(i=0;i<height;i++){
           if((i%2)==0)continue;
           for(j=0;j<(width/2);j++){
               if((4*j+3)>(2*width))break;
               yuv420[ynum+ynum/4+k*2*width/4+j]=yuv422[i*2*width+4*j+3];

           }
            k++;
       }

       return 1;
}

yuv420转jpeg:待测试

uint32_t yuv420sp_to_jpg(int width, int height, unsigned char *inputYuv,unsigned char *outJpeg)
{
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;
    JSAMPROW row_pointer[1];
    int i = 0, j = 0;
    unsigned char *pY, *pU, *pV;
    unsigned char yuvbuf[width * 3];
    unsigned long outSize;
    cinfo.err = jpeg_std_error(&jerr);//用于错误信息
    jpeg_create_compress(&cinfo);  //初始化压缩对象
    jpeg_mem_dest(&cinfo, &outJpeg, &outSize);
    cinfo.image_width = width;//设置输入图片宽度
    cinfo.image_height = height;//设置图片高度
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_YCbCr;//设置输入图片的格式,支持RGB/YUV/YCC等等
    cinfo.dct_method = JDCT_FLOAT;
    jpeg_set_defaults(&cinfo);//其它参数设置为默认的!
    jpeg_set_quality(&cinfo, 40, TRUE);//设置转化图片质量,范围0-100
    jpeg_start_compress(&cinfo, TRUE);
    pY = inputYuv ;
    pU = inputYuv +1 ;
    pV = inputYuv + 3;
    j = 1;
    while (cinfo.next_scanline < cinfo.image_height) {
        int index = 0;
        for (i = 0; i < width; i += 2){//输入的YUV图片格式为标准的YUV444格式,所以需要把YUV420转化成YUV444.
            yuvbuf[index++] = *pY;
            yuvbuf[index++] = *pU;
            yuvbuf[index++] = *pV;
            pY += 2;
            yuvbuf[index++] = *pY;
            yuvbuf[index++] = *pU;
            yuvbuf[index++] = *pV;
            pY += 2;
            pU += 4;
            pV += 4;
        }
        row_pointer[0] = yuvbuf;
        (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);//单行图片转换压缩
        j++;
    }
    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);

    fwrite(outJpeg, outSize, 1, jpeg_fd);
    fclose(jpeg_fd);

    return (uint32_t)outSize;
}

yuyv转jpeg:

#define IMAGE_W 1280
#define IMAGE_H 720

#define OUTPUT_BUF_SIZE 4096

typedef struct {
    struct jpeg_destination_mgr pub;
    JOCTET * buffer;
    unsigned char *outbuffer;
    int outbuffer_size;
    unsigned char *outbuffer_cursor;
    int *written;
}mjpg_destination_mgr;

typedef mjpg_destination_mgr *mjpg_dest_ptr;

METHODDEF(void) init_destination(j_compress_ptr cinfo) {
    mjpg_dest_ptr dest =(mjpg_dest_ptr) cinfo->dest;
    dest->buffer =(JOCTET *)(*cinfo->mem->alloc_small)((j_common_ptr) cinfo, JPOOL_IMAGE, OUTPUT_BUF_SIZE*sizeof(JOCTET));
    *(dest->written) = 0;
    dest->pub.next_output_byte = dest->buffer;
    dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
}

METHODDEF(boolean) empty_output_buffer(j_compress_ptr cinfo) {
    mjpg_dest_ptr dest =(mjpg_dest_ptr) cinfo->dest;
    memcpy(dest->outbuffer_cursor, dest->buffer, OUTPUT_BUF_SIZE);
    dest->outbuffer_cursor += OUTPUT_BUF_SIZE;
    *(dest->written) += OUTPUT_BUF_SIZE;
    dest->pub.next_output_byte = dest->buffer;
    dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
    return TRUE;
}

METHODDEF(void) term_destination(j_compress_ptr cinfo) {
    mjpg_dest_ptr dest =(mjpg_dest_ptr) cinfo->dest;
    size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
    /* Write any data remaining in the buffer */
    memcpy(dest->outbuffer_cursor, dest->buffer, datacount);
    dest->outbuffer_cursor += datacount;
    *(dest->written) += datacount;
}

void dest_buffer(j_compress_ptr cinfo, unsigned char *buffer, int size, int *written) {
    mjpg_dest_ptr dest;
    if(cinfo->dest == NULL) {
        cinfo->dest =(struct jpeg_destination_mgr *)(*cinfo->mem->alloc_small)((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(mjpg_destination_mgr));
    }

    dest =(mjpg_dest_ptr)cinfo->dest;
    dest->pub.init_destination = init_destination;
    dest->pub.empty_output_buffer = empty_output_buffer;
    dest->pub.term_destination = term_destination;
    dest->outbuffer = buffer;
    dest->outbuffer_size = size;
    dest->outbuffer_cursor = buffer;
    dest->written = written;
}

//......YUYV.....JPEG..
int compress_yuyv_to_jpeg(unsigned char *buf, unsigned char *buffer, int size, int quality)
{
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;
    JSAMPROW row_pointer[1];
    unsigned char *line_buffer, *yuyv;
    int z;
    static int written;
    //int count = 0;
    //printf("%s\n", buf);
    line_buffer = (unsigned char*)calloc(IMAGE_W * 3, 1);
    yuyv = buf;
    printf("compress start...\n");
    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);
    /* jpeg_stdio_dest(&cinfo, file); */
    dest_buffer(&cinfo, buffer, size, &written);
    cinfo.image_width = IMAGE_W;
    cinfo.image_height = IMAGE_H;
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;
    jpeg_set_defaults(&cinfo);
    jpeg_set_quality(&cinfo, quality, TRUE);
    jpeg_start_compress(&cinfo, TRUE);
    z = 0;
    while(cinfo.next_scanline < IMAGE_H) {
        int x;
        unsigned char *ptr = line_buffer;
        for(x = 0; x < IMAGE_W; x++) {
            int r, g, b;
            int y, u, v;
            if(!z)
                y = yuyv[0] << 8;
            else
                y = yuyv[2] << 8;
            u = yuyv[1] - 128;
            v = yuyv[3] - 128;
            r =(y +(359 * v))>> 8;
            g =(y -(88 * u) -(183 * v)) >> 8;
            b =(y +(454 * u)) >> 8;
            *(ptr++) =(r > 255) ? 255 :((r < 0) ? 0 : r);
            *(ptr++) =(g > 255) ? 255 :((g < 0) ? 0 : g);
            *(ptr++) =(b > 255) ? 255 :((b < 0) ? 0 : b);
            if(z++) {
                z = 0;
                yuyv += 4;
            }
        }
        row_pointer[0] = line_buffer;
        jpeg_write_scanlines(&cinfo, row_pointer, 1);
    }
    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);
    free(line_buffer);
    return(written);
}

使用方法:
compress_yuyv_to_jpeg(buf, buffer,(IMAGE_W * IMAGE_H), 80);

 

### YUV格式介绍 YUV是一种色彩空间表示法,主要用于视频编码、图像处理以及电视广播等领域。它通过将亮度(Luma, Y)和色度(Chroma, U/V)分离的方式,有效地减少了数据冗余并提升了压缩效率[^1]。 #### 数据结构与表现形式 YUV格式可以根据其内部的数据排列方式分为两种主要类别:**打包格式**和**平面格式**。 - **打包格式**是指Y、U、V分量按特定顺序交错存储在一个连续的内存块中,这种格式通常便于硬件访问和实时处理。 - **平面格式**则是将Y、U、V分别存放在独立的内存区域中,这种方式更适合软件操作和后期编辑[^2]。 #### 应用领域 1. **视频编码与压缩** YUV因其高效的压缩特性和良好的视觉质量,在现代视频编码标准中占据重要地位。无论是流媒体服务还是物理介质(如DVD、蓝光),都广泛采用基于YUV的颜色模型进行数据存储和传输。 2. **电视广播** 在传统模拟电视信号传输过程中,PAL和NTSC等制式均依赖于YUV体系来传递彩色画面信息。这不仅简化了信号调制流程,也增强了抗干扰能力。 3. **图像处理与计算机视觉** 利益于YUV独特的亮度/色度分解机制,该格式被频繁应用于诸如颜色匹配、对象识别及运动跟踪之类的高级算法开发当中。特别是针对人类皮肤色调检测的任务,利用YUV能取得更精确的结果。 4. **学习与研究工具支持** 针对希望深入理解或实际运用YUV格式的研究人员和技术爱好者们,存在一些公共资源可供下载使用。例如某开源项目就提供了标准化尺寸(1920×1080)下的样本文件集合及其配套可视化程序,极大地方便了相关人员的学习实践工作[^4]。 ```python import numpy as np from PIL import Image def yuv_to_rgb(yuv_image_path, width=1920, height=1080): """ 将YUV格式图片换成RGB模式显示 参数: yuv_image_path (str): 输入YUV文件路径. width (int): 图像宽度,默认为1920像素. height (int): 图像高度,默认为1080像素. 返回: RGB图像实例. """ with open(yuv_image_path, 'rb') as f: raw_data = np.frombuffer(f.read(), dtype=np.uint8) # 假设输入的是NV12格式(YUV 4:2:0),调整数组形状 y_plane_size = width * height uv_plane_size = int(width / 2) * int(height / 2) y_channel = raw_data[:y_plane_size].reshape((height, width)) u_channel = raw_data[y_plane_size:y_plane_size + uv_plane_size].reshape((int(height / 2), int(width / 2))) v_channel = raw_data[y_plane_size + uv_plane_size:].reshape((int(height / 2), int(width / 2))) rgb_array = cv2.cvtColor(np.stack([y_channel,u_channel,v_channel], axis=-1),cv2.COLOR_YUV2BGR_NV12) return Image.fromarray(rgb_array,"RGB") if __name__ == "__main__": img = yuv_to_rgb('example.yuv') img.show() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值