Newer
Older
ISCamRecorder / ISCamRecorder / ISCamera.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Diagnostics;
using TIS.Imaging;
using System.Windows.Forms;

namespace ISCamRecorder {
    internal class ISCamera {
        readonly string ICCF_FILE = @"dfk33ux290.iccf"; // 設定ファイル
        readonly string CAMERA_FORMAT = "RGB32 (1920x1080)";    // 設定ファイル無い時の解像度
        readonly float FRAME_RATE = 40F;    // 設定ファイル無い時のFPS

        ICImagingControl _Cam;     // カメラオブジェクト
        string _SerialNumber;       // シリアル番号
        VCDButtonProperty _Trigger; // トリガー設定
        FrameRateCounter _Fps = new FrameRateCounter(10);     // フレームレート計測
        SinkListener _SinkListener = new SinkListener();
        FrameQueueSink _PreviewSink;
        FrameQueueSink _RecSink;
        IFrameQueueBuffer[] _bufferlist;

        public float FrameRate { get { return _Fps.FrameRate; } }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="cameraControl"></param>
        /// <param name="serialNumber"></param>
        public ISCamera(ICImagingControl cameraControl, string serialNumber) {
            _Cam = cameraControl;
            _SerialNumber = serialNumber;
        }

        /// <summary>
        /// カメラ接続とプレビュー開始
        /// </summary>
        /// <returns></returns>
        public bool Connect() {
            if (_Cam.DeviceValid) return true;

            // 接続
            _Cam.Device = _Cam.Devices.FirstOrDefault(
                c => c.GetSerialNumber().Equals(_SerialNumber));
            if (!_Cam.DeviceValid) return false;

            // 撮影条件設定
            try {
                if (File.Exists(ICCF_FILE)){
                    _Cam.LoadDeviceState(ICCFImport.Import(ICCF_FILE), false);
                    Debug.WriteLine($"Camera #{_SerialNumber} loaded config {ICCF_FILE}");
                } else {
                    //Debug.WriteLine($"Can't find config {ICCF_FILE}");
                    _Cam.VideoFormat = _Cam.VideoFormats.FirstOrDefault(
                        c => c.Name.Equals(CAMERA_FORMAT));
                    _Cam.DeviceFrameRate = _Cam.DeviceFrameRates.FirstOrDefault(
                        c => (c > FRAME_RATE - 0.1F && c < FRAME_RATE + 0.1F));
                    Debug.WriteLine($"Camera #{_SerialNumber} sets {_Cam.VideoFormat}, {_Cam.DeviceFrameRate:0.0}fps");
                }
            } catch (ICException iex) {
                MessageBox.Show(iex.Message, "Camera Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return false;
            }

            // 表示設定
            _Cam.LiveDisplayDefault = false;
            SetDisplaySize();
            _Cam.ImageRingBufferSize = 5;
            _Trigger = _Cam.VCDPropertyItems.Find<VCDButtonProperty>(
                VCDGUIDs.VCDID_TriggerMode, VCDGUIDs.VCDElement_SoftwareTrigger);
            _RecSink = new FrameQueueSink(_SinkListener, MediaSubtypes.RGB32);
            _PreviewSink = new FrameQueueSink(CaptureFrame, MediaSubtypes.RGB32, 5);
            _Cam.Sink = _PreviewSink;

            _Cam.LiveStart();

            return true;
        }

        /// <summary>
        /// Sink変更
        /// </summary>
        /// <param name="isRec">true:録画 false:プレビュー</param>
        public void ChangeSink(bool isRec) {
            _Cam.LiveStop();
            if (isRec) _Cam.Sink = _RecSink;
            else _Cam.Sink = _PreviewSink;
            _Cam.LiveStart();
        }

        /// <summary>
        /// 録画
        /// </summary>
        public void RecordToMemory() {
            Debug.WriteLine($"Cam {_SerialNumber} starts recoding.");
            var framesToCapture = 30;
            _RecSink.AllocAndQueueBuffers(framesToCapture);
            while (true) {
                if (framesToCapture <= _RecSink.OutputQueueSize + 1) break;
            }
            _bufferlist = _RecSink.PopAllOutputQueueBuffers();
            Debug.WriteLine($"Cam {_SerialNumber} buffersize {_bufferlist.Length}.");

            for (int i = 0; i < _bufferlist.Length; i++) {

                //デバイスが生成したフレーム番号が格納されます。
                string strFrameNumber = _bufferlist[i].FrameMetadata.DeviceFrameNumber.ToString();

                //(有効な場合)デバイスのタイムスタンプが格納されます。
                // デバイス固有のタイムソースによるタイムスタンプです。
                string strDeviceTimeStamp = _bufferlist[i].FrameMetadata.DeviceTimeStamp.ToString();

                //このフレームの最初のパケットをドライバが受信した時刻が格納されます。
                string strSampleStartTime = _bufferlist[i].FrameMetadata.DriverFrameFirstPacketTime.ToString(@"hhmmss\.fff");

                //ドライバがこのフレームに与えたフレーム番号が格納されます。
                string strDriverFrameNumber = _bufferlist[i].FrameMetadata.DriverFrameNumber.ToString();

                var fileName = $"Cam{_SerialNumber.Substring(_SerialNumber.Length-2)}_" + strSampleStartTime + ".jpg";
                TIS.Imaging.FrameExtensions.SaveAsJpeg(_bufferlist[i], fileName, 80);
            }

            _bufferlist = null;
            GC.Collect();

            Debug.WriteLine($"Cam {_SerialNumber} ends recoding.");
        }

        /// <summary>
        /// 表示サイズ設定
        /// </summary>
        public void SetDisplaySize() {
            if (!_Cam.DeviceValid) return;

            var vf = _Cam.VideoFormatCurrent;
            if (vf.Height * _Cam.Width < vf.Width * _Cam.Height) {
                _Cam.LiveDisplayLeft = 0;
                _Cam.LiveDisplayWidth = _Cam.Width;
                var h = vf.Height * _Cam.Width / vf.Width;
                _Cam.LiveDisplayTop = (_Cam.Height - h) / 2;
                _Cam.LiveDisplayHeight = h;
            } else {
                _Cam.LiveDisplayTop = 0;
                _Cam.LiveDisplayHeight = _Cam.Width;
                var w = vf.Width * _Cam.Height / vf.Height;
                _Cam.LiveDisplayLeft = (_Cam.Width - w) / 2;
                _Cam.LiveDisplayWidth = w;
            }
        }

        /// <summary>
        /// フレーム取得時
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        private FrameQueuedResult CaptureFrame(IFrameQueueBuffer buffer) {
            _Fps.Shot();
            return FrameQueuedResult.ReQueue;
        }

        /// <summary>
        /// トリガーモード変更
        /// </summary>
        /// <param name="enable"></param>
        public void SetTriggerMode(bool enable) {
            _Cam.LiveStop();
            _Cam.DeviceTrigger = enable;
            _Cam.LiveStart();
        }

        /// <summary>
        /// ソフトウェアトリガー発信
        /// </summary>
        public void SWTrigger() {
            if (_Cam.DeviceValid && _Trigger != null) _Trigger.Push();
        }

        /// <summary>
        /// プロパティ設定(ダイアログ)
        /// </summary>
        /// <returns></returns>
        public string SetProperty() {
            if (!_Cam.DeviceValid) return "";
            _Cam.ShowPropertyDialog();
            return _Cam.SaveDeviceState();
        }

        /// <summary>
        /// プロパティ設定(条件指定)
        /// </summary>
        /// <param name="config"></param>
        /// <returns></returns>
        public string SetProperty(string config) {
            if (!_Cam.DeviceValid) return "";
            _Cam.LiveStop();
            _Cam.LoadDeviceState(config, false);
            _Cam.LiveStart();
            return config;
        }

        /// <summary>
        /// カメラ情報文字列
        /// </summary>
        /// <returns></returns>
        public string CameraInfo() {
            return $"({_SerialNumber}) {_Fps.FrameRate:0.0}fps";
        }

        /// <summary>
        /// 1秒録画に要するメモリ量
        /// </summary>
        /// <returns></returns>
        public float MemoryFor1SecRecoding() {
            if (!_Cam.DeviceValid) return 0;
            var vf = _Cam.VideoFormatCurrent;
            int frameSize = vf.BitsPerPixel / 8 * vf.Width * vf.Height;
            int bcs = 1024 * 1024;
            return _Fps.FrameRate * frameSize / bcs;
        }
    }
}