diff --git a/TIASshot/Cameras/CameraBase.cs b/TIASshot/Cameras/CameraBase.cs
index 0e92a2a..17f0c56 100644
--- a/TIASshot/Cameras/CameraBase.cs
+++ b/TIASshot/Cameras/CameraBase.cs
@@ -14,7 +14,6 @@
using System.Windows.Forms;
using System.Media;
using OpenCvSharp;
-using OpenCvSharp.Aruco;
namespace TIASshot {
internal abstract class CameraBase {
@@ -43,20 +42,14 @@
protected Rect _roi;
// プライベートメンバ
- readonly Dictionary ARDict = CvAruco.GetPredefinedDictionary(PredefinedDictionaryName.Dict4X4_50);
- 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 UpdateRate;
- int _detectionCount = 0;
- Point2f _lastPosition = new Point2f(0, 0);
// 色補正処理(TCC 変換行列の計算・色変換)
readonly ColorCorrector _colorCorrector;
+ // チャート検出処理(ARマーカー検出・マスク生成)
+ readonly ChartDetector _chartDetector;
+
///
/// カメラの基本クラス
///
@@ -66,6 +59,7 @@
var tccSrgb = LoadMatFromCsv(Config.GetString("File/TccSrgbRef"));
var tccXyz = LoadMatFromCsv(Config.GetString("File/TccXyzRef"));
_colorCorrector = new ColorCorrector(tccSrgb, tccXyz);
+ _chartDetector = new ChartDetector(_form.ShowMessage);
}
///
@@ -157,72 +151,12 @@
///
///
protected void DetectChart(Mat img) {
+ // チャート検出・マスク生成は ChartDetector に委譲する
+ var masks = _chartDetector.DetectChart(img);
+ if (masks == null) return;
- // ARマーカー検出
- CvAruco.DetectMarkers(img, ARDict, out var corners, out var ids,
- new DetectorParameters(), out var rejectedImgPoints);
- if (ids.Length < 1) return;
-
- // マーカー座標格納
- var ptsPict = new List();
- var ptsModel = new List();
- Point2f position = new Point2f();
- float y40 = 0, y41 = 0;
- for (int i = 0; i < ids.Length; i++) {
- if (ids[i] == 40) {
- ptsPict.AddRange(corners[i]);
- ptsModel.AddRange(PointsDst40);
- position = corners[i][3];
- y40 = corners[i][3].Y;
- }
- if (ids[i] == 41) {
- ptsPict.AddRange(corners[i]);
- ptsModel.AddRange(PointsDst41);
- y41 = corners[i][3].Y;
- }
- }
- if (ptsPict.Count < 8) return;
- if (y40 > y41) {
- _form.ShowMessage("舌診チャートが上下逆方向です");
- return;
- }
-
- // チャートの固定判定
- _form.ShowMessage("舌診チャートの検出中");
- var dist = (float)position.DistanceTo(_lastPosition);
- if (dist < Config.GetFloat("Calib/ChartSetCriteria")) {
- _detectionCount++;
- } else {
- _detectionCount = 0;
- }
- _lastPosition = position;
- if (_detectionCount < Config.GetInt("Calib/ChartSetCount")) return;
-
- // ホモグラフィの計算
- var matPtsPict = Mat.FromArray(ptsPict);
- var matPtsModel = Mat.FromArray(ptsModel);
- var matH = Cv2.FindHomography(matPtsModel, matPtsPict);
- var imgF = new Mat(1545, 810, MatType.CV_8UC3);
- Cv2.WarpPerspective(img, imgF, matH, imgF.Size());
-
- // チャートマスク作成
_chartMasks.Clear();
- var roiSize = ptsPict.Count < 8 ? 60 : 80;
- for (int i = 0; i < 24; i++) {
- var row = i % 6;
- var col = i / 6;
- var x = 581 - col * 144 + (ptsPict.Count < 8 ? 10 : 0);
- var y = 318 + row * 144 + (ptsPict.Count < 8 ? 10 : 0);
- var roi = new Rect(x, y, roiSize, roiSize);
- using (var mask = new Mat(1545, 810, MatType.CV_8U)) {
- Cv2.Rectangle(mask, roi, new Scalar(255), Cv2.FILLED);
- var maskF = new Mat(img.Size(), MatType.CV_8U);
- Cv2.WarpPerspective(mask, maskF, matH, maskF.Size());
- _chartMasks.Add(maskF);
- }
- }
-
- _form.ShowMessage("舌診チャート検出 校正中");
+ _chartMasks.AddRange(masks);
_calibrating = Config.GetInt("Calib/Frames");
}
diff --git a/TIASshot/ChartDetection/ChartDetector.cs b/TIASshot/ChartDetection/ChartDetector.cs
new file mode 100644
index 0000000..94597b8
--- /dev/null
+++ b/TIASshot/ChartDetection/ChartDetector.cs
@@ -0,0 +1,106 @@
+using System;
+using System.Collections.Generic;
+using OpenCvSharp;
+using OpenCvSharp.Aruco;
+
+namespace TIASshot {
+ ///
+ /// 舌診チャートの検出(ARマーカー検出・固定判定・ホモグラフィ計算・マスク生成)を担うクラス.
+ /// CameraBase から委譲される.フォーム通知は呼び出し側が提供する.
+ ///
+ internal class ChartDetector {
+
+ readonly Dictionary ARDict = CvAruco.GetPredefinedDictionary(PredefinedDictionaryName.Dict4X4_50);
+ 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),
+ };
+ int _detectionCount = 0;
+ Point2f _lastPosition = new Point2f(0, 0);
+
+ // 状態表示(呼び出し側が提供)
+ readonly Action _showMessage;
+
+ public ChartDetector(Action showMessage) {
+ _showMessage = showMessage;
+ }
+
+ ///
+ /// チャートの検出.固定が確認できた場合のみチャートマスク(24 枚)を返す.
+ /// 未検出・上下逆・未固定の場合は null を返す.
+ ///
+ ///
+ /// チャートマスクリスト,または null
+ public List DetectChart(Mat img) {
+
+ // ARマーカー検出
+ CvAruco.DetectMarkers(img, ARDict, out var corners, out var ids,
+ new DetectorParameters(), out var rejectedImgPoints);
+ if (ids.Length < 1) return null;
+
+ // マーカー座標格納
+ var ptsPict = new List();
+ var ptsModel = new List();
+ Point2f position = new Point2f();
+ float y40 = 0, y41 = 0;
+ for (int i = 0; i < ids.Length; i++) {
+ if (ids[i] == 40) {
+ ptsPict.AddRange(corners[i]);
+ ptsModel.AddRange(PointsDst40);
+ position = corners[i][3];
+ y40 = corners[i][3].Y;
+ }
+ if (ids[i] == 41) {
+ ptsPict.AddRange(corners[i]);
+ ptsModel.AddRange(PointsDst41);
+ y41 = corners[i][3].Y;
+ }
+ }
+ if (ptsPict.Count < 8) return null;
+ if (y40 > y41) {
+ _showMessage("舌診チャートが上下逆方向です");
+ return null;
+ }
+
+ // チャートの固定判定
+ _showMessage("舌診チャートの検出中");
+ var dist = (float)position.DistanceTo(_lastPosition);
+ if (dist < Config.GetFloat("Calib/ChartSetCriteria")) {
+ _detectionCount++;
+ } else {
+ _detectionCount = 0;
+ }
+ _lastPosition = position;
+ if (_detectionCount < Config.GetInt("Calib/ChartSetCount")) return null;
+
+ // ホモグラフィの計算
+ var matPtsPict = Mat.FromArray(ptsPict);
+ var matPtsModel = Mat.FromArray(ptsModel);
+ var matH = Cv2.FindHomography(matPtsModel, matPtsPict);
+ var imgF = new Mat(1545, 810, MatType.CV_8UC3);
+ Cv2.WarpPerspective(img, imgF, matH, imgF.Size());
+
+ // チャートマスク作成
+ var chartMasks = new List();
+ var roiSize = ptsPict.Count < 8 ? 60 : 80;
+ for (int i = 0; i < 24; i++) {
+ var row = i % 6;
+ var col = i / 6;
+ var x = 581 - col * 144 + (ptsPict.Count < 8 ? 10 : 0);
+ var y = 318 + row * 144 + (ptsPict.Count < 8 ? 10 : 0);
+ var roi = new Rect(x, y, roiSize, roiSize);
+ using (var mask = new Mat(1545, 810, MatType.CV_8U)) {
+ Cv2.Rectangle(mask, roi, new Scalar(255), Cv2.FILLED);
+ var maskF = new Mat(img.Size(), MatType.CV_8U);
+ Cv2.WarpPerspective(mask, maskF, matH, maskF.Size());
+ chartMasks.Add(maskF);
+ }
+ }
+
+ _showMessage("舌診チャート検出 校正中");
+ return chartMasks;
+ }
+ }
+}
diff --git a/TIASshot/TIASshot.csproj b/TIASshot/TIASshot.csproj
index e52dceb..3da5606 100644
--- a/TIASshot/TIASshot.csproj
+++ b/TIASshot/TIASshot.csproj
@@ -119,6 +119,7 @@
+