動画フレーム切り出し

 投稿者:しばっち  投稿日:2019年 9月26日(木)20時08分50秒
  open cvライブラリーを使用して、十進BASIC上で画像ファイルだけでなく、
動画ファイルも読めるようになりました。(笑)

下記プログラムでは動画ファイルを読み込み、およそ1秒間隔(調整可 0.3秒~2秒)で
画像表示します(動画本来のフレームレートでは負荷が高いのでわざと落としています)

※音は出ません。

なお、実行時にはopencv_world300.dll 及び opencv_ffmpeg300.dll が必要です(BASIC.EXEと同じフォルダに入れてください)

下記URLからダウンロードしてください。(imagetool.zip)

https://36.gigafile.nu/1125-n8d2d72a2da1c926a4d213cd6f41f8bd3

ダウンロード期限:2019年11月25日(月)
ダウンロードキー:設定していません

※警告
open cvは日本語パスに対応していません。


OPTION BASE 0
FILE GETNAME VIDEONAME$,"動画ファイル|*.mp4;*.avi;*.wmv;*.mkv;*.flv;*.mpg;*.mov"
IF VIDEONAME$="" THEN STOP
CALL VIDEOINFO(VIDEONAME$,WIDTH,HEIGHT,MAXFRAME,FPS)
PRINT WIDTH;HEIGHT;MAXFRAME;FPS
DIM M(WIDTH,HEIGHT) !'バッファー
CALL GINIT(WIDTH,HEIGHT)
LET T=INT(TIME)
DO
LOOP WHILE INT(TIME)=T
LET I=0 !'動画フレームナンバー
LOCATE VALUE NOWAIT(1),RANGE .3 TO 2,AT 1:SECOND
DO
   LOCATE VALUE NOWAIT(1):SECOND  !'表示間隔
   LET SECOND=ROUND(SECOND,2)
   LET T=TIME
   PRINT I;"/";MAXFRAME-1
   CALL GETVIDEOFRAME(VIDEONAME$,WIDTH,HEIGHT,M,I)
   MAT PLOT CELLS,IN 0,0;WIDTH-1,HEIGHT-1:M !'画像表示
   DO
   LOOP WHILE TIME-T<=SECOND !'ウェイト
   LET I=I+INT(FPS*SECOND+.1)
   IF INT(FPS*SECOND+.1)=0 THEN LET I=I+1
LOOP WHILE I<MAXFRAME-1
PRINT MAXFRAME-1;"/";MAXFRAME-1
CALL GETVIDEOFRAME(VIDEONAME$,WIDTH,HEIGHT,M,MAXFRAME-1)
MAT PLOT CELLS,IN 0,0;WIDTH-1,HEIGHT-1:M !'画像表示
END

EXTERNAL SUB VIDEOINFO(VIDEONAME$,WIDTH,HEIGHT,MAXFRAME,FPS)
OPTION CHARACTER BYTE
LET WIDTH$=REPEAT$(CHR$(0),8)
LET HEIGHT$=REPEAT$(CHR$(0),8)
LET MAXFRAME$=REPEAT$(CHR$(0),8)
LET FPS$=REPEAT$(CHR$(0),8)
LET NUM=VIDEOINFO_(VIDEONAME$,WIDTH$,HEIGHT$,MAXFRAME$,FPS$)
IF NUM=-1 THEN
   PRINT "動画ファイルをロードできません"
   STOP
END IF
LET WIDTH=UNPACKDBL(WIDTH$)
LET HEIGHT=UNPACKDBL(HEIGHT$)
LET MAXFRAME=UNPACKDBL(MAXFRAME$)
LET FPS=UNPACKDBL(FPS$)
!'
FUNCTION VIDEOINFO_(VIDEONAME$,WIDTH$,HEIGHT$,MAXFRAME$,FPS$)
   ASSIGN ".\DLL\getvideoframe.dll","videoinfo"
END FUNCTION
END SUB

EXTERNAL SUB GETVIDEOFRAME(VIDEONAME$,XSIZE,YSIZE,M(,),N)
OPTION CHARACTER BYTE
LET MAP$=REPEAT$(CHR$(0),XSIZE*YSIZE*3)
LET NUM=GETVIDEOFRAME_(VIDEONAME$,MAP$,INT(N+.5))
IF NUM=-1 THEN
   PRINT "動画ファイルをロードできません"
   STOP
END IF
FOR Y=0 TO YSIZE-1
   FOR X=0 TO XSIZE-1
      LET ADR=(Y*XSIZE+X)*3+1
      LET R=ORD(MAP$(ADR+2:ADR+2))
      LET G=ORD(MAP$(ADR+1:ADR+1))
      LET B=ORD(MAP$(ADR:ADR))
      LET M(X,Y)=COLORINDEX(R/255,G/255,B/255)
   NEXT X
NEXT Y
!'
FUNCTION GETVIDEOFRAME_(VIDEONAME$,MAP$,NUM)
   ASSIGN ".\DLL\getvideoframe.dll","getvideoframe"
END FUNCTION
END SUB

EXTERNAL SUB GINIT(XSIZE,YSIZE)
SET BITMAP SIZE XSIZE,YSIZE
SET COLOR MIX(0) 0,0,0
SET COLOR MODE "NATIVE"
CLEAR
SET POINT STYLE 1
SET WINDOW 0,XSIZE-1,YSIZE-1,0
END SUB

---------------------------------------------------------------------------------
                           getvideoframe.cpp


#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace std;
using namespace cv;

extern "C"  __declspec(dllexport) int videoinfo(char *filename,double *width,double *height,double *max_frame,double *fps)
{
    Mat img;
    VideoCapture cap(filename);
    if (!cap.isOpened()) return -1;
    *width=cap.get(CV_CAP_PROP_FRAME_WIDTH); //縦の大きさ
    *height=cap.get(CV_CAP_PROP_FRAME_HEIGHT); //横の大きさ
    *max_frame=cap.get(CV_CAP_PROP_FRAME_COUNT); //フレーム数
    *fps=cap.get(CV_CAP_PROP_FPS); //フレームレート
    return 0;
}

extern "C"  __declspec(dllexport) int getvideoframe(char *filename,char *framedata,int num)
{
    Mat img;
    VideoCapture cap(filename);
    if (!cap.isOpened()) return -1;
    cap.set(CV_CAP_PROP_POS_FRAMES,num);

    int width=cap.get(CV_CAP_PROP_FRAME_WIDTH); //縦の大きさ
    int height=cap.get(CV_CAP_PROP_FRAME_HEIGHT); //横の大きさ
    cap>>img ; //1フレーム分取り出してimgに保持させる

    for(int y=0; y<height; y++)
        for(int x=0; x<width; x++)
            for(int c=0; c<3; c++)
                framedata[(y*width+x)*3+c]=img.at<cv::Vec3b>(y,x)[c]; // c=0 blue, c=1 green, c=2 red
    return 0;
}
 

戻る