diff --git a/ISCamRecorder/CvCamera.cs b/ISCamRecorder/CvCamera.cs index 0ad46da..91be303 100644 --- a/ISCamRecorder/CvCamera.cs +++ b/ISCamRecorder/CvCamera.cs @@ -31,11 +31,13 @@ /// OpenCVカメラで撮影する /// class CvCamera { + readonly string _CamID = "CvCam"; VideoCapture camera = null; // カメラオブジェクト FrameRateCounter _Fps = new FrameRateCounter(10); // フレームレート計測 List _RecFrames = new List(); // 録画画像 float _RecFrameRate = 0; // 録画フレームレート MainForm _MainForm = null; // メインフォーム + bool _Snap = false; /// /// コンストラクタ @@ -74,11 +76,20 @@ camera.Read(frame); var bmp = BitmapConverter.ToBitmap(frame); + // 録画 if (_MainForm.State == STATE.Recoding) { _RecFrames.Add(new FrameInfo(frame.Clone())); if (_RecFrameRate == 0) _RecFrameRate = _Fps.FrameRate; } + // 静止画保存 + if (_Snap) { + var outDir = Path.Combine(_MainForm.OutputBaseDir, "image"); + var filename = Path.Combine(outDir, $"{_CamID}_{DateTime.Now.ToString("yyyyMMdd_HHmmss")}.{_MainForm.ImageType.ToLower()}"); + Cv2.ImWrite(filename, frame); + _Snap = false; + } + // 表示 if (_MainForm.State != STATE.Exit) { _MainForm.CvCameraPic.Invoke((MethodInvoker)delegate { @@ -100,20 +111,19 @@ /// /// /// - public void SaveToFile(string imageType) { + public void SaveToFile() { if (_RecFrames.Count < 1) return; - var CamID = "CvCam"; - Debug.WriteLine($"{CamID} starts saving with {_RecFrameRate:0.0}fps."); + Debug.WriteLine($"{_CamID} starts saving with {_RecFrameRate:0.0}fps."); // 保存先確保 - var outDir2 = Path.Combine(_MainForm.OutputDir, CamID); + var outDir2 = Path.Combine(_MainForm.OutputDir, _CamID); Directory.CreateDirectory(outDir2); // 動画保存準備 - var movieFile = Path.Combine(_MainForm.OutputDir, $"{CamID}_{_MainForm.RecodingTimeStr}.mp4"); + var movieFile = Path.Combine(_MainForm.OutputDir, $"{_CamID}_{_MainForm.RecodingTimeStr}.mp4"); var writer = new VideoWriter(movieFile, FourCC.H264, _RecFrameRate, _RecFrames[0].FrameImage.Size()); for (int i = 0; i < _RecFrames.Count; i++) { string strSampleTime = _RecFrames[i].FrameTime.ToString(@"HHmmss\.fff"); - var fileName = $"{CamID}_{strSampleTime}.{imageType.ToLower()}"; + var fileName = $"{_CamID}_{strSampleTime}.{_MainForm.ImageType.ToLower()}"; var filePath = Path.Combine(outDir2, fileName); _RecFrames[i].FrameImage.SaveImage(filePath); writer.Write(_RecFrames[i].FrameImage); @@ -122,7 +132,7 @@ _RecFrames.Clear(); _RecFrameRate = 0; - Debug.WriteLine($"{CamID} ends saving."); + Debug.WriteLine($"{_CamID} ends saving."); } /// @@ -144,5 +154,12 @@ int bcs = 1024 * 1024; return _Fps.FrameRate * frameSize / bcs; } + + /// + /// 静止画撮影 + /// + public void Snap() { + _Snap = true; + } } } diff --git a/ISCamRecorder/ISCamera.cs b/ISCamRecorder/ISCamera.cs index fc15cd0..3b01697 100644 --- a/ISCamRecorder/ISCamera.cs +++ b/ISCamRecorder/ISCamera.cs @@ -111,7 +111,6 @@ TIS.Imaging.IFrameQueueBuffer frm = snapSink.SnapSingle(TimeSpan.FromSeconds(5)); var outDir = Path.Combine(_MainForm.OutputBaseDir, "image"); - Directory.CreateDirectory(outDir); var filename = Path.Combine(outDir, $"{_CamID}_{DateTime.Now.ToString("yyyyMMdd_HHmmss")}.{_MainForm.ImageType.ToLower()}"); switch (_MainForm.ImageType) { case "JPG": @@ -153,16 +152,15 @@ /// ファイル保存 /// /// - public void SaveToFile(string outDir, float frameRate, int movieRate, - string imageType, string recTime) { + public void SaveToFile(float frameRate) { Debug.WriteLine($"{_CamID} starts saving with {frameRate}fps."); // 保存先確保 - var outDir2 = Path.Combine(outDir, _CamID); + var outDir2 = Path.Combine(_MainForm.OutputDir, _CamID); Directory.CreateDirectory(outDir2); // 動画保存準備 - var movieFile = Path.Combine(outDir, $"{_CamID}_{recTime}.mp4"); + var movieFile = Path.Combine(_MainForm.OutputDir, $"{_CamID}_{_MainForm.RecodingTimeStr}.mp4"); var writer = new H264Writer(movieFile, - _RecSink.OutputFrameType, (int)frameRate, movieRate * 1000); + _RecSink.OutputFrameType, (int)frameRate, _MainForm.MovieRate * 1000); writer.Begin(); // ファイル保存 var firstDriverTime = _bufferlist[0].FrameMetadata.DriverFrameFirstPacketTime; @@ -171,9 +169,9 @@ var driverTime = _bufferlist[i].FrameMetadata.DriverFrameFirstPacketTime; var frameTime = _MainForm.RecodingTime.Add(driverTime - firstDriverTime); // パケットをドライバが受信した時刻 string strSampleTime = frameTime.ToString(@"HHmmss\.fff"); - var fileName = $"{_CamID}_{strSampleTime}.{imageType.ToLower()}"; + var fileName = $"{_CamID}_{strSampleTime}.{_MainForm.ImageType.ToLower()}"; var filePath = Path.Combine(outDir2, fileName); - switch (imageType) { + switch (_MainForm.ImageType) { case "JPG": FrameExtensions.SaveAsJpeg(_bufferlist[i], filePath, JPEG_QUALITY); break; diff --git a/ISCamRecorder/MainForm.Designer.cs b/ISCamRecorder/MainForm.Designer.cs index 3da747e..8848283 100644 --- a/ISCamRecorder/MainForm.Designer.cs +++ b/ISCamRecorder/MainForm.Designer.cs @@ -387,6 +387,7 @@ this.TxtRecodingDulation.TabIndex = 8; this.TxtRecodingDulation.Text = "3"; this.TxtRecodingDulation.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.TxtRecodingDulation.TextChanged += new System.EventHandler(this.TxtRecodingDulation_TextChanged); this.TxtRecodingDulation.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.NumberKeyOnly); // // label1 @@ -498,6 +499,7 @@ this.TxtMovieRate.TabIndex = 20; this.TxtMovieRate.Text = "3000"; this.TxtMovieRate.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.TxtMovieRate.TextChanged += new System.EventHandler(this.TxtMovieRate_TextChanged); this.TxtMovieRate.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.NumberKeyOnly); // // label6 diff --git a/ISCamRecorder/MainForm.cs b/ISCamRecorder/MainForm.cs index b830c47..bee4a3c 100644 --- a/ISCamRecorder/MainForm.cs +++ b/ISCamRecorder/MainForm.cs @@ -48,6 +48,7 @@ Task _CvCameraThread; // opencvカメラスレッド Task _RecodingThread; // 録画スレッド float _TriggerFrameRate = 30.0F; // トリガーフレームレート + float _RecodingDulation = 0; // 録画時間 private ulong _availablePhysicalMemory; //合計物理メモリ public Chart SensorChart { get { return chart1; } } // 外部からのアクセス用 @@ -58,7 +59,7 @@ public string OutputBaseDir { get { return TxtOutputDir.Text; } } // データ保存フォルダ public string OutputDir { get { return Path.Combine(OutputBaseDir, $"rec{RecodingTimeStr}"); } } // データ保存フォルダ public string ImageType { get; private set; } - + public int MovieRate { get; private set; } /// /// コンストラクタ @@ -92,6 +93,8 @@ _CvCameraThread = Task.Run(CvCameraThread); ImageType = CboImageType.Text; + MovieRate = int.Parse(TxtMovieRate.Text); + _RecodingDulation = float.Parse(TxtRecodingDulation.Text); State = STATE.Idle; } @@ -249,23 +252,6 @@ } /// - /// 録画時間テキストボックスでキー押下時 - /// - /// - /// - private void NumberKeyOnly(object sender, KeyPressEventArgs e) { - //バックスペースが押された時は有効(Deleteキーも有効) - if (e.KeyChar == '\b' || e.KeyChar == '.') { - return; - } - - //数値0~9以外が押された時はイベントをキャンセルする - if ((e.KeyChar < '0' || '9' < e.KeyChar)) { - e.Handled = true; - } - } - - /// /// 動画撮影 /// /// @@ -292,33 +278,24 @@ /// private void RecodingThread() { - string recodingDulationTxt = ""; - string movieRateTxt = ""; - string imageTypeTxt = ""; - Color originalButtonColor = Color.Gray; + // 録画開始サウンド + var player = new SoundPlayer(@"start.wav"); + player.Play(); + // 録画モードへ変更 + Color originalButtonColor = Color.Gray; this.Invoke((MethodInvoker)delegate { _Cameras.ForEach(c => c.ChangeSink(true)); - //BtnRecodeMovie.Enabled = false; BtnSetProperty.Enabled = false; BtnRecodeMovie.Text = "撮影中"; originalButtonColor = BtnRecodeMovie.BackColor; BtnRecodeMovie.BackColor = Color.Orange; - - recodingDulationTxt = TxtRecodingDulation.Text; - movieRateTxt = TxtMovieRate.Text; - imageTypeTxt = CboImageType.Text; }); - // 録画条件設定 - var frameRate = _Cameras.Select(c => c.FrameRate).Average(); - var framesToCapture = (int)(float.Parse(recodingDulationTxt) * frameRate + 1.0F); - var movieRate = int.Parse(movieRateTxt); - var imageType = imageTypeTxt; // 録画開始 - var player = new SoundPlayer(@"start.wav"); - player.Play(); + var frameRate = _Cameras.Select(c => c.FrameRate).Average(); + var framesToCapture = (int)(_RecodingDulation * frameRate + 1.0F); RecodingTime = DateTime.Now; Directory.CreateDirectory(OutputDir); State = STATE.Recoding; @@ -331,23 +308,24 @@ } Task.WaitAll(tasks); + // 保存準備 State = STATE.Saving; player = new SoundPlayer(@"end.wav"); player.Play(); - - // 保存 this.Invoke((MethodInvoker)delegate { + BtnRecodeMovie.Enabled = false; BtnRecodeMovie.Text = "保存中"; BtnRecodeMovie.BackColor = Color.Aqua; }); + + // 保存 for (var i = 0; i < _Cameras.Count; i++) { var cam = _Cameras[i]; - tasks[i] = Task.Run(() => cam.SaveToFile( - OutputDir, frameRate, movieRate, imageType, RecodingTimeStr)); + tasks[i] = Task.Run(() => cam.SaveToFile(frameRate)); } Task.WaitAll(tasks); - _CvCamera.SaveToFile(imageType); + _CvCamera.SaveToFile(); // プレビューモードへ変更 this.Invoke((MethodInvoker)delegate { @@ -367,7 +345,14 @@ /// private void BtnSnapImage_Click(object sender, EventArgs e) { if (State != STATE.Idle) return; + + var player = new SoundPlayer(@"snap.wav"); + player.Play(); + + var outDir = Path.Combine(OutputBaseDir, "image"); + Directory.CreateDirectory(outDir); _Cameras.ForEach(c => c.SnapImage()); + _CvCamera.Snap(); } /// @@ -391,6 +376,23 @@ } /// + /// 録画時間テキストボックスでキー押下時 + /// + /// + /// + private void NumberKeyOnly(object sender, KeyPressEventArgs e) { + //バックスペースが押された時は有効(Deleteキーも有効) + if (e.KeyChar == '\b' || e.KeyChar == '.') { + return; + } + + //数値0~9以外が押された時はイベントをキャンセルする + if ((e.KeyChar < '0' || '9' < e.KeyChar)) { + e.Handled = true; + } + } + + /// /// 画像形式選択時 /// /// @@ -398,5 +400,23 @@ private void CboImageType_SelectedIndexChanged(object sender, EventArgs e) { ImageType = CboImageType.Text; } + + /// + /// 動画レート変更時 + /// + /// + /// + private void TxtMovieRate_TextChanged(object sender, EventArgs e) { + MovieRate = int.Parse(TxtMovieRate.Text); + } + + /// + /// 記録時間変更時 + /// + /// + /// + private void TxtRecodingDulation_TextChanged(object sender, EventArgs e) { + _RecodingDulation = float.Parse(TxtRecodingDulation.Text); + } } } diff --git a/ISCamRecorder/media/snap.wav b/ISCamRecorder/media/snap.wav new file mode 100644 index 0000000..5448f8d --- /dev/null +++ b/ISCamRecorder/media/snap.wav Binary files differ