[優化篇]
還以上篇中給出的灰度化代碼為例
procedure Grayscale(const Bitmap:TBitmap);
var
X: Integer;
Y: Integer;
PRGB: pRGBTriple;
Gray: Byte;
begin
for Y := 0 to (Bitmap.Height - 1) do
begin
PRGB := Bitmap.ScanLine[Y];
for X := 0 to (Bitmap.Width - 1) do
begin
Gray := Trunc(0.3 * PRGB^.rgbtRed + 0.59 * PRGB^.rgbtGreen + 0.11 * PRGB^.rgbtBlue);
PRGB^.rgbtRed:=Gray;
PRGB^.rgbtGreen:=Gray;
PRGB^.rgbtBlue:=Gray;
Inc(PRGB);
end;
end;
end;
實際應用中,這種方法已經很快了,但實際上還存在可以優化的余地。
Gray := Trunc(0.3 * Red + 0.59 * Green + 0.11 * Blue);//這句用的是浮點運算
在圖像處理中,速度就是生命,能不用浮點運算,就最好不要用!
Gray := (30 * Red + 59 * Green + 11 * Blue) div 100;
雖然這樣一改,運算次數多了一次,但在我的雷鳥1.1G上,處理速度大概能提高5%左右!而同主頻下(或略低,如Athlon 1600+相當於P4 1.6G)AMD的CPU浮點運算能力比Intel的較強,整數運算能力較弱,所以用Intel的CPU在這裡更能體現出優勢!
注:x div 100 和 Trunc(x/100)的效果是相同的,但查看其匯編代碼可知一個用的指令是div,而另一個是fdiv(即進行浮點運算),還要調用函數Trunc,其處理速度差距非常大,所以能用 x div 100 的時候就不要用 Trunc(x/100)。
但這還不是最快的,再看一個:
Gray := HiByte(77 * Red + 151 * Green + 28 * Blue);
即
Gray := (77 * Red + 151 * Green + 28 * Blue) shr 8;
(建議用後一種,不要調用函數)
這種方法比最原始的方法快了近3/4!
什麼意思呢?用77,151,28分別除以256試試~~~
移位是什麼意思呢,和10進制的進位,退位聯系一下,是不是可以近似的理解為乘除2的n次方呢?當然這和真正意義的乘除法是不一樣的!比如shr(右移),和真正的除法相比,比如shr 1,只有最後一個字位為0時(既為2的倍數),它才等於除2!如二進制數110(6)右移1位變為11(3),和6/2=3結果相同。
當然這和一開始的灰度化效果有了些誤差!
如果允許存在更大的誤差,還可以考慮另一種方法:
Gray := (Red shr 2) + (Red shr 4) + (Green shr 1) + (Green shr 4) + (Blue shr 3);
連乘法都沒用,完全用移位實現,結合上面的解釋,用除法來理解該表達式,其值只是約等於(0.3125 * Red + 0.5625 * Green + 0.125 * Blue),和一開始的加權平均值有了比較大的誤差!但如果對速度有苛刻的要求的話,可以怎麼用!這比上一種方法還能再快5%!