Open CVによる動画保存について

このQ&Aのポイント
  • Open CVを使用してwebカメラから映像を動画として保存しようとしています。フォームアプリケーションで作成した場合にエラーが発生しています。
  • 動画の保存方法はtimerを使用して30msec間隔でカメラから画像を取得し、動画として保存する方法です。
  • cvWriteFrame(rec,srcImage); の箇所でエラーが発生しており、『保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリが壊れていることが考えられます。』というエラーメッセージが表示されます。
回答を見る
  • ベストアンサー

Open CVによる動画保存について

現在,Open CVを使用して,webカメラからから取得した映像を動画として保存しようとしています。 公式サイトや参考書のコードを丸写ししテストしています。 コンソールアプリケーションで作成した場合は,問題なく動画を保存できましたが,フォームアプリケーションで作成した場合,エラーで停止してしまいます。 動作としては,timerを使用して,30msec間隔でカメラから画像を取得し,動画として保存というものです。 CvCapture *capture;//画像 CvVideoWriter* rec; IplImage *srcImage; private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) { timer1->Interval=30; timer1->Enabled=true; capture = cvCaptureFromCAM(0); srcImage = cvQueryFrame(capture); rec = cvCreateVideoWriter("movie.avi",CV_FOURCC('M','J','P','G'),30,cvSize(100,100)); } private: System::Void timer1_Tick() {    captureImage(); } private:System::Void captureImage(void){ cvFlip(srcImage,srcImage,0); srcImage=cvQueryFrame(capture); cvWriteFrame(rec,srcImage); } 上記の, cvWriteFrame(rec,srcImage); の箇所で停止してしまいます。 ビルドは成功しているのですが,実行時の1目でエラーになります。 エラー内容『保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリが壊れていることが考えられます。』 どなたか原因がわかるかたがいらっしゃいましたら,ご教授いただけますでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.2

もうちょっと詳しく読んでみましたが http://opencv.jp/opencv-2svn/c/highgui_reading_and_writing_images_and_video.html#queryframe > 返された画像は,ユーザによって解放されたり変更されたりするべきではありません. > また,エラーが起きて,NULLが返される場合もあります. → cvFlip(srcImage,srcImage,0); でsrcImageを変更している。 (そもそも、この場所でcvFlipする意味がわからない) → エラーのチェックがない と、問題となりそうなことをやってます。 画面表示とファイル出力とで処理のタイミングは当然変わるので、その結果不具合が顕著になっただけかもしれません。 あと、cvWriteFrameが完了する前にタイマー割り込みが発生した場合にも問題が発生しそうです

con014057
質問者

お礼

ご回答ありがとうございます。 いろいろと試してみましたが,cvVideosWriterのFOURCCの設定がまずかったようです。非圧縮だとうまく保存できました(サイズはすごく大きいですが...) アドバイスありがとうございました。

その他の回答 (1)

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.1

あくまで予想ですが > timer1->Enabled=true; この時点でタイマーが動きだして、以下のキャプチャの準備が出来ないうちに タイマー割り込み発生 → timer1_Tick() → captureImage() と呼ばれている、ってことは無いですか?

con014057
質問者

お礼

ご回答ありがとうございます。 アドバイスを元にプログラムを変更しましたが,うまくいきませんでした... cvWriteFrame(rec,srcImage);ではなく,ウィンドウに画像を表示するプログラムなら問題なく動作するのですが...

関連するQ&A

  • Open CVについて

    現在Open CVを用いて,VC++2008 ExpressのWindows Formアプリケーションを作成しています。 main_formのpictuteBoxにUSBカメラから画像を取得して表示し,sub_formはアプリケーションの設定用フォームで,USBカメラの解像度などの情報を取得して表示しようとしています。 main_form.hの先頭部分に以下のように記述しています。 #include <cv.h> #include <highgui.h> #include "sub_form.h" CvCapture *capture1 = 0; sub_formの先頭部分に以下のように記述しています。 #include "main_form.h" #include <cv.h> CvCapture *capture2 = 0; 上記のように記述後,ビルド使用とすると, 『...\sub_form.h(457) error C2065: 'CvCapture' : 定義されていない識別子です。』 と,sub_formのみでエラーが出てしまいます。 cv.hをインクルードしているのに,なぜこのようなエラーがでてしまうのでしょうか? お分かりになる方がいらっしゃいましたら,ご教授宜しくお願い致します。

  • Open CVについて

    現在,OpenCVとVC++2008のC++/CLIでwindows formアプリケーションを作成しています。 フォーム上のpictureBoxにUSBカメラから取得した画像を,録画しながら,pictureBoxに表示させています。しかし,取り込んだ画像が,pictureBoxに収まり切っていないようです。(添付画像のようなに枠内の画像に対して,肌色部分しか,pictureBoxに表示されていない状態) コードは http://hisoap.jugem.jp/?eid=156 を参考に,以下のように記述しています。 CvCapture *capture srcImage = cvQueryFrame(capture); Bitmap^ bmpPicBox = gcnew Bitmap(pictureBox->Width, pictureBox->Height); pictureBox->Image = bmpPicBox; Graphics^g = Graphics::FromImage(pictureBox->Image); Bitmap^ bmp = gcnew Bitmap(pictureBox->Width, pictureBox->Height, srcImage->widthStep,System::Drawing::Imaging::PixelFormat::Format24bppRgb, IntPtr(srcImage->imageData)); g->DrawImage(bmp, 0, 0, srcImage->width , srcImage->height); どのようにすれば,画像をpictureBoxにぴったりと表示させることができるでしょうか?

  • OpenCVでキャプチャした画像をbmp保存したい

    OpenCVでカメラからキャプチャした画像(コマ画像)をbmpで保存しようと思っています。 以下のプログラムで一応bmp画像は保存できるのですが、キー入力をしないと保存できません。 #include <iostream> #include <stdio.h> #include <cv.h> #include <highgui.h> #include <math.h> #include <stdlib.h> int main(void){ //画像保存用 char str[32]; //キー入力用 int key; //カメラの用意 CvCapture *capture; IplImage *frame = NULL; //カメラ画像用 //カメラ・デバイスの先頭ポインタを取得 capture = cvCaptureFromCAM(-1); //カメラ画像のサイズ double height = 240; double width = 320; //カメラ初期化 if(capture == NULL){ //カメラが見つからなかった場合 printf("カメラが見つかりません\n"); return (0); } //カメラ画像を表示するウィンドウの生成 cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height); cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width); cvNamedWindow("CaptureFromCamera", CV_WINDOW_AUTOSIZE); //キー入力されたら画像をキャプチャ while(1){ //カメラ画像からフレーム画像を取り込む frame = cvQueryFrame(capture); if(frame == NULL) break; //画像の表示 cvShowImage("CaptureFromCamera", frame); //sキー入力で画像を保存、Escキー入力でループから抜ける key = cvWaitKey(10); if(key == '\x1b') break; else if(key == 's'){ sprintf(str, "Capture_Bitmap.bmp"); cvSaveImage(str, frame); } } //キャプチャの解放 cvReleaseCapture(&capture); //ウィンドウの破棄 cvDestroyWindow("CaptureFromCamera"); } 自分が作りたいプログラムは、 ・カメラからコマ画像を取得 ↓ ・それをbmp形式にする ↓ ・変換した画像はファイルにではなく、プログラム中の変数に保存 ↓ ・プログラムが動いている間ずっとこの処理を行う というものです。 特に変換した画像をプログラムが動いている間、ずっと変数に保存し続ける方法がわかりません。 プログラム中の変数に保存したい理由は、保存したコマ画像を用いてテンプレートマッチングなどを行いたいからです。 どなたか教えていただけると助かります。

  • open cvで配列の値をテキストに出力するプログラム

    こんにちわ。  今、open cvで映像を読み込みその映像の何フレーム目でキー入力がされたかを出力するプログラムを作成しています。  そこで、キー入力されたキーとその時のフレーム、時間の結果を配列に格納して、その内容をテキストに出力したいのですがうまくいきません。ファイル出力された結果は上書きされて最後に行ったキー入力の結果しか出力されません。全ての結果をテキストに出力できるようにしたいのでお願いします。  いろいろ不具合があると思うので教えてください。 ---------------------------------------------- #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include "cxcore.h" #include "cv.h" #include "image.h" //読み込む動画ファイル名 char* input_filename="video2_result.avi"; //IplImage IplImage* src; IplImage* gray; IplImage* canny; int main(void) { char wname[] = "input"; CvCapture* capture; IplImage *frame; int key; int a[1000]; int count = 0; FILE *fp; time_t timer; struct tm *date; char str[256]; capture = cvCaptureFromFile("video2_result.avi"); cvNamedWindow(wname,1); for(;;){ frame = cvQueryFrame(capture); if(frame == NULL) break; cvShowImage(wname,frame); key = cvWaitKey(30); /*キー入力*/ if(key == 'q') break; if(key == 'a'){ printf("%d\n",count); /*現在時間の取得*/ timer = time(NULL);/* 経過時間を取得 */ date = localtime(&timer);/* 経過時間を時間を表す構造体 date に変換 */ strftime(str, 255, "%Y, %B, %d, %A %p%I:%M:%S", date); printf("%s\n", str); } count++; } cvReleaseCapture( &capture ); cvDestroyAllWindows(); //入力結果をファイルに出力 fp = fopen("frame.txt","w"); { fprintf(fp,"%d,\n",a[count]); fprintf(fp,"%s,\n",str); fprintf(fp,"\r\n"); } fclose(fp); return 0; } --------------------------------------------------- これが作成中のプログラムです。

  • OpenCVで動画の指定したフレームをキャプチャ

    現在,動画像処理を勉強している者です. OpenCV 2.3.1を使って動画像から任意のフレームを切り出し,Bitmapに格納する方法がわからなくて困っています. cvWaitKeyを使ってプログラムをスリープさせながら,繰返しすれば動画っぽく表示することはできるのですが,「40フレーム目から処理したい」といったことをするためにはどうすればいいのでしょうか. 以下のコードでプロパティをいじって動画の真ん中のフレームを切り出すつもりだったのですが,無理でした... cvSetCaptureProperty(capture, CV_CAP_PROP_POS_FRAMES, frame_count / 2.0); この後にIplImage型の変数にcvQueryFrame(capture)を突っ込んでもnullでした...なぜ... ※なお,capture←動画ファイル frame_count←総フレーム数がそれぞれ格納されています.

  • openCVの動画書き込みのプログラムを作っているのですが・・・

    openCVの動画書き込みのプログラムを作っているのですが・・・ openCVで、読み込んだ動画(元動画)を背景差分法で2値化処理して出来た動画を保存する、というプログラムを作っています。 しかし、保存された動画を見ると、上手く書き込まれていません。というのも、元動画は15秒あるのですが、保存された動画を見ると、わずか2秒ほどで再生が終わってしまいます。 以下がプログラムのソースです。 #include <stdio.h> #include <cv.h> #include <cxcore.h> #include <highgui.h> #define THRESHOLD_MAX_VALUE 255 #define THRESHOLD 45 #define WIDTH 960 #define HEIGHT 540 int main( int argc, char **argv ){ int key; CvCapture *capture = NULL; IplImage *frameImage; IplImage *backgroundImage = cvCreateImage( cvSize(WIDTH, HEIGHT), IPL_DEPTH_8U, 1 ); IplImage *grayImage = cvCreateImage( cvSize(WIDTH, HEIGHT), IPL_DEPTH_8U, 1 ); IplImage *differenceImage = cvCreateImage( cvSize(WIDTH, HEIGHT), IPL_DEPTH_8U, 1 ); IplImage *binaryImage = cvCreateImage( cvSize(WIDTH, HEIGHT), IPL_DEPTH_8U, 1 ); double fps = 30.0; CvVideoWriter* VideoWriter = cvCreateVideoWriter("binary.avi", CV_FOURCC('F','L','V','1'), fps, cvSize(WIDTH, HEIGHT), 0 ); if ( ( capture = cvCreateFileCapture( "00011.avi" ) ) == NULL ) { printf( "File Not Found\n" ); return -1; } frameImage = cvLoadImage("haikei.bmp"); if(frameImage == NULL){ printf("Can't Get\n"); return -1; } cvCvtColor( frameImage, backgroundImage, CV_BGR2GRAY ); while ( 1 ) { frameImage = cvQueryFrame( capture ); if ( frameImage == NULL ){ break; } cvCvtColor( frameImage, grayImage, CV_BGR2GRAY ); cvAbsDiff( grayImage, backgroundImage, differenceImage ); cvThreshold( differenceImage, binaryImage, THRESHOLD, THRESHOLD_MAX_VALUE, CV_THRESH_BINARY ); cvWriteFrame(VideoWriter, binaryImage); key = cvWaitKey( 10 ); if ( key == 'q' ) { break; } } cvReleaseCapture( &capture ); cvReleaseVideoWriter( &VideoWriter ); cvReleaseImage( &backgroundImage ); cvReleaseImage( &grayImage ); cvReleaseImage( &differenceImage ); cvReleaseImage( &binaryImage ); return 0; } 抽出している際に、プロンプト画面に Compiler did not align stack variables.~ と出てきます。 また、非圧縮などでやると再生が出来ません。 PC環境はWindowsXPです。 助けてください!!

  • C# 簡単なシューティング 自機移動について

    かなりの初心者で困っています。 簡単なシューティングを作ろうとおもっています。 使用ソフトはVisualC#2005です。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace WindowsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } //自機(右移動) private void button3_Click(object sender, EventArgs e) { if (timer1.Enabled == false) { timer2.Enabled = false; timer1.Enabled = true; } else { timer1.Enabled = false; timer3.Enabled = false; timer4.Enabled = false; } } private void timer1_Tick(object sender, EventArgs e) { pictureBox1.Left = pictureBox1.Left + 2; } //自機(左) private void button4_Click(object sender, EventArgs e) { if (timer2.Enabled == false) { timer1.Enabled = false; timer2.Enabled = true; } else { timer2.Enabled = false; timer3.Enabled = false; timer4.Enabled = false; } } private void timer2_Tick(object sender, EventArgs e) { pictureBox1.Left = pictureBox1.Left - 2; } //自機(上) private void button1_Click(object sender, EventArgs e) { if (timer3.Enabled == false) { timer4.Enabled = false; timer3.Enabled = true; } else { timer1.Enabled = false; timer2.Enabled = false; timer3.Enabled = false; } } private void timer3_Tick(object sender, EventArgs e) { pictureBox1.Top = pictureBox1.Top - 2; } //自機(下) private void button2_Click(object sender, EventArgs e) { if (timer4.Enabled == false) { timer3.Enabled = false; timer4.Enabled = true; } else { timer1.Enabled = false; timer2.Enabled = false; timer4.Enabled = false; } } private void timer4_Tick(object sender, EventArgs e) { pictureBox1.Top = pictureBox1.Top + 2; } } } 自機は画像(PictureBox)でボタンによって上下左右に移動します。 FormのSizeは800,630です。 自機の移動がボタンなのでキー入力によって操作できるようにしたいのですが、 それと、自機の移動範囲を画面からでないようにしたいです。 あまりC#を理解できてない上でつくったのでおかしな点が多々あると思います。 教えていただける方がいると助かります。

  • C++ の フレンドクラスについての疑問

    vc++でプログラムを作っています。 クラスのアクセス制限の部分で疑問が出てきたので、ソースとその疑問について 下記に示しています。 const int CAMERA_NUMBER = 0 class CalculateMatrix{ public: □static bool computeFundamentalMatrix( const cv::Mat P1 , const cv::Mat P2 , const cv::Mat T1 , const cv::Mat T2 , cv::Mat &F ); }; class ReferenceCameras{ □friend class CalculateMatrix; public: □ReferenceCameras(); □void setP(); □void setC(); □void setSilhouette(); private: □cv::Mat ShilhouetteImage; □int index; □cv::Mat P; □cv::Mat C; □cv::Mat F; }; void main(){ □ReferenceCameras camera0; //この宣言でプライベートメンバのF以外に全て値が入ります □ReferenceCameras camera1;  //               〃 □CalculateMatrix::computeFundamentalMatrix( cameras0.P, cameras1.P , cameras0.C , cameras1.C , cameras1.F ); } という感じで ReferenceCameras型の camera0,camera1を作って そのCalculateMatrix::computeFundamentalMatrixの計算を行い。 camera1のFを計算する。 というのをやりたいのですが、main内のCalculateMatrix:FundamentalMatrixに引数を入れる部分でエラーが出ていてprivateメンバにアクセスできませんと出ます。 普通なら private で宣言しているので、そういうエラーが出るのは当然かと思いますが、 フレンドクラスの設定をしているのに、このエラーが出るのが理解できません。 結構調べたんですが、フレンドクラス、フレンド関数の部分と静的関数、ユーティリティ関数について絡めて解説しているのはなかったので詰まっています。 どうかみなさんの力を貸してください。 p.s. 何をやりたいのかわからん。や、定義書いてないやん。などの誹謗中傷はおやめください。心が傷つきます。

  • opencvについてわからないことがあります。

    IplImage *frame, *img_gray, *img_out;//画像変数宣言 CvPoint pushpt[10]; int cnum; CvScalar color[10]; int _tmain(int argc, _TCHAR* argv[]) { int key=0; int wait=100; int newFrame=0; CvCapture* src; //ビデオキャプチャ宣言 CvVideoWriter* rec; //ビデオライタ宣言 void on_mouse(int event,int x,int y,int flags,void *param); cvNamedWindow ("入力映像");//表示ウインドウの作成 cvNamedWindow ("出力映像"); src = cvCaptureFromFile("movie.avi");//映像取得 cvSetMouseCallback("入力映像",on_mouse,0); if(src == NULL){//ファイルが読み込めない場合 printf ("canot open\n"); //cvWaitKey(0); return -1; } cnum=-1; newFrame=1; frame = cvQueryFrame(src);//初期フレーム取得 //画像領域の確保 //img_gray = cvCreateImage(cvSize(frame->width, frame->height), IPL_DEPTH_8U, 1); img_out = cvCreateImage(cvSize(frame->width, frame->height), IPL_DEPTH_8U, 3); //ビデオファイル書き込み設定 rec = cvCreateVideoWriter("movie_out.avi",CV_FOURCC('X','V','I','D'),30,cvSize(frame->width, frame->height)); for(int i=0;i<10;i++){//クリックした数だけiを増やして色を変える color[i]=CV_RGB((int)(255.0/10*(10-i)),(int)(255.0/10*i),0); } while(1){//映像が終了するまで繰り返す if(newFrame){ frame = cvQueryFrame(src);//1フレーム取得 cvCopy (frame,img_out,0); newFrame=0; } if(frame == NULL) break;//映像終了時 //cvLine(frame,cvPoint(50,50),cvPoint(100,100),CV_RGB(255,0,0),2,CV_AA,0); //draw mark for(int i=0;i<=cnum;i++){//クリックした数だけ円を描画 cvCircle(img_out,pushpt[i],10,color[i],2,CV_AA,0); } cvShowImage ("入力映像", frame);//1フレーム表示 cvShowImage ("出力映像", img_out); cvWriteFrame(rec ,img_out);//1フレーム書き込み key=0; key=cvWaitKey(wait);//key 'n'の入力を待つ if(key == 'n'){ cnum=-1; newFrame=1; } if(key==27) break;//escキーを押した時終了 } cvDestroyAllWindows();//すべての表示ウインドウ破棄 cvReleaseCapture(&src);//ビデオキャプチャの解放 cvReleaseVideoWriter(&rec);//ビデオライタの解放 cvReleaseImage(&img_gray);//画像領域の解放 cvReleaseImage(&img_out); return 0; } //追加 void on_mouse(int event,int x,int y,int flags,void *param){ //printf("OnMouseDown\n"); if(event == CV_EVENT_LBUTTONDOWN){ cnum++; if(cnum>10) cnum=10;//マークの最大点制限 pushpt[cnum] = cvPoint(x,y); printf("OnMouse:%d\n",cnum); //cvCircle(frame,pushpt,20,CV_RGB(255,128,0),8,CV_AA,0); } } このソースコードを実行すると、nキーで1フレーム進む動画が2つ表示されます。 1つは読み込んだ動画を表示しています。 もう1つはそれを録画して、動画ファイルとして書き出しています。 読み込んだ動画上にマウスでクリックすると、録画の画面上に丸でマークをします。 ここまではできました。 しかし、ここから次に書くことができません。 1フレーム目でマウスでクリックしてマークをします。 次に、nキーを押して2フレーム目に進みます。(この時1フレームでマークしたものは消えています。) そして、2フレーム目でマウスでクリックして、マークをすると1フレーム目でマークしたものが一緒に出てくる(できれば色が薄くなって) ということがしたいです。 pushptという配列に座標がはいっているのは、わかっているのですがどう書けばよいかわかりません。 教えてくださいお願いします。

  • C#について・・・

    次のようなブログラムなのですが、ラジオボタンが上手く切り替わりません。 どこを修正すると上手くいくでしょうか? <<文字数オーバーのため省略>> public Form1() { // // Windows フォーム デザイナ サポートに必要です。 // InitializeComponent(); if(isJapanStyle) { label5.Text=string.Format("0時0分0秒"); label6.Text=string.Format("0時0分0秒"); } else { label5.Text=string.Format("00:00:00"); label6.Text=string.Format("00:00:00"); } // // TODO: InitializeComponent 呼び出しの後に、コンストラクタ コードを追加してください。 // <<文字数オーバーのため 省略>> static void Main() { Application.Run(new Form1()); } protected void button1_Click(object sender, System.EventArgs e) { if(isJapanStyle) { label5.Text=string.Format("{0}時{1}分{2}秒",dt.Hour,dt.Minute,dt.Second); } else { label5.Text=DateTime.Now.ToString("T"); } recTime=dt; timer2.Stop(); timer3.Start(); } private void button2_Click(object sender, System.EventArgs e) { Application.Exit(); } private void timer1_Tick(object sender, System.EventArgs e) { dt=DateTime.Now; if(isJapanStyle) { label4.Text=string.Format("{0}時{1}分{2}秒",dt.Hour,dt.Minute,dt.Second); } else { label4.Text=DateTime.Now.ToString("T"); } } private void timer3_Tick(object sender, System.EventArgs e) { keika=dt-recTime; if(isJapanStyle) { label6.Text=string.Format("{0}時間{1}分{2}秒",keika.Hours,keika.Minutes,keika.Seconds); } else { label6.Text=string.Format("{0}:{1}:{2}",keika.Hours,keika.Minutes,keika.Seconds); } } private void timer2_Tick(object sender, System.EventArgs e) { timer3.Stop(); } private void radioButton2_CheckedChanged(object sender, System.EventArgs e) { isJapanStyle=false; } private void radioButton1_CheckedChanged(object sender, System.EventArgs e) { isJapanStyle=true; } } }

専門家に質問してみよう