RGB24,RGB565,RGB444圖片質量比較


以下圖片,第二幅是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,可以忽略不計。

例子代碼如下:

// 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; }

能傳大圖不?

可以傳大圖啊


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM