因自己的程序中需對一個窗體區域頻繁進行彩色轉灰度處理
為此專門寫了個函數
處理對象是一塊經常變化的動態區域
且是一系列繪圖中的一部分
速度要求較高
算法上力求簡單
所以采用以下兩步方案
基於DDB來寫
雖然轉入DIB
可不必面對各種色深
會統一算法
但轉換過程會讓速度上慢很多
再者這只是針對屏幕位圖的函數
並無保存需要
考慮實際情況
我只寫了
位三種色深下的算法
其實
兩種位圖是最快的了
不管多大的圖只需處理
與
次運算
可是現在哪有人的屏幕
還使用這兩種顯示模式呢?想想就沒這個必要了
相比之下
位時最快
位時最慢
心裡有點不滿意
但好在速度都不慢
差距也不超過
%
灰度算法本來就不復雜
但我還是做了簡化
正常處理時一般需對RGB做加權平均
取個值來統一三基色
但這需涉及浮點運算
速度上不去
效果卻不見得有多好
我的方法很簡單
就是取三基色之一的值
統一起來
考慮人眼對綠色最敏感
所以算法就成RGB轉GGG了
嚴格的說
這不叫彩轉灰
叫綠轉灰更合適
RGB的排列G是在中間的
想利用高速Long運算
用B值最快的
但已經夠簡化了
再簡下去
自己都過意不去
(用B值時
位下
速度還可快
/
)
這種算法當然有缺陷
主要是對一些偏色圖效果不好
但好在這種情況在色彩豐富的界面中不存在
C
G
M WinXP SP
下的測試情況
IDE環境下
X
的位圖
位屏幕
毫秒
位屏幕
毫秒
N代碼編譯
全部優化打開
X
的位圖
位屏幕
毫秒
位屏幕
毫秒
注
沒有
位環境
所以也就沒測了
Option Explicit
Private Type BITMAP
bmType As Long
bmWidth As Long
bmHeight As Long
bmWidthBytes As Long
bmPlanes As Integer
bmBitsPixel As Integer
bmBits As Long
End Type
Private Type MemHdc
hdc As Long
Bmp As Long
obm As Long
End Type
Private Declare Function GetObj Lib
gdi
Alias
GetObjectA
(ByVal hObject As Long
ByVal nCount As Long
lpObject As Any) As Long
Private Declare Function SelectObject Lib
gdi
(ByVal hdc As Long
ByVal hObject As Long) As Long
Private Declare Function DeleteObject Lib
gdi
(ByVal hObject As Long) As Long
Private Declare Function DeleteDC Lib
gdi
(ByVal hdc As Long) As Long
Private Declare Function BitBlt Lib
gdi
(ByVal hDestDC As Long
ByVal x As Long
ByVal y As Long
ByVal nWidth As Long
ByVal nHeight As Long
ByVal hSrcDC As Long
ByVal xSrc As Long
ByVal ySrc As Long
ByVal dwRop As Long) As Long
Private Declare Function CreateCompatibleDC Lib
gdi
(ByVal hdc As Long) As Long
Private Declare Function CreateCompatibleBitmap Lib
gdi
(ByVal hdc As Long
ByVal nWidth As Long
ByVal nHeight As Long) As Long
Private Declare Function GetBitmapBits Lib
gdi
(ByVal hBitmap As Long
ByVal dwCount As Long
lpBits As Any) As Long
Private Declare Function SetBitmapBits Lib
gdi
(ByVal hBitmap As Long
ByVal dwCount As Long
lpBits As Any) As Long
Private Declare Function GetTickCount Lib
kernel
() As Long
Private Declare Sub CopyMemory Lib
kernel
Alias
RtlMoveMemory
(pDest As Any
pSource As Any
ByVal dwLength As Long)
平時常做圖形處理
自己的兩個公用函數也就用上了
Private Function NewMyHdc(dHdc As Long
w As Long
h As Long
Optional Bm As Long) As MemHdc
With NewMyHdc
hdc = CreateCompatibleDC(dHdc)
If Bm =
Then
Bmp = CreateCompatibleBitmap(dHdc
w
h)
Else
Bmp = Bm
End If
obm = SelectObject(
hdc
Bmp)
End With
End Function
Private Function DelMyHdc(MyHdc As MemHdc
Optional nobmp As Boolean) As MemHdc
With MyHdc
If
hdc <>
And
obm <>
Then SelectObject
hdc
obm
If nobmp = False And
Bmp <>
Then DeleteObject
Bmp
If
hdc <>
Then DeleteDC
hdc
End With
End Function
灰度處理主函數
Private Function GrayBmp(dHdc As Long
x As Long
y As Long
w As Long
h As Long) As Long
Dim tmpdc As MemHdc
Dim i As Long
j As Long
m As Long
k As Byte
l As Long
Dim Bm As BITMAP
AllBytes As Long
LineBytes As Long
Dim dBits() As Byte
Dim dBits
() As Integer
Dim dBits
() As Long
On Error GoTo last
With tmpdc
tmpdc = NewMyHdc(dHdc
w
h)
GetObj
Bmp
Len(Bm)
Bm
If Bm
bmBitsPixel <
Then GoTo last
BitBlt
hdc
w
h
dHdc
x
y
vbSrcCopy
LineBytes = Bm
bmWidthBytes
AllBytes = LineBytes * h
Select Case Bm
bmBitsPixel
Case
ReDim dBits
(AllBytes \
)
GetBitmapBits
Bmp
AllBytes
dBits
(
)
For i =
To AllBytes \
dBits
(i) = ((dBits
(i) And &HFF
&) \ &H
) * &H
dBits
(i) = (dBits
(i) And &HFF) * &H
用B值運算
Next
SetBitmapBits
Bmp
AllBytes
dBits
(
)
GrayBmp =
Case
ReDim dBits(AllBytes
)
GetBitmapBits
Bmp
AllBytes
dBits(
)
For j =
To h
m = j * LineBytes
For i = m To m + w *
Step
dBits(i) = dBits(i +
)
dBits(i +
) = dBits(i)
Next
Next
SetBitmapBits
Bmp
AllBytes
dBits(
)
GrayBmp =
Case
按
格式運算
ReDim dBits
(AllBytes \
)
GetBitmapBits
Bmp
AllBytes
dBits
(
)
For j =
To h
m = j * LineBytes \
For i = m To m + w
l = dBits
(i) And &H
C
&
l = l *
+ l + l \
CopyMemory dBits
(i)
l
這句沒辦法
不用CopyMemory
會溢出
低效源於此
Next
Next
SetBitmapBits
Bmp
AllBytes
dBits
(
)
GrayBmp =
End Select
BitBlt dHdc
x
y
w
h
hdc
vbSrcCopy
End With
last:
DelMyHdc tmpdc
End Function
Private Sub Form_Load()
ScaleMode =
AutoRedraw = True
Picture = LoadPicture(
f:\
jpg
)
Command
Caption =
測試
End Sub
測試用代碼
Private Sub Form_Resize()
PaintPicture Picture
ScaleWidth
ScaleHeight
End Sub
Private Sub Command
_Click()
Dim t As Long
s As String
s
As String
i As Long
t = GetTickCount
GrayBmp hdc
ScaleWidth
ScaleHeight
Refresh
MsgBox GetTickCount
t & s
End Sub
From:http://tw.wingwit.com/Article/program/net/201311/13229.html