Newer
Older
ISCamRecorder / ISCamRecorder / CvCamera.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using System.Drawing;
using System.Diagnostics;
using System.IO;

namespace ISCamRecorder {

    struct FrameInfo {
        public DateTime FrameTime { get; private set; }
        public Mat FrameImage { get; private set; }

        public FrameInfo(Mat frame) {
            FrameImage = frame;
            FrameTime = DateTime.Now;
        }
    }

    internal class CvCamera {
        VideoCapture camera = null;     // カメラオブジェクト
        bool _ExitSignal = false;       // 終了シグナル
        Bitmap[] _Buffer = new Bitmap[2];   // ダブルバッファ
        int _WriteBufferID = 0;         // 書き込みバッファ番号
        FrameRateCounter _Fps = new FrameRateCounter(10);   // フレームレート計測
        bool _Recoding = false;     // 録画中フラグ
        List<FrameInfo> _RecFrames = new List<FrameInfo>(); // 録画画像
        float _RecFrameRate = 0;    // 録画フレームレート

        /// <summary>
        /// カメラ接続
        /// </summary>
        /// <returns></returns>
        public bool Open(int id, int frameWidth, int frameHeight) {
            camera = new VideoCapture(id);
            if (!camera.IsOpened()) {
                camera.Dispose();
                camera = null;
                return false;
            }
            camera.FrameWidth = frameWidth;
            camera.FrameHeight = frameHeight;
            return true;
        }

        /// <summary>
        /// 撮影ループ
        /// </summary>
        public void CameraLoop() {
            // 撮影ループ
            while (!_ExitSignal) {
                using (var frame = new Mat()) {
                    camera.Read(frame);
                    if (_Recoding) {
                        _RecFrames.Add(new FrameInfo(frame.Clone()));
                    }
                    _Buffer[_WriteBufferID] = BitmapConverter.ToBitmap(frame);
                    _WriteBufferID = 1 - _WriteBufferID; // バッファ切り替え
                    _Fps.Shot();
                }
            }

            // 終了処理(メモリ解放)
            if (camera != null) camera.Dispose();
        }

        public void SaveToFile(string outDir, string imageType, string recTime) {
            if (_RecFrames.Count < 1) return;
            var CamID = "CvCam";
            Debug.WriteLine($"{CamID} starts saving with 0.0fps.");
            // 保存先確保
            var outDir2 = Path.Combine(outDir, CamID);
            Directory.CreateDirectory(outDir2);
            // 動画保存準備
            var movieFile = Path.Combine(outDir, $"{CamID}_{recTime}.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 filePath = Path.Combine(outDir2, fileName);
                _RecFrames[i].FrameImage.SaveImage(filePath);
                writer.Write(_RecFrames[i].FrameImage);
            }
            writer.Release();

            _RecFrames.Clear();
            Debug.WriteLine($"{CamID} ends saving.");
        }

        /// <summary>
        /// 録画開始
        /// </summary>
        public void StartRecoding() {
            if (_RecFrames.Count > 0) _RecFrames.Clear();
            _RecFrameRate = _Fps.FrameRate;
            _Recoding = true;
        }

        /// <summary>
        /// 録画中断
        /// </summary>
        public void StopRecoding() {
            _Recoding = false;
        }

        /// <summary>
        /// 撮影画像の取得
        /// </summary>
        /// <returns></returns>
        public Bitmap GetImage() {
            return _Buffer[1 - _WriteBufferID];
        }

        /// <summary>
        /// 停止
        /// </summary>
        public void Stop() {
            _ExitSignal = true;
        }

        /// <summary>
        /// カメラ情報文字列
        /// </summary>
        /// <returns></returns>
        public string CameraInfo() {
            if (camera == null) return "接続中";
            return $"{camera.FrameWidth}x{camera.FrameHeight} {_Fps.FrameRate:0.0} fps";
        }

        /// <summary>
        /// 1秒録画に要するメモリ量
        /// </summary>
        /// <returns></returns>
        public float MemoryFor1SecRecoding() {
            if (camera == null) return 0;
            int frameSize = 3 * camera.FrameWidth * camera.FrameHeight;
            int bcs = 1024 * 1024;
            return _Fps.FrameRate * frameSize / bcs;
        }
    }
}