Newer
Older
TIASShot / TIASshot / Cameras / IScam.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using TIS.Imaging;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using System.Diagnostics;
using System.Drawing;
using System.Threading;
using System.IO;

namespace TIASshot {
    internal class IScam : CameraBase {
        ICImagingControl _ic;
        VCDRangeProperty _brightness;
        VCDRangeProperty _gain;
        VCDRangeProperty _exposure;
        VCDRangeProperty _gamma;
        VCDRangeProperty _whiteBalanceBlue;
        VCDRangeProperty _whiteBalanceGreen;
        VCDRangeProperty _whiteBalanceRed;
        FrameQueueSink _queueSink;
        FrameSnapSink _snapSink;
        FrameSnapSink _snapSinkRef;

        /// <summary>
        /// IScamコンストラクタ
        /// </summary>
        /// <param name="form"></param>
        /// <param name="ic"></param>
        public IScam(Form1 form, ICImagingControl ic, string deviceName) : base(form) {
            _ic = ic;
            DeviceName = deviceName;
        }

        /// <summary>
        /// IScam接続
        /// </summary>
        /// <returns></returns>
        public override bool Connect() {
            if (!BootCheck()) return false;

            var configFile = $"{DeviceName}.xml";
            if (!File.Exists(configFile)) {
                ErrorMsg = $"{configFile}が見つかりません";
                return false;
            }
            _ic.LoadDeviceStateFromFile(configFile, true);
            if (!_ic.DeviceValid) {
                ErrorMsg = $"設定ファイル{configFile}の読み込みに失敗しました";
                return false;
            }
            //if (!_ic.LoadShowSaveDeviceState(configFile)) {
            //    return false;
            //}
            _roi = new Rect(
                Config.GetInt($"{DeviceName}/ROI/X"),
                Config.GetInt($"{DeviceName}/ROI/Y"),
                Config.GetInt($"{DeviceName}/ROI/W"),
                Config.GetInt($"{DeviceName}/ROI/H"));

            _queueSink = new FrameQueueSink(Retrieve, MediaSubtypes.RGB24, 5);
            _snapSink = new FrameSnapSink(MediaSubtypes.RGB24);
            _ic.Sink = _queueSink;
            DeviceName = _ic.DeviceCurrent.Name;
            SetInfo("カメラ型番", DeviceName);
            SerialNumber = _ic.DeviceCurrent.GetSerialNumber();
            SetInfo("カメラSN", SerialNumber);
            _brightness = _ic.VCDPropertyItems.Find<VCDRangeProperty>(VCDGUIDs.VCDID_Brightness, VCDGUIDs.VCDElement_Value);
            _gain = _ic.VCDPropertyItems.Find<VCDRangeProperty>(VCDGUIDs.VCDID_Gain, VCDGUIDs.VCDElement_Value);
            _exposure = _ic.VCDPropertyItems.Find<VCDRangeProperty>(VCDGUIDs.VCDID_Exposure, VCDGUIDs.VCDElement_Value);
            _gamma = _ic.VCDPropertyItems.Find<VCDRangeProperty>(VCDGUIDs.VCDID_Gamma, VCDGUIDs.VCDElement_Value);
            _whiteBalanceBlue = _ic.VCDPropertyItems.Find<VCDRangeProperty>(VCDGUIDs.VCDID_WhiteBalance, VCDGUIDs.VCDElement_WhiteBalanceBlue);
            _whiteBalanceGreen = _ic.VCDPropertyItems.Find<VCDRangeProperty>(VCDGUIDs.VCDID_WhiteBalance, VCDGUIDs.VCDElement_WhiteBalanceGreen);
            _whiteBalanceRed = _ic.VCDPropertyItems.Find<VCDRangeProperty>(VCDGUIDs.VCDID_WhiteBalance, VCDGUIDs.VCDElement_WhiteBalanceRed);
            Debug.WriteLine($"Exposure range: {_exposure.RangeMin} to {_exposure.RangeMax}  value={_exposure.Value}" );
            Debug.WriteLine($"Gain range: {_gain.RangeMin} to {_gain.RangeMax}  value={_gain.Value}");
            Debug.WriteLine($"Brightness range: {_brightness.RangeMin} to {_brightness.RangeMax}  value={_brightness.Value}");
            Debug.WriteLine($"Gamma range: {_gamma.RangeMin} to {_gamma.RangeMax}  value={_gamma.Value}");
            Debug.WriteLine($"White Balance Blue range: {_whiteBalanceBlue.RangeMin} to {_whiteBalanceBlue.RangeMax}  value={_whiteBalanceBlue.Value}");
            Debug.WriteLine($"White Balance Green range: {_whiteBalanceGreen.RangeMin} to {_whiteBalanceGreen.RangeMax}  value={_whiteBalanceGreen.Value}");
            Debug.WriteLine($"White Balance Red range: {_whiteBalanceRed.RangeMin} to {_whiteBalanceRed.RangeMax}  value={_whiteBalanceRed.Value}");

            _ic.LiveStart();
            return true;
        }

        /// <summary>
        /// IScam切断
        /// </summary>
        public override void Disconnect() {
            _ic.LiveStop();
        }

        /// <summary>
        /// フレーム取得処理
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        private FrameQueuedResult Retrieve(IFrameQueueBuffer buffer) {
            var frameType = buffer.FrameType;

            using (Mat img = Mat.FromPixelData(frameType.Height, frameType.Width, MatType.CV_8UC3, buffer.GetIntPtr())) {
                using (Mat imgt_full = img.T()) {
                    using (var imgt = new Mat(imgt_full, _roi)) {
                        _form.ShowImage(imgt.ToBitmap());
                        ProcessCalibrationFrame(imgt);
                    }
                }
            }

            return FrameQueuedResult.ReQueue;
        }

        /// <summary>
        /// ゲイン/ホワイトバランスの反映(IScam 固有)
        /// </summary>
        /// <param name="whitePatch">白パッチの計測値</param>
        protected override void ApplyWhiteBalance(Scalar whitePatch) {
            _whiteBalanceBlue.Value = (int)(0.5 + _whiteBalanceBlue.Value * GetRatio((float)whitePatch.Val0, Config.GetFloat("Calib/Reference/B")));
            _whiteBalanceGreen.Value = (int)(0.5 + _whiteBalanceGreen.Value * GetRatio((float)whitePatch.Val1, Config.GetFloat("Calib/Reference/G")));
            _whiteBalanceRed.Value = (int)(0.5 + _whiteBalanceRed.Value * GetRatio((float)whitePatch.Val2, Config.GetFloat("Calib/Reference/R")));
        }

        /// <summary>
        /// 校正収束時のホワイトバランス値ログ出力(IScam 固有)
        /// CalcTcc の前に呼ばれ,元コードの Debug.WriteLine 順序を再現する.
        /// </summary>
        protected override void LogCalibrationConverged() {
            Debug.WriteLine($"White Balance Blue range: {_whiteBalanceBlue.RangeMin} to {_whiteBalanceBlue.RangeMax}  value={_whiteBalanceBlue.Value}");
            Debug.WriteLine($"White Balance Green range: {_whiteBalanceGreen.RangeMin} to {_whiteBalanceGreen.RangeMax}  value={_whiteBalanceGreen.Value}");
            Debug.WriteLine($"White Balance Red range: {_whiteBalanceRed.RangeMin} to {_whiteBalanceRed.RangeMax}  value={_whiteBalanceRed.Value}");
        }

        /// <summary>
        /// 校正完了時のカメラ情報記録(IScam 固有)
        /// CalcTcc の後に呼ばれ,SetInfo で各値を保存する.
        /// </summary>
        /// <param name="imgt">処理対象 Mat</param>
        protected override void RecordCalibrationInfo(Mat imgt) {
            SetInfo("Exposure(ms)", $"{(float)_exposure.Value / 10}");
            SetInfo("Brightness", $"{_brightness.Value}");
            SetInfo("Gamma", $"{_gamma.Value}");
            SetInfo("Gain", $"{_gain.Value}");
            SetInfo("Gain B", $"{_whiteBalanceBlue.Value}");
            SetInfo("Gain G", $"{_whiteBalanceGreen.Value}");
            SetInfo("Gain R", $"{_whiteBalanceRed.Value}");
            SetInfo("画像幅", $"{imgt.Width}");
            SetInfo("画像高さ", $"{imgt.Height}");
        }

        /// <summary>
        /// 撮影
        /// </summary>
        /// <param name="numImages"></param>
        /// <param name="interval"></param>
        protected override void Shot(int numImages = 1, int interval = 0) {
            _ic.LiveStop();
            _ic.Sink = _snapSink;
            _ic.LiveStart();
            _snapSinkRef = _ic.Sink as FrameSnapSink;

            _shots.Clear();
            _snapSinkRef.SnapSingle(TimeSpan.FromSeconds(5));   // 最初のフレームを捨てる

            var thread = new Thread(() => SaveThread(numImages));
            thread.Start();

            RunShotLoop(numImages, interval);

            _ic.LiveStop();
            _ic.Sink = _queueSink;
            _ic.LiveStart();
        }

        /// <summary>
        /// 撮影開始処理(IScam 固有): Shot 内でインライン実行済みのため空実装
        /// </summary>
        protected override void BeginShot() { }

        /// <summary>
        /// 1 フレーム取得(IScam 固有)
        /// </summary>
        /// <returns>撮影した Mat(呼び出し元が _shots に追加する)</returns>
        protected override Mat CaptureFrame() {
            var buffer = _snapSinkRef.SnapSingle(TimeSpan.FromSeconds(5));
            using (Mat img = Mat.FromPixelData(buffer.FrameType.Height, buffer.FrameType.Width, MatType.CV_8UC3, buffer.GetIntPtr())) {
                using (Mat imgt_full = img.T()) {
                    return new Mat(imgt_full, _roi);
                }
            }
        }

        /// <summary>
        /// 撮影終了処理(IScam 固有): Shot 内でインライン実行済みのため空実装
        /// </summary>
        protected override void EndShot() { }
    }
}