動きの検出

 動画の中の動いた部分の検出を行います。
プログラムは、Delphi-OpenCV-master に添付されているものです。
ファイルは、文字化けしているのと、他のサンプルと同じで、オリジナルのままでは、動作しません。
最初の画像取得時、少し待たないとプログラムの起動に失敗するのは、他のプログラムと同じですが、待ち方が若干違います。
Delphiのバージョンの差なのか、PCの差なのかは判りません。

 前の画像と差のあった部分を取り出して、その範囲を赤枠で表示します。


プログラム

 プログラムは、Delphi-OpenCV-masterに添付されているサンプルなので、それを修正して下さい。

program MotionDetect;

{$APPTYPE CONSOLE}
{$POINTERMATH ON}
{$R *.res}

uses
  System.SysUtils,
  System.Math,
  ocv.highgui_c,
  ocv.core_c,
  ocv.core.types_c,
  ocv.imgproc_c,
  ocv.imgproc.types_c;

 {$DEFINE RECT} //- using cvBoundingRect - work correctly
                  // - not defined RECT - using cvMinAreaRect2

var
  storage       : pCvMemStorage = nil;
  capture       : pCvCapture    = nil;
  frame         : pIplImage     = nil;
  frame_grey    : pIplImage     = nil;
  difference_img: pIplImage     = nil;
  oldframe_grey : pIplImage     = nil;
  contours      : pCvSeq        = nil;
  c             : pCvSeq        = nil;
{$IFDEF RECT}
  rect: TCvRect;
{$ELSE}
  rect2d: TCvBox2D;
{$ENDIF}
  key  : integer;
  first: boolean = true;

// 小さい部分の消去
function remove_small_objects(img_in: pIplImage; size: integer): pIplImage;
var
  img_out     : pIplImage;
  s_storage   : pCvMemStorage;
  s_contours  : pCvSeq;
  black, white: TCvScalar;
  area        : double;
begin
  img_out    := cvCloneImage(img_in);
  s_storage  := cvCreateMemStorage(0);
  s_contours := nil;
  black      := CV_RGB(0, 0, 0);
  white      := CV_RGB(255, 255, 255);
  s_contours := AllocMem(SizeOf(TCvSeq));
  cvClearMemStorage(s_storage);
  cvFindContours(img_in, s_storage, @s_contours, SizeOf(TCvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0));
  while (s_contours <> nil) do
  begin
    area := cvContourArea(s_contours, CV_WHOLE_SEQ);
    if abs(area) <= size then
      cvDrawContours(img_out, s_contours, black, black, -1, CV_FILLED, 8, cvPoint(0, 0))
    else
      cvDrawContours(img_out, s_contours, white, white, -1, CV_FILLED, 8, cvPoint(0, 0));
    s_contours := s_contours.h_next;
  end;
  cvReleaseMemStorage(s_storage);
  s_contours := nil;
  FreeMem(s_contours, SizeOf(TCvSeq));
  result := img_out;
end;

begin
  try
    capture    := cvCreateCameraCapture(0);
    if not Assigned(capture) then
      Halt(1);

    // 画像のサイズ設定 カメラによって値を修正します           追加
    cvSetCaptureProperty(Capture, CV_CAP_PROP_FRAME_WIDTH, 320);
    cvSetCaptureProperty(Capture, CV_CAP_PROP_FRAME_HEIGHT, 240);

    storage    := cvCreateMemStorage(0);

    // Create a new named window with title: result  追加
    cvNamedWindow('Output Image', CV_WINDOW_AUTOSIZE);
    // frame が 取得されるまで待ちます  追加
    while frame = nil do begin
      frame    := cvQueryFrame(capture);
      key := cvwaitkey(100);      // cvNamedWindowを実行しておかないとcvwaitkeyが動作しません
      if key = 27 then begin
        cvReleaseCapture(capture);
        cvReleaseMemStorage(storage);
        cvDestroyAllWindows();
        Halt(1);
      end;
    end;
    // greyimage領域作成
    frame_grey := cvCreateImage(cvSize(frame^.width, frame^.height), IPL_DEPTH_8U, 1);
    writeln('>MotionDetect start');
    writeln('>画像表示画面選択 ESC キーで終了');
    while true do
    begin
      frame := cvQueryFrame(capture);                         // 一フレーム取り出し
      if frame = nil then
        break;
      cvCvtColor(frame, frame_grey, CV_RGB2GRAY);             // グレー画像変換
      if first then
      begin
        difference_img := cvCloneImage(frame_grey);           // クローン領域の作成
        oldframe_grey  := cvCloneImage(frame_grey);
        cvConvertScale(frame_grey, oldframe_grey, 1.0, 0.0);  // 等倍コピー
        first := false;
      end;
      cvAbsDiff(oldframe_grey, frame_grey, difference_img);   // 差分計算
      cvSmooth(difference_img, difference_img, CV_BLUR);      // 平滑化
      // Thresholdの値 25 を変更すると感度が変わります
      cvThreshold(difference_img, difference_img, 25, 255, CV_THRESH_BINARY);
      // 小さい画像(100以下)の削除
      difference_img := remove_small_objects(difference_img, 100);

      contours := AllocMem(SizeOf(TCvSeq));
      cvClearMemStorage(storage);
      // 輪郭の抽出
      cvFindContours(difference_img, storage, @contours, SizeOf(TCvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE,
        cvPoint(0, 0));
      c := contours;
      while (c <> nil) do
      begin
{$IFDEF RECT}
        rect := cvBoundingRect(c, 0);
        cvRectangle(frame, cvPoint(rect.x, rect.y), cvPoint(rect.x + rect.width, rect.y + rect.height),
          cvScalar(0, 0, 255, 0), 2, 8, 0);
{$ELSE}
        rect2d := cvMinAreaRect2(c);
        cvRectangle(frame, cvPoint(Round(rect2d.center.x - rect2d.size.width / 2),
          Round(rect2d.center.y - rect2d.size.height / 2)), cvPoint(Round(rect2d.center.x + rect2d.size.width / 2),
          Round(rect2d.center.y + rect2d.size.height / 2)), cvScalar(0, 0, 255, 0), 2, 8, 0);
{$ENDIF}
        c := c.h_next;
      end;
      cvShowImage('Output Image', frame);
      cvShowImage('Difference Image', difference_img);
      cvConvertScale(frame_grey, oldframe_grey, 1.0, 0.0);
      cvClearMemStorage(storage);
      contours := nil;
      c        := nil;
      FreeMem(contours, SizeOf(TCvSeq));
      key := cvWaitKey(33);
      if (key = 27) then
        break;
    end;
    // メモリーの解放
    cvReleaseMemStorage(storage);
    cvReleaseCapture(capture);
    cvReleaseImage(oldframe_grey);
    cvReleaseImage(difference_img);
    cvReleaseImage(frame_grey);
    cvDestroyAllWindows();
  except
    on E: Exception do
      WriteLn(E.ClassName, ': ', E.Message);
  end;
end.

画像処理一覧へ戻る

      最初に戻る