セピア色変換


以下は,ここに書いたモノクロパレットを 使わずに画像をグレースケール変換するコードである. NTSC系加重平均法を使っている.

type
   TRGB = packed record R, G, B: Byte; end;
   PRGB = ^TRGB;

function RoundToByte( Value: Integer ): Byte;
begin
   if Value > 255 then
      Result := 255
   else if Value < 0 then
      Result := 0
   else
      Result := Value;
end;

procedure TMainForm.MonoActionExecute(Sender: TObject);
var
  Bmp: TBitmap;
  P: PRGB;
  I, J, Y: Integer;
begin
   Screen.Cursor := crHourGlass;
   Bmp := TBitmap.Create;
   try
     Bmp.Width := Image.Picture.Bitmap.Width;
     Bmp.Height := Image.Picture.Bitmap.Height;
     Bmp.PixelFormat := pf24bit;
     Bmp.Canvas.Draw( 0, 0, Image.Picture.Bitmap );

     for J := 0 to Bmp.Height - 1 do
     begin
        P := Bmp.ScanLine[ J ];
        for I := 0 to Bmp.Width - 1 do
        begin
           Y := Trunc( 0.2990 * P^.R + 0.5870 * P^.G + 0.1440 * P^.B ); // 階調値を計算
           P^.R := RoundToByte( Y ); // R, G, B に Y を割り当てる.
           P^.G := RoundToByte( Y );
           P^.B := RoundToByte( Y );
           Inc( P );
        end;
     end;
     Image.Picture.Bitmap := Bmp;
   finally
     Bmp.Free;
     Screen.Cursor := crDefault;
   end;
end;

このコードで,新たなRGBを割り当てている部分に, 以下に示すRGB系からYUV系への変換式を使ってみる. YUV系とは,輝度(Y),赤の色差(U)および青の色差(V)で色を表現する方法であり, 実際のTV放送で使われている. UおよびVの値をいろいろ変えてみると,面白い効果が得られる.

R = Y + 1.4026 * V * 255
G = Y - 0.3444 * U * 255 - 0.7114 * V * 255
B = Y + 1.7330 * U * 255

実際のコードは以下のようになる.

procedure TMainForm.SepiaActionExecute(Sender: TObject);
var
  Bmp: TBitmap;
  P: PRGB;
  I, J, Y: Integer;
  U, V: Double;
begin
   Screen.Cursor := crHourGlass;
   Bmp := TBitmap.Create;
   try
     Bmp.Width := Image.Picture.Bitmap.Width;
     Bmp.Height := Image.Picture.Bitmap.Height;
     Bmp.PixelFormat := pf24bit;
     Bmp.Canvas.Draw( 0, 0, Image.Picture.Bitmap );

     U := FUValue;
     V := FVValue;
     for J := 0 to Bmp.Height - 1 do
     begin
        P := Bmp.ScanLine[ J ];
        for I := 0 to Bmp.Width - 1 do
        begin
           Y := Trunc( 0.2990 * P^.R + 0.5870 * P^.G + 0.1440 * P^.B );
           P^.R := RoundToByte( Trunc( Y + 1.4026 * V * 255 ) );
           P^.G := RoundToByte( Trunc( Y - 0.3444 * U * 255 - 0.7114 * V * 255 ) );
           P^.B := RoundToByte( Trunc( Y + 1.7330 * U * 255  ) );
           Inc( P );
        end;
     end;
     Image.Picture.Bitmap := Bmp;
   finally
     Bmp.Free;
     Screen.Cursor := crDefault;
   end;
end;

UおよびVにいろいろな値を設定して上記コードを実行した例を以下に示す. U=0.05およびV=-0.1とすると,セピア色の画像になる.
原画像
U=0.02, V=-0.05
U=0.05, V=-0.1
U=-0.05, V=0.04
U=0.05, V=0.05
U=-0.06, V=-0.06


お問い合わせはメールにて: akasaka@klc.ac.jp

戻る
SEO [PR] 爆速!無料ブログ 無料ホームページ開設 無料ライブ放送