前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >RGB24,RGB565,RGB444图片质量比较

RGB24,RGB565,RGB444图片质量比较

作者头像
xiny120
发布2019-06-11 11:09:14
4.8K0
发布2019-06-11 11:09:14
举报
文章被收录于专栏:毛毛v5毛毛v5

以下图片,第二幅是RGB24的原图。第一幅是对第二幅进行RGB444的有损变换图,第三幅是对第二幅进行RGB565的有损变换图。其中肉眼很难分辨RGB565和RGB24的差别。RGB444有明显噪点。

RGB444图片

RGB24原图

RGB565图片

转换都是用的ffmpeg的sws_scale算法。

主要是想比较每种图片的大小。

文件大小

其中 188_720_576.bmp是原图 1216K 188_720_576.bmp_444_1.bmp是转RGB444之后再转回RGB24保存的图片。所以大小也是1216K 188_720_576.bmp_555_1.bmp是转RGB565之后再转回RGB24保存的图片。所以大小也是1216K 188_720_576.bmp_444_1_2.raw是转RGB444之后的裸数据。大小是810K 188_720_576.bmp_555_1_2.raw是转RGB565之后的裸数据。大小也是810K 188_720_576.bmp_444_1_2.raw.zip是RGB444裸数据zip压缩后的文件。大小是185K 188_720_576.bmp_555_1_2.raw.zip是RGB565裸数据zip压缩后的文件。大小也是335K

得出结论因为RGB565和RGB444实际占用字节都是16bit,所以 裸数据文件大小一样。但是RGB444实际上只用了12bit,有4bit无用进行0填充,所以zip压缩率比较大。

然后又进行了一个尝试,就是把RGB444的4bit数据移除。两个RGB444有效数据(4byte)合并成3byte。得到的裸数据文件大小和压缩大小如下:

32bit RGB444数据移除8bit无效数据组成24bit

我们看到,在移除RGB444的无用数据后,裸数据大小由原来的810K减少到608K.(810*3/4=607.5),但是实际zip压缩文件只是从185K变成183K,可以忽略不计。

例子代码如下:

代码语言:javascript
复制
// RGBStudy.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include <Windows.h>
#include <iostream>
#include <string>
#include <wingdi.h>

#pragma warning(disable:4996)

#ifdef __cplusplus  
extern "C" {
#endif  

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libavutil/imgutils.h>
#include <libavutil/parseutils.h>
#include <libavutil/file.h>
#include <libswscale/swscale.h>

#ifdef __cplusplus  
}
#endif  
int go(char *argv);


int main()
{

    go((char*)"d:\\188_720_576.bmp");
    std::cout << "Hello World!\n"; 

}


int go(char *argv){
    BITMAPFILEHEADER bmpFHeader;
    BITMAPINFOHEADER bmpIHeader;
    uint8_t *src_data[4], *dst_data[4];
    int src_linesize[4], dst_linesize[4];
    int src_w = 640, src_h = 480, dst_w, dst_h;
    enum AVPixelFormat src_pix_fmt = AV_PIX_FMT_RGB24, dst_pix_fmt = AV_PIX_FMT_RGB565;
    const char *dst_filename = NULL;
    std::string file,file0;
    FILE *dst_file;
    int dst_bufsize;
    struct SwsContext *sws_ctx, *sws_ctx1;
    int i, ret;

    dst_filename = argv;
    file = dst_filename;
    file = file + "_555_1.bmp";
    file0 = dst_filename;
    file0 = file0 + "_555_1_2.raw";
    dst_w = src_w;
    dst_h = src_h;

    dst_file = fopen(dst_filename, "rb");
    if (dst_file) {
        fseek(dst_file, 0L, SEEK_END);
        int len = ftell(dst_file);
        if (len > 0) {
            char* buf0 = new char[len];
            char* buf = buf0;
            fseek(dst_file, 0L, SEEK_SET);
            fread(buf, 1, len, dst_file);
            fclose(dst_file);

            memcpy(&bmpFHeader, buf, sizeof(BITMAPFILEHEADER));
            int nHeadLen = bmpFHeader.bfOffBits - sizeof(BITMAPFILEHEADER);
            memcpy(&bmpIHeader, buf + sizeof(BITMAPFILEHEADER), nHeadLen);

            src_w = dst_w = bmpIHeader.biWidth;
            src_h = dst_h = bmpIHeader.biHeight;

            buf += bmpFHeader.bfOffBits;
            len = len - bmpFHeader.bfOffBits;

            sws_ctx = sws_getContext(src_w, src_h, src_pix_fmt,
                dst_w, dst_h, dst_pix_fmt,
                SWS_BILINEAR, NULL, NULL, NULL);
            if (!sws_ctx) {
                fprintf(stderr,
                    "Impossible to create scale context for the conversion "
                    "fmt:%s s:%dx%d -> fmt:%s s:%dx%d\n",
                    av_get_pix_fmt_name(src_pix_fmt), src_w, src_h,
                    av_get_pix_fmt_name(dst_pix_fmt), dst_w, dst_h);
                ret = AVERROR(EINVAL);
            }
            else {
                sws_ctx1 = sws_getContext(src_w, src_h, dst_pix_fmt,
                    dst_w, dst_h, src_pix_fmt,
                    SWS_BILINEAR, NULL, NULL, NULL);
                if (!sws_ctx1) {
                    fprintf(stderr,
                        "Impossible to create scale context for the conversion "
                        "fmt:%s s:%dx%d -> fmt:%s s:%dx%d\n",
                        av_get_pix_fmt_name(src_pix_fmt), src_w, src_h,
                        av_get_pix_fmt_name(dst_pix_fmt), dst_w, dst_h);
                    ret = AVERROR(EINVAL);
                }
                else {
                    if ((ret = av_image_alloc(src_data, src_linesize,
                        src_w, src_h, src_pix_fmt, 16)) < 0) {
                        fprintf(stderr, "Could not allocate source image\n");
                    }
                    else {
                        if ((ret = av_image_alloc(dst_data, dst_linesize,
                            dst_w, dst_h, dst_pix_fmt, 1)) < 0) {
                            fprintf(stderr, "Could not allocate destination image\n");
                        }
                        else {
                            dst_bufsize = ret;
                            memcpy(src_data[0], buf, len);
                            int a = sws_scale(sws_ctx, (const uint8_t * const*)src_data,
                                src_linesize, 0, src_h, dst_data, dst_linesize);
                            /*
                            //memset(dst_data[0], 0xFF, dst_linesize[0]*dst_h);
                            short* p = (short*)dst_data[0];
                            short* p1 = 0;
                            short* p0 = 0;
                            char* bufp = new char[dst_linesize[0] * dst_h];
                            char* bufp0 = bufp;
                            int ip0 = 0;
                            int ip1 = 0;
                            int ip = 0;
                            int bufplen = 0;
                            for (int i = 0; i < dst_linesize[0] * dst_h / 2 / 2; i++) {
                                p0 = p++;
                                p1 = p++;
                                ip0 = *p0 & 0x00000FFF; // 16bit中低4bit不用。
                                ip1 = *p1 & 0x00000FFF; // 16bit中低4bit不用。
                                //((uint)a) << 12 + (uint)(b)
                                ip = ip1 << 12 | (ip0);
                                memcpy(bufp0, &ip, 3);
                                bufp0 += 3;
                                
                                //*p = *p & 0x000F; // 红色通道
                                //*p = *p & 0x00F0; // 绿色通道
                                //*p = *p & 0x0F00; // 蓝色通道
                                
                            }


                            dst_file = fopen(file0.c_str(), "wb");
                            fwrite(bufp, 1, (bufp0 - bufp), dst_file);
                            fclose(dst_file);
                            delete [] bufp;
                            */

                            dst_file = fopen(file0.c_str(), "wb");
                            fwrite(dst_data[0], 1, dst_linesize[0] * dst_h, dst_file);
                            fclose(dst_file);

                            memset(src_data[0], 0xFF, len);

                            int b = sws_scale(sws_ctx1, (const uint8_t * const*)dst_data,
                                dst_linesize, 0, src_h, src_data, src_linesize);
                            


                            dst_file = fopen(file.c_str(), "wb");
                            fwrite(&bmpFHeader, sizeof(bmpFHeader), 1, dst_file);
                            fwrite(&bmpIHeader, sizeof(bmpIHeader), 1, dst_file);
                            fwrite(&bmpIHeader, sizeof(bmpIHeader), 1, dst_file);
                            fwrite(&bmpIHeader, sizeof(bmpIHeader), 1, dst_file);
                            fwrite(&bmpIHeader, sizeof(bmpIHeader), 1, dst_file);
                            fseek(dst_file, bmpFHeader.bfOffBits, SEEK_SET);
                            fwrite(src_data[0], 1, len, dst_file);
                            fclose(dst_file);

                            fprintf(stderr, "Scaling succeeded. Play the output file with the command:\n"
                                "ffplay -f rawvideo -pix_fmt %s -video_size %dx%d %s\n",
                                av_get_pix_fmt_name(dst_pix_fmt), dst_w, dst_h, dst_filename);
                            av_freep(&dst_data[0]);
                        }
                        av_freep(&src_data[0]);
                    }
                    sws_freeContext(sws_ctx1);
                }
                sws_freeContext(sws_ctx);
            }
            delete[] buf0;
        }
        else {
            fclose(dst_file);
        }
    }
    return ret < 0;
}

能传大图不?

可以传大图啊

Screen Content (SC) video coding http://www.doc88.com/p-0377419240625.html

http://www.doc88.com/p-6039625062473.html

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.04.12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档