private void 와핑ToolStripMenuItem_Click(object sender, EventArgs e)
{
if (src == null) return;
using (perspect Pp = new perspect())
using (IplImage temp = Pp.Perspective(src))
{
result = temp.Clone();
}
pictureBoxIpl2.ImageIpl = result;
}
- 그 다음 이미지를 와핑 시키기 위해서 사용할 클래스를 생성해줍니다
- 그리고 생성된 클래스 파일에 아래와 같이 코딩해 줍니다
using System;
using System.Collections.Generic;
using System.Text;
using OpenCvSharp;
namespace OpenCV_V1
{
class perspect : IDisposable
{
IplImage Pp;
public IplImage Perspective(IplImage srcImg)
{
// cvGetPerspectiveTransform + cvWarpPerspective
// 화상상의 4점에 대응하는 투시 투영 변환 행렬을 계산해, 그 행렬을 이용해 화상 전체의 투시 투영 변환을 실시한다.
// (1) 화상을 읽어들여, 출력용 화상 영역의 확보를 행한다
using (IplImage dstImg = srcImg.Clone())
{
// (2) 사각형의 변환전과 변환 후의 대응하는 정점을 각각 세트 해
// cvWarpPerspective를 이용해 투시 투영 변환 행렬을 요구한다
CvPoint2D32f[] srcPnt = new CvPoint2D32f[4];
CvPoint2D32f[] dstPnt = new CvPoint2D32f[4];
srcPnt[0] = new CvPoint2D32f(150.0f, 150.0f);
srcPnt[1] = new CvPoint2D32f(150.0f, 300.0f);
srcPnt[2] = new CvPoint2D32f(350.0f, 300.0f);
srcPnt[3] = new CvPoint2D32f(350.0f, 150.0f);
dstPnt[0] = new CvPoint2D32f(200.0f, 200.0f);
dstPnt[1] = new CvPoint2D32f(150.0f, 300.0f);
dstPnt[2] = new CvPoint2D32f(350.0f, 300.0f);
dstPnt[3] = new CvPoint2D32f(300.0f, 200.0f);
using (CvMat mapMatrix = Cv.GetPerspectiveTransform(srcPnt, dstPnt))
{
// (3) 지정된 아핀 행렬에 의해, cvWarpAffine를 이용해 화상을 회전시킨다
Cv.WarpPerspective(srcImg, dstImg, mapMatrix, Interpolation.Linear | Interpolation.FillOutliers, CvScalar.ScalarAll(100));
Pp = dstImg.Clone();
return Pp;
}
}
}
public void Dispose()
{
if (Pp != null) Cv.ReleaseImage(Pp);
}
}
}
private void 사각형찾기ToolStripMenuItem_Click(object sender, EventArgs e)
{
if (src == null) return;
using (Squre Sq = new Squre())
using (IplImage temp = Sq.Squares(src))
{
result = temp.Clone();
}
pictureBoxIpl2.ImageIpl = result;
}
private void 원형찾기ToolStripMenuItem_Click(object sender, EventArgs e)
{
if (src == null) return;
using (Squre Sq = new Squre())
using (IplImage temp = Sq.HoughCircles(src))
{
result = temp.Clone();
}
pictureBoxIpl2.ImageIpl = result;
}
- 다음에 사각과 원형을 검출해주고 그 위에 윤곽선을 그려줄 기능을 할 클래스를 작성 할께요
- 생성된 클래스 파일에 아래와 같이 소스코드를 생성해 줍니다
using System;
using System.Collections.Generic;
using System.Text;
using OpenCvSharp;
namespace OpenCV_V1
{
class Squre : IDisposable
{
const int Thresh = 50;
IplImage squr;
static double Angle(CvPoint pt1, CvPoint pt2, CvPoint pt0)
{
double dx1 = pt1.X - pt0.X;
double dy1 = pt1.Y - pt0.Y;
double dx2 = pt2.X - pt0.X;
double dy2 = pt2.Y - pt0.Y;
return (dx1 * dx2 + dy1 * dy2) / Math.Sqrt((dx1 * dx1 + dy1 * dy1) * (dx2 * dx2 + dy2 * dy2) + 1e-10);
}
public IplImage Squares(IplImage src)
{
CvMemStorage storage = new CvMemStorage(0);
DrawSquares(src, FindSquares4(src, storage));
return squr;
}
//원형 검출
public IplImage HoughCircles(IplImage src)
{
squr = new IplImage(src.Size, BitDepth.U8, 3);
IplImage gray = new IplImage(src.Size, BitDepth.U8, 1);
Cv.Copy(src, squr);
Cv.CvtColor(src, gray, ColorConversion.BgrToGray);
Cv.Smooth(gray, gray, SmoothType.Gaussian, 9);
CvMemStorage Storage = new CvMemStorage();
CvSeq<CvCircleSegment> circles = Cv.HoughCircles(gray, Storage, HoughCirclesMethod.Gradient, 1, 100, 150, 50, 0, 0);
foreach (CvCircleSegment item in circles)
{
Cv.Circle(squr, item.Center, (int)item.Radius, CvColor.Blue, 3);
}
return squr;
}
//사각 검출
static CvPoint[] FindSquares4(IplImage img, CvMemStorage storage)
{
const int N = 11;
CvSize sz = new CvSize(img.Width & -2, img.Height & -2);
IplImage timg = img.Clone(); // make a copy of input image
IplImage gray = new IplImage(sz, BitDepth.U8, 1);
IplImage pyr = new IplImage(sz.Width / 2, sz.Height / 2, BitDepth.U8, 3);
// create empty sequence that will contain points -
// 4 points per square (the square's vertices)
CvSeq<CvPoint> squares = new CvSeq<CvPoint>(SeqType.Zero, CvSeq.SizeOf, storage);
// select the maximum ROI in the image
// with the width and height divisible by 2
timg.ROI = new CvRect(0, 0, sz.Width, sz.Height);
// down-scale and upscale the image to filter out the noise
Cv.PyrDown(timg, pyr, CvFilter.Gaussian5x5);
Cv.PyrUp(pyr, timg, CvFilter.Gaussian5x5);
IplImage tgray = new IplImage(sz, BitDepth.U8, 1);
// find squares in every color plane of the image
for (int c = 0; c < 3; c++)
{
// extract the c-th color plane
timg.COI = c + 1;
Cv.Copy(timg, tgray, null);
// try several threshold levels
for (int l = 0; l < N; l++)
{
// hack: use Canny instead of zero threshold level.
// Canny helps to catch squares with gradient shading
if (l == 0)
{
// apply Canny. Take the upper threshold from slider
// and set the lower to 0 (which forces edges merging)
Cv.Canny(tgray, gray, 0, Thresh, ApertureSize.Size5);
// dilate canny output to remove potential
// holes between edge segments
Cv.Dilate(gray, gray, null, 1);
}
else
{
// apply threshold if l!=0:
// tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0
Cv.Threshold(tgray, gray, (l + 1) * 255.0 / N, 255, ThresholdType.Binary);
}
// find contours and store them all as a list
CvSeq<CvPoint> contours;
Cv.FindContours(gray, storage, out contours, CvContour.SizeOf, ContourRetrieval.List, ContourChain.ApproxSimple, new CvPoint(0, 0));
// test each contour
while (contours != null)
{
// approximate contour with accuracy proportional
// to the contour perimeter
CvSeq<CvPoint> result = Cv.ApproxPoly(contours, CvContour.SizeOf, storage, ApproxPolyMethod.DP, contours.ContourPerimeter() * 0.02, false);
// square contours should have 4 vertices after approximation
// relatively large area (to filter out noisy contours)
// and be convex.
// Note: absolute value of an area is used because
// area may be positive or negative - in accordance with the
// contour orientation
if (result.Total == 4 && Math.Abs(result.ContourArea(CvSlice.WholeSeq)) > 1000 && result.CheckContourConvexity())
{
double s = 0;
for (int i = 0; i < 5; i++)
{
// find minimum Angle between joint
// edges (maximum of cosine)
if (i >= 2)
{
double t = Math.Abs(Angle(result[i].Value, result[i - 2].Value, result[i - 1].Value));
s = s > t ? s : t;
}
}
// if cosines of all angles are small
// (all angles are ~90 degree) then write quandrange
// vertices to resultant sequence
if (s < 0.3)
{
for (int i = 0; i < 4; i++)
{
//Console.WriteLine(result[i]);
squares.Push(result[i].Value);
}
}
}
// take the next contour
contours = contours.HNext;
}
}
}
// release all the temporary images
gray.Dispose();
pyr.Dispose();
tgray.Dispose();
timg.Dispose();
return squares.ToArray();
}
/// <summary>
/// the function draws all the squares in the image
/// </summary>
/// <param name="img"></param>
/// <param name="squares"></param>
private void DrawSquares(IplImage img, CvPoint[] squares)
{
using (IplImage cpy = img.Clone())
{
// read 4 sequence elements at a time (all vertices of a square)
for (int i = 0; i < squares.Length; i += 4)
{
CvPoint[] pt = new CvPoint[4];
// read 4 vertices
pt[0] = squares[i + 0];
pt[1] = squares[i + 1];
pt[2] = squares[i + 2];
pt[3] = squares[i + 3];
// draw the square as a closed polyline
Cv.PolyLine(cpy, new CvPoint[][] { pt }, true, CvColor.Green, 3, LineType.AntiAlias, 0);
}
// show the resultant image
squr = cpy.Clone();
}
}
public void Dispose()
{
if (squr != null) Cv.ReleaseImage(squr);
}
}
}