调色板

我们知道,自然界中的所有颜色都可以由红、绿、蓝(R,G,B)组合而成。有的颜色含有红色成分多一些,如深红;有的含有红色成分少一些,如浅红。针对含有红色成分的多少,可以分成0到255共256个等级,0级表示不含红色成分;255级表示含有100%的红色成分。同样,绿色和蓝色也被分成256级。这种分级概念称为量化。

这样,根据红、绿、蓝各种不同的组合我们就能表示出256×256×256,约1600万种颜色。这么多颜色对于我们人眼来说已经足够丰富了。

表1.1    常见颜色的RGB组合值

颜色

R

G

B

255

0

0

0

255

0

绿

0

0

255

255

255

0

255

0

255

0

255

255

255

255

255

0

0

0

128

128

128

你大概已经明白了,当一幅图中每个象素赋予不同的RGB值时,能呈现出五彩缤纷的颜色了,这样就形成了彩色图。的确是这样的,但实际上的做法还有些差别。

让我们来看看下面的例子。

有一个长宽各为200个象素,颜色数为16色的彩色图,每一个象素都用R、G、B三个分量表示。因为每个分量有256个级别,要用8位(bit),即一个字节(byte)来表示,所以每个象素需要用3个字节。整个图象要用200×200×3,约120k字节,可不是一个小数目呀!如果我们用下面的方法,就能省的多。

因为是一个16色图,也就是说这幅图中最多只有16种颜色,我们可以用一个表:表中的每一行记录一种颜色的R、G、B值。这样当我们表示一个象素的颜色时,只需要指出该颜色是在第几行,即该颜色在表中的索引值。举个例子,如果表的第0行为255,0,0(红色),那么当某个象素为红色时,只需要标明0即可。

让我们再来计算一下:16种状态可以用4位(bit)表示,所以一个象素要用半个字节。整个图象要用200×200×0.5,约20k字节,再加上表占用的字节为3×16=48字节.整个占用的字节数约为前面的1/6,省很多吧?

这张R、G、B的表,就是我们常说的调色板(Palette),另一种叫法是颜色查找表LUT(Look Up Table),似乎更确切一些。Windows位图中便用到了调色板技术。其实不光是Windows位图,许多图象文件格式如pcx、tif、gif等都用到了。所以很好地掌握调色板的概念是十分有用的。

真彩色

有一种图,它的颜色数高达256×256×256种,也就是说包含我们上述提到的R、G、B颜色表示方法中所有的颜色,这种图叫做真彩色图(true color)。真彩色图并不是说一幅图包含了所有的颜色,而是说它具有显示所有颜色的能力,即最多可以包含所有的颜色。表示真彩色图时,每个象素直接用R、G、B三个分量字节表示,而不采用调色板技术。原因很明显:如果用调色板,表示一个象素也要用24位,这是因为每种颜色的索引要用24位(因为总共有224种颜色,即调色板有224行),和直接用R,G,B三个分量表示用的字节数一样,不但没有任何便宜,还要加上一个256×256×256×3个字节的大调色板。所以真彩色图直接用R、G、B三个分量表示,它又叫做24位色图。

我们知道,真彩图中包含最多达224种颜色,怎样从中选出256种颜色,又要使颜色的失真比较小,这是一个比较复杂的问题。一种简单的做法是将R:G:B以3:3:2表示,即取R,G的高3位,B的高两位,组成一个字节,这样就可以表示256种颜色了,但不难想象,这种方法的失真肯定很严重。

我们下面介绍的算法能够比较好地实现真彩图到256色图的转换。它的思想是:准备一个长度为4096的数组,代表4096种颜色。对图中的每一个象素,取R、G、B的最高四位,拼成一个12位的整数,对应的数组元素加1。全部统计完后,就得到了这4096种颜色的使用频率。其中,可能有一些颜色一次也没用到,即对应的数组元素为零(假设不为零的数组元素共有PalCounts个)。将这些为零的数组元素清除出去,使得前PalCounts个元素都不为零。将这PalCounts个数按从大到小的顺序排列(这里我们使用起泡排序)。这样,前256种颜色就是用的最多的颜色,它们将作为调色板上的256种颜色。对于剩下的PalCounts-256种颜色并不是简单地丢弃,而是用前256种颜色中的一种来代替,代替的原则是找有最小平方误差的那个。再次对图中的每一个象素,取R、G、B的最高四位,拼成一个12位的整数,如果对应值在前256种颜色中,则直接将该索引值填入位图数据中,如果是在后PalCounts-256种颜色中,则用代替色的索引值填入位图数据中。

下面的两幅图中,图5.3是原真彩图,图.54是用上面的算法转换成的256色图,可以看出,效果还不错。

DDB,DIB的区别

DDB(设备相关位图)
DIB(设备无关位图)

DDB依赖于具体设备:
DDB的颜色模式必需与输出设备相一致。例如,如果当前的显示设备是256色模式,那么DDB必然也是256色的。
在256色以下的位图中存储的像素值是系统调色板的索引,其颜色依赖于系统调色板。
由于DDB高度依赖输出设备,所以DDB只能存在于内存中,它要么在视频内存中,要么在系统内存中

DIB的与设备无关性主要体现在以下两个方面:
DIB的颜色模式与设备无关。例如,一个256色的DIB即可以在真彩色显示模式下使用,也可以在16色模式下使用。
256色以下(包括256色)的DIB拥有自己的颜色表,像素的颜色独立于系统调色板。
由于DIB不依赖于具体设备,因此可以用来永久性地保存图象。DIB一般是以*.BMP文件的形式保存在磁盘中的,有时也会保存在*.DIB文件中。运行在不同输出设备下的应用程序可以通过DIB来交换图象。

DDB的创建
MFC的CBitmap类封装了DDB。该类提供了几个函数用来创建DDB:
BOOL LoadBitmap( LPCTSTR lpszResourceName );
BOOL LoadBitmap( UINT nIDResource );
该函数从资源中载入一幅位图,若载入成功则返回TRUE。资源位图实际上是一个DIB,该函数在载入时把它转换成了DDB。
BOOL CreateBitmap( int nWidth, int nHeight, UINT nPlanes, UINT nBitcount, const void* lpBits );
    该函数用来创建一幅空白的DDB。参数nWidth和nHeight以像素为单位说明了位图的宽度和高度。nPlanes是DDB的色平面数,nBitcount是每个色平面的颜色位数。一般来说,nPlanes为1,而nBitcount代表DDB中每个像素值所占的位数,但在创建16色DDB时,nPlanes为4,而nBitcount为1。参数lpBits指向存储像素阵列的数组,该数组应该逐行存储位图的每个像素值。注意,数组中每行像素的数目必需是偶数个字节,如果是奇数,则应该用0补足。若创建成功函数返回TRUE。

BOOL CreateCompatibleBitmap( CDC* pDC, int nWidth, int nHeight );
    该函数创建一个与指定设备上下文兼容的DDB。参数pDC指向一个设备上下文,nWidth和nHeight是DDB的尺寸。若创建成功函数返回TRUE。

至于DIB,MFC未提供现成的类来封装DIB。要想使用DIB,首先应该了解DIB的结构。这个你可以到任何一本图像处理资料中找到详细说明。

DIB的颜色信息储存在自己的颜色表中,程序一般要根据颜色表为DIB创建逻辑调色板。在输出一幅DIB之前,程序应该将其逻辑调色板选入到相关的设备上下文中并实现到系统调色板中,然后再调用相关的GDI函数(如::SetDIBitsToDevice或::StretchDIBits)输出DIB。在输出过程中,GDI函数会把DIB转换成DDB,这项工作主要包括以下两步:

将DIB的颜色格式转换成与输出设备相同的颜色格式。例如,在真彩色的显示模式下要显示一个256色的DIB,则应该将其转换成24位的颜色格式。
将DIB像素的逻辑颜色索引转换成系统调色板索引。

常见的位图有单色(实际是1位图,,2的一次方为2,,因此它是2色图,,黑白色)、16色(实际是4位图,,2的4次方16,,因此它能表示16种颜色)、256色(实际是8位图,,这种位图的每个像素都用8位刚好一个字节来表示,2的8次方为256,因此它能表示256种颜色也即256种RGB的组合也即这种位图的色深)、16位(2的16次方=65536)及24位(2的24次方=1677万种颜色和256级灰度值
色深差不了很多,所以效果其实与16位图不相差几多)真彩色5种,对于前三者(即不大于256色)都可以调色板方式进行存储,而对16位及24位真彩色以调色板进行存储是不划算的,它们直接按照R,G,B分量进行存储。

BMP

BMP一般存的是RGB数据,常见的RGB格式如下:

RGB565 RGB565使用16位表示一个像素,这16位中的5位用于R,6位用于G,5位用于B。程序中通常使用一个字(WORD,一个字等于两个字节)来操作一个像素。
RGB555 RGB555是另一种16位的RGB格式,RGB分量都用5位表示(剩下的1位不用)。
RGB24 RGB24使用24位来表示一个像素,RGB分量都用8位表示,取值范围为0-255。

RGB32 RGB32使用32位来表示一个像素,RGB分量各用去8位,剩下的8位用作Alpha通道或者不用。

下面就让我们来看一看Windows的位图文件(.bmp文件)的格式是什么样子的。

bmp文件大体上分成四个部分,如图1.3所示。

位图文件头BITMAPFILEHEADER

位图信息头BITMAPINFOHEADER

调色板Palette

实际的位图数据ImageDate

 

BMP具体分析如下:

BMP文件由文件头、位图信息头、颜色信息和图形数据四部分组成。

1. BMP文件头

BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。

其结构定义如下:

typedef struct tagBITMAPFILEHEADER
{
WORDbfType;   // 位图文件的类型,必须为BM
DWORD   bfSize;   // 位图文件的大小,以字节为单位
WORDbfReserved1;  // 位图文件保留字,必须为0
WORDbfReserved2;  // 位图文件保留字,必须为0
DWORD   bfOffBits; // 位图数据的起始位置,以相对于位图
// 文件头的偏移量表示,以字节为单位
} BITMAPFILEHEADER;
2. 位图信息头

BMP位图信息头数据用于说明位图的尺寸等信息。
typedef struct tagBITMAPINFOHEADER{
   DWORD  biSize;   // 本结构所占用字节数
   LONGbiWidth;  // 位图的宽度,以像素为单位
   LONGbiHeight; // 位图的高度,以像素为单位
   WORD   biPlanes; // 目标设备的级别,必须为1
   WORD   biBitCount// 每个像素所需的位数,必须是1(双色),
  // 4(16色),8(256色)或24(真彩色)之一
   DWORD  biCompression;   // 位图压缩类型,必须是 0(不压缩),
  // 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
   DWORD  biSizeImage; // 位图的大小,以字节为单位
   LONGbiXPelsPerMeter; // 位图水平分辨率,每米像素数
   LONGbiYPelsPerMeter;  // 位图垂直分辨率,每米像素数
   DWORD  biClrUsed;// 位图实际使用的颜色表中的颜色数
   DWORD  biClrImportant;// 位图显示过程中重要的颜色数
} BITMAPINFOHEADER;
 3. 颜色表

颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。RGBQUAD结构的定义如下:

typedef struct tagRGBQUAD {
BYTErgbBlue;// 蓝色的亮度(值范围为0-255)
BYTErgbGreen;   // 绿色的亮度(值范围为0-255)
BYTErgbRed; // 红色的亮度(值范围为0-255)
BYTErgbReserved;// 保留,必须为0
} RGBQUAD;
颜色表中RGBQUAD结构数据的个数有biBitCount来确定:
当biBitCount=1,4,8时,分别有2,16,256个表项;
当biBitCount=24时,没有颜色表项。
   位图信息头和颜色表组成位图信息,BITMAPINFO结构定义如下:
typedef struct tagBITMAPINFO {
   BITMAPINFOHEADER bmiHeader;   // 位图信息头
   RGBQUAD  bmiColors[1];  // 颜色表
} BITMAPINFO;
4. 位图数据

位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:

当biBitCount=1时,8个像素占1个字节;当biBitCount=4时,2个像素占1个字节;
当biBitCount=8时,1个像素占1个字节;当biBitCount=24时,1个像素占3个字节;
Windows规定一个扫描行所占的字节数必须是 4的倍数(即以long为单位),不足的以0填充,

一个扫描行所占的字节数计算方法: DataSizePerLine= (biWidth* biBitCount+31)/8;

// 一个扫描行所占的字节数 DataSizePerLine= DataSizePerLine/4*4; // 字节数必须是4的倍数

位图数据的大小(不压缩情况下): DataSize= DataSizePerLine* biHeight;

下面是windows存RGB图的一段代码

<span style="font-size:12px;"><span style="font-size:14px;">void CreateBMPImage(const char *filename, unsigned char *pData, int iWidth, int iHeight, int bpp)
{BITMAPFILEHEADER bmpheader;BITMAPINFO bmpinfo;bmpheader.bfType = ('M'<<8)|'B';bmpheader.bfReserved1 = 0;bmpheader.bfReserved2 = 0;bmpheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);bmpheader.bfSize = bmpheader.bfOffBits + iWidth* iHeight*bpp/8;bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);bmpinfo.bmiHeader.biWidth = iWidth;bmpinfo.bmiHeader.biHeight = iHeight;bmpinfo.bmiHeader.biPlanes = 1;bmpinfo.bmiHeader.biBitCount = bpp;bmpinfo.bmiHeader.biCompression = BI_RGB;bmpinfo.bmiHeader.biSizeImage = 0;bmpinfo.bmiHeader.biXPelsPerMeter = 100;bmpinfo.bmiHeader.biYPelsPerMeter = 100;bmpinfo.bmiHeader.biClrUsed = 0;bmpinfo.bmiHeader.biClrImportant = 0;FILE *fp = NULL;   fp = fopen(filename,"wb");if(fp!=NULL){fwrite(&bmpheader,sizeof(BITMAPFILEHEADER),1,fp);fwrite(&bmpinfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);fwrite(pData,iWidth*iHeight*bpp/8,1,fp);fclose(fp);}
}</span></span>

RGB

RGB565
  RGB565使用16位表示一个像素,这16位中的5位用于R,6位用于G,5位用于B。
RGB555
  RGB555是另一种16位的RGB格式,RGB分量都用5位表示(剩下的1位不用)。
RGB24
  RGB24使用24位来表示一个像素,RGB分量都用8位表示,取值范围为0-255。注意在内存中RGB各分量的排列顺序为:BGR BGR BGR…。
RGB32
  RGB32使用32位来表示一个像素,RGB分量各用去8位,剩下的8位用作Alpha通道或者不用。(ARGB32就是带Alpha通道的RGB32。)注意在内存中RGB各分量的排列顺序为:BGRA BGRA BGRA…。

YUV

YUV从何而来呢?在现代彩色电视系统中,通常采用三管彩色摄像机或彩色CCD摄像机进行摄像,然后把摄得的彩色图像信号经分色、分别放大校正后得到 RGB,再经过矩阵变换电路得到亮度信号Y和两个色差信号R-Y(即U)、B-Y(即V),最后发送端将亮度和色差三个信号分别进行编码,用同一信道发送出去。这种色彩的表示方法就是所谓的YUV色彩空间表示。

YUV是被欧洲电视系统所采用的一种颜色编码方法(属于PAL)。YUV主要用于优化彩色视频信号的传输,使其向后兼容老式黑白电视。与RGB视频信号传输相比,它最大的优点在于只需占用极少的带宽(RGB要求三个独立的视频信号同时传输)。其中“Y”表示明亮度(Luminance或Luma),也就是灰阶值;而“U”和“V”表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。“亮度”是通过RGB输入信号来创建的,方法是将RGB信号的特定部分叠加到一起。“色度”则定义了颜色的两个方面—色调与饱和度,分别用U和V来表示。其中,V反映了GB输入信号红色部分与RGB信号亮度值之间的差异。而U反映的是RGB输入信号蓝色部分与RGB信号亮度值之同的差异。
        采用YUV色彩空间的重要性是它的亮度信号Y和色度信号U、V是分离的。如果只有Y信号分量而没有U、V分量,那么这样表示的图像就是黑白灰度图像。彩色电视采用YUV空间正是为了用亮度信号Y解决彩色电视机与黑白电视机的兼容问题,使黑白电视机也能接收彩色电视信号。
YUV与RGB相互转换的公式如下(RGB取值范围均为0-255):
Y = 0.299R + 0.587G + 0.114B  U = -0.147R - 0.289G + 0.436B  V = 0.615R - 0.515G - 0.100B
R = Y + 1.14V  G = Y - 0.39U - 0.58V  B = Y + 2.03U

YUV Formats分成两个格式:

  • 紧缩格式(packed formats):将Y、U、V值储存成Macro Pixels阵列,和RGB的存放方式类似。
  • 平面格式(planar formats):将Y、U、V的三个份量分别存放在不同的矩阵中。

紧缩格式(packed format)中的YUV是混合在一起的,对于YUV4:4:4格式而言,用紧缩格式很合适的,因此就有了UYVY、YUYV等。平面格式(planar formats)是指每Y份量,U份量和V份量都是以独立的平面组织的,也就是说所有的U份量必须在Y份量后面,而V份量在所有的U份量后面,此一格式适用于采样(subsample)。平面格式(planar format)有I420(4:2:0)、YV12、IYUV等。

跨度

width:表示图片的逻辑宽度,在这里就是640,这个值与色深无关及其他都无关,你所见的宽度就是它的值。pitch:表示图片中一行数据所占的字节数,或者说是跨度,在这里应该是640*3,因为图片宽度是640,每个像素是3个字节数据,那么一行数据就是640*3。

调色板,真彩色,DDB,DIB,BMP,RGB,YUV相关推荐

  1. Toolbar控件:32位真彩色大图标

    一.创建普通toolbar 1.         新建一MFC程序,在Dlg头文件中添加一个CToolBar类的成员变量CToolBar m_Toolbar; 2.         然后在头文件中定义 ...

  2. 【作业】RGB/BMP转YUV格式及YUV视频拼接

    简介 RGB文件 RGB文件是原始的没有压缩的包含红绿蓝三种颜色的图像文件. 常见的RGB格式例如RGB24,也就是一组RGB像素中的R.G.B各占8比特,即一个字节,一组RGB一共是24个比特. 这 ...

  3. c语言读取24位bmp图像,[原创]在TC下显示24位真彩色BMP位图

    [原创]在TC下显示24位真彩色BMP位图 在TC下显示24位BMP 虽然在TC显示24位图像上的速度远远比不上256色的速度快,但是真彩色色彩带给我们的视觉上的冲击是256色远远不能达到的.我们今天 ...

  4. BMP真彩色转256色

    原文链接:http://pyhcx.blog.51cto.com/713166/144126/ 1.     位图格式   位图文件主要分为4个部分组成:文件头,信息头,调色板,图像数据. 1.) 文 ...

  5. 如何科学地利用高光谱图像合成真彩色RGB图像?

    如何科学地利用高光谱图像合成真彩色RGB图像? 1. 前言 参考链接: 色匹配函数是什么? - 知乎 (zhihu.com) 23. 颜色知识1-人类的视觉系统与颜色 - 知乎 (zhihu.com) ...

  6. matlab实现基于24位真彩色BMP图像的文件信息隐藏方法(实验内容)

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一.24位真彩色BMP图像 1.简介 2.文件格式 二.算法(四种) 三.matlab实现 1.图像文件尾部添加信息 2.位 ...

  7. 图像位深度 8位 16位 24位 32位区别对比 RGB 真彩色 基本概念:(大小,深度,通道)位深度数据类型转换原理 Mat数据读取(opencv里的imread)

    位深度 位深度是指在记录数字图像的颜色时,计算机实际上是用每个像素需要的二进制数值位数来表示的.计算机之所以能够显示颜色,是采用了一种称作"位"( bit ) 的记数单位来记录所表 ...

  8. 索引图像和真彩色RGB图像介绍

    简单介绍二值图像.灰度图像.索引图像和真彩色RGB图像四种基本类型. (1) 二值图像: 一幅二值图像的二维矩阵仅由0.1两个值构成,"0"代表黑色,"1"代白 ...

  9. 格式转换——bmp 2 yuv

    一.BMP文件的组成结构 BMP(全称Bitmap)是Windows操作系统中的标准图像文件格式,可以分成两类:设备相关位图(DDB)和设备无关位图(DIB),使用广泛.它采用位映射存储格式,除了图像 ...

最新文章

  1. 3.2 读入两个参数
  2. 菲波那契数列(信息学奥赛一本通-T1188)
  3. [luogu3244 SHOI2016] 黑暗前的幻想乡(容斥原理+矩阵树定理)
  4. Vmware workstation 安装解压 vmwaretools 提示只读文件
  5. 步入restful之前先了解一下localStorage
  6. oj 小黑华丽的逆袭机会
  7. 操作系统课后答案第六章
  8. 根据银行卡号判断银行卡是否正确与归属银行
  9. 一款度盘高速下载工具
  10. MATLAB struct函数(结构体数组)
  11. 图数据库查询语言Cypher
  12. 读后感——《软件工程》——软件的本质及软件工程
  13. 员工身高体重决定能否晋升?自如回应
  14. HDU 1348(Wall)
  15. 农村经济与科技杂志农村经济与科技杂志社农村经济与科技编辑部2022年第9期目录
  16. 投资银行理论与实务(一):投资银行学概论
  17. 有趣的Python:Python控制键盘鼠标
  18. Python3零基础学习笔记七
  19. es 指定排序字段_ElasticSearch按照指定字段排序 | 三分钟
  20. AE基础教程第一阶段——09快速预览

热门文章

  1. mysql数据迁移_MySQL 数据迁移
  2. Marco's Java【Shiro入门(二) 之 使用Shiro实现认证及授权+shiro.ini】
  3. 爬虫概念以及网站首页爬取
  4. 运维(17) OHTTPS配置免费证书及宝塔网站管理配置
  5. Windows网络编程,报错error: ‘getpid‘ was not declared in this scope
  6. Android HIDL 介绍学习和实战应用
  7. 什么是用户画像,用户画像的作用是什么?
  8. 有一种感情,叫回家过年
  9. 《Ray Tracing in One Weekend》阅读笔记 - 5、表面法线和多个物体
  10. 安装GitHub上一些库的注意事项