2018/5/27
 
表示画像の各種画像ファイルへの保存追加


Webカメラ「AVICAP32.DLL」の利用

 Webカメラを利用する為のDLLが Win2000の時代から、AVICAP32.DLLが、Window OSに組み込まれています。
これを利用する事で簡単に、Webカメラの画像をパソコンに表示することが出来ます。
古くからあるので、インターネットで探せば、使用例が見つかりますが、どの様なものか確認をしてみました。
 Webカメラ用のソフトは、OSに組み込まれているので、一般的な使用には、特に作る必要はないのですが、画像による測定に利用するには、一番安価な方法なので、取り上げてみました。
Webカメラは安価です。

 Webカメラは、バッファローの"BSWHD06M" で、 1280×960:12fps、1280×720:30fps、640×480:30fps、640×360:30fps、352×288:30fps、320×240:30fps、176×144:30fps、160×120:30fps となっています。
AVICAP32.DLLを使用した場合、1280×960の解像度については、設定方法が悪いのか動作しませんでした。
DirectXを使用した例がインターネット上に有ったので、ダウンロードしてテストした結果、1280×960で動作しましたので、AVICAP32.DLLの制限かと思われます。
OpenCVでも1280×960の解像度で動作します。
WM_CAP_DLG_VIDEOFORMATを利用して、確認した結果、AVICAP32.DLLのデフォルト設定は、640×480が最大の解像度となっていました。

 Delphiで画像の編集をするには、Delphiのビットマップにする必要がありますが、AVICAP32.DLLを利用してカメラの画像を編集用に取り込む方法としては、クリップボードにコピーし、クリップボードから貼り付ける方法と、実行表示画面から、コピーする方法があります。
表示画面からビットマップをコピーする場合は、Form か Panelに表示しておいて、そのビットマップをTbitmapにコピーします。


 DirectXを使用して、画像を表示するプログラムは、http://www.delphibasics.info/home/delphibasicsprojects/directxdelphiwebcamcaptureexample からサンプルプログラムがダウンロードできます。
Delphi2007用なので、XE の場合 Char -> ansiChar に注意すれば、容易に動作します。

サンプルプログラム
  動画保存中は、マウスカーソルが、矢印から待ち時間のアイコンに替わりますが、そのまま、停止のボタンをクリックすれば、動画として保存されます。
又、動画保存中は表示画像が乱れます。
 ドライバーのバージョン取得用 capGetDriverDescription の wDriverIndex の値がインターネットで調べると、WORD となっていますが、実際にはDWORD (Cardinalと同じ) に設定しないと正常に動作しません。
 サンプルプログラムは、Delphi XE7で、UniCoadなので external 'AVICAP32.DLL' name '**********W'を呼び出しています。

プログラム

unit unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, ComCtrls, StrUtils, Clipbrd, Vcl.Buttons,
  Vcl.ExtDlgs, system.UITypes;

type
  TForm1 = class(TForm)
    btnConnectClick: TButton;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Image1: TImage;
    Button5: TButton;
    SavePictureDialog1: TSavePictureDialog;
    Button6: TButton;
    ListBox1: TListBox;
    GroupBox1: TGroupBox;
    RadioButton1: TRadioButton;
    RadioButton2: TRadioButton;
    RadioButton3: TRadioButton;
    Panel1: TPanel;
    Button7: TButton;
    procedure btnConnectClickClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button6Click(Sender: TObject);
    procedure Button7Click(Sender: TObject);
  private
    { Private 宣言 }

  public
    { Public 宣言 }

 const
    WM_CAP_DRIVER_CONNECT           = WM_USER + 10;
    WM_CAP_DRIVER_DISCONNECT        = WM_USER + 11;
    WM_CAP_FILE_SET_CAPTURE_FILEA   = WM_USER + 20;
    WM_CAP_SAVEDIB                  = WM_USER + 25;
    WM_CAP_SEQUENCE                 = WM_USER + 62;
    WM_CAP_GRAB_FRAME               = WM_USER + 60;
    WM_CAP_SEQUENCE_NOFILE          = WM_USER + 63;
    WM_CAP_EDIT_COPY                = WM_USER + 30;
    WM_CAP_SET_OVERLAY              = WM_USER + 51;
    WM_CAP_SET_SCALE                = WM_USER + 53;
    WM_CAP_SET_PREVIEWRATE          = WM_USER + 52;
    WM_CAP_SET_PREVIEW              = WM_USER + 50;
    WM_CAP_STOP                     = WM_USER + 68;

    WM_CAP_SET_CALLBACK_VIDEOSTREAM = WM_USER + 6;
    WM_CAP_SET_CALLBACK_ERROR       = WM_USER + 2;
    WM_CAP_SET_CALLBACK_STATUSA     = WM_USER + 3;
    WM_CAP_SET_CALLBACK_FRAME       = WM_USER + 5;
    WM_CAP_GET_VIDEOFORMAT          = WM_USER + 44;
    WM_CAP_SET_VIDEOFORMAT          = WM_USER + 45;

    WM_CAP_DLG_VIDEOSOURCE          = WM_USER + 42;
    WM_CAP_DLG_VIDEOFORMAT          = WM_USER + 41;
    WM_CAP_DLG_VIDEODISPLAY         = WM_USER + 43;

  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
var
  CaptureWnd   : HWND;
  Filename     : ansistring;
  lpBmpInfo    : Bitmapinfo;
  CaptureWidth : integer;
  CaptureHeight: integer;
  ViewWidth    : integer;
  ViewHeight   : integer;

// バッファサイズが確保できないのか
//  CaptureWidth  :integer  = 1280;     // NG
//  CaptureHeight :integer  = 960;

const
  str_Connect = 'Webカメラに接続';
  str_Disconn = '接続解除';
  CaptureLeft     = 0;
  CaptureTop      = 0;

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


function capCreateCaptureWindow(WindowName: PChar;
    dwStyle: Cardinal; x,y, nWidth,nHeight: Integer;
    ParentWin: HWnd; nID: Integer): HWnd; stdcall;
     external 'AVICAP32.DLL' name 'capCreateCaptureWindowW';


function capGetDriverDescription(wDriverIndex: DWORD;
    lpszName: LPWSTR; cbName : integer;
    lpszVer : LPWSTR; cbVer  : Integer): Boolean; stdcall;
     external 'AVICAP32.DLL' name 'capGetDriverDescriptionW';

procedure TForm1.btnConnectClickClick(Sender: TObject);
begin
  if (Sender as TButton).Caption = str_Connect then begin
    if RadioButton1.Checked then begin
      CaptureWidth    := 1280;     // ok
      CaptureHeight   := 720;
      ViewWidth       := 640;
      ViewHeight      := 360;
    end;
    if RadioButton2.Checked then begin
      CaptureWidth    := 640;     // ok
      CaptureHeight   := 480;
      ViewWidth       := 480;
      ViewHeight      := 360;
    end;
    if RadioButton3.Checked then begin
      CaptureWidth    := 640;     // ok
      CaptureHeight   := 360;
      ViewWidth       := 640;
      ViewHeight      := 360;
    end;
    Panel1.Width    := ViewWidth;
    Panel1.Height   := ViewHeight;
    // デバイスの設定とハンドルの取得 画像の出力先panel1
    CaptureWnd := capCreateCaptureWindow('Window',
        WS_CHILD or WS_VISIBLE, CaptureLeft, CaptureTop,
        CaptureWidth, CaptureHeight, Panel1.Handle, 0);
    if CaptureWnd <> 0 then begin
//      SendMessage(CaptureWnd, WM_CAP_SET_CALLBACK_VIDEOSTREAM, 0, 0);
//      SendMessage(CaptureWnd, WM_CAP_SET_CALLBACK_ERROR, 0, 0);
//      SendMessage(CaptureWnd, WM_CAP_SET_CALLBACK_STATUSA, 0, 0);

      //デバイスへの接続
      SendMessage(CaptureWnd, WM_CAP_DRIVER_CONNECT, 0, 0);

      // カメラ画像の調整
//      SendMessage(CaptureWnd, WM_CAP_DLG_VIDEOSOURCE, 0, 0);

      // カメラの解像度とフォーマットの指定
      // WM_CAP_DLG_VIDEOFORMATは、4:3 で最大サイズ640×480です。
//      SendMessage(CaptureWnd, WM_CAP_DLG_VIDEOFORMAT, 0, 0);

      // Video フォーマットの取得
      SendMessage(CaptureWnd, WM_CAP_GET_VIDEOFORMAT, sizeof(lpBmpInfo), Cardinal(@lpBmpInfo));
      // 解像度の設定
      with lpbmpInfo.bmiHeader do begin
        biWidth := CaptureWidth;
        biHeight := CaptureHeight;
        biSizeImage := biWidth * biHeight * biBitCount div 8;
//        biCompression := BI_RGB;
      end;
      // Video フォーマットの設定
      SendMessage(CaptureWnd, WM_CAP_SET_VIDEOFORMAT, sizeof(lpBmpInfo), Cardinal(@lpBmpInfo));

      //プレビュースケール 変倍有効設定
      SendMessage(CaptureWnd, WM_CAP_SET_SCALE, 1, 0);
      //プレビューのコマ数(ミリ秒)
      SendMessage(CaptureWnd, WM_CAP_SET_PREVIEWRATE, 35, 0);

      // 表示サイズの指定
      SetWindowPos(CaptureWnd, HWND_BOTTOM, 0, 0,
           ViewWidth, ViewHeight,
           SWP_NOMOVE or SWP_NOZORDER);

      // プレビュー開始
      SendMessage(CaptureWnd, WM_CAP_SET_PREVIEW, 1, 0);
    end;
    (Sender as TButton).Caption:= str_Disconn
  end
  else begin
    if CaptureWnd <> 0 then begin
      // デバイスへの接続解除
      SendMessage(CaptureWnd, WM_CAP_DRIVER_DISCONNECT, 0, 0);
      // CaptureようWindowの破棄
      DestroyWindow(CaptureWnd);
      // ハンドルのクリア
      CaptureWnd := 0;
      (Sender as TButton).Caption:= str_Connect;
    end;
  end;
end;

// クリップボードへコピー
procedure TForm1.Button1Click(Sender: TObject);
begin
  if CaptureWnd <> 0 then
    SendMessage(CaptureWnd, WM_CAP_EDIT_COPY, 1, 0 );
end;

// ファイルへ保存
// SendMessageで送るファイル名はAnsiStringの必要があります。
procedure TForm1.Button2Click(Sender: TObject);
begin
  if CaptureWnd <> 0 then begin
    SavePictureDialog1.Filter := '画像ファイル|*.bmp';
    if SavePictureDialog1.Execute then begin
      Filename := ansistring(ChangeFileExt(SavePictureDialog1.FileName,'.bmp'));
    end
    else exit;
    SendMessage(CaptureWnd, WM_CAP_SAVEDIB, 0, Cardinal(pAnsiChar(Filename)));
  end;
end;

// ファイルへの動画保存開始
// SendMessageで送るファイル名はAnsiStringの必要があります。
procedure TForm1.Button3Click(Sender: TObject);
begin
  if CaptureWnd <> 0 then begin
    SavePictureDialog1.Filter := '動画ファイル|*.avi';
    if SavePictureDialog1.Execute then begin
      Filename := ansistring(ChangeFileExt(SavePictureDialog1.FileName,'.avi'));
    end
    else exit;
    SendMessage(CaptureWnd, WM_CAP_FILE_SET_CAPTURE_FILEA, 0, Cardinal(pAnsichar (Filename)));
    SendMessage(CaptureWnd, WM_CAP_SEQUENCE, 0, 0);
  end;
end;

// 動画保存の停止
procedure TForm1.Button4Click(Sender: TObject);
begin
  if CaptureWnd <> 0 then
    SendMessage(CaptureWnd, WM_CAP_STOP, 0, 0);
end;

// クリップボードから画像貼り付け
procedure TForm1.Button5Click(Sender: TObject);
var
  bitmm: TPicture;
begin
  if Clipboard.HasFormat(CF_DIB) then begin
    bitmm := TPicture.Create;
    try
      bitmm.Bitmap.Assign(Clipboard);
      Image1.Canvas.StretchDraw(rect(0, 0, CaptureWidth div 4, CaptureHeight div 4), bitmm.Bitmap);
    finally
      bitmm.Free;
    end;
  end;
end;

// ドライバーバージョンの取得
procedure TForm1.Button6Click(Sender: TObject);
var 
  Indx : Cardinal;
  szName, szVersion: array[0..MAX_PATH] of Char;
begin
  ListBox1.Clear;
  for Indx := 0 to 9 do begin
    if capGetDriverDescription(Indx, @szName, sizeof(szName), @szVersion, sizeof(szVersion)) then begin
      ListBox1.Items.Add(szName + ' (' + szVersion + ')');
    end;
  end;
end;

// Panle1に表示している画像をそのままコピーしてファイルに保存します。
// ファイル形式はWICでサポートしている全ての種類です。
procedure TForm1.Button7Click(Sender: TObject);
label
  FEXIT;
var
  srcDC   : HDC;
  Bmp     : TBitmap;
  cBMP    : HBITMAP;
  WIC     : TWicImage;
  WICF    : TWicImageFormat;

  Fname   : String;
  ExeStr  : String;
  FnameTop: String;
  Findex  : integer;

  function WFormatSet: Boolean;                                            // 拡張子によるファイルフォーマット設定
  begin
    Result := false;
    ExeStr := LowerCase(ExeStr);
    if ExeStr = '.jpg'  then  begin WICF := Wifjpeg; Result := True; end;
    if ExeStr = '.jpeg' then  begin WICF := Wifjpeg; Result := True; end;
    if ExeStr = '.tif'  then  begin WICF := Wiftiff; Result := True; end;
    if ExeStr = '.tiff' then  begin WICF := Wiftiff; Result := True; end;
    if ExeStr = '.png'  then  begin WICF := Wifpng;  Result := True; end;
    if ExeStr = '.gif'  then  begin WICF := Wifgif;  Result := True; end;
    if ExeStr = '.bmp'  then  begin WICF := Wifbmp;  Result := True; end;
    if ExeStr = '.wdp'  then  begin WICF := WifWMPhoto; Result := True; end;
    if ExeStr = '.hdp'  then  begin WICF := WifWMPhoto; Result := True; end;
  end;

begin
  // Bitmapを準備
  Bmp := TBitmap.Create;
  cBMP := 0;
  try
    srcDC := GetDC(Panel1.Handle);
// サイズ設定 フォーマットが分からない場合はコンパチ設定
// サイズを指定したハンドルを生成して、それをBitmapハンドルに代入します
    cBMP := CreateCompatibleBitmap(srcDC, ViewWidth, ViewHeight);
    Bmp.Handle := cBMP;
// フォーマットコンパチの場合はサイズのみ指定で可
//    Bmp.Width := ViewWidth;
//    bmp.Height := ViewHeight;
    try
      // Bitmapに画像をコピーします
      BitBlt(Bmp.Canvas.Handle, 0, 0,  ViewWidth, ViewHeight, srcDC, CaptureLeft, CaptureTop, SRCCOPY);
    finally
      ReleaseDC(Panel1.Handle, srcDC);
    end;
    SavePictureDialog1.Filter := SaveFileFilter;
//  SavePictureDialog1.DefaultExt := GraphicExtension(TWicImage);
    if not SavePictureDialog1.Execute then goto FEXIT;
    ExeStr := ExtractFileExt(SavePictureDialog1.FileName);
    if ExeStr = '' then begin                                                // 拡張子がなかったら
      Findex := SavePictureDialog1.FilterIndex;                              // FilterIndexによる拡張子の設定
      case Findex of
        1, 3 : Fname := ChangeFileExt(SavePictureDialog1.FileName,'.jpg');   // 拡張子の設定
           2 : Fname := ChangeFileExt(SavePictureDialog1.FileName,'.png');   // 拡張子の設定
           4 : Fname := ChangeFileExt(SavePictureDialog1.FileName,'.gif');   // 拡張子の設定
           5 : Fname := ChangeFileExt(SavePictureDialog1.FileName,'.bmp');   // 拡張子の設定
           6 : Fname := ChangeFileExt(SavePictureDialog1.FileName,'.tif');   // 拡張子の設定
           7 : Fname := ChangeFileExt(SavePictureDialog1.FileName,'.wdp');   // 拡張子の設定
      end;
    end
    else
      Fname := SavePictureDialog1.FileName;
    ExeStr := ExtractFileExt(Fname);                                         // 拡張子だけ取り出し
    if not WFormatSet then begin                                             // 拡張子によるファイルフォーマット設定と確認
      application.MessageBox('ファイルの拡張子が間違っています。','注意', 0);
      goto FEXIT;
    end;
    FnameTop := ExtractFileName(Fname);                                      // ファイル名だけ取り出し
    if Length(FnameTop) = Length(ExeStr) then begin                          // ファイル名の長さ確認
      application.MessageBox('ファイル名がありません。','注意', 0);
      goto FEXIT;
    end;

    if FileExists(Fname) then                                                // ファイル名によるファイル検索
      if MessageDlg('既に同じ名前のファイルがあります上書きしますか ' + ExtractFileName(Fname) + '?',
                                                      mtConfirmation, [mbYes, mbNo], 0, mbNo) = IDNo then goto FEXIT;

    WIC := TWicImage.Create;                                                 // TWicImage生成
    try
      WIC.Assign(Bmp);                                                       // TWicImageにビットマップデーター割り付け
      WIC.ImageFormat := WICF;                                               // 保存フォーマットセット
      WIC.SaveTofile(Fname);                                                 // ファイルの書き出し
    finally
      WIC.Free;                                                              // TWicImage解放
    end;
FEXIT:
  finally
    DeleteObject(cBmp);
    Bmp.Free;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  top := (screen.Height - Height) div 2;
  left := (screen.Width - Width) div 2;
  btnConnectClick.Caption := str_Connect;
  CaptureWnd := 0;
  panel1.Caption := '';
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if CaptureWnd <> 0 then begin
    SendMessage(CaptureWnd, WM_CAP_DRIVER_DISCONNECT, 0, 0);
    DestroyWindow(CaptureWnd);
  end;
end;

end.


    download Webcameradelphi.zip

画像処理一覧へ戻る

      最初に戻る