diff --git a/TIASshot/Config.cs b/TIASshot/Config.cs
index bbbdd92..6a79cc4 100644
--- a/TIASshot/Config.cs
+++ b/TIASshot/Config.cs
@@ -61,5 +61,15 @@
}
return value;
}
+
+ ///
+ /// 設定ファイルから文字列を取得
+ ///
+ ///
+ ///
+ public static string GetString(string param) {
+ XmlNode node = doc.SelectSingleNode($"//Config/{param}");
+ return node?.InnerText ?? "";
+ }
}
}
diff --git a/TIASshot/Form1.Designer.cs b/TIASshot/Form1.Designer.cs
index 8218abe..f48df48 100644
--- a/TIASshot/Form1.Designer.cs
+++ b/TIASshot/Form1.Designer.cs
@@ -32,8 +32,9 @@
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();
this.txtMessage = new System.Windows.Forms.TextBox();
+ this.txtSaveFolder = new System.Windows.Forms.TextBox();
+ this.label3 = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.picPreview)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.picDisplay)).BeginInit();
this.SuspendLayout();
@@ -88,9 +89,9 @@
//
// picPreview
//
- this.picPreview.Location = new System.Drawing.Point(15, 377);
+ this.picPreview.Location = new System.Drawing.Point(12, 565);
this.picPreview.Name = "picPreview";
- this.picPreview.Size = new System.Drawing.Size(108, 57);
+ this.picPreview.Size = new System.Drawing.Size(79, 57);
this.picPreview.TabIndex = 4;
this.picPreview.TabStop = false;
this.picPreview.Visible = false;
@@ -102,7 +103,7 @@
| System.Windows.Forms.AnchorStyles.Right)));
this.picDisplay.Location = new System.Drawing.Point(292, 6);
this.picDisplay.Name = "picDisplay";
- this.picDisplay.Size = new System.Drawing.Size(340, 428);
+ this.picDisplay.Size = new System.Drawing.Size(449, 610);
this.picDisplay.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.picDisplay.TabIndex = 5;
this.picDisplay.TabStop = false;
@@ -121,27 +122,15 @@
// btnCalib
//
this.btnCalib.AllowDrop = true;
- this.btnCalib.Location = new System.Drawing.Point(15, 324);
+ this.btnCalib.Location = new System.Drawing.Point(100, 579);
this.btnCalib.Name = "btnCalib";
- this.btnCalib.Size = new System.Drawing.Size(111, 37);
+ this.btnCalib.Size = new System.Drawing.Size(88, 37);
this.btnCalib.TabIndex = 7;
this.btnCalib.Text = "校正";
this.btnCalib.UseVisualStyleBackColor = true;
this.btnCalib.Visible = false;
this.btnCalib.Click += new System.EventHandler(this.btnCalib_Click);
//
- // btnCheck
- //
- this.btnCheck.AllowDrop = true;
- this.btnCheck.Location = new System.Drawing.Point(144, 324);
- 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.Visible = false;
- this.btnCheck.Click += new System.EventHandler(this.btnCheck_Click);
- //
// txtMessage
//
this.txtMessage.BackColor = System.Drawing.Color.LemonChiffon;
@@ -153,13 +142,33 @@
this.txtMessage.TabIndex = 9;
this.txtMessage.Text = "舌診チャートを設置してください.";
//
+ // txtSaveFolder
+ //
+ this.txtSaveFolder.Font = new System.Drawing.Font("MS UI Gothic", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(128)));
+ this.txtSaveFolder.Location = new System.Drawing.Point(15, 459);
+ this.txtSaveFolder.Name = "txtSaveFolder";
+ this.txtSaveFolder.ReadOnly = true;
+ this.txtSaveFolder.Size = new System.Drawing.Size(268, 23);
+ this.txtSaveFolder.TabIndex = 10;
+ //
+ // label3
+ //
+ this.label3.AutoSize = true;
+ this.label3.Font = new System.Drawing.Font("MS UI Gothic", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(128)));
+ this.label3.Location = new System.Drawing.Point(12, 440);
+ this.label3.Name = "label3";
+ this.label3.Size = new System.Drawing.Size(123, 16);
+ this.label3.TabIndex = 11;
+ this.label3.Text = "データ保存フォルダ";
+ //
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
- this.ClientSize = new System.Drawing.Size(644, 452);
+ this.ClientSize = new System.Drawing.Size(753, 634);
+ this.Controls.Add(this.label3);
+ this.Controls.Add(this.txtSaveFolder);
this.Controls.Add(this.txtMessage);
- this.Controls.Add(this.btnCheck);
this.Controls.Add(this.btnCalib);
this.Controls.Add(this.btnShotMulti);
this.Controls.Add(this.picDisplay);
@@ -191,8 +200,9 @@
private System.Windows.Forms.PictureBox picDisplay;
private System.Windows.Forms.Button btnShotMulti;
private System.Windows.Forms.Button btnCalib;
- private System.Windows.Forms.Button btnCheck;
private System.Windows.Forms.TextBox txtMessage;
+ private System.Windows.Forms.TextBox txtSaveFolder;
+ private System.Windows.Forms.Label label3;
}
}
diff --git a/TIASshot/Form1.cs b/TIASshot/Form1.cs
index dc69258..d4d0d8a 100644
--- a/TIASshot/Form1.cs
+++ b/TIASshot/Form1.cs
@@ -9,6 +9,7 @@
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Interop;
+using System.Xml.Serialization;
namespace TIASshot {
public partial class Form1 : Form {
@@ -45,6 +46,7 @@
}
txtDeviceName.Text = _lucam.DeviceName;
txtSerialNo.Text = _lucam.SerialNumber;
+ txtSaveFolder.Text = Config.GetString("SaveFolder");
EnableShots(false);
_lucam.StartStopPreview();
}
@@ -86,15 +88,6 @@
}
///
- /// 動作チェックボタン
- ///
- ///
- ///
- private void btnCheck_Click(object sender, EventArgs e) {
- _lucam.Check();
- }
-
- ///
/// 画像表示
///
///
diff --git a/TIASshot/Lucam.cs b/TIASshot/Lucam.cs
index 985946e..3ad9af8 100644
--- a/TIASshot/Lucam.cs
+++ b/TIASshot/Lucam.cs
@@ -16,6 +16,8 @@
using System.Configuration;
using System.Web.ModelBinding;
using System.Windows.Controls;
+using System.IO;
+using static System.Resources.ResXFileRef;
namespace TIASshot {
@@ -29,20 +31,21 @@
public string ErrorMsg { get; private set; }
readonly Dictionary ARDict = CvAruco.GetPredefinedDictionary(PredefinedDictionaryName.Dict4X4_50);
- readonly float RefRGB;
- readonly float UpdateRate;
readonly Point2f[] PointsDst40 = new Point2f[] {
new Point2f(345, 130),new Point2f(465, 130),new Point2f(465, 250),new Point2f(345, 250),
};
readonly Point2f[] PointsDst41 = new Point2f[]{
new Point2f(345, 1200), new Point2f(465, 1200), new Point2f(465, 1320), new Point2f(345, 1320),
};
+ readonly float RefRGB;
+ readonly float UpdateRate;
+ readonly Mat TCC_SRGB;
IntPtr _hCam = IntPtr.Zero;
PictureBox _picPreview, _picDisplay;
Form1 _form;
bool _isPreview = false;
- bool _check = false;
+ //bool _check = false;
int _calibrating = 0;
bool _calibrated = false;
dll.LucamSnapshot _snap;
@@ -54,6 +57,7 @@
List _chartMasks = new List();
int _detectionCount = 0;
Point2f _lastPosition = new Point2f(0, 0);
+ Mat _convRGB2SRGB;
///
/// コンストラクタ
@@ -69,6 +73,8 @@
RefRGB = Config.GetFloat("ReferenceValue");
UpdateRate = Config.GetFloat("UpdateRate");
+ TCC_SRGB = LoadMatFromCsv(Config.GetString("TccTableCsvSrgb"));
+
// カメラパラメータの初期値
_snap.BufferLastFrame = false;
_snap.Exposure = Config.GetFloat("Exposure");
@@ -111,6 +117,10 @@
ErrorMsg = "設定ファイル(Config.xml)の読み込みに失敗しました.\r\n終了します.";
return false;
}
+ if (TCC_SRGB is null) {
+ ErrorMsg = $"ファイル({Config.GetString("TccTableCsvSrgb")})の読み込みに失敗しました.\r\n終了します.";
+ return false;
+ }
var numCam = dll.LucamNumCameras();
if ( numCam < 1 ) {
@@ -274,6 +284,7 @@
}
_calibrating--;
if (_calibrating == 0) {
+ _convRGB2SRGB = CalcConvertMatrix(imgt, TCC_SRGB);
_form.ShowMessage("自動校正完了");
_form.EnableShots();
_calibrated = true;
@@ -291,6 +302,44 @@
}
///
+ /// 変換行列算出
+ ///
+ /// 画像
+ /// 変換目標の24x3行列
+ private Mat CalcConvertMatrix(Mat img, Mat target) {
+ // 画像からチャートのRGB値算出
+ var arrRGB = new Mat(24, 3, MatType.CV_64FC1);
+ for (int i = 0; i < _chartMasks.Count; i++) {
+ var rgb = Cv2.Mean(img, _chartMasks[i]);
+ arrRGB.At(i, 0) = rgb.Val0;
+ arrRGB.At(i, 1) = rgb.Val1;
+ arrRGB.At(i, 2) = rgb.Val2;
+ }
+ var extended = ExtendMat(arrRGB);
+ //Debug.WriteLine("extended");
+ //Debug.WriteLine(extended.Dump());
+
+ // 変換行列算出
+ Mat convMat = new Mat(17, 3, MatType.CV_64FC1);
+ Cv2.Solve(extended, target, convMat, DecompTypes.SVD);
+ //Debug.WriteLine("convMat");
+ //Debug.WriteLine(convMat.Dump());
+
+ // 変換精度検証
+ var converted = extended * convMat;
+ //Debug.WriteLine("converted");
+ //Debug.WriteLine(converted.ToMat().Dump());
+
+ //Mat impSRGB = converted.ToMat().Reshape(3);
+ //Cv2.ImWrite("impSRGB.png", impSRGB);
+
+ var diff = Math.Sqrt(Cv2.Norm(target, converted, NormTypes.L2));
+ Debug.WriteLine($"変換行列の誤差 = {diff:.000}");
+
+ return convMat;
+ }
+
+ ///
/// 画像撮影1枚
///
public void ShotOne() {
@@ -318,16 +367,20 @@
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(_snap.Format.Height, _snap.Format.Width, MatType.CV_8UC3, rgbImage)) {
//Cv2.ImWrite($"orig_{i:00}.jpg", img);
using (Mat imgt = img.T()) {
- Cv2.ImWrite($"snap_{i:00}.jpg", imgt);
+ Cv2.ImWrite($"conv0_{i:00}.jpg", imgt);
+ using (var converted = ConvertImage(imgt, _convRGB2SRGB)) {
+ Cv2.ImWrite($"conv1_{i:00}.jpg", converted);
+ }
}
}
+
+ if (i < numImages - 1) Thread.Sleep(interval);
}
rgbImage = null;
rawImage = null;
@@ -373,10 +426,85 @@
}
///
- /// 動作チェック有効化
+ /// csvファイルからMatを読み込む
///
- public void Check() {
- _check = true;
+ ///
+ ///
+ ///
+ private Mat LoadMatFromCsv(string csvFile) {
+ try {
+ var arr = new List();
+ int cols = -1;
+ using (var reader = new StreamReader(csvFile)) {
+ while (!reader.EndOfStream) {
+ var line = reader.ReadLine();
+ var valStrs = line.Split(',');
+ if (cols == -1) cols = valStrs.Length;
+ else if (cols != valStrs.Length) throw new Exception("cols != valStrs.Length");
+ var vals = valStrs.Select(x => double.Parse(x)).ToArray();
+ arr.Add(vals);
+ }
+ }
+ var m = new Mat(arr.Count, cols, MatType.CV_64FC1);
+ for (var row = 0; row < arr.Count; row++) {
+ for (var col = 0; col < cols; col++) {
+ m.At(row, col) = arr[row][col];
+ }
+ }
+ return m;
+ } catch (Exception) {
+ return null;
+ }
+ }
+
+ ///
+ /// 画像の色変換
+ ///
+ ///
+ ///
+ /// double型画像
+ private Mat ConvertImage(Mat src, Mat conv) {
+ if (src.Type() != MatType.CV_64FC3) {
+ src.ConvertTo(src, MatType.CV_64FC3);
+ }
+ var flatten = src.Reshape(3, src.Height * src.Width);
+ var extended = ExtendMat(flatten);
+ var converted = (extended * conv).ToMat();
+ var convertedImage = converted.Reshape(3, src.Height);
+ return convertedImage;
+ }
+
+ ///
+ /// 行列の拡張 3次元→17次元
+ ///
+ ///
+ ///
+ private Mat ExtendMat(Mat src) {
+ if (src.Cols * src.Channels() != 3) return src;
+ var dst = new Mat(src.Rows, 17, MatType.CV_64FC1);
+ for (int row = 0; row < src.Rows; row++) {
+ var b = src.Cols == 1 ? src.At(row, 0)[0] : src.At(row, 0);
+ var g = src.Cols == 1 ? src.At(row, 0)[1] : src.At(row, 1);
+ var r = src.Cols == 1 ? src.At(row, 0)[2] : src.At(row, 2);
+ dst.At(row, 0) = r;
+ dst.At(row, 1) = g;
+ dst.At(row, 2) = b;
+ dst.At(row, 3) = r * g;
+ dst.At(row, 4) = r * b;
+ dst.At(row, 5) = g * b;
+ dst.At(row, 6) = r * r;
+ dst.At(row, 7) = g * g;
+ dst.At(row, 8) = b * b;
+ dst.At(row, 9) = r * r * b;
+ dst.At(row, 10) = r * r * g;
+ dst.At(row, 11) = g * g * r;
+ dst.At(row, 12) = g * g * b;
+ dst.At(row, 13) = b * b * r;
+ dst.At(row, 14) = b * b * g;
+ dst.At(row, 15) = r * g * b;
+ dst.At(row, 16) = 1.0;
+ }
+ return dst;
}
///
diff --git a/TIASshot/TIASshot.csproj b/TIASshot/TIASshot.csproj
index 44f81fa..d1e6c2f 100644
--- a/TIASshot/TIASshot.csproj
+++ b/TIASshot/TIASshot.csproj
@@ -153,6 +153,8 @@
- copy /Y $(ProjectDir)config.xml $(TargetDir)
+ copy /Y $(ProjectDir)config.xml $(TargetDir)
+copy /Y $(ProjectDir)tcc_srgb.csv $(TargetDir)
+
\ No newline at end of file
diff --git a/TIASshot/config.xml b/TIASshot/config.xml
index 3b5432f..2c4d0f7 100644
--- a/TIASshot/config.xml
+++ b/TIASshot/config.xml
@@ -5,8 +5,8 @@
2.62
1.72
1.70
- 230
- 230
+ 220
+ 220
200
0.5
50
@@ -15,4 +15,6 @@
1000
4.0
30
+ tcc_srgb.csv
+ C:\TIAS_Data
diff --git a/TIASshot/tcc_srgb.csv b/TIASshot/tcc_srgb.csv
new file mode 100644
index 0000000..67d9f83
--- /dev/null
+++ b/TIASshot/tcc_srgb.csv
@@ -0,0 +1,24 @@
+92,110,181
+77,77,164
+61,57,146
+60,56,130
+98,95,176
+105,95,153
+69,63,105
+136,133,156
+80,77,97
+106,110,164
+131,153,176
+89,121,168
+226,226,226
+144,144,144
+118,118,118
+94,94,94
+70,70,70
+48,48,48
+147,103,66
+73,157,90
+71,77,184
+93,199,205
+150,108,189
+192,162,77