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 @@ +