반응형

안녕하세요

 

요즘은 매일 OpenCvSharp 포스팅 자료 만들기 하는냐고 하루가 다 가는거 같네요

 

인터넷을 보고 따라하고 분석하고 오류 수정하고

 

그러고 실행해서 결과 분석하고 그 과정을 캡쳐 캡쳐 하여 포스팅 준비를 합니다

 

제 글을 보시는 분들이 작은 정보를 하나라도 더 알아가시게 하기 위해 노력합니다ㅎㅎ

(광고 눌러달라고 구걸하는 겁니다ㅋㅋㅋ)

 

이번 포스팅 역시 기존 포스팅들과 연계되어 진행 되니 처음 오신분들이나 이해가 잘 되지 않는 분들은

 

첫 포스팅 부터 읽어 보시기 바랍니다

 

https://codingman.tistory.com/49

 

[C#]OpenCvSharp 라이브러리 사용하기 #1

안녕하세요 저번 포스팅에 C#으로 OpenCvSharp 라이브러리를 등록하여 구현하는 포스팅을 준비하던중에 OpenCv 3,4 버전에서 오류가 발생하는 문제가 있다는 얘길 듣고 부랴부랴 포스팅 내용을 검토해봤는데 역시..

codingman.tistory.com

 

이번 포스팅은 컨투어 찾기인데요 

 

원본 이미지의 윤곽선을 검출하거나 또는 라인을 그려서 Depth별 윤곽선을 찾아서 그릴수 있는데요

 

이번 포스팅에서 이러한 여러가지 검출 방법을 하나씩 구현해 보도록 할께요

 

언제나 그렇듯 실행을 위한 메뉴 구성 부터 해볼께요

 

[디자인]

- 메뉴 항목에 다음과 같이 메뉴를 생성합니다

  (매번 추가하는 작업이라 이제 대충 설명할께요ㅎ)

- 전에 하듯이 메뉴별 클릭 이벤트를 생성합니다

[Source Code]

        private void findContoursToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //FindContours를 통한 2단계 계층 구성 방법
            if (src == null) return;
            using (FindContours Sq = new FindContours())
            using (IplImage temp = Sq.Contour(src))
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;
        }

        private void startFindContoursToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //StartFindContours를 통한 모든 컨투어 검색 구성 방법
            if (src == null) return;
            using (FindContours Sq = new FindContours())
            using (IplImage temp = Sq.Contour(src))
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;
        }

        private void userContourToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //단계별 Line을 그려서 윤곽을 구성하는 방법
            using (contour Ct = new contour())
            using (IplImage temp = Ct.FindContours())
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;
        }

 

- 해당 메뉴들별로 하는 일을 똑같이 윤곽선 검출 입니다

- 하지만 기능별로 검출 방식이 약간식 차이가 있으니 잘 확인하시기 바랍니다

 

- 클래스 생성

  (각 기능별 클래스를 생성합니다)

 

*FindContours

 - FindContours 함수를 사용하여 2단계 Depth까지 윤곽선을 검출 하는 방식

  [Source Code]

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;

namespace OpenCV_V1
{
    class FindContours : IDisposable
    {
        IplImage bin;
        IplImage con;

        public IplImage Binary(IplImage src)
        {
            bin = new IplImage(src.Size, BitDepth.U8, 1);
            Cv.CvtColor(src, bin, ColorConversion.RgbToGray);
            Cv.Threshold(bin, bin, 150, 255, ThresholdType.Binary);
            return bin;
        }

        public IplImage Contour(IplImage src)
        {
            con = new IplImage(src.Size, BitDepth.U8, 3);
            bin = new IplImage(src.Size, BitDepth.U8, 1);

            Cv.Copy(src, con);
            bin = this.Binary(src);

            CvMemStorage Storage = new CvMemStorage();
            CvSeq<CvPoint> contours;

            Cv.FindContours(bin, Storage, out contours, CvContour.SizeOf, ContourRetrieval.List, ContourChain.ApproxNone);

            Cv.DrawContours(con, contours, CvColor.Yellow, CvColor.Red, 1, 4, LineType.AntiAlias);

            Cv.ClearSeq(contours);
            Cv.ReleaseMemStorage(Storage);

            return con;
        }

        public void Dispose()
        {
            if (bin != null) Cv.ReleaseImage(bin);
            if (con != null) Cv.ReleaseImage(con);
        }
    }
}

 

*StartFindContours

  - StartFindContours 함수를 사용하여 단일 윤곽선을 검출하여 while문을 사용하여 모든 윤곽선을 검출하는 방법

 [Source Code]

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;

namespace OpenCV_V1
{
    class MultFindContours : IDisposable
    {
        IplImage bin;
        IplImage con;

        public IplImage Binary(IplImage src)
        {
            bin = new IplImage(src.Size, BitDepth.U8, 1);
            Cv.CvtColor(src, bin, ColorConversion.RgbToGray);
            Cv.Threshold(bin, bin, 150, 255, ThresholdType.Binary);
            return bin;
        }

        public IplImage Contour(IplImage src)
        {
            con = new IplImage(src.Size, BitDepth.U8, 3);
            bin = new IplImage(src.Size, BitDepth.U8, 1);

            Cv.Copy(src, con);
            bin = this.Binary(src);

            CvMemStorage Storage = new CvMemStorage();
            CvSeq<CvPoint> contours;

            CvContourScanner scanner = Cv.StartFindContours(bin, Storage, CvContour.SizeOf, ContourRetrieval.List, ContourChain.ApproxNone);

            // #1        
            while (true)
            {
                contours = Cv.FindNextContour(scanner);

                if (contours == null) break;
                else
                {
                    Cv.DrawContours(con, contours, CvColor.Yellow, CvColor.Red, 1, 4, LineType.AntiAlias);
                }
            }
            Cv.EndFindContours(scanner);

            // #2        
            //foreach (CvSeq<CvPoint> c in scanner)
            //{
            //    con.DrawContours(c, CvColor.Yellow, CvColor.Red, 1, 4, LineType.AntiAlias);
            //}
            //Cv.ClearSeq(contours);

            Cv.ReleaseMemStorage(Storage);

            return con;
        }

        public void Dispose()
        {
            if (bin != null) Cv.ReleaseImage(bin);
            if (con != null) Cv.ReleaseImage(con);
        }
    }
}

 

*UserContour

  - 사용자가 임의 라인을 생성하여 3 Depth까지의 윤곽선을 검출하는 방법

 [Source Code]

using System;
using System.Collections.Generic;
using System.Text;
using OpenCvSharp;

namespace OpenCV_V1
{
    class contour : IDisposable
    {
        IplImage cont;
        public IplImage FindContours()
        {
            // cvFindContoursm cvDrawContours
            // 화상중으로부터 윤곽을 검출해,-1~+1까지의 레벨에 있는 윤곽을 그린다

            const int SIZE = 500;

            using (IplImage img = new IplImage(SIZE, SIZE, BitDepth.U8, 1))
            {
                // 화상의 초기화
                img.Zero();
                for (int i = 0; i < 6; i++)
                {
                    int dx = (i % 2) * 250 - 30;
                    int dy = (i / 2) * 150;
                    if (i == 0)
                    {
                        for (int j = 0; j <= 10; j++)
                        {
                            double angle = (j + 5) * Cv.PI / 21;
                            CvPoint p1 = new CvPoint(Cv.Round(dx + 100 + j * 10 - 80 * Math.Cos(angle)), Cv.Round(dy + 100 - 90 * Math.Sin(angle)));
                            CvPoint p2 = new CvPoint(Cv.Round(dx + 100 + j * 10 - 30 * Math.Cos(angle)), Cv.Round(dy + 100 - 30 * Math.Sin(angle)));
                            Cv.Line(img, p1, p2, CvColor.White, 1, LineType.AntiAlias, 0);
                        }
                    }
                    Cv.Ellipse(img, new CvPoint(dx + 150, dy + 100), new CvSize(100, 70), 0, 0, 360, CvColor.White, -1, LineType.AntiAlias, 0);
                    Cv.Ellipse(img, new CvPoint(dx + 115, dy + 70), new CvSize(30, 20), 0, 0, 360, CvColor.Black, -1, LineType.AntiAlias, 0);
                    Cv.Ellipse(img, new CvPoint(dx + 185, dy + 70), new CvSize(30, 20), 0, 0, 360, CvColor.Black, -1, LineType.AntiAlias, 0);
                    Cv.Ellipse(img, new CvPoint(dx + 115, dy + 70), new CvSize(15, 15), 0, 0, 360, CvColor.White, -1, LineType.AntiAlias, 0);
                    Cv.Ellipse(img, new CvPoint(dx + 185, dy + 70), new CvSize(15, 15), 0, 0, 360, CvColor.White, -1, LineType.AntiAlias, 0);
                    Cv.Ellipse(img, new CvPoint(dx + 115, dy + 70), new CvSize(5, 5), 0, 0, 360, CvColor.Black, -1, LineType.AntiAlias, 0);
                    Cv.Ellipse(img, new CvPoint(dx + 185, dy + 70), new CvSize(5, 5), 0, 0, 360, CvColor.Black, -1, LineType.AntiAlias, 0);
                    Cv.Ellipse(img, new CvPoint(dx + 150, dy + 100), new CvSize(10, 5), 0, 0, 360, CvColor.Black, -1, LineType.AntiAlias, 0);
                    Cv.Ellipse(img, new CvPoint(dx + 150, dy + 150), new CvSize(40, 10), 0, 0, 360, CvColor.Black, -1, LineType.AntiAlias, 0);
                    Cv.Ellipse(img, new CvPoint(dx + 27, dy + 100), new CvSize(20, 35), 0, 0, 360, CvColor.White, -1, LineType.AntiAlias, 0);
                    Cv.Ellipse(img, new CvPoint(dx + 273, dy + 100), new CvSize(20, 35), 0, 0, 360, CvColor.White, -1, LineType.AntiAlias, 0);
                }

                // 윤곽의 검출
                CvSeq<CvPoint> contours;
                CvMemStorage storage = new CvMemStorage();
                // native style
                Cv.FindContours(img, storage, out contours, CvContour.SizeOf, ContourRetrieval.Tree, ContourChain.ApproxSimple);
                contours = Cv.ApproxPoly(contours, CvContour.SizeOf, storage, ApproxPolyMethod.DP, 3, true);

                // wrapper style
                //img.FindContours(storage, out contours, ContourRetrieval.Tree, ContourChain.ApproxSimple);
                //contours = contours.ApproxPoly(storage, ApproxPolyMethod.DP, 3, true);

                // 윈도우에 표시
                using (CvWindow window_image = new CvWindow("image", img))
                using (CvWindow window_contours = new CvWindow("contours"))
                {
                    CvTrackbarCallback onTrackbar = delegate (int pos)
                    {
                        IplImage cnt_img = new IplImage(SIZE, SIZE, BitDepth.U8, 3);
                        CvSeq<CvPoint> _contours = contours;
                        int levels = pos - 3;
                        if (levels <= 0) // get to the nearest face to make it look more funny
                        {
                            //_contours = _contours.HNext.HNext.HNext;
                        }
                        cnt_img.Zero();
                        Cv.DrawContours(cnt_img, _contours, CvColor.Red, CvColor.Green, levels, 3, LineType.AntiAlias);
                        window_contours.ShowImage(cnt_img);
                        cont = cnt_img.Clone();
                        cnt_img.Dispose();
                    };
                    window_contours.CreateTrackbar("levels+3", 3, 7, onTrackbar);
                    onTrackbar(3);

                    Cv.WaitKey();
                }
            }
            return cont;

        }
        public void Dispose()
        {
            if (cont != null) cont.Dispose();
        }
    }
}

 

- 각 윤곽선 검출 방법별로 결과를 확인 합니다

 

[결과 창]

*FindContours

*StartFindContours

*UserContour

반응형
반응형

안녕하세요

 

벌써 OpenCvSharp를 공부한지 1달정도 되어 가는거 같네요

 

너무 범위가 넓어서 하나씩 하나씩 하자는 마음으로 시작했는데 끝이 안보이니깐 의욕이 점점 떨어지네요ㅎ

 

저번시간에 모폴로지에 대해 포스팅 했는데 이번시간에는 

 

OpenCv의 Filter2D() 함수를 사용해서 사용자 지정 마스크 기능들을 구현해 볼려고 합니다

 

사용자 지정 마스크는 Filter2D의 함수를 어떻게 사용하는냐에 따라 지정될수 있습니다

 

[주요 함수 설명]

C# : Filter2DCv.Filter2D(s1, temp, b, new CvPoint(-1, -1));

  • s1 : 이미지
  • temp : 대상이미지
  • b : 커널 행렬
  • new CvPoint(-1, -1) : 커널 앵커

C# : ThresholdCv.Threshold(temp, temp, 80, 255, ThresholdType.BinaryInv);

  • temp : 이미지
  • trmp : 대상이미지
  • 80 : 임계치
  • 255 : 기준값을 넘었을 때 적용할 최대값
  • ThresholdType.BinaryInv : 임계치의 유형

연속 포스팅이라서 처음 디자인을 구성하시는경우에는 처음 라이브러리 등록 포스팅 부터 보시기 바랍니다

https://codingman.tistory.com/49

 

[C#]OpenCvSharp 라이브러리 사용하기 #1

안녕하세요 저번 포스팅에 C#으로 OpenCvSharp 라이브러리를 등록하여 구현하는 포스팅을 준비하던중에 OpenCv 3,4 버전에서 오류가 발생하는 문제가 있다는 얘길 듣고 부랴부랴 포스팅 내용을 검토해봤는데 역시..

codingman.tistory.com

[디자인]

- Menu에 필터 -> 유저마스크 -> 선명화1, 선명화2, 선명화3, 수평엣지, 수직엣지를 등록해 주세요

 

- 각 메뉴에 클릭 이벤트 설정

  (클릭 이벤트 설정하는 방법은 생략하겟습니다)

  (그리고 이벤트 순서는 바뀌어도 문제되지 않습니다)

 

 

- 클릭이벤트별 다음과 같이 코딩 합니다

[Source Code]

        private void 선명화1ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (Mask Mk = new Mask())
            using (IplImage temp = Mk.SunMyung1(src))
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;
        }

        private void 선명화2ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (Mask Mk = new Mask())
            using (IplImage temp = Mk.SunMyung2(src))
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;
        }

        private void 선명화3ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (Mask Mk = new Mask())
            using (IplImage temp = Mk.SunMyung3(src))
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;
        }

        private void 수평엣지ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (Mask Mk = new Mask())
            using (IplImage temp = Mk.H_Edge(src))
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;
        }

        private void 수직엣ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (Mask Mk = new Mask())
            using (IplImage temp = Mk.V_Edge(src))
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;
        }

 

- 사용자 지정 마스크 기능을 구현할 Class 파일을 하나 생성 합니다

  (클래스 생성 방법은 여러번 포스팅 하였기 때문에 생략 하도록 하겠습니다)

  (이전 포스팅 자료를 참고 하시기 바랍니다)

 

- 신규로 생성한 클래스 파일에 다음과 같이 코딩 합니다

[Source Code]

using System;
using System.Collections.Generic;
using System.Text;
using OpenCvSharp;

namespace OpenCV_V1
{
    class Mask : IDisposable
    {
        IplImage maskimg;

        //세가지 필터로 선명화 시키기
        public IplImage SunMyung1(IplImage src)
        {
            double[,] _b = new double[,]{ {0.0f/5.0f, -1.0f/5.0f, 0.0f/5.0f},
                                          {-1.0f/5.0f, 9.0f/5.0f, -1.0f/5.0f},
                                          {0.0f/5.0f, -1.0f/5.0f, 0.0f/5.0f} };

            using (CvMat b = CvMat.FromArray(_b))
            using (IplImage temp = new IplImage(src.Size, BitDepth.U8, 1))
            using (IplImage s1 = new IplImage(src.Size, BitDepth.U8, 1))
            {
                Cv.CvtColor(src, s1, ColorConversion.BgrToGray);
                Cv.Filter2D(s1, temp, b, new CvPoint(-1, -1));
                maskimg = temp.Clone();
            }
            return maskimg;
        }

        public IplImage SunMyung2(IplImage src)
        {
            double[,] _b = new double[,]{ {0, -1, 0},
                                          {-1, 5, -1},
                                          {0, -1, 0} };

            using (CvMat b = CvMat.FromArray(_b))
            using (IplImage temp = new IplImage(src.Size, BitDepth.U8, 1))
            using (IplImage s1 = new IplImage(src.Size, BitDepth.U8, 1))
            {
                Cv.CvtColor(src, s1, ColorConversion.BgrToGray);
                Cv.Filter2D(s1, temp, b, new CvPoint(-1, -1));
                maskimg = temp.Clone();

            }
            return maskimg;

        }

        public IplImage SunMyung3(IplImage src)
        {
            double[,] _b = new double[,]{ {-1, -1, -1},
                                          {-1, 9, -1},
                                          {-1, -1, -1} };

            using (CvMat b = CvMat.FromArray(_b))
            using (IplImage temp = new IplImage(src.Size, BitDepth.U8, 1))
            using (IplImage s1 = new IplImage(src.Size, BitDepth.U8, 1))
            {
                Cv.CvtColor(src, s1, ColorConversion.BgrToGray);
                Cv.Filter2D(s1, temp, b, new CvPoint(-1, -1));
                maskimg = temp.Clone();


            }
            return maskimg;

        }

        //수직 엣지 찾기
        public IplImage V_Edge(IplImage src) //그레이 변환된 이미지
        {
            double[,] _b = new double[,]{ {-1, 0, 1},
                                          {-1, 0, 1},
                                          {-1, 0, 1} };


            using (CvMat b = CvMat.FromArray(_b))
            using (IplImage temp = new IplImage(src.Size, BitDepth.U8, 1))
            using (IplImage s1 = new IplImage(src.Size, BitDepth.U8, 1))
            {
                Cv.CvtColor(src, s1, ColorConversion.BgrToGray);
                Cv.Filter2D(s1, temp, b, new CvPoint(-1, -1));
                Cv.Threshold(temp, temp, 80, 255, ThresholdType.BinaryInv); //이진화

                maskimg = temp.Clone();


            }
            return maskimg;
        }



        //수평 엣지 찾기
        public IplImage H_Edge(IplImage src)
        {
            double[,] _b = new double[,]{ {1, 1, 1},
                                          {0, 0, 0},
                                          {-1, -1, -1} };


            using (CvMat b = CvMat.FromArray(_b))
            using (IplImage temp = new IplImage(src.Size, BitDepth.U8, 1))
            using (IplImage s1 = new IplImage(src.Size, BitDepth.U8, 1))
            {
                Cv.CvtColor(src, s1, ColorConversion.BgrToGray);
                Cv.Filter2D(s1, temp, b, new CvPoint(-1, -1));
                Cv.Threshold(temp, temp, 80, 255, ThresholdType.BinaryInv);

                maskimg = temp.Clone();


            }
            return maskimg;
        }



        public void Dispose()
        {
            if (maskimg != null) Cv.ReleaseImage(maskimg);
        }
    }
}

 

- 빌드 후 실행하신뒤 각 기능별 결과를 확인 합니다

 

[결과 창]
*선명화1

 

*선명화2

 

*선명화3

 

*수직 엣지

 

*수평엣지

 

결과를 보면 약간씩 차이점이 보이실 겁니다

 

감사합니다

반응형
반응형

안녕하세요

 

이번 OpenCvSharp를 이용한 포스팅에서 다룰 연산은 모폴로지 연산 입니다

 

모폴로지는 영상이나 이미지의 화소값을 이용하여 이미지의 형태학적 작업을 할 수 있습니다

 

[*모폴로지 연산의 종류와 간단한 설명]

  1. 팽장(Dilate)
    - 255값의 화소가 부풀어서 커지는것
  2. 침식(Erode)
    - 255값의 화소가 깎이는 것
  3. 열기연산(Opening)
    -작은 흰 점들을 없앤 뒤 큰 덩어리들은 다시 원래 크기로 키우는 연산
  4. 닫기연산(Closing)
    - 약간 떨어진 선이나 공간을 잇거나 채우고 난 뒤 전체 크기를 원래대로 줄이는 연산
  5. 그라디언트연산(Gradient)
    - 영역의 외곽선만 남기는 효과를 주는 연산
  6. 탑햇연산(TopHat)
    - 열기연산(Opening)이 수행된 부분을 빼내는 연산
  7. 블랙연산(BalckHat)
    - 원본 이미지에서 어두운 영역을 강조하는 연산

역시 영상, 이미지 분야는 어려운거 같다 모두 수학적 공식을 통해 색상을 조절하고 세밀한 조절을 통해

 

이미지나 영상의 효과나 처리를 주는데 비전공자로써는 도저히 이해가 되질 않는다ㅎ

 

나는 나의 전공으로 돌아와서 코딩을 해보겠다ㅋㅋ

 

이번 포스팅도 저번 포스팅에 이어 진행되므로 이전 포스팅을 읽고 진행 하는것이

 

이해가 빠를것이다

 

https://codingman.tistory.com/62

 

[C#] OpenCvSharp 이미지 옵티컬플로우 처리하기

안녕하세요 이번 포스팅은 OpenCvSharp로 이미지 옵티컬플로우 처리를 해보도록 하겠습니다 일단 옵티컬플로우가 무엇인지 알아야 이해가 빠를거 같은데요 저도 배우고 있는 단계라 정확한 정의는 못 내리겠습니다..

codingman.tistory.com

 

모폴로지 연산처리를 위해 Menu에 버튼을 생성한다

 

[디자인]

- 알고리즘 항목에 모폴로지를 만들고 세부 메뉴로 아래 리스트별로 생성 시킨다

 

- 세부 메뉴로 생성된 모폴로지 연산 처리별 클릭 이벤트 생성

 

[Source Code]

- 이벤트별 클래스 호출 코딩을 작성해 준다

        private void dilateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (Morphology Mp = new Morphology())
            using (IplImage temp = Mp.DilateMorphology(src))
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;
        }

        private void erodeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (Morphology Mp = new Morphology())
            using (IplImage temp = Mp.ErodeMorphology(src))
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;
        }

        private void openingToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (Morphology Mp = new Morphology())
            using (IplImage temp = Mp.OpenMorphology(src))
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;
        }

        private void closingToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (Morphology Mp = new Morphology())
            using (IplImage temp = Mp.CloseMorphology(src))
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;
        }

        private void gradientToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (Morphology Mp = new Morphology())
            using (IplImage temp = Mp.GradientMorphology(src))
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;
        }

        private void topHatToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (Morphology Mp = new Morphology())
            using (IplImage temp = Mp.TopHatMorphology(src))
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;
        }

        private void balckHatToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (Morphology Mp = new Morphology())
            using (IplImage temp = Mp.BlackHatMorphology(src))
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;
        }

 

- 모폴로지 클래스 파일 생성

  (클래스명칭 : Morphology.cs)

 

[Source Code]

- 생성한 클래스 파일에 다음과 같으 코딩 한다

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenCvSharp;

namespace OpenCV_V1
{
    class Morphology : IDisposable
    {
        IplImage morph;


        public IplImage DilateMorphology(IplImage src)
        {
            // 구조 요소를 지정하고, 확장 모폴로지 연산을 행한다

            //(1) 화상 읽어들여, 연산 결과 화상 영역의 확보를 행한다
            using (IplImage srcImg = src.Clone())
            using (IplImage dstImg = srcImg.Clone())
            using (IplImage tmpImg = srcImg.Clone())
            {
                //(2) 구조 요소를 생성한다 
                IplConvKernel element = Cv.CreateStructuringElementEx(9, 9, 4, 4, ElementShape.Rect, null);
                //(3) 모폴로지 연산을 실행한다 
                Cv.Dilate(srcImg, dstImg, element, 1);
                morph = dstImg.Clone();

            }
            return morph;
        }

        public IplImage ErodeMorphology(IplImage src)
        {

            // 구조 요소를 지정하고, 축소 모폴로지 연산을 행한다

            //(1) 화상 읽어들여, 연산 결과 화상 영역의 확보를 행한다
            using (IplImage srcImg = src.Clone())
            using (IplImage dstImg = srcImg.Clone())
            using (IplImage tmpImg = srcImg.Clone())
            {
                //(2) 구조 요소를 생성한다 
                IplConvKernel element = Cv.CreateStructuringElementEx(9, 9, 4, 4, ElementShape.Rect, null);
                //(3) 모폴로지 연산을 실행한다 
                Cv.Erode(srcImg, dstImg, element, 1);
                morph = dstImg.Clone();
            }
            return morph;
        }

        public IplImage OpenMorphology(IplImage src)
        {

            // 구조 요소를 지정하고, 오픈 모폴로지 연산을 행한다

            //(1) 화상 읽어들여, 연산 결과 화상 영역의 확보를 행한다
            using (IplImage srcImg = src.Clone())
            using (IplImage dstImg = srcImg.Clone())
            using (IplImage tmpImg = srcImg.Clone())
            {
                //(2) 구조 요소를 생성한다 
                IplConvKernel element = Cv.CreateStructuringElementEx(9, 9, 4, 4, ElementShape.Rect, null);
                //(3) 모폴로지 연산을 실행한다 
                Cv.MorphologyEx(srcImg, dstImg, tmpImg, element, MorphologyOperation.Open, 1);
                morph = dstImg.Clone();

            }
            return morph;
        }

        public IplImage CloseMorphology(IplImage src)
        {

            // 구조 요소를 지정하고, 닫힘 모폴로지 연산을 행한다

            //(1) 화상 읽어들여, 연산 결과 화상 영역의 확보를 행한다
            using (IplImage srcImg = src.Clone())
            using (IplImage dstImg = srcImg.Clone())
            using (IplImage tmpImg = srcImg.Clone())
            {
                //(2) 구조 요소를 생성한다 
                IplConvKernel element = Cv.CreateStructuringElementEx(9, 9, 4, 4, ElementShape.Rect, null);
                //(3) 모폴로지 연산을 실행한다 
                Cv.MorphologyEx(srcImg, dstImg, tmpImg, element, MorphologyOperation.Close, 1);
                morph = dstImg.Clone();

            }
            return morph;
        }

        public IplImage GradientMorphology(IplImage src)
        {

            // 구조 요소를 지정하고, 그라디언트 모폴로지 연산을 행한다

            //(1) 화상 읽어들여, 연산 결과 화상 영역의 확보를 행한다
            using (IplImage srcImg = src.Clone())
            using (IplImage dstImg = srcImg.Clone())
            using (IplImage tmpImg = srcImg.Clone())
            {
                //(2) 구조 요소를 생성한다 
                IplConvKernel element = Cv.CreateStructuringElementEx(9, 9, 4, 4, ElementShape.Rect, null);
                //(3) 모폴로지 연산을 실행한다 
                Cv.MorphologyEx(srcImg, dstImg, tmpImg, element, MorphologyOperation.Gradient, 1);
                morph = dstImg.Clone();
            }
            return morph;
        }

        public IplImage TopHatMorphology(IplImage src)
        {

            // 구조 요소를 지정하고, 탑햇 모폴로지 연산을 행한다

            //(1) 화상 읽어들여, 연산 결과 화상 영역의 확보를 행한다
            using (IplImage srcImg = src.Clone())
            using (IplImage dstImg = srcImg.Clone())
            using (IplImage tmpImg = srcImg.Clone())
            {
                //(2) 구조 요소를 생성한다 
                IplConvKernel element = Cv.CreateStructuringElementEx(9, 9, 4, 4, ElementShape.Rect, null);
                //(3) 모폴로지 연산을 실행한다 
                Cv.MorphologyEx(srcImg, dstImg, tmpImg, element, MorphologyOperation.TopHat, 1);
                morph = dstImg.Clone();
            }
            return morph;
        }

        public IplImage BlackHatMorphology(IplImage src)
        {

            // 구조 요소를 지정하고, 블랙햇 모폴로지 연산을 행한다

            //(1) 화상 읽어들여, 연산 결과 화상 영역의 확보를 행한다
            using (IplImage srcImg = src.Clone())
            using (IplImage dstImg = srcImg.Clone())
            using (IplImage tmpImg = srcImg.Clone())
            {
                //(2) 구조 요소를 생성한다 
                IplConvKernel element = Cv.CreateStructuringElementEx(9, 9, 4, 4, ElementShape.Rect, null);
                //(3) 모폴로지 연산을 실행한다 
                Cv.MorphologyEx(srcImg, dstImg, tmpImg, element, MorphologyOperation.BlackHat, 1);
                morph = dstImg.Clone();
            }
            return morph;
        }

        public void Dispose()
        {
            if (morph != null) Cv.ReleaseImage(morph);
        }
    }
}

 

[결과 창]

*팽창 연산 결과 화면

 

*침식 연산 결과 화면

 

* 열기 연산 결과 화면

 

* 닫기 연산 결과 화면

 

*그라디언트연산 결과 화면

 

*탑햇 연산 결과 화면

 

*블랙햇 연산 결과 화면

 

각 결과 화면을 보면 모폴로지 연산별 차이를 확인 할 수 있습니다

반응형
반응형

안녕하세요

 

이번 포스팅은 OpenCvSharp로 이미지 옵티컬플로우 처리를 해보도록 하겠습니다

 

일단 옵티컬플로우가 무엇인지 알아야 이해가 빠를거 같은데요

 

저도 배우고 있는 단계라 정확한 정의는 못 내리겠습니다ㅠ

 

다만 제가 공부한걸로는 옵티컬플로우는 광류 또는 광학 흐름 뭐 이렇게 표현을 하더라구요

 

제가 이해한것을 쉽게 풀어서 설명을 하자면 영상이나 이미지의 역학적인 흐름을 표시하는겁니다

 

현재 프레임과 다음 프레임간의 매칭을 통해 어떠한 변화를 캣치해서 그걸 선이나 원으로 흐름을 표시하는것이죠

 

검색을 해보니 보통 이미지 보다는 영상쪽에서 많이 사용하는 기능같습니다

 

예를들면 현재 모습과 다음 모습을 비교했을때 이것이 동일한 위치에서 찍힌 이미지인지 판단을 하고 싶다고 했을때

 

옵티컬플로우로 이미지를 처리하게 되면 어떠한 조건에 의해 이미지속의 물체들이 광학 흐름을 했는지 표기를 한다는것

 

입니다

 

신기할 따름이죠ㅎ

 

저도 사진이나 영상편집의 전공자가 아니여서 좀 더 심도 있는 지식을 설명드리지 못해서 죄송합니다

 

하지만 분명한건 OpenCv를 공부하면 반드시 나오는 기능중에 하나라는게 핵심인거죠

 

그만큼 사용도가 많다는 얘기일거 같은데요

 

C#으로 옵티컬플로우를 구현해서 좀 더 분석 해보도록 하곘습니다

 

OpenCvSharp에서 옵티컬플로우를 사용하기 위한 주요 함수에 대한 설명 부터 할께요

 

바로 이 함수 CalcOpticalFlowBM() 입니다

 

C#에서 어떻게 사용되는지 설명해 드릴께요

 

Cv.CalcOpticalFlowBM(srcImg1, srcImg2, block, shift, maxRange, false, velx, vely);
  • srcImg1 - 이전 프레임
  • srcImg2 - 현재 프레임
  • block - 검출에 사용할 블록의 크기
  • shift - 블록의 이격 거리를 의미(값이 낮을 수록 검출 간격이 촘촘해 집니다)
  • maxRange - 블록 주변의 인접한 블록 크기 

이제 디자인을 만들어 보겟습니다

 

OpenCvSharp에 대한 연제 포스팅을 하다 보니 이미 만들어진 디자인에 살을 계속 붙여 나가는 식으로 

 

개발을 진행하여 초기 디자인 생성에 대한 포스팅은 아래 링크를 확인해 주시기 바랍니다

 

https://codingman.tistory.com/49

 

[C#]OpenCvSharp 라이브러리 사용하기 #1

안녕하세요 저번 포스팅에 C#으로 OpenCvSharp 라이브러리를 등록하여 구현하는 포스팅을 준비하던중에 OpenCv 3,4 버전에서 오류가 발생하는 문제가 있다는 얘길 듣고 부랴부랴 포스팅 내용을 검토해봤는데 역시..

codingman.tistory.com

 

[디자인]

- Menu에 비교 대상 이미지를 불러오기 위한 메뉴를 생성합니다

  (저는 그림읽기, 그림읽기2로 만들었는데요)

  (그림읽기 버튼은 pictureBoxIpl1(좌측)에 이미지 넣기 용도)

  (그림읽기2 버튼은 pictureBoxIpl2(우측)에 이미지 넣기 용도)

- 두번재로 옵티컬플로우 처리를 위한 메뉴도 생성해 줍니다

 

- 그다음 그림읽기, 그림읽기2, 옵티컬플로우 순서로 클릭 이벤트를 생성 합니다

   (순서는 상관 없습니다)

[Source Code]

        private void 옵티컬플로우ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            src = Cv.LoadImage(openFileDialog1.FileName, LoadMode.Color);
            result = Cv.LoadImage(openFileDialog2.FileName, LoadMode.Color);

            pictureBoxIpl1.ImageIpl = src;
            pictureBoxIpl2.ImageIpl = result;

            using (optical Op = new optical())
            {
                Op.OpticalFlowBM(openFileDialog1.FileName, openFileDialog2.FileName);
            }
        }

 

[Source Code]

        private void 그림읽기ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)  //파일 읽어 오기 추가
            {
                loadImage(openFileDialog1.FileName);
            }
            else
            {
                return;
            }

        }
        
        private void loadImage(String filename)
        {
            src = new IplImage(filename, LoadMode.AnyColor); //Opencv형태로 그림 파일을 읽어다 src에 저장
            pictureBoxIpl1.ImageIpl = src;
        
        }

[Source Code]

        private void 그림읽기2ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (openFileDialog2.ShowDialog() == DialogResult.OK)  //파일 읽어 오기 추가
            {
                loadImage2(openFileDialog2.FileName);
            }
            else
            {
                return;
            }
        }
        
        private void loadImage2(String filename)
        {
            src2 = new IplImage(filename, LoadMode.AnyColor); //Opencv형태로 그림 파일을 읽어다 src에 저장
            pictureBoxIpl2.ImageIpl = src2;

        }

 

- 옵티컬플로우 처리를 위한 클래스 생성

[Source Code]

using System;
using System.Collections.Generic;
using System.Text;
using OpenCvSharp;

namespace OpenCV_V1
{
    class optical : IDisposable
    {
        public void OpticalFlowBM(String file1, String file2)
        {
            // cvCalcOpticalFlowBM
            // 블록 매칭에 의한 옵티컬 플로우의 계산

            const int blockSize = 10;
            const int shiftSize = 1;

            CvSize block = new CvSize(blockSize, blockSize);
            CvSize shift = new CvSize(shiftSize, shiftSize);
            CvSize maxRange = new CvSize(50, 50);

            using (IplImage srcImg1 = Cv.LoadImage(file1, LoadMode.GrayScale))
            using (IplImage srcImg2 = Cv.LoadImage(file2, LoadMode.GrayScale))
            using (IplImage dstImg = Cv.LoadImage(file2, LoadMode.Color))
            {
                CvSize VelSize = new CvSize
                {
                    Width = (dstImg.Width - block.Width + shift.Width) / shift.Width,
                    Height = (dstImg.Height - block.Height + shift.Height) / shift.Height
                };

                using (CvMat velx = Cv.CreateMat(VelSize.Height, VelSize.Width, MatrixType.F32C1))
                using (CvMat vely = Cv.CreateMat(VelSize.Height, VelSize.Width, MatrixType.F32C1))
                {
                    Cv.SetZero(velx);
                    Cv.SetZero(vely);
                    
                    // (2) 옵티컬 플로우의 계산 
                    Cv.CalcOpticalFlowBM(srcImg1, srcImg2, block, shift, maxRange, false, velx, vely);
                    
                    // (3) 계산된 플로우를 그리기
                    for (int i = 0; i < velx.Rows; i++)
                    {
                        for (int j = 0; j < vely.Cols; j++)
                        {
                            int dx = (int)Cv.GetReal2D(velx, i, j);
                            int dy = (int)Cv.GetReal2D(vely, i, j);

                            Cv.Line(dstImg,
                                new CvPoint(j * shiftSize, i * shiftSize),
                                new CvPoint(j * shiftSize + dx, i * shiftSize + dy),
                                new CvColor(255, 0, 0), 1, LineType.AntiAlias, 0);

                        }
                    }
                }

                using (CvWindow w = new CvWindow("옵티컬플로우"))
                {
                    w.Image = dstImg;
                    Cv.WaitKey(0);
                }
            }
        }
        public void Dispose()
        {
        }
    }
}

* 해당 CalcOpticalFlowBM 위치에서 Exception이 발생할 경우

   - dstImg의 크기가 원본 이미지 보다 클경우 발생하오니 디버깅 해보시기 바랍니다

     (검색을 해보니 OpenCvSharp 버전에 따라서 발생하기도 한다고 합니다)

     (참고로 저는 문제가 발생하여 VelSize를 통해 가로, 세로 길이를 구하도록 변경하엿습니다)

 

[결과 창]

 

* 예제로 사용할려는 이미지가 좌측과 우측에 사물 이동의 흔적이 있어야 처리가 되오니 

   샘플용 사진을 사용할때 주의하시기 바랍니다

반응형
반응형

안녕하세요

 

이번 포스팅은 저번 포스팅(코너검출)에 이어 직선을 검출하는 기능을 구현해 보도록 하겠습니다

 

저번 포스팅에 대한 정보를 확인하고자 한다면  아래의 링크를 확인하시기 바랍니다

 

https://codingman.tistory.com/60

 

[C#] OpenCvSharp 이미지 코너 검출하기

안녕하세요 이번 포스팅은 불러온 이미지에서 CornerMinEigenVal을 이용한 코너 검출 그리고 CornerHarris를 이용한 코너 검출을 포스팅 해볼려고 합니다 일단 포스팅을 읽기에 앞서 OpenCvSharp에 대해서 공부하..

codingman.tistory.com

이번 포스팅에서는 직선 검출을 해볼껀데요

 

OpenCv에서 직선 검출시 사용할 함수는 바로 HoughLines2()함수 입니다

 

[함수 설명]

C# : public CvSeq HoughLines2(CvMat lineStorage, HoughLinesMethod method, double rho, double theta, int threshold, double param1, double param2);

 

  • lineStorage - 감지 된 라인의 스토리지입니다.
  • method - 허프 변환의 방법을 의미
    HoughLinesMethod.Standard : 기본 허프 변환
    HoughLinesMethod.Probabilistic : 확률적 허프변환, 전체 선이 아닌 선의 일부만 반환함. 선의 일부분은 시작점과 끝정보로 나타난다
    HoughLinesMethod.MultiScale : 기본 허프 변환에서 멀티 스케일 변형
  • rho - 필셀 단위로 나타나는 거리 값
  • theta - 라디안 단위로 나타나는 각도 값
  • threshold - 임계값, 해당 축적 값이 해당 값보다 크면 Line이 출력된다
  • param1 - 파라미터
    기본 허프 변환에서는 이 값이 사용되지 않는다
    Probabilistic 허프 변환에서는 선 길이의 최소 값을 나타낸다
    MultiScale 허프 변환에서는 거리 값에 대한 나누는 수를 의미한다
  • param2 - 파라미터
    기본 허프 변환에서는 이 값이 사용되지 않는다
    Probabilistic 허프 변환에서는 선들 사이의 최대 갭을 의미한다
    MultiScale 허프 변환에서는 각도에 대한 나누는 수를 의미한다

 

주요 함수 설명은 위와 같습니다 그럼 이제 구현을 하기 위한 디자인을 해보겟습니다

 

[디자인]

- 메인폼의 Menu트립에서 다음과 같이 디자인 합니다

 

- 해당 Menu 트립의 항목의 클릭 이벤트 설정

 

- 클릭이벤트에 다음과 같은 코딩은 합니다

 

[Source Code]

        private void 허프직선ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (hough Hg = new hough())
            using (IplImage temp = Hg.HoughLines(src))
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;

        }

 

- 직선 검출을 위한 Class파일을 생성합니다

  (저는 Class명칭을 다음과 같이 hough.cs로 생성하엿습니다)

 

[Class Source Code]

using System;
using System.Collections.Generic;
using System.Text;
using OpenCvSharp;

namespace OpenCV_V1
{
    class hough : IDisposable
    {
        IplImage houghLine;

        public IplImage HoughLines(IplImage src)
        {
            // cvHoughLines2
            // 확률적 허프 변환을 지정해 선분의 검출을 실시한다

            // (1) 화상 읽기 
            using (IplImage srcImgStd = src.Clone())
            using (IplImage srcImgGray = new IplImage(src.Size, BitDepth.U8, 1))
            {
                Cv.CvtColor(srcImgStd, srcImgGray, ColorConversion.BgrToGray);

                // (2) 허프변환을 위한 캐니엣지 처리 
                Cv.Canny(srcImgGray, srcImgGray, 50, 200, ApertureSize.Size3);

                using (CvMemStorage storage = new CvMemStorage())
                {


                    // (3) 표준적 허프 변환에 의한 선의 검출과 검출된 선 그리기
                    CvSeq lines = srcImgGray.HoughLines2(storage, HoughLinesMethod.MultiScale, 1, Math.PI / 180, 50, 0, 0);
                    int limit = Math.Min(lines.Total, 10);
                    for (int i = 0; i < limit; i++)
                    {

                        CvLineSegmentPolar elem = lines.GetSeqElem<CvLineSegmentPolar>(i).Value;
                        float rho = elem.Rho;
                        float theta = elem.Theta;

                        double a = Math.Cos(theta);
                        double b = Math.Sin(theta);
                        double x0 = a * rho;
                        double y0 = b * rho;
                        CvPoint pt1 = new CvPoint { X = Cv.Round(x0 + 1000 * (-b)), Y = Cv.Round(y0 + 1000 * (a)) };
                        CvPoint pt2 = new CvPoint { X = Cv.Round(x0 - 1000 * (-b)), Y = Cv.Round(y0 - 1000 * (a)) };
                        srcImgStd.Line(pt1, pt2, CvColor.Red, 3, LineType.AntiAlias, 0);
                    }

                    houghLine = srcImgStd.Clone();
                }

            }
            return houghLine;
        }


        public void Dispose()
        {
            if (houghLine != null) Cv.ReleaseImage(houghLine);
        }
    }
}

 

이렇게 Class파일까지 생성한 뒤 실행해서 확인해보면 다음과 같은 결과가 나타납니다

 

[결과 창]

 

이미지에서 Line을 검출하여 표시하는데 이미지처리를 하지 않고 원본 파일에서 그냥 검출 시도를 했을 경우 

 

다음과 같이 인식율이 상당히 이상하게 나오네요

 

아마 인식율을 높이기 위해서는 이미지처리(흑백전환 및 픽셀 전환, 등)을 통해 직선을 좀 더 명확하게 

 

구별할 수 있도록 변경한 후에 처리시키는게 좋을거 같네요

반응형
반응형

안녕하세요

 

이번 포스팅은 불러온 이미지에서 CornerMinEigenVal을 이용한 코너 검출 그리고 CornerHarris를 이용한 코너 검출을

 

포스팅 해볼려고 합니다

 

일단 포스팅을 읽기에 앞서 OpenCvSharp에 대해서 공부하면서 연결해서 포스팅 중인데

 

이미지를 불러오는 방법이나 이미지 처리에 관련된 기본 포스팅은 아래 링크를 통해 확인하시기 바랍니다

 

연제성 포스팅이기 때문에 해당 본문 내용이 다소 생략될수 잇으니 양해 바랍니다

 

https://codingman.tistory.com/49

 

[C#]OpenCvSharp 라이브러리 사용하기 #1

안녕하세요 저번 포스팅에 C#으로 OpenCvSharp 라이브러리를 등록하여 구현하는 포스팅을 준비하던중에 OpenCv 3,4 버전에서 오류가 발생하는 문제가 있다는 얘길 듣고 부랴부랴 포스팅 내용을 검토해봤는데 역시..

codingman.tistory.com

포스팅에 앞서 공부한 내용을 설명하고 프로그램에 대한 부분도 설명 드리겠습니다

 

이미지 처리 기법중 여러 방식의 코너 검출이 있습니다

 

그중 OpenCv는 4가지 커널을 사용하여 코너를 검출 합니다

 

- 사각형

- 다이아몬드

- X

- 십자

이 형태의 커널들을 이용하여 팽창, 침식 시킨 후 차영상을 통해 코너를 검출한다고 합니다

 

이러한 형태를 사용하여 쉽게 코너를 검출할 수 있는 함수가 OpenCv에 존재하는데요

 

바로 goodFeaturesToTrack라는 함수 입니다

 

해당 함수의 형태는

 

C#: void GoodFeaturesToTrack(CvArr image, CvArr eigImage, CvArr tempImage, out CvPoint2D32f[] corners, ref int cornerCount, double qualityLevel, double minDistance, CvArr mask);

 

• image – 8비트, 32비트 부동소수점 단일 이미지

eigImage 이미지와 동일한 크기의 임시 부동 소수점 32 비트 이미지

tempImage eigImage 와 크기 및 형식이 다른 임시 이미지

• corners – 검출된 코너를 담을 벡터

cornerCount– 반환될 코너의 최대 개수, 만약 찾아낸 코너의 수가 더 많을 경우, 강력한 코너가 반환된다.

• qualityLevel – 코너라고 판단하기 위한 기준이 되는 최소의 값, 이 값은 최고의 minimal eigenvalue를 가지는 코너의                         quality에 곱해지며, 그 값보다 작은 quality를 갖는 코너는 코너라고 판단하지 않는다. 예를 들어,

                     최고의 minimal eigenvalue=1500 이고, qualityLevel= 0.01 이면, quality가 15보다 작은 코너는

                     무시된다.

• minDistance – 반환되는 코너 사이의 최소 유클리디안 거리

• mask – 코너를 찾을 관심영역, input과 크기가 동일해야한다..

 

이렇게 사용되어 집니다

 

그러면 우선 메인폼의 디자인부터 설정하겠습니다

 

[디자인]

  - 메인폼의 Menu트립에서 다음과 같이 디자인 합니다

  - 최상단에 알고리즘 -> 코너검출 -> EigenVal / Harris

 

   - Menu 트립에 클릭 이벤트를 생성합니다

      

 

[Source Code]

- EigenVal / Harris의 각각의 클릭 이벤트에 다음과 같은 코딩을 해줍니다

        private void eigenValToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (corner Cn = new corner())
            using (IplImage temp = Cn.EigenValCornerDetect(src))
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;

        }
        private void harrisToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (corner Cn = new corner())
            using (IplImage temp = Cn.HarrisCornerDetect(src))
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;

        }

 

- 코너 검출을 위한 Class 생성

  (클래스명징은 corner로 사용하였습니다)

 

[Class Sorce Code]

- Class 생성 방법은 이전 포스팅에서 설명했기 때문에 생략하도록 하겠습니다

using System;
using System.Collections.Generic;
using System.Text;
using OpenCvSharp;

namespace OpenCV_V1
{
    class corner : IDisposable
    {
        IplImage cor;


        public IplImage EigenValCornerDetect(IplImage src)
        {
            // cvGoodFeaturesToTrack, cvFindCornerSubPix
            // 화상의 코너 검출

            int cornerCount = 150;

            using (IplImage dstImg = src.Clone())
            using (IplImage srcImgGray = new IplImage(src.Size, BitDepth.U8, 1))
            using (IplImage eigImg = new IplImage(srcImgGray.GetSize(), BitDepth.F32, 1))
            using (IplImage tempImg = new IplImage(srcImgGray.GetSize(), BitDepth.F32, 1))
            {
                Cv.CvtColor(dstImg, srcImgGray, ColorConversion.BgrToGray);

                CvPoint2D32f[] corners;
                // (1) CornerMinEigenVal를 이용한 코너 검출
                Cv.GoodFeaturesToTrack(srcImgGray, eigImg, tempImg, out corners, ref cornerCount, 0.1, 15);
                Cv.FindCornerSubPix(srcImgGray, corners, cornerCount, new CvSize(3, 3), new CvSize(-1, -1), new CvTermCriteria(20, 0.03));
                // (2) 코너 그리기
                for (int i = 0; i < cornerCount; i++)
                    Cv.Circle(dstImg, corners[i], 3, new CvColor(255, 0, 0), 2);

                cor = dstImg.Clone();

            }

            return cor;
        }

        public IplImage HarrisCornerDetect(IplImage src)
        {
            // cvGoodFeaturesToTrack, cvFindCornerSubPix
            // 화상의 코너 검출

            int cornerCount = 150;

            using (IplImage dstImg = src.Clone())
            using (IplImage srcImgGray = new IplImage(src.Size, BitDepth.U8, 1))
            using (IplImage eigImg = new IplImage(srcImgGray.GetSize(), BitDepth.F32, 1))
            using (IplImage tempImg = new IplImage(srcImgGray.GetSize(), BitDepth.F32, 1))
            {
                Cv.CvtColor(dstImg, srcImgGray, ColorConversion.BgrToGray);

                CvPoint2D32f[] corners;



                // (1) CornerHarris를 이용한 코너 검출
                cornerCount = 150;
                Cv.GoodFeaturesToTrack(srcImgGray, eigImg, tempImg, out corners, ref cornerCount, 0.1, 15, null, 3, true, 0.01);
                Cv.FindCornerSubPix(srcImgGray, corners, cornerCount, new CvSize(3, 3), new CvSize(-1, -1), new CvTermCriteria(20, 0.03));
                // (2) 코너 그리기
                for (int i = 0; i < cornerCount; i++)
                    Cv.Circle(dstImg, corners[i], 3, new CvColor(0, 0, 255), 2);

                cor = dstImg.Clone();

            }

            return cor;
        }

        public void Dispose()
        {
            if (cor != null) Cv.ReleaseImage(cor);
        }
    }
}

 

이렇게 Class까지 생성한 다음 빌드 하여 실행 시키면 다음과 같은 결과 값을 얻을수 잇습니다

 

[결과창]

*EigenVal

*Harris

반응형
반응형

안녕하세요

 

이번 시간에는 OpenCv를 통한 이미지 회전, 축소, 확대 기능을 만들어 볼려고 합니다

 

해당 기능을 구현하기 위해서 OpenCvSharp 라이브러리 등록부터 알아봐야 하는데 

 

아래 링크를 통해 확인해 보시기 바랍니다

 

https://codingman.tistory.com/49

 

[C#]OpenCvSharp 라이브러리 사용하기 #1

안녕하세요 저번 포스팅에 C#으로 OpenCvSharp 라이브러리를 등록하여 구현하는 포스팅을 준비하던중에 OpenCv 3,4 버전에서 오류가 발생하는 문제가 있다는 얘길 듣고 부랴부랴 포스팅 내용을 검토해봤는데 역시..

codingman.tistory.com

 

그러면 해당 기능을 사용하기 위한 메뉴 등록부터 진행 하겠습니다

 

[디자인]

  - 다음과 같이 Menu에 이미지처리 -> 회전, 확대, 축소 버튼을 만들어 주세요

 

  - 각각의 버튼에 클릭이벤트를 생성해 주세요

    (이벤트 생성 방법은 여러차례 포스팅하였으므로 생략하도록 할께요)

 

[Source Code]

-회전 클릭 이벤트

        private void 회전ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (geometry Go = new geometry())
            using (IplImage temp = Go.Affine(src))
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;

        }

 - 확대 클릭 이벤트

        private void 확대ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (geometry Go = new geometry())
            using (IplImage temp = Go.MyPyrUp(src))
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;

        }

 

- 축소 클릭 이벤트

        private void 축소ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (geometry Go = new geometry())
            using (IplImage temp = Go.MyPyrDown(src))
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;

        }

 

[클래스 생성]

- 이미지처리를 위한 전용 클래스 생성

 

- 클래스명은 geometry.cs로 지정하였습니다

  (클래스명은 굳이 똑같이 하지 않으셔도 됩니다)

 

 

[Source Code]

using System;
using System.Collections.Generic;
using System.Text;
using OpenCvSharp;

namespace OpenCV_V1
{
    class geometry : IDisposable
    {
        IplImage geo;

        #region Affine 변환
        //어파인 변환
        public IplImage Affine(IplImage src)
        {
            // cvGetAffineTransform + cvWarpAffine
            // 화상상의 3점에 대응하는 Affine 변환 행렬을 계산, 그 행렬을 이용하여 화상 전체의 Affine 변환을 실시한다.

            // (1) 화상을 읽어들이고, 출력용 화상의 메모리를 확보한다
            using (IplImage srcImg = src.Clone())
            using (IplImage dstImg = srcImg.Clone())
            {
                // (2) 삼각형의 회전전과 회전 후의 대응하는 정점을 각각 세트 해  
                //    cvGetAffineTransform를 이용해 Affine 행렬을 구한다  
                CvPoint2D32f[] srcPnt = new CvPoint2D32f[3];
                CvPoint2D32f[] dstPnt = new CvPoint2D32f[3];
                srcPnt[0] = new CvPoint2D32f(200.0f, 200.0f);
                srcPnt[1] = new CvPoint2D32f(250.0f, 200.0f);
                srcPnt[2] = new CvPoint2D32f(200.0f, 100.0f);
                dstPnt[0] = new CvPoint2D32f(300.0f, 100.0f);
                dstPnt[1] = new CvPoint2D32f(300.0f, 50.0f);
                dstPnt[2] = new CvPoint2D32f(200.0f, 100.0f);
                using (CvMat mapMatrix = Cv.GetAffineTransform(srcPnt, dstPnt))
                {
                    // (3) 지정된 어파인 행렬에 의해, cvWarpAffine를 사용해 화상을 회전시킨다
                    Cv.WarpAffine(srcImg, dstImg, mapMatrix, Interpolation.Linear | Interpolation.FillOutliers, CvScalar.ScalarAll(0));

                    geo = dstImg.Clone();

                }
            }
            return geo;
        }
        #endregion

        #region PyrUpDown



        //이미지의 확대
        public IplImage MyPyrUp(IplImage src)
        {
            using (IplImage srcImg = src.Clone())
            using (IplImage dstImg = new IplImage(srcImg.Width * 2, srcImg.Height * 2, srcImg.Depth, srcImg.NChannels))
            {
                // (1) 입력 화상에 대한 화상 피라미드를 구성

                Cv.PyrUp(srcImg, dstImg, CvFilter.Gaussian5x5);
                geo = dstImg.Clone();

            }
            return geo;
        }



        //이미지의 축소

        public IplImage MyPyrDown(IplImage src)
        {
            using (IplImage srcImg = src.Clone())
            using (IplImage dstImg = new IplImage(srcImg.Width / 2, srcImg.Height / 2, srcImg.Depth, srcImg.NChannels))
            {
                // (1) 입력 화상에 대한 화상 피라미드를 구성
                Cv.PyrDown(srcImg, dstImg, CvFilter.Gaussian5x5);
                geo = dstImg.Clone();

            }
            return geo;
        }

        #endregion 

        public void Dispose()
        {
            if (geo != null) geo.Dispose();
        }
    }
}
 

[결과 창]

- 이미지 회전

 

- 이미지 축소

 

-이미지 확대

 

반응형
반응형

안녕하세요

 

이번 포스팅은 OpenCvSharp을 이용한 이미지 얼굴 검출 기능 입니다

 

포스팅에 앞서 준비물이 필요합니다

 

1. haarcascade_frontalface_alt.xml 파일을 다운로드 받아 해당 Degub 폴더에 삽입해주세요.

 

haarcascade_frontalface_alt.zip
0.10MB

 

 

자 이렇게 준비물이 준비가 완료가 되셨다면 아래 단계를 따라해 주세요

 

[디자인]

  - 메뉴에 얼굴검출 메뉴를 등록해 주세요

 

[Source Code]

  - 해당 메뉴에 클릭이벤트를 기능을 만들어 주세요

        private void haar얼굴검출ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (Face FA = new Face())
            using (IplImage temp = FA.FaceDetect(src))
            {
                result = temp.Clone();

            }
            pictureBoxIpl2.ImageIpl = result;

        }

 

그리고 클래스를 생성해 줍니다

 

[Source Code]

- 저는 클래스명을 Face로 생성하였습니다

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using OpenCvSharp;

namespace OpenCV_V1
{
    class Face : IDisposable
    {
        IplImage FindFace;

        public IplImage FaceDetect(IplImage src)
        {
            // CvHaarClassifierCascade, cvHaarDetectObjects
            // 얼굴을 검출하기 위해서 Haar 분류기의 캐스케이드를 이용한다

            CvColor[] colors = new CvColor[]{
                new CvColor(0,0,255),
                new CvColor(0,128,255),
                new CvColor(0,255,255),
                new CvColor(0,255,0),
                new CvColor(255,128,0),
                new CvColor(255,255,0),
                new CvColor(255,0,0),
                new CvColor(255,0,255),
            };

            const double scale = 1.04;
            const double scaleFactor = 1.139;
            const int minNeighbors = 2;

            using (IplImage img = src.Clone())
            using (IplImage smallImg = new IplImage(new CvSize(Cv.Round(img.Width / scale), Cv.Round(img.Height / scale)), BitDepth.U8, 1))
            {
                // 얼굴 검출용의 화상의 생성
                using (IplImage gray = new IplImage(img.Size, BitDepth.U8, 1))
                {
                    Cv.CvtColor(img, gray, ColorConversion.BgrToGray);
                    Cv.Resize(gray, smallImg, Interpolation.Linear);
                    Cv.EqualizeHist(smallImg, smallImg);
                }

                using (CvHaarClassifierCascade cascade = CvHaarClassifierCascade.FromFile(Application.StartupPath + "\\" + "haarcascade_frontalface_alt.xml"))
                using (CvMemStorage storage = new CvMemStorage())
                {
                    storage.Clear();

                    // 얼굴의 검출

                    CvSeq<CvAvgComp> faces = Cv.HaarDetectObjects(smallImg, cascade, storage, scaleFactor, minNeighbors, 0, new CvSize(30, 30), new CvSize(0, 0));

                    // 검출한 얼굴에 원을 그린다
                    for (int i = 0; i < faces.Total; i++)
                    {
                        CvRect r = faces[i].Value.Rect;
                        CvPoint center = new CvPoint
                        {
                            X = Cv.Round((r.X + r.Width * 0.5) * scale),
                            Y = Cv.Round((r.Y + r.Height * 0.5) * scale)
                        };
                        int radius = Cv.Round((r.Width + r.Height) * 0.25 * scale);
                        img.Circle(center, radius, colors[i % 8], 3, LineType.AntiAlias, 0);
                    }
                }
                FindFace = img.Clone();
                return FindFace;
            }
        }

        public void Dispose()
        {
            if (FindFace != null) FindFace.Dispose();
        }
    }
}

 

[결과 창]

  - 실행하게 되면 다음과 같은 결과가 나오게 됩니다

    얼굴 인식율이 100%로는 아니지만 90%로 이상 검출이 가능한거 같네요

반응형

+ Recent posts