2012-01-19 4 views
1

現在、Canvas.Pixels[]プロパティをループし、キャンバス上の各ピクセルを読み取って赤/青のバイトをスワップします(特定の理由により)。しかし、1枚の画像に平均2秒かかり、変換に必要な画像は8,000枚を超える(一晩)。私はScanLineの方法を使ってこれをはるかに高速にすることができると理解していますが、ScanLineについては何も知りません。私が快適であるよりもはるかに低いレベルのコーディングです。これを達成する最速の方法は何ですか?私はこれを実行するためにいくつかの時間を待つつもりですが、私は半分以上でその時間を切り刻むことができればまだいいです。ScanLineを使用して赤/青のバイトを交換する高速方法

今のところ、これは私が使用する手順です:

procedure SwapBytes(var Bmp: TBitmap); 
var 
    X, Y: Integer; 
    R, G, B: Byte; 
    C: TColor; 
begin 
    for Y := 0 to Bmp.Height - 1 do begin 
    for X := 0 to Bmp.Width - 1 do begin 
     C:= Bmp.Canvas.Pixels[X,Y]; 
     R:= GetRValue(C); 
     G:= GetGValue(C); 
     B:= GetBValue(C); 
     Bmp.Canvas.Pixels[X,Y]:= RGB(B, G, R) 
    end; 
    end; 
end; 

を追加しました注:8,000以上の画像の最初の変換は、私はこれを必要とする理由の最初のステップです。しかし私は、私たちのソフトウェアで同じことを使用して、必要に応じてその場でイメージを自動的に変換します。したがって、私はこれをクライアントに配布することができないため、サードパーティのコンバータは動作しません。

+3

ありますScanLineの使用とRGBトリプルへのアクセスを示す[docwiki]のサンプル(http://docwiki.embarcadero.com/CodeExamples/en/ScanLine_(Delphi))。 –

+0

ああ、イメージを変換するためのユーティリティを書いていたことが分かりました。 「変換する必要がある写真は8000点以上あります(一晩)」。気にしないで。 –

+0

@KenWhiteありがとう、それを見て... –

答えて

9

私は次のようなものを試します。このバージョンのみ24ビットのビットマップのためにある:

procedure SwapRedBluePixels(ABitmap: TBitmap); 
var 
    X: Integer; 
    Y: Integer; 
    Red: Byte; 
    Pixel: PRGBTriple; 
begin 
    // check for the bit depth, it must be 24-bit if you use PRGBTriple pointer 
    // for line scan; if it wouldn't the iterated line pointers would point to 
    // another place in the memory 
    if ABitmap.PixelFormat <> pf24bit then 
    begin 
    ShowMessage('Your bitmap has color depth different from 24-bit'); 
    Exit; 
    end; 
    // iterate through the image vertically 
    for Y := 0 to (ABitmap.Height - 1) do 
    begin 
    // access the line of pixels and get the pointer to the first pixel of 
    // that line 
    Pixel := ABitmap.ScanLine[Y]; 
    // iterate through the scanned line pixels horizontally 
    for X := 0 to (ABitmap.Width - 1) do 
    begin 
     // store the pixel's red channel value 
     Red := Pixel.rgbtRed; 
     // modify the pixel's red channel value 
     Pixel.rgbtRed := Pixel.rgbtBlue; 
     // modify the pixel's blue channel value 
     Pixel.rgbtBlue := Red; 
     // increment to get the next pixel pointer of the scanned line 
     Inc(Pixel); 
    end; 
    end; 
end; 

アップデート2:

このバージョンは、24ビットおよび32ビットのビットマップのためにある:

procedure SwapRedBluePixels(ABitmap: TBitmap); 
var 
    X: Integer; 
    Y: Integer; 
    Red: Byte; 
    Size: Integer; 
    Pixels: PByteArray; 
begin 
    // check the color depth and set the size of the pixel arrangement 
    case ABitmap.PixelFormat of 
    pf24bit: Size := SizeOf(TRGBTriple); 
    pf32bit: Size := SizeOf(TRGBQuad); 
    else 
    // if the image is not 24-bit or 32-bit go away 
    begin 
     ShowMessage('Your bitmap has unsupported color depth!'); 
     Exit; 
    end; 
    end; 

    // iterate through the image vertically 
    for Y := 0 to (ABitmap.Height - 1) do 
    begin 
    // access the line of pixels and get the pointer to the first pixel of 
    // that line 
    Pixels := ABitmap.ScanLine[Y]; 
    // iterate through the scanned line pixels horizontally 
    // for 24-bit images the pixels are stored like 
    // B -> G -> R -> B -> G -> R etc. 
    // for 32-bit images the pixels are stored like 
    // B -> G -> R -> A -> B -> G -> R -> A etc. 
    // so we can simply use e.g. byte array and iterate through 
    // it, if we have 24-bit image, we have to read each element, 
    // if 32-bit we have to skip the alpha (reserved) channel 
    for X := 0 to (ABitmap.Width - 1) do 
    begin 
     // store the pixel's red channel value 
     Red := Pixels^[(X * Size) + 2]; 
     // modify the pixel's red channel value 
     Pixels^[(X * Size) + 2] := Pixels^[(X * Size)]; 
     // modify the pixel's blue channel value 
     Pixels^[(X * Size)] := Red; 
    end; 
    end; 
end; 
+0

いいですね、ありがとう。しかし、私はちょうど何かを考えました。「ScanLine」が1つのチャンネル(赤色は1、青色は1)だけを読み取ることができ、その行をちょうど入れ替えることができるのでしょうか? –

+1

@Jerry赤と青の線は別々にはありません。それはピクセルのラインです。これは、ビットマップの仕組みです。 –

+0

ニースは時間の約1/3に切り詰めました –