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;
using System.Windows.Forms;
namespace ISCamRecorder {
/// <summary>
/// 撮影フレーム情報クラス
/// 撮影画像と撮影時間をペアで記録
/// </summary>
struct FrameInfo {
public DateTime FrameTime { get; private set; }
public Mat FrameImage { get; private set; }
public FrameInfo(Mat frame) {
FrameImage = frame;
FrameTime = DateTime.Now;
}
}
/// <summary>
/// 汎用カメラクラス
/// OpenCVカメラで撮影する
/// </summary>
class CvCamera {
readonly string _CamID = "CvCam"; // 記録用デバイス名
VideoCapture camera = null; // カメラオブジェクト
FrameRateCounter _Fps = new FrameRateCounter(10); // フレームレート計測
List<FrameInfo> _RecFrames = new List<FrameInfo>(); // 録画画像
MainForm _MF = null; // メインフォームインスタンス
bool _Snap = false; // 静止画撮影フラグ
public float CameraFPS { get; private set; } = 0;
public float CurrentFPS { get { return _Fps.FrameRate; } }
/// <summary>
/// コンストラクタ
/// </summary>
/// <param name="mf">メインフォーム</param>
public CvCamera(MainForm mf) {
_MF = mf;
}
/// <summary>
/// カメラ接続
/// </summary>
/// <returns></returns>
public bool Open(int id, int frameWidth, int frameHeight) {
camera = new VideoCapture(id);
if (!camera.IsOpened()) {
camera.Dispose();
camera = null;
MessageBox.Show("追加カメラに接続できません", "Error",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return false;
}
camera.FrameWidth = frameWidth;
camera.FrameHeight = frameHeight;
CameraFPS = (float)camera.Fps;
return true;
}
/// <summary>
/// 撮影ループ
/// </summary>
public void CameraLoop() {
var rblabel = Cv2.ImRead("RBlabel398x133.png");
var roi = new Rect(10, 10, rblabel.Width, rblabel.Height);
// 撮影ループ
while (_MF.State != STATE.Exit) {
using (var frame = new Mat()) {
// 撮影
camera.Read(frame);
if (_MF.IsReverseBlood) {
rblabel.CopyTo(new Mat(frame, roi));
}
var bmp = BitmapConverter.ToBitmap(frame);
// 録画
if (_MF.State == STATE.Recoding && _MF.Setting.RecCameras[4]) {
_RecFrames.Add(new FrameInfo(frame.Clone()));
}
// 静止画保存
if (_Snap) {
var outDir = Path.Combine(_MF.Setting.SaveDir, "image");
var filename = Path.Combine(outDir,
$"{_CamID}_{DateTime.Now.ToString("yyyyMMdd_HHmmss")}.{_MF.Setting.ImageType.ToLower()}");
Cv2.ImWrite(filename, frame);
_Snap = false;
}
// 表示
if (_MF.State != STATE.Exit) {
_MF.CvCameraPic.Invoke((MethodInvoker)delegate {
_MF.CvCameraPic.Image = bmp;
});
}
_Fps.Shot();
}
}
// 終了処理(メモリ解放)
if (camera != null) camera.Dispose();
}
/// <summary>
/// 記録データをファイルに保存
/// </summary>
/// <param name="outDir"></param>
/// <param name="imageType"></param>
/// <param name="recTime"></param>
public void SaveToFile() {
if (_RecFrames.Count < 1) return;
Debug.WriteLine($"{_CamID} starts saving with {CameraFPS:0.0}fps.");
// 保存先確保
var outDir2 = Path.Combine(_MF.OutputDir, _CamID);
Directory.CreateDirectory(outDir2);
// 動画保存準備
var movieFile = Path.Combine(_MF.OutputDir, $"{_CamID}_{_MF.RecodingTimeStr}.mp4");
var writer = new VideoWriter(movieFile, FourCC.H264,
CameraFPS, _RecFrames[0].FrameImage.Size());
for (int i = 0; i < _RecFrames.Count; i++) {
string strSampleTime = _RecFrames[i].FrameTime.ToString(@"HHmmss\.fff");
var fileName = $"{_CamID}_{strSampleTime}.{_MF.Setting.FrameType}";
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>
/// <returns></returns>
public string CameraInfo() {
if (camera == null) return "接続中";
try {
return $"{camera.FrameWidth}x{camera.FrameHeight} {_Fps.FrameRate:0.0} fps";
} catch (Exception _) {
return "";
}
}
/// <summary>
/// 1秒録画に要するメモリ量
/// </summary>
/// <returns></returns>
public float ConsumedMemoryPerSecond() {
if (camera == null) return 0;
int frameSize = 3 * camera.FrameWidth * camera.FrameHeight;
int bcs = 1024 * 1024;
return CameraFPS * frameSize / bcs;
}
/// <summary>
/// 静止画撮影
/// </summary>
public void Snap() {
_Snap = true;
}
}
}