如何將真彩色圖轉換為各種灰度圖
轉自:http://www.cppblog.com/windcsn/archive/2006/07/27/Grayscale.html
首先來看一下彩色圖和灰度圖的特點。
在計算機中使用最多的 RGB 彩色空間,分別對應紅、綠、藍三種顏色;通過調配三個分量的比例來組成各種顏色。一般可以使用 1 、 2 、 4 、 8 、 16 、 24、 32 位來儲存這三顏色,不過現在一個分量最大是用 8 位來表示,最大值是 255 ,對於 32 位的顏色,高 8 位是用來表示通明度的。彩色圖一般指 16 位以上的圖。灰度圖有一個特殊之處就是組成顏色的三個分量相等;而一般灰度圖是 8 位以下。
在彩色電視機系統中,通常使用一種叫 YUV 的色彩空間,其中 Y 表示亮度訊號;也就是這個 YUV 空間解決了彩色電視機和黑白電視機的相容問題。
對於人眼來說,亮度訊號是最敏感的,如果將彩色影象轉換為灰度影象,僅僅需要轉換儲存亮度訊號就可以。
從 RGB 到 YUV 空間的 Y 轉換公式為:
Y = 0.299R+0.587G+0.114B
在 WINDOWS 中,表示 16 位以上的圖和以下的圖有點不同; 16 位以下的圖使用一個調色盤來表示選擇具體的顏色,調色盤的每個單元是 4 個位元組,其中一個透明度;而具體的畫素值儲存的是索引,分別是 1 、 2 、 4 、 8 位。 16 位以上的圖直接使用畫素表示顏色。
那麼如何將彩色圖轉換為灰度圖呢?
灰度圖中有調色盤,首先需要確定調色盤的具體顏色取值。我們前面提到了,灰度圖的三個分量相等。
當轉換為 8 位的時候,調色盤中有 256 個顏色,每個正好從 0 到 255 個,三個分量都相等。
當轉換為 4 位的時候,調色盤中 16 個顏色,等間隔平分 255 個顏色值,三個分量都相等。
當轉換為 2 位的時候,調色盤中 4 個顏色,等間隔平分 255 個顏色,三個分量相等。
當轉換為 1 位的時候,調色盤中兩個顏色,是 0 和 255 ,表示黑和白。
將彩色轉換為灰度時候,按照公式計算出對應的值,該值實際上是亮度的級別;亮度從 0 到 255 ;由於不同的位有不同的亮度級別,所以 Y 的具體取值如下:
Y = Y/ (1<<(8- 轉換的位數 ));
最後一點需要注意,得到 Y 值存放方式是不同的;分別用對應的位數來儲存對應的 Y 值。
這裡是程式碼片段:
計算調色盤和 Y 的值程式碼。
2
3 int width,
4
5 int height,
6
7 DWORD & dwGraySize,
8
9 int nToBit)
10
11 {
12
13 DWORD nRowLen = TS_4BYTESALIGN(width * nToBit);
14
15 DWORD nColorTableSize = (( 1 << nToBit) * sizeof (RGBQUAD));
16
17 DWORD nColorNum = 1 << nToBit;
18
19 dwGraySize = nRowLen * height + nColorTableSize;
20
21 LPBYTE lpNewImgBuf = NULL;
22
23 BYTE r,g,b;
24
25 float y;
26
27
28
29 lpNewImgBuf = new BYTE[dwGraySize];
30
31 LPBYTE lpPixels = (LPBYTE)(lpNewImgBuf + nColorTableSize);
32
33 LPRGBQUAD lpvColorTable = (LPRGBQUAD)lpNewImgBuf;
34
35 memset(lpNewImgBuf, 0 ,dwGraySize);
36
37
38
39 for ( int i = 0 ;i < nColorNum;i ++ )
40
41 {
42
43 if (nToBit == 8 )
44
45 {
46
47 ( * (lpvColorTable)).rgbBlue = (BYTE)i;
48
49 ( * (lpvColorTable)).rgbGreen = (BYTE)i;
50
51 ( * (lpvColorTable)).rgbRed = (BYTE)i;
52
53 }
54
55 else if (nToBit == 4 )
56
57 {
58
59 ( * (lpvColorTable)).rgbBlue = (BYTE)(i << ( 8 - nToBit)) + i;
60
61 ( * (lpvColorTable)).rgbGreen = (BYTE)(i << ( 8 - nToBit)) + i;
62
63 ( * (lpvColorTable)).rgbRed = (BYTE)(i << ( 8 - nToBit)) + i;
64
65 }
66
67 else if (nToBit == 2 )
68
69 {
70
71 ( * (lpvColorTable)).rgbBlue = (BYTE)( 255 / 3 ) * i;
72
73 ( * (lpvColorTable)).rgbGreen = (BYTE)( 255 / 3 ) * i;
74
75 ( * (lpvColorTable)).rgbRed = (BYTE)( 255 / 3 ) * i;
76
77 }
78
79 else if (nToBit == 1 )
80
81 {
82
83 ( * (lpvColorTable)).rgbBlue = (BYTE) 255 * i;
84
85 ( * (lpvColorTable)).rgbGreen = (BYTE) 255 * i;
86
87 ( * (lpvColorTable)).rgbRed = (BYTE) 255 * i;
88
89 }
90
91
92
93 ( * (lpvColorTable)).rgbReserved = 0 ;
94
95 lpvColorTable ++ ;
96
97 }
98
99
100
101 LPBYTE lpOldImage = lpByte;
102
103 LPBYTE lpTempPixel = lpPixels;
104
105 int loops = 0 ;
106
107 int nStop = 0 ;
108
109 for ( long h = 0 ;h < height;h ++ )
110
111 {
112
113 for ( long w = 0 ;w < width;w ++ )
114
115 {
116
117 b = (unsigned char )( * lpOldImage ++ );
118
119 g = (unsigned char )( * lpOldImage ++ );
120
121 r = (unsigned char )( * lpOldImage ++ );
122
123
124
125 y = ( float )(r * 0.299 + g * 0.587 + b * 0.114 ) ;
126
127 BYTE bVal = (BYTE)y >> ( 8 - nToBit);
128
129 SetPixelValueByBits(lpTempPixel,nToBit,loops,(BYTE)bVal);
130
131 // ErrorDiffuse(lpPixels,nToBit,loops,((int)y) - (bVal<<(8-nToBit)),
132
133 // w,h,nRowLen,dwGraySize-nColorTableSize);
134
135 }
136
137 }
138
139
140
141 return lpNewImgBuf;
142
143 }
144
145
下面是設定畫素值的程式碼:
2
3 {
4
5 switch (nBits)
6
7 {
8
9 case 8 :
10
11 * (lpByte ++ ) = value;
12
13 break ;
14
15 case 4 :
16
17 {
18
19 if (loops)
20
21 {
22
23 loops = 0 ;
24
25 BYTE bVal = ( * lpByte) & 0xF0 ;
26
27 value &= 0x0F ;
28
29 bVal = (bVal >> 4 ) + value;
30
31 if (bVal > 0x0F ) bVal = 0x0F ;
32
33 ( * lpByte) <<= 4 ;
34
35 ( * lpByte) += bVal;
36
37 lpByte ++ ;
38
39 }
40
41 else
42
43 {
44
45 value &= 0x0F ;
46
47 ( * lpByte) += value;
48
49 if (( * lpByte) > 0x0F ) ( * lpByte) = 0x0F ;
50
51 loops = 1 ;
52
53 }
54
55 }
56
57 break ;
58
59 case 2 :
60
61 {
62
63 value &= 0x03 ;
64
65 ( * lpByte) += value;
66
67 if (loops != 3 )
68
69 {
70
71 ( * lpByte) <<= 2 ;
72
73 loops ++ ;
74
75 }
76
77 else
78
79 {
80
81 loops = 0 ;
82
83 lpByte ++ ;
84
85 }
86
87 }
88
89 break ;
90
91 case 1 :
92
93 {
94
95 value &= 0x01 ;
96
97 ( * lpByte) += value;
98
99 if (loops != 7 )
100
101 {
102
103 ( * lpByte) <<= 1 ;
104
105 loops ++ ;
106
107 }
108
109 else
110
111 {
112
113 loops = 0 ;
114
115 lpByte ++ ;
116
117 }
118
119 }
120
121 break ;
122
123 }
124
125 }
126
有一點需要說明的:
在計算 Y 值的時候,使用的整數除法,這是有誤差的,為了消除誤差,需要採用誤差擴散的演算法,也就是將該誤差值向其鄰近的想素點擴散,當然按照一定的比例來分配;例如:整除之後,餘數是 5 ,採用 3/2/3 的策略,就是,右邊畫素和正下面的畫素各佔 3/8 ,而右下角的畫素佔 2/8 。在這方面我發現 ACDSEE 做的很好,其影象的漸進做的很好。
原始碼下載:ImageConvert.zip
相關文章
- 24位真彩色轉換為8位灰度圖片(完整程式碼)
- 將24位BMP真彩圖轉換成BMP灰度圖
- 將彩色圖轉化為灰度圖及其原理介紹
- python將矩陣轉化為灰度圖Python矩陣
- 如何將PPT幻燈片轉換為圖片
- 如何將圖片轉換成影片?
- 如何將圖片轉word?圖文轉換選轉易俠
- 如何將圖片轉換為向量?(透過DashScope API呼叫)API
- Java將地圖轉換為陣列[Snippet]Java地圖陣列
- 如何將heic格式轉換成jpg圖片?
- 利用命令列將pdf轉換為長圖命令列
- Java將彩色PDF轉為灰度Java
- 使用 NocoDB 一鍵將各種資料庫轉換為智慧表格資料庫
- CSS把彩色圖片變為灰度圖片CSS
- PowerPoint怎麼將文字轉換為SmartArt圖形
- Python 將Word轉換為JPG、PNG、SVG圖片PythonSVG
- 如何將InputStream轉換為DataSource
- 將img圖片轉換為base64位編碼
- [Python] 各種轉換Python
- Activity轉換為View和把圖片轉換為ViewView
- aspose word轉換pdf檔案後將pdf檔案轉換為圖片png
- echart 各種圖實現
- 怎麼將heic轉為jpg格式,哪個圖片轉換器好用
- 將圖象列表轉換成裝置無關點陣圖 (轉)
- 圖片格式怎麼轉換,如何轉換jpg
- PowerPoint 2007無法將Excel圖表轉換為圖形物件Excel物件
- 如何使用 Javascript 將圖示字型渲染為圖片JavaScript
- Photoshop將png轉為ico圖示
- javascript將img圖片轉換為base64位編碼形式JavaScript
- 輕鬆將點陣圖轉換為向量圖,享受高品質影像——Vector Magic for Mac/winMac
- PDF轉換CAD圖紙,如何快速轉換呢?
- 如何將CentOS 8轉換為CentOS StreamCentOS
- javascript如何將字串轉換為數字JavaScript字串
- 如何將文字轉換為向量?(方法二)
- 如何將文字轉換為向量?(方法三)
- C#/VB.NET 將彩色PDF轉為灰度C#
- 圖片格式轉換,JPG圖片轉換成PDF
- JPG轉CAD,JPG圖片如何轉換成CAD圖紙?