カメラから得た画像データをバックグランドで連続保存を行っています。
前回の質問ではi7 2700Kを使っており、難なく保存ができておりました。
しかし、下記にあるCPUを使って連続撮影を行った場合、最初は調子が良かったのですが、保存を進めていくうちに動作が重くなりプログラムが止まってしまいます。
質問を箇条書きにすると
・そもそもBackgroundWorkerはマルチスレッドなのか?
・原因はHDDのアクセスの問題か?CPUに負荷をかけ過ぎなのか?
・動作が重くなるのはただ単にスペックが足りていないのか?
・どこを改善すればよいのか?
です。
C++/CLIは必ず使うものとします。
事実、私は、マルチスレッドもクロック周波数もアクセス速度がどうのこうのも右も左もわからない状態です。
以上のことよろしくお願いいたします。
OS:Win7 CPU:i7 L640(Core i7-640LM?)
コンパイラ:VS2010
ライブラリ:OpenCV2.4
以下、ソースコード
OpenCVのヘッダとライブラリ読み込み部分省略
iDSProgamForm.h
#pragma once
namespace iDSProgram {
using namespace System;
using namespace System::Text;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Collections::Generic;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
/// <summary>
/// iDSProgramForm の概要
/// </summary>
public ref class iDSProgramForm : public System::Windows::Forms::Form
{
public:
iDSProgramForm(void)
{
InitializeComponent();
//
//TODO: ここにコンストラクター コードを追加します
//
}
protected:
/// <summary>
/// 使用中のリソースをすべてクリーンアップします。
/// </summary>
~iDSProgramForm()
{
if (components)
{
delete components;
}
}
private: System::ComponentModel::BackgroundWorker^ SvGraphWork;
protected:
protected:
protected:
private: System::Windows::Forms::PictureBox^ pictureBox1;
private: System::Windows::Forms::Timer^ RecordTimer;
private: System::Windows::Forms::Button^ buttonStart;
private: System::Windows::Forms::Button^ StopBtn;
private: System::Windows::Forms::ProgressBar^ progressBar;
private: System::Windows::Forms::ProgressBar^ RecordBar;
private: System::Windows::Forms::ProgressBar^ ShutterBar;
private: System::ComponentModel::IContainer^ components;
private:
/// <summary>
/// 必要なデザイナー変数です。
/// </summary>
#pragma region Windows Form Designer generated code
/// <summary>
/// デザイナー サポートに必要なメソッドです。このメソッドの内容を
/// コード エディターで変更しないでください。
/// </summary>
void InitializeComponent(void)
{
this->components = (gcnew System::ComponentModel::Container());
this->SvGraphWork = (gcnew System::ComponentModel::BackgroundWorker());
this->pictureBox1 = (gcnew System::Windows::Forms::PictureBox());
this->RecordTimer = (gcnew System::Windows::Forms::Timer(this->components));
this->buttonStart = (gcnew System::Windows::Forms::Button());
this->StopBtn = (gcnew System::Windows::Forms::Button());
this->progressBar = (gcnew System::Windows::Forms::ProgressBar());
this->RecordBar = (gcnew System::Windows::Forms::ProgressBar());
this->ShutterBar = (gcnew System::Windows::Forms::ProgressBar());
(cli::safe_cast<System::ComponentModel::ISupportInitialize^ >(this->pictureBox1))->BeginInit();
this->SuspendLayout();
//
// SvGraphWork
//
this->SvGraphWork->WorkerReportsProgress = true;
this->SvGraphWork->WorkerSupportsCancellation = true;
this->SvGraphWork->DoWork += gcnew System::ComponentModel::DoWorkEventHandler(this, &iDSProgramForm::SvGraphWork_DoWork);
this->SvGraphWork->ProgressChanged += gcnew System::ComponentModel::ProgressChangedEventHandler(this, &iDSProgramForm::SvGraphWork_ProgressChanged);
this->SvGraphWork->RunWorkerCompleted += gcnew System::ComponentModel::RunWorkerCompletedEventHandler(this, &iDSProgramForm::SvGraphWork_RunWorkerCompleted);
//
// pictureBox1
//
this->pictureBox1->BorderStyle = System::Windows::Forms::BorderStyle::FixedSingle;
this->pictureBox1->Location = System::Drawing::Point(13, 13);
this->pictureBox1->Name = L"pictureBox1";
this->pictureBox1->Size = System::Drawing::Size(640, 480);
this->pictureBox1->TabIndex = 0;
this->pictureBox1->TabStop = false;
//
// RecordTimer
//
this->RecordTimer->Interval = 1;
this->RecordTimer->Tick += gcnew System::EventHandler(this, &iDSProgramForm::RecordTimer_Tick);
//
// buttonStart
//
this->buttonStart->Location = System::Drawing::Point(660, 13);
this->buttonStart->Name = L"buttonStart";
this->buttonStart->Size = System::Drawing::Size(75, 23);
this->buttonStart->TabIndex = 1;
this->buttonStart->Text = L"撮影";
this->buttonStart->UseVisualStyleBackColor = true;
this->buttonStart->Click += gcnew System::EventHandler(this, &iDSProgramForm::buttonStart_Click);
//
// StopBtn
//
this->StopBtn->Location = System::Drawing::Point(787, 13);
this->StopBtn->Name = L"StopBtn";
this->StopBtn->Size = System::Drawing::Size(75, 23);
this->StopBtn->TabIndex = 5;
this->StopBtn->Text = L"撮影やめ!";
this->StopBtn->UseVisualStyleBackColor = true;
this->StopBtn->Click += gcnew System::EventHandler(this, &iDSProgramForm::StopBtn_Click);
//
// progressBar
//
this->progressBar->Location = System::Drawing::Point(660, 49);
this->progressBar->Name = L"progressBar";
this->progressBar->Size = System::Drawing::Size(202, 23);
this->progressBar->TabIndex = 2;
//
// RecordBar
//
this->RecordBar->Location = System::Drawing::Point(660, 79);
this->RecordBar->Maximum = 400;
this->RecordBar->Name = L"RecordBar";
this->RecordBar->Size = System::Drawing::Size(202, 23);
this->RecordBar->TabIndex = 3;
//
// ShutterBar
//
this->ShutterBar->Location = System::Drawing::Point(660, 109);
this->ShutterBar->Maximum = 200;
this->ShutterBar->Name = L"ShutterBar";
this->ShutterBar->Size = System::Drawing::Size(202, 23);
this->ShutterBar->TabIndex = 4;
//
// iDSProgramForm
//
this->AutoScaleDimensions = System::Drawing::SizeF(6, 12);
this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
this->ClientSize = System::Drawing::Size(874, 528);
this->Controls->Add(this->StopBtn);
this->Controls->Add(this->ShutterBar);
this->Controls->Add(this->RecordBar);
this->Controls->Add(this->progressBar);
this->Controls->Add(this->buttonStart);
this->Controls->Add(this->pictureBox1);
this->Name = L"iDSProgramForm";
this->Text = L"iDSProgramForm";
this->FormClosed += gcnew System::Windows::Forms::FormClosedEventHandler(this, &iDSProgramForm::iDSProgramForm_FormClosed);
this->Load += gcnew System::EventHandler(this, &iDSProgramForm::iDSProgramForm_Load);
(cli::safe_cast<System::ComponentModel::ISupportInitialize^ >(this->pictureBox1))->EndInit();
this->ResumeLayout(false);
}
#pragma endregion
private: System::Void RecordTimer_Tick(System::Object^ sender, System::EventArgs^ e);
private: System::Void iDSProgramForm_Load(System::Object^ sender, System::EventArgs^ e);
private: System::Void iDSProgramForm_FormClosed(System::Object^ sender, System::Windows::Forms::FormClosedEventArgs^ e);
private: System::Void SvGraphWork_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e);
private: System::Void SvGraphWork_ProgressChanged(System::Object^ sender, System::ComponentModel::ProgressChangedEventArgs^ e);
private: System::Void SvGraphWork_RunWorkerCompleted(System::Object^ sender, System::ComponentModel::RunWorkerCompletedEventArgs^ e);
private: System::Void buttonStart_Click(System::Object^ sender, System::EventArgs^ e);
private: System::Void StopBtn_Click(System::Object^ sender, System::EventArgs^ e);
void DrawCvImage(IplImage *CvImage);
};
}
#include "stdafx.h"
#include "iDSProgramForm.h"
#define MEM 400
CvCapture *capture = 0;
IplImage *frame = 0;
IplImage *svframe[MEM] = {0};
int saveCount;
int RecordCount;
int countbuf;
bool RecordFlag;
bool SaveStertFlag;
int count=0;
using namespace iDSProgram;
System::Void iDSProgramForm::iDSProgramForm_Load(System::Object^ sender, System::EventArgs^ e){
RecordCount = 0;
saveCount=0;
capture = cvCreateCameraCapture(1);
RecordTimer->Enabled = true;
RecordFlag = false;
SaveStertFlag = false;
countbuf=0;
RecordBar->Maximum = MEM;
ShutterBar->Maximum = MEM/2;
}
System::Void iDSProgramForm::RecordTimer_Tick(System::Object^ sender, System::EventArgs^ e){
frame = cvQueryFrame (capture);
DrawCvImage(frame);
cvWaitKey(10);
if(RecordFlag){
svframe[RecordCount] = cvCloneImage(frame);
RecordBar->Value = RecordCount;
ShutterBar->Value = saveCount;
RecordCount++;
if(RecordCount%(MEM/2) == 0){
saveCount=0;
SaveStertFlag=true;
SvGraphWork->RunWorkerAsync(10);
}
if(RecordCount>MEM)
RecordCount=0;
}
}
System::Void iDSProgramForm::buttonStart_Click(System::Object^ sender, System::EventArgs^ e) {
buttonStart->Enabled = false;
RecordFlag = true;
SaveStertFlag = false;
}
System::Void iDSProgramForm::StopBtn_Click(System::Object^ sender, System::EventArgs^ e){
RecordFlag = false;
SaveStertFlag = false;
}
System::Void iDSProgramForm::iDSProgramForm_FormClosed(System::Object^ sender, System::Windows::Forms::FormClosedEventArgs^ e){
cvReleaseCapture (&capture);
}
System::Void iDSProgramForm::SvGraphWork_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e){
// 別スレッドで実行されるため、このメソッドでは
// UI(コントロール)を操作してはいけない
// このメソッドへのパラメータ
int bgWorkerArg = (int)e->Argument;
// senderの値はbgWorkerの値と同じ
BackgroundWorker^ worker = (BackgroundWorker^)(sender);
// 時間のかかる処理
while(SaveStertFlag){
System::Threading::Thread::Sleep(1);
char fname[255];
sprintf(fname,"DATA\\%05d.bmp",count);
cvSaveImage(fname,svframe[saveCount+((countbuf%2)*(MEM/2))]);
cvReleaseImage(&svframe[saveCount+((countbuf%2)*(MEM/2))]);
saveCount++;
count++;
if(saveCount>(MEM/2)){
saveCount=0;
SaveStertFlag = false;
countbuf++;
}
int percentage = saveCount * 100 / (MEM/2); // 進ちょく率
worker->ReportProgress(percentage);
// ProgressChangedイベント発生
}
// この後、RunWorkerCompletedイベントが発生
}
System::Void iDSProgramForm::SvGraphWork_ProgressChanged(System::Object^ sender, System::ComponentModel::ProgressChangedEventArgs^ e){
progressBar->Value = e->ProgressPercentage;
}
System::Void iDSProgramForm::SvGraphWork_RunWorkerCompleted(System::Object^ sender, System::ComponentModel::RunWorkerCompletedEventArgs^ e){
buttonStart->Enabled = true;
}
void iDSProgramForm::DrawCvImage(IplImage *CvImage) {
//IplImageをピクチャボックスへ描画
///////////////////////////////////
// Graphicsの確保
//
if ((pictureBox1->Image == nullptr)
|| (pictureBox1->Width != CvImage->width)
|| (pictureBox1->Height != CvImage->height)){
//ピクチャボックスをビットマップ画像サイズに合わせる
pictureBox1->Width = CvImage->width;
pictureBox1->Height = CvImage->height;
//PictureBoxと同じ大きさのBitmapクラスを作成する。
Bitmap^ bmpPicBox = gcnew Bitmap(pictureBox1->Width, pictureBox1->Height);
//空のBitmapをPictureBoxのImageに指定する。
pictureBox1->Image = bmpPicBox;
}
//Graphicsクラスの作成(空のピクチャボックスからGraphicsを作成する)
Graphics^g = Graphics::FromImage(pictureBox1->Image);
///////////////////////////////////
// IplImageからBitmapの確保
//
//IplImageの画像データのポインタ(imageData)をBitmapへ渡し、Bitmapを作成
Bitmap^ bmp = gcnew Bitmap(CvImage->width, CvImage->height, CvImage->widthStep,
System::Drawing::Imaging::PixelFormat::Format24bppRgb, IntPtr(CvImage->imageData));
///////////////////////////////////
// 画像の描画
//
//ピクチャボックスのImageへ
g->DrawImage(bmp, 0, 0, CvImage->width, CvImage->height);
pictureBox1->Refresh();
delete g;
}