画像のミラー処理

 画像のミラー処理は、簡単なのですが、一応サンプルプログラムを作成してみました。

水平ミラー  左図は、水平方向のミラー処理です。
垂直方向のミラー処理も可能です。
処理は単純にピクセル単位で、左右、又は、上下を入れ替えるだけです。

 ファイルをTBitmapに読み込んで、ミラー用TBitmapに左右、又は、上下を入れ替えるて書き込みます。
ピクセル単位で処理をすると、処理速度が遅いので、ScanLineを使用します。
更に、TBitmapを24ビットフォーマットし、TRGBtriple レコードのポインターを使用して、3バイト単位で処理ができるようにします。



範囲指定 マウスで範囲を指定すれば、指定した範囲だけの、左右、又は、上下のミラー処理が可能です。
実際には、まず全体を、そのままコピーして、その後、指定された範囲のミラー処理をします。


サンプルプログラムには組み込んでありませんが、縦と横のミラーを同時に行えば、180度回転した画像となります。

 サンプルプログラム

本サンプルプログラムには、画像の保存はありません、保存処理のある画像処理プログラムもあるので、必要であれば、それを参照して追加してください。
保存処理は、アンシャープマスキング画像の回転のプログラムに組み込んであります。

unit MirroringMain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls, Vcl.ExtDlgs, system.Types;

type
  TForm1 = class(TForm)
    FileOpen: TButton;
    Image1: TImage;
    Image2: TImage;
    OpenPictureDialog1: TOpenPictureDialog;
    HMirroring: TButton;
    VMirroring: TButton;
    RadioGroup1: TRadioGroup;
    procedure FormCreate(Sender: TObject);
    procedure FileOpenClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure HMirroringClick(Sender: TObject);
    procedure VMirroringClick(Sender: TObject);
    procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure Image1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  private
    { Private 宣言 }
    procedure Allimagecopy;
    procedure HImgeCopy;
    procedure VImgeCopy;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

type
  TPrgbarry = array[0..0] of Trgbtriple;      // 24ビットカラーレコード 32ビット用はTRGBQuadArray
  Prgbarry  = ^TPrgbarry;                     // ポインターの宣言
                                              // 配列のポインターであればよいので、配列の大きさは1 [0..0]にします。

implementation

{$R *.dfm}
const
  OpenFileFilter =
    '画像ファイル|*.png;*.jpg;*.gif;*.bmp;*.tif;*.ico;*.wdp'+
    '|*.png|*.png' +
    '|*.jpg|*.jpg' +
    '|*.gif|*.gif' +
    '|*.bmp|*.bmp' +
    '|*.tif|*.tif' +
    '|*.ico|*.ico' +
    '|*.wdp|*.wdp';

  SaveFileFilter =
    '画像ファイル|*.png;*.jpg;*.gif;*.bmp;*.tif;*.wdp' +
    '|*.png|*.png' +
    '|*.jpg|*.jpg' +
    '|*.gif|*.gif' +
    '|*.bmp|*.bmp' +
    '|*.tif|*.tif' +
    '|*.wdp|*.wdp';

  ImageHW   = 384;                            // 表示枠サイズ

var
  GHeight, GWidth : integer;
  Vrect           : Trect;
  InBitmap        : TBitmap;
  OutBitmap       : TBitmap;
  Origin          : TPoint;
  EndPoint        : TPoint;
  Drawing         : Boolean;
  NewMove         : Boolean;
  OX, EX, OY, EY  : Integer;
  IHeight         : Integer;
  IWidth          : Integer;
  SWidth          : integer;                    // サンプル画像幅
  SHeight         : integer;                    // サンプル画像高さ


procedure TForm1.FileOpenClick(Sender: TObject);
var
  WIC         : TWICImage;
  InFilename  : String;
begin
  HMirroring.Enabled := False;
  VMirroring.Enabled := False;
  RadioGroup1.Enabled := False;
  VRect := Rect(0, 0, Image1.Width, Image1.Height);
  Image1.Canvas.Brush.Style := bsSolid;
  Image1.Canvas.Brush.Color := clBtnface;
  Image1.Canvas.FillRect(VRect);                              // Canvas 画像消去
  Image2.Canvas.Brush.Style := bsSolid;
  Image2.Canvas.Brush.Color := clBtnface;
  Image2.Canvas.FillRect(VRect);                              // Canvas 画像消去
  OpenPictureDialog1.Filter := OpenFileFilter;                // ファイルオープンフィルターの設定
  if OpenPictureDialog1.Execute then                          // ファイルが指定されたら
    begin
      WIC := TWICImage.Create;                                // TWICImageの生成
      try
        InFilename := OpenPictureDialog1.FileName;            // ファイル名の取得
        WIC.LoadFromFile(InFilename);                         // 画像の読み込み
        GHeight := WIC.Height;                                // 画像高さ取得
        GWidth  := WIC.Width;                                 // 画像幅
        IWidth  := ImageHW;                                   // 出力先イメージ1の幅
        IHeight := ImageHW;                                   // 出力先イメージ1の高さ
        if GHeight <= GWidth then                             // 縦横比により出力サイズ設定
          IHeight := Round(IWidth * GHeight / GWidth)
        else
          IWidth := Round(IHeight * GWidth / GHeight);
        Image1.Width := IWidth;
        Image1.Height:= IHeight;
        Image1.Picture.Bitmap.SetSize(IWidth, IHeight);
        Image2.Width := IWidth;
        Image2.Height:= IHeight;
        Image2.Picture.Bitmap.SetSize(IWidth, IHeight);
        VRect := Rect(0, 0, IWidth, IHeight);                 // 出力枠設定
        Image1.Canvas.StretchDraw(VRect, WIC);                // 出力枠に変倍出力
        InBitmap.Width  := GWidth;
        InBitmap.Height := GHeight;
        InBitmap.Canvas.Draw(0, 0, WIC);                      // DrawでInBitmapに入力画像設定フォーマット24ビットに変換
        OutBitmap.Width  := GWidth;
        OutBitmap.Height := GHeight;
      finally
        WIC.Free;                                             // TWICImage 解放
      end;
    end
    else exit;
  HMirroring.Enabled := True;
  VMirroring.Enabled := True;
  RadioGroup1.Enabled := True;
end;

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Drawing := True;
  with Image1.Canvas do begin                                            // マウスダウンフラグセット
    Brush.Color := clWhite;
    Brush.Style := bsClear;
    Pen.Color := ClBlack;
    Pen.Width := 2;
  end;
  Origin := Point(X, Y);                                                  // 座標の保存
  NewMove := True;
end;

procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  if Drawing and (Shift = [ssLeft]) then begin
    With Image1.Canvas do begin
      Pen.Mode := pmNotXor;                                   // ペンモード Not Xor
      if not NewMove then begin                         // 最初の移動には消去がありません
        MoveTo(Origin.X, Origin.Y);                           // 前の線消去
        LineTo(EndPoint.X, Origin.Y);
        LineTo(EndPoint.X, EndPoint.Y);
        LineTo(Origin.X, EndPoint.Y);
        LineTo(Origin.X, Origin.Y);                           // 前の線消去
      end;
      EndPoint := point(X, Y);                                // 新しい座標を保存
      MoveTo(Origin.X, Origin.Y);                             // 新しい線の描画
      LineTo(EndPoint.X, Origin.Y);
      LineTo(EndPoint.X, EndPoint.Y);
      LineTo(Origin.X, EndPoint.Y);
      LineTo(Origin.X, Origin.Y);                             // 新しい線の描画 
      NewMove := False;
      Pen.Mode := pmCopy;
    end;                                     		       // ペンモード通常に
  end;
end;

procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  TMPI        : integer;
  Scal        : Double;
begin
  if not Drawing or NewMove then exit;
  Image1.Canvas.Pen.Mode := pmNotXor;                                   // ペンモード Not Xor
  Image1.Canvas.MoveTo(Origin.X, Origin.Y);                             // 前の線消去
  Image1.Canvas.LineTo(EndPoint.X, Origin.Y);
  Image1.Canvas.LineTo(EndPoint.X, EndPoint.Y);
  Image1.Canvas.LineTo(Origin.X, EndPoint.Y);
  Image1.Canvas.LineTo(Origin.X, Origin.Y);                             // 前の線消去
  Image1.Canvas.Pen.Mode := pmCopy;                                     // ペンモード通常に
  NewMove := False;
  Drawing := False;
  // 範囲指定正規方向へ変換
  if Origin.X > EndPoint.X then begin
    TMPI := Origin.X;
    Origin.X := EndPoint.X;
    EndPoint.X := TMPI;
  end;
  if Origin.Y > EndPoint.Y then begin
    TMPI := Origin.Y;
    Origin.Y := EndPoint.Y;
    EndPoint.Y := TMPI;
  end;
  IWidth  := Image1.Width;
  IHeight := Image1.Height;
  // マウスポイントを元画像座標に変換
  Scal := GWidth / IWidth;                                    // 元画像と表示画像の倍率
  OX := Round(Origin.X * Scal);
  EX := Round(EndPoint.X * Scal);
  OY := Round(Origin.Y * Scal);
  EY := Round(EndPoint.Y * Scal);
  if OX < 0 then OX := 0;
  if EX > GWidth - 1 Then EX := GWidth - 1;
  if OY < 0 then OY := 0;
  if EY > GHeight - 1 then EY := GHeight - 1;
  // 範囲サイズ設定
  SWidth  := EX - OX;
  SHeight := EY - OY;
  Allimagecopy;                                        // 全Copy
  case RadioGroup1.ItemIndex of
    0: HImgeCopy;
    1: VImgeCopy;
  end;
end;

procedure TForm1.Allimagecopy;                                // 全Copy
var
  I, J        : integer;
  OutPrgbarray  : Prgbarry;
  InpPrgbarray  : Prgbarry;
begin
  for I := 0 to GHeight - 1 do begin
    InpPrgbarray := InBitmap.ScanLine[I];
    OutPrgbarray := OutBitmap.ScanLine[I];
    for J := 0 to GWidth - 1 do begin
      OutPrgbarray[J] := InpPrgbarray[J];                     // 単純コピー
    end;
  end;
  Image2.Canvas.StretchDraw(VRect, OutBitmap);                // 出力枠に変倍出力
end;

procedure TForm1.HImgeCopy;                 // 指定範囲横方向ミラーコピー
var
  I, J        : integer;
  OutPrgbarray  : Prgbarry;
  InpPrgbarray  : Prgbarry;
begin
  for I := OY to EY do begin
    InpPrgbarray := InBitmap.ScanLine[I];
    OutPrgbarray := OutBitmap.ScanLine[I];
    for J := OX  to EX do begin
      OutPrgbarray[OX + EX - J] := InpPrgbarray[J];           // 横方向の配列を逆にしてコピー
    end;
  end;
  Image2.Canvas.StretchDraw(VRect, OutBitmap);                // 出力枠に変倍出力
end;

procedure TForm1.VImgeCopy;                                  // 指定範囲縦方向ミラーコピー
var
  I, J        : integer;
  OutPrgbarray  : Prgbarry;
  InpPrgbarray  : Prgbarry;
begin
  for I := OY to EY do begin
    InpPrgbarray := InBitmap.ScanLine[I];
    OutPrgbarray := OutBitmap.ScanLine[OY + EY - I];          // 縦方向の配列を逆にしてコピー
    for J := OX  to EX do begin
      OutPrgbarray[J] := InpPrgbarray[J];
    end;
  end;
  Image2.Canvas.StretchDraw(VRect, OutBitmap);                // 出力枠に変倍出力
end;

procedure TForm1.HMirroringClick(Sender: TObject);            // 横方向ミラー
var
  I, J        : integer;
  M1Width     : integer;
  OutPrgbarray  : Prgbarry;
  InpPrgbarray  : Prgbarry;
begin
  M1Width := GWidth - 1;
  for I := 0 to GHeight - 1 do begin
    InpPrgbarray := InBitmap.ScanLine[I];
    OutPrgbarray := OutBitmap.ScanLine[I];
    for J := 0 to M1Width - 1 do begin
      OutPrgbarray[J] := InpPrgbarray[M1Width - J];           // 横方向の配列を逆にしてコピー
    end;
  end;
  Image2.Canvas.StretchDraw(VRect, OutBitmap);                // 出力枠に変倍出力
end;

procedure TForm1.VMirroringClick(Sender: TObject);            // 縦方向ミラー
var
  I, J        : integer;
  M1Height    : integer;
  OutPrgbarray  : Prgbarry;
  InpPrgbarray  : Prgbarry;
begin
  M1Height := GHeight - 1;
  for I := 0 to M1Height do begin
    InpPrgbarray := InBitmap.ScanLine[M1Height - I];          // 縦方向の配列を逆にしてコピー
    OutPrgbarray := OutBitmap.ScanLine[I];
    for J := 0 to GWidth - 1 do begin
      OutPrgbarray[J] := InpPrgbarray[J];
    end;
  end;
  Image2.Canvas.StretchDraw(VRect, OutBitmap);                // 出力枠に変倍出力
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.Width  := ImageHW;
  Image1.Height := ImageHW;
  Image2.Width  := ImageHW;
  Image2.Height := ImageHW;
  InBitmap  := TBitmap.Create;
  OutBitmap := TBitmap.Create;
  InBitmap.PixelFormat  := pf24bit;                           // 24ビットカラーに設定
  OutBitmap.PixelFormat := pf24bit;                           // 24ビットカラーに設定
  RadioGroup1.Caption := '範囲選択';
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  InBitmap.Free;
  OutBitmap.Free;
end;
end.

    download Mirroring.zip

画像処理一覧へ戻る

      最初に戻る