国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

由圖像的灰度化看基本圖像處理(1)

2019-11-18 18:37:15
字體:
來源:轉載
供稿:網(wǎng)友
 

[基礎篇]

首先看一段實現(xiàn)24位色圖像灰度化轉換的代碼

PRocedure Grayscale(const Bitmap:TBitmap);
var
  X: Integer;
  Y: Integer;
  R,G,B,Gray: Byte;
  Color: TColor;
begin
  for Y := 0 to (Bitmap.Height - 1) do
  begin
    for X := 0 to (Bitmap.Width - 1) do
    begin
      Color := Bitmap.Canvas.Pixels[X,Y];
      R := Color and $FF;
      G := (Color and $FF00) shr 8;
      B := (Color and $FF0000) shr 16;
      Gray := Trunc(0.3 * R + 0.59 * G + 0.11 * B);
      Bitmap.Canvas.Pixels[X,Y] := Gray shl 16 or Gray shl 8 or Gray;
    end
  end
end;

{這段代碼效率是非常低的,但可以方便我們理解同時一些問題}

Delphi的幫助中對TColor已經(jīng)有了詳細的描述,這可以方便我們理解上面的代碼!

  首先看:

  R := Color and $FF;
  G := (Color and $FF00) shr 8;
  B := (Color and $FF0000) shr 16;

  這是段常見的從TColor中提取三原色的代碼,但它是什么意思呢?
首先應該知道and是與(.)運算,0.1=0,0.0=0,1.1=1,以取綠色為例:$FF00實際上就是$00FF00,它與一個TColor類型數(shù)按位進行與運算后,表示紅色和綠色的位都變?yōu)榱?00,而表示綠色的部分不變(0,1和1進行與運算值都不變),再右移8位,自然就獲得了綠色值的8位表示!

  再獲得三原色的值后,就是計算灰度值,0.3 * Red + 0.59 * Green + 0.11 * Blue 這是求加權平均值的公式。(因為人眼對顏色的敏感度不同,所以權值不同,就像在pf16bit中用了6位表示綠色,其它兩種顏色只用了5位,這問題以后另寫文章說明)

  然后就是像素顏色信息的寫回,剛才是右移,現(xiàn)在自然就是左移,而或(+)運算就是(0+1=1,0+0=0,1+1=1),舉個簡單例子就是:($FF shl 16 = $FF0000) or ($FF shl 8 = $FF00) or $FF = $FFFFFF ,其實這里的或運算當然也可以用 + 代替。

  雖然上面的代碼實現(xiàn)了24位色圖像的灰度化,但當圖像比較大時,速度非常慢,為什么?查看相關VCL代碼可知調用Bitmap.Canvas.Pixels獲取,寫入像素的顏色信息實際上是利用了API GetPixel、SetPixel,這種方法是非常低效的!(唯一的好處是在進行一些和顏色無關的操作,如圖像的旋轉,翻轉時不需要因為PixelFormat的不同而修改代碼)所以應該換一種更高效的訪問像素點數(shù)據(jù)的方法,如用API GetDIBits、SetDIBits,但這種方法比較復雜,好在Delphi3以后版本的TBitmap中提供了Scanline。利用Scanline可以快速對像素進行訪問!

還是以24位色(PixelFormats=pf24bit)為例,可改寫為:

procedure Grayscale(const Bitmap:TBitmap);
const
  PixelCountMax = 32768;
type
  pRGBTripleArray = ^TRGBTripleArray;
  TRGBTripleArray = ARRAY[0..PixelCountMax-1] OF TRGBTriple;
var
  Row: pRGBTripleArray;
  X: Integer;
  Y: Integer;
  Gray: Byte;
begin
  for Y := 0 to (Bitmap.Height - 1) do
  begin
    Row := Bitmap.ScanLine[Y];
    for X := 0 to (Bitmap.Width - 1) do
    begin
      Gray := Trunc(0.3 * Row^[X].rgbtRed + 0.59 * Row^[X].rgbtGreen + 0.11 * Row^[X].rgbtBlue);
      Row^[X].rgbtRed:=Gray;
      Row^[X].rgbtGreen:=Gray;
      Row^[X].rgbtBlue:=Gray;
    end;
  end;
end;

上面的例子用了一個TRGBTriple數(shù)組

  PRGBTriple = ^TRGBTriple;
  tagRGBTRIPLE = packed record
    rgbtBlue: Byte;
    rgbtGreen: Byte;
    rgbtRed: Byte;
  end;
  TRGBTriple = tagRGBTRIPLE;

這種方法會限制位圖的大小,但一般不用理會,直接用TBitmap可處理不了那么大的位圖

當然也可用指針的移動實現(xiàn),實測結果這樣更快~~~

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;

下篇中將進行進一步的探討!


上一篇:“無限”位四則運算

下一篇:由圖像的灰度化看基本圖像處理(2)

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
學習交流
熱門圖片

新聞熱點

疑難解答

圖片精選

網(wǎng)友關注

主站蜘蛛池模板: 永城市| 呼玛县| 香港 | 保德县| 改则县| 西乌珠穆沁旗| 衡东县| 来安县| 饶阳县| 房产| 清水河县| 屏山县| 临漳县| 四子王旗| 岗巴县| 二手房| 大关县| 嘉峪关市| 曲松县| 扶风县| 长垣县| 如东县| 安陆市| 彩票| 柳江县| 临武县| 杭锦旗| 岢岚县| 汝州市| 连州市| 阿坝| 盐城市| 彰化县| 沂水县| 古浪县| 汝州市| 微山县| 南雄市| 北安市| 怀柔区| 遵义市|