diff --git a/TIASshot/Form1.Designer.cs b/TIASshot/Form1.Designer.cs index f9252c3..3c2230f 100644 --- a/TIASshot/Form1.Designer.cs +++ b/TIASshot/Form1.Designer.cs @@ -23,26 +23,29 @@ /// コード エディターで変更しないでください。 /// private void InitializeComponent() { - this.button1 = new System.Windows.Forms.Button(); + this.btnShotOne = new System.Windows.Forms.Button(); this.label1 = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label(); this.txtDeviceName = new System.Windows.Forms.TextBox(); this.txtSerialNo = new System.Windows.Forms.TextBox(); this.picPreview = new System.Windows.Forms.PictureBox(); this.picDisplay = new System.Windows.Forms.PictureBox(); + this.btnShotMulti = new System.Windows.Forms.Button(); + this.btnCalib = new System.Windows.Forms.Button(); + this.btnCheck = new System.Windows.Forms.Button(); ((System.ComponentModel.ISupportInitialize)(this.picPreview)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.picDisplay)).BeginInit(); this.SuspendLayout(); // - // button1 + // btnShotOne // - this.button1.Location = new System.Drawing.Point(12, 76); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(110, 37); - this.button1.TabIndex = 0; - this.button1.Text = "button1"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); + this.btnShotOne.Location = new System.Drawing.Point(12, 117); + this.btnShotOne.Name = "btnShotOne"; + this.btnShotOne.Size = new System.Drawing.Size(111, 37); + this.btnShotOne.TabIndex = 0; + this.btnShotOne.Text = "1枚撮影"; + this.btnShotOne.UseVisualStyleBackColor = true; + this.btnShotOne.Click += new System.EventHandler(this.btnShot1_Click); // // label1 // @@ -80,9 +83,9 @@ // // picPreview // - this.picPreview.Location = new System.Drawing.Point(14, 129); + this.picPreview.Location = new System.Drawing.Point(15, 302); this.picPreview.Name = "picPreview"; - this.picPreview.Size = new System.Drawing.Size(115, 85); + this.picPreview.Size = new System.Drawing.Size(108, 57); this.picPreview.TabIndex = 4; this.picPreview.TabStop = false; this.picPreview.Visible = false; @@ -99,18 +102,54 @@ this.picDisplay.TabIndex = 5; this.picDisplay.TabStop = false; // + // btnShotMulti + // + this.btnShotMulti.AllowDrop = true; + this.btnShotMulti.Location = new System.Drawing.Point(12, 160); + this.btnShotMulti.Name = "btnShotMulti"; + this.btnShotMulti.Size = new System.Drawing.Size(111, 37); + this.btnShotMulti.TabIndex = 6; + this.btnShotMulti.Text = "連続撮影"; + this.btnShotMulti.UseVisualStyleBackColor = true; + this.btnShotMulti.Click += new System.EventHandler(this.btnShotMulti_Click); + // + // btnCalib + // + this.btnCalib.AllowDrop = true; + this.btnCalib.Location = new System.Drawing.Point(12, 74); + this.btnCalib.Name = "btnCalib"; + this.btnCalib.Size = new System.Drawing.Size(111, 37); + this.btnCalib.TabIndex = 7; + this.btnCalib.Text = "校正"; + this.btnCalib.UseVisualStyleBackColor = true; + this.btnCalib.Click += new System.EventHandler(this.btnCalib_Click); + // + // btnCheck + // + this.btnCheck.AllowDrop = true; + this.btnCheck.Location = new System.Drawing.Point(12, 226); + this.btnCheck.Name = "btnCheck"; + this.btnCheck.Size = new System.Drawing.Size(111, 37); + this.btnCheck.TabIndex = 8; + this.btnCheck.Text = "チェック"; + this.btnCheck.UseVisualStyleBackColor = true; + this.btnCheck.Click += new System.EventHandler(this.btnCheck_Click); + // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(644, 377); + this.Controls.Add(this.btnCheck); + this.Controls.Add(this.btnCalib); + this.Controls.Add(this.btnShotMulti); this.Controls.Add(this.picDisplay); this.Controls.Add(this.picPreview); this.Controls.Add(this.txtSerialNo); this.Controls.Add(this.txtDeviceName); this.Controls.Add(this.label2); this.Controls.Add(this.label1); - this.Controls.Add(this.button1); + this.Controls.Add(this.btnShotOne); this.Name = "Form1"; this.Text = "Form1"; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing); @@ -124,13 +163,16 @@ #endregion - private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button btnShotOne; private System.Windows.Forms.Label label1; private System.Windows.Forms.Label label2; private System.Windows.Forms.TextBox txtDeviceName; private System.Windows.Forms.TextBox txtSerialNo; private System.Windows.Forms.PictureBox picPreview; private System.Windows.Forms.PictureBox picDisplay; + private System.Windows.Forms.Button btnShotMulti; + private System.Windows.Forms.Button btnCalib; + private System.Windows.Forms.Button btnCheck; } } diff --git a/TIASshot/Form1.cs b/TIASshot/Form1.cs index da7b418..31d52af 100644 --- a/TIASshot/Form1.cs +++ b/TIASshot/Form1.cs @@ -21,7 +21,7 @@ public Form1() { InitializeComponent(); - _lucam = new Lucam(picPreview, picDisplay); + _lucam = new Lucam(this, picPreview, picDisplay); var version = Assembly.GetExecutingAssembly().GetName().Version; Text = $"{APP_NAME} ver.{version.Major}.{version.Minor}"; @@ -30,10 +30,6 @@ #endif } - private void button1_Click(object sender, EventArgs e) { - - } - /// /// フォームロード /// @@ -41,9 +37,10 @@ /// private void Form1_Load(object sender, EventArgs e) { if (!_lucam.Connect()) { - MessageBox.Show("カメラが見つかりません.\r\n終了します.", APP_NAME, + MessageBox.Show(_lucam.ErrorMsg, APP_NAME, MessageBoxButtons.OK, MessageBoxIcon.Warning); Close(); + return; } txtDeviceName.Text = _lucam.DeviceName; txtSerialNo.Text = _lucam.SerialNumber; @@ -58,5 +55,41 @@ private void Form1_FormClosing(object sender, FormClosingEventArgs e) { _lucam.Disconnect(); } + + /// + /// 画像撮影1枚 + /// + /// + /// + private void btnShot1_Click(object sender, EventArgs e) { + _lucam.ShotOne(); + } + + /// + /// 複数画像撮影 + /// + /// + /// + private void btnShotMulti_Click(object sender, EventArgs e) { + _lucam.ShotMulti(); + } + + /// + /// 校正 + /// + /// + /// + private void btnCalib_Click(object sender, EventArgs e) { + _lucam.Calibration(); + } + + /// + /// 動作チェックボタン + /// + /// + /// + private void btnCheck_Click(object sender, EventArgs e) { + _lucam.Check(); + } } } diff --git a/TIASshot/Lucam.cs b/TIASshot/Lucam.cs index f5aafac..148b2c0 100644 --- a/TIASshot/Lucam.cs +++ b/TIASshot/Lucam.cs @@ -10,6 +10,9 @@ using OpenCvSharp.Extensions; using System.Drawing; using System.Windows.Interop; +using System.Threading; +using OpenCvSharp.Dnn; +using System.Windows.Media.Animation; namespace TIASshot { @@ -20,13 +23,19 @@ public string DeviceName { get; private set; } = "Unknown"; public string SerialNumber { get; private set; } + public string ErrorMsg { get; private set; } private IntPtr _hCam = IntPtr.Zero; private PictureBox _picPreview, _picDisplay; + private Form1 _form; private bool _isPreview = false; + private bool _check = false; + private int _calibrating = 0; + private dll.LucamSnapshot _snap; + private dll.LucamConversion _convert; private dll.LucamRgbPreviewCallback _callbackHandler; private int _callbackId; - private int _count = 0; + //private int _count = 0; private Bitmap[] _bmps = new Bitmap[2]; private int _bmpIndex = 0; @@ -35,9 +44,42 @@ /// /// /// - public Lucam(PictureBox preview, PictureBox display) { + public Lucam(Form1 form, PictureBox preview, PictureBox display) { _picPreview = preview; _picDisplay = display; + _form = form; + + // Default value for taking a snapshot. + _snap.BufferLastFrame = false; + _snap.Exposure = 20; + _snap.ExposureDelay = 0; + _snap.flReserved1 = 0; + _snap.flReserved2 = 0; + _snap.Format.BinningX = 1; + _snap.Format.BinningY = 1; + _snap.Format.FlagsX = 0; + _snap.Format.FlagsY = 0; + _snap.Format.Height = 1024; + _snap.Format.PixelFormat = dll.LucamPixelFormat.PF_8; + _snap.Format.SubSampleX = 1; + _snap.Format.SubSampleY = 1; + _snap.Format.Width = 1280; + _snap.Format.X = 0; + _snap.Format.Y = 0; + _snap.Gain = 2.0f; + _snap.GainBlue = 1; + _snap.GainGrn1 = 1; + _snap.GainGrn2 = 1; + _snap.GainRed = 1; + _snap.ShutterType = dll.LucamShutterType.GlobalShutter; + _snap.StrobeDelay = 0.1f; + _snap.StrobeFlags = 0; + _snap.Timeout = 5000; + _snap.ulReserved2 = 0; + _snap.UseHwTrigger = false; + + _convert.DemosaicMethod = dll.LucamDemosaicMethod.HIGH_QUALITY; + _convert.CorrectionMatrix = dll.LucamCorrectionMatrix.LED; } /// @@ -47,6 +89,11 @@ public bool Connect() { var numCam = dll.LucamNumCameras(); if ( numCam < 1 ) { + ErrorMsg = "カメラが見つかりません.\r\n終了します."; + return false; + } + if (numCam > 1) { + ErrorMsg = "複数のカメラが見つかりました.\r\n正しいカメラを1つ接続してください.\r\n終了します."; return false; } @@ -64,7 +111,7 @@ _callbackHandler = new dll.LucamRgbPreviewCallback(PreviewCallback); _callbackId = dll.LucamAddRgbPreviewCallback(_hCam, _callbackHandler, IntPtr.Zero, dll.LucamPixelFormat.PF_24); if (_callbackId == -1) { - MessageBox.Show("Cannot add rgb preview callback, fail to start preview"); + ErrorMsg = "コールバックの登録に失敗しました.\r\n終了します."; return false; } @@ -77,7 +124,10 @@ /// public bool StartStopPreview() { if (_isPreview) { + //dll.LucamRemoveRgbPreviewCallback(_hCam, _callbackId); + //Debug.WriteLine("CB解除"); var ret = dll.LucamStreamVideoControl(_hCam, dll.LucamStreamMode.STOP_STREAMING, _picPreview.Handle.ToInt32()); + Debug.WriteLine("プレビュー停止"); if (!ret) { return false; } @@ -116,24 +166,151 @@ using (Mat img = Mat.FromPixelData(1024, 1280, MatType.CV_8UC3, pData)) { using (Mat imgt = img.T()) { _bmps[_bmpIndex] = imgt.ToBitmap(); + + Scalar m; + using (Mat mask = new Mat(imgt.Size(), MatType.CV_8UC1)) { + Cv2.Rectangle(mask, new Rect(300, 165, 100, 100), new Scalar(255), Cv2.FILLED); + m = Cv2.Mean(imgt, mask); + } + if (_check || _calibrating > 0) { + Debug.WriteLine(m); + _check = false; + } + + if (_calibrating > 0 && _calibrating % 5 == 0) { + float target = 230; + float rate = 0.5F; + float mb = target / (float)m.Val0; + float mg = target / (float)m.Val1; + float mr = target / (float)m.Val2; + mb = (mb - 1.0F) * (m.Val0 > 254 ? 1.0F : rate) + 1.0F; + mg = (mg - 1.0F) * (m.Val1 > 254 ? 1.0F : rate) + 1.0F; + mr = (mr - 1.0F) * (m.Val2 > 254 ? 1.0F : rate) + 1.0F; + float value; + dll.LucamPropertyFlag flag; + dll.LucamGetProperty(_hCam, dll.LucamProperty.GAIN_BLUE, out value, out flag); + Debug.WriteLine($"Gain Blue {value} * {mb} -> {value * mb} ({flag})"); + value *= mb; + dll.LucamSetProperty(_hCam, dll.LucamProperty.GAIN_BLUE, value, flag); + dll.LucamGetProperty(_hCam, dll.LucamProperty.GAIN_GREEN1, out value, out flag); + Debug.WriteLine($"Gain Green1 {value} * {mg} -> {value * mg}"); + value *= mg; + dll.LucamSetProperty(_hCam, dll.LucamProperty.GAIN_GREEN1, value, flag); + dll.LucamGetProperty(_hCam, dll.LucamProperty.GAIN_GREEN2, out value, out flag); + Debug.WriteLine($"Gain Green2 {value} * {mg} -> {value * mg}"); + value *= mg; + dll.LucamSetProperty(_hCam, dll.LucamProperty.GAIN_GREEN2, value, flag); + dll.LucamGetProperty(_hCam, dll.LucamProperty.GAIN_RED, out value, out flag); + Debug.WriteLine($"Gain Red {value} * {mr} -> {value * mr}"); + value *= mr; + dll.LucamSetProperty(_hCam, dll.LucamProperty.GAIN_RED, value, flag); + } + if (_calibrating > 0) _calibrating--; } } - SafeDisplay(); - //_picDisplay.Image = _bmps[_bmpIndex]; + //SafeDisplay(); + _picDisplay.Image = _bmps[_bmpIndex]; _bmpIndex = (_bmpIndex + 1) % 2; if (_bmps[_bmpIndex] != null) _bmps[_bmpIndex].Dispose(); } /// + /// 画像撮影1枚 + /// + public void ShotOne() { + Shot(); + } + + /// + /// 複数画像撮影 + /// + public void ShotMulti() { + Shot(5, 1000); + } + + /// + /// 撮影 + /// + /// + /// + private void Shot(int numImages=1, int interval = 1000) { + SetSnapParam(); + dll.LucamEnableFastFrames(_hCam, ref _snap); + var imageSize = _snap.Format.Width * _snap.Format.Height; + var rawImage = new byte[imageSize]; + var rgbImage = new byte[imageSize * 3]; + for (var i = 0; i < numImages; i++) { + var ret = dll.LucamTakeFastFrame(_hCam, rawImage); + //Debug.WriteLine(ret); + if (i < numImages - 1) Thread.Sleep(interval); + + dll.LucamConvertFrameToRgb24(_hCam, rgbImage, rawImage, _snap.Format.Width, _snap.Format.Height, dll.LucamPixelFormat.PF_8, ref _convert); + using (Mat img = Mat.FromPixelData(1024, 1280, MatType.CV_8UC3, rgbImage)) { + Cv2.ImWrite($"orig_{i:00}.jpg", img); + using (Mat imgt = img.T()) { + Cv2.ImWrite($"snap_{i:00}.jpg", imgt); + } + } + } + rgbImage = null; + rawImage = null; + + dll.LucamDisableFastFrames(_hCam); + } + + public void Calibration() { + Debug.WriteLine("校正前"); + SetSnapParam(); + + dll.LucamOneShotAutoExposure(_hCam, 150, 0, 0, _snap.Format.Width, _snap.Format.Height); + //dll.LucamOneShotAutoExposure(_hCam, 100, 165, 300, 100, 100); + //Thread.Sleep(1000); + //dll.LucamOneShotAutoExposure(_hCam, 200, 165, 300, 100, 100); + //Thread.Sleep(1000); + //dll.LucamOneShotAutoExposure(_hCam, 200, 165, 300, 100, 100); + dll.LucamOneShotAutoWhiteBalance(_hCam, 0, 0, _snap.Format.Width, _snap.Format.Height); + //dll.LucamOneShotAutoWhiteBalance(_hCam, 165, 300, 100, 100); + + Debug.WriteLine("校正後"); + SetSnapParam(); + + _calibrating = 30; + } + + private void SetSnapParam() { + dll.LucamPropertyFlag flag; + float value = 0; + dll.LucamGetProperty(_hCam, dll.LucamProperty.EXPOSURE, out value, out flag); + _snap.Exposure = value; + dll.LucamGetProperty(_hCam, dll.LucamProperty.GAIN, out value, out flag); + _snap.Gain = value; + dll.LucamGetProperty(_hCam, dll.LucamProperty.GAIN_BLUE, out value, out flag); + _snap.GainBlue = value; + dll.LucamGetProperty(_hCam, dll.LucamProperty.GAIN_GREEN1, out value, out flag); + _snap.GainGrn1 = value; + dll.LucamGetProperty(_hCam, dll.LucamProperty.GAIN_GREEN2, out value, out flag); + _snap.GainGrn2 = value; + dll.LucamGetProperty(_hCam, dll.LucamProperty.GAIN_RED, out value, out flag); + _snap.GainRed = value; + Debug.WriteLine($"Exp {_snap.Exposure} Gain {_snap.Gain} GainBlue {_snap.GainBlue} GainGrn1 {_snap.GainGrn1} GainGrn2 {_snap.GainGrn2} GainRed {_snap.GainRed}"); + } + + public void Check() { + _check = true; + } + + /// /// カメラ切断 /// public void Disconnect() { - if (_isPreview) { - StartStopPreview(); + if (_hCam != IntPtr.Zero) { + if (_isPreview) { + StartStopPreview(); + } + api.CameraClose(_hCam); + _hCam = IntPtr.Zero; + Debug.WriteLine("カメラ切断"); } - Debug.WriteLine("カメラ切断"); - api.CameraClose(_hCam); - _hCam = IntPtr.Zero; } } }