이번장에서는 Geometric model finder를 c# opencvsharp으로 구현하는걸 하겠다. 두개의 포스트에 걸쳐서 진행할 것이다.
우선 opencvsharp을 사용하는 방법을 모르시는 분들은 밑에 글을 참고하시면 된다.
사용할 준비가 되었으면 이미지를 하나 우선 mat 형식으로 읽는다. 읽는 거를 표시하기 위해서
xaml에 image를 ImageShow라는 이름으로 추가해주고.
<Image Grid.Column="1" Name="ImageShow"/>
Cv2.ImRead()로 읽는다.
OpenFileDialog of = new OpenFileDialog();
of.Filter = "Image files (*.png;*.bmp;*.jpg)|*.png;*.bmp;*.jpg|All files (*.*)|*.*";
if (of.ShowDialog() == true)
{
tp = Cv2.ImRead(of.FileName);
ImageShow.Source=BitmapSourceConverter.ToBitmapSource(tp);
}
그 다음 포인트 정보를 저장하기 위해 pointinfo 클래스를 하나 선언해둔다.
public class PointInfo
{
/// <summary>
/// Point of edge
/// </summary>
/// <remarks>
/// (x,y)
/// </remarks>
public OpenCvSharp.Point Point;
/// <summary>
/// Center of edge
/// </summary>
/// <remarks>
/// (x0,y0)
/// </remarks>
public Point2d Center { get; private set; }
/// <summary>
/// Point-Center
/// </summary>
/// <remarks>
/// (x-x0,y-y0)
/// </remarks>
public Point2d Offset { get; private set; }
/// <summary>
/// Derivative at Point
/// </summary>
/// <remarks>
/// (dx,dy)
/// </remarks>
public Point2d Derivative;
/// <summary>
/// Magnitude at Point
/// </summary>
/// <remarks>
/// 1/√(dx²+dy²)
/// </remarks>
public double Magnitude;
/// <summary>
/// Direction at Point
/// </summary>
/// <remarks>
/// atan2(dy,dx) (not currently in use)
/// </remarks>
public double Direction;
/// <summary>
/// Calc Offset with Point by center
/// </summary>
/// <param name="center"></param>
public void Update(Point2d center)
{
Center = center;
Offset = Point - center;
}
}
그 다음 이미지 geometric 으로 하려면 컨투어를 따야되므로 흑백이미지로 변환해야된다.
Cv2.CvtColor(원본 Mat,output Mat, ColorConversionCodes.RGB2GRAY);
그 다음 변환된 output mat이 너무 불필요한 컨투어가 나오면 geometric을 추출하기 곤란 하므로 canny알고리즘으로 엣지를 정리하고,
Cv2.Canny(output Mat, output, 10, 100, 3, false);
findcontours 함수로 geometric 경로를 찾는다.
Cv2.FindContours(output, out var contours, out var hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxNone);
여기서 RetrievalModes를 external로 해야 외각선을 따서 원하는 geometric 경로를 얻을 수있다.
그다음 Sobel알고리즘을 이용해서 x,와 y의 방향에 대한 gredients를 구하고.
Cv2.Sobel(output, x, MatType.CV_64F, 1, 0, 3);
Cv2.Sobel(output, y, MatType.CV_64F, 0, 1, 3)
magnitude와 direction을 cartToPolar알고리즘으로 구한다.
Cv2.CartToPolar(x, y, magnitude, direction);
이제 컨투어의 갯수만큼 엣지 경로를 저장하면 되는데 geometric model finder의 역활을 하려면 불필요한 컨투어는 지워서 저장해놔야된다. 이건 다음장에 설명하고 우선은 다 지워진 깔끔한 이미지라고 가정했을때는
var sum = new Point2d(0, 0);
for (int i = 0, m = contours.Length; i < m; i++)
{
for (int j = 0, n = contours[i].Length; j < n; j++)
{
var cur = contours[i][j];
var fdx = gx.At<double>(cur.Y, cur.X, 0); // dx
var fdy = gy.At<double>(cur.Y, cur.X, 0); // dy
var der = new Point2d(fdx, fdy); // (dx,dy)
var mag = magnitude.At<double>(cur.Y, cur.X, 0); // √(dx²+dy²)
var dir = direction.At<double>(cur.Y, cur.X, 0); // atan2(dy,dx)
results.Add(new PointInfo
{
Point = cur,
Derivative = der,
Direction = dir,
Magnitude = mag == 0 ? 0 : 1 / mag,
});
sum += cur;
}
}
위와 같이 저장해 두면 된다. 이때 sum은 이 geometric의 중점이 어딘지 표시하기 위해 계산하는데 쓰인데
실제로 geometric의 중심을 구하려면 아까 pointinfo선언한 클래스에서 update를 호출하면서 구하면 된다.
var center = new Point2d(sum.X / results.Count, sum.Y / results.Count);
foreach (var item in results)
{
item.Update(center);
}
그 다음 Geometric 의 모양과 중점을 그려서 한번 확인해주면 Model 생성은 끝이다.
다음장에서는 불필요한 컨투어를 지우는 방법과 실제로 이 만들어 준 model로 찾는 것을 하도록 하겠다.
Cv2.DrawContours(원본 칼라 Mat, new[] { results.Select(_ => _.Point) }, -1, Scalar.LightGreen, 1);
Cv2.Circle(원본 칼라 Mat, center.ToPoint(), 2, Scalar.Red, -1);
'C# 윈도우 프로그래밍' 카테고리의 다른 글
c# tensorflow object detection(1) (0) | 2022.12.17 |
---|---|
Geometric model finder C#(2) (0) | 2022.12.17 |
AI 딥러닝 objectdetection YOLO c# 프로그래밍 (0) | 2022.12.11 |
Opencvsharp 탬플릿 매칭 c# (template Matching) opencv (0) | 2022.12.11 |
opencvsharp 실시간 마우스 처리 opencv c# (0) | 2022.12.11 |