'Programing > OpenCV' 카테고리의 다른 글

수직에지기반 차량인식  (0) 2016.11.30
제스쳐 인식  (0) 2016.11.30
플러드필  (0) 2016.11.30
Opencv C# 모폴로지  (0) 2016.11.30
영상 모폴로지 자체 커널 만들기  (0) 2016.11.30



핸드 트래킹을 통해 손의 제스쳐를 이용해 컴퓨터를 제어할 수 있는 프로그램제작을 위한 예광탄을 만들었다.

RGB 컬러모델을 HSV로 변환하여 피부영역을 구하고해당 피부영역의 최대 면적의 영역을 남긴다해당 영역의 윤곽을 구하고 영역 중의 가장 긴 부분을 손가락으로 판정하였으며판정 결과 오차와 정확한 손가락 검출이 불가능하여 손의 무게중심을 이용하는 방법으로 테스트 해봐야 할 것 같다.






class Gestures

    {

 

        int TPL_WIDTH = MouseSystem.img_move.Width;

        int TPL_HEIGHT = MouseSystem.img_move.Height;

       

        const double THRESHOLD = 0.3;

 

        IplImage tpl, tm;

        int object_x0, object_y0;

       

 

        IplImage imgHSV;

        IplImage imgH;

        IplImage imgS;

        IplImage imgV;

        IplImage imgBackProjection;

        IplImage imgFlesh;

        IplImage imgHull;

        IplImage imgDefect;

        IplImage imgContour;

        IplImage[] hsvPlanes = new IplImage[3];

        IplImage imgclick;

        IplImage imgmove;

        CvMemStorage storage = new CvMemStorage();

 

        CvHistogram hist;

       

        CvPoint p1, p2;

        public Gestures()

        {

        }

       

        unsafe Point getCenter(IplImage img)

        {

            float []mask = new float[3];

            IplImage dist;

            IplImage dist8u;

            IplImage dist32s;

            int max;

            Point p = new Point();

            byte* ptr;

            dist = Cv.CreateImage(Cv.GetSize(img), BitDepth.F32, 1);

            dist8u = Cv.CloneImage(img);

            dist32s = Cv.CreateImage(Cv.GetSize(img), BitDepth.S32, 1);

 

            //거리변환 행렬 생성

            mask[0] = 1f;

            mask[1] = 1.5f;

 

            Cv.DistTransform(img, dist, DistanceType.User, 3, mask, null);

 

            Cv.ConvertScale(dist, dist, 10000);

            Cv.Pow(dist, dist, 0.5);

 

            Cv.ConvertScale(dist, dist32s, 1.00.5);

            Cv.AndS(dist32s, Cv.ScalarAll(255), dist32s, null);

            Cv.ConvertScale(dist32s, dist8u, 10);

            max = 0;

            for (int i = max; i < dist8u.Height; i++)

            {

                int index = i * dist8u.WidthStep;

                for (int j = 0; j<dist8u.Width; j++)

                {

                    ptr = (byte*)img.ImageData;                   

                    if((char)ptr[index +j] > max)

                    {

                        max = (char)dist8u[index + j];

                        p.X = j;

                        p.Y = i;

                    }                   

                }

            }

            return p;

 

        }

        public void Convexty(IplImage imgSrc)

        {

            try

            {

                imgHSV = new IplImage(imgSrc.Size, BitDepth.U8, 3);

                imgH = new IplImage(imgSrc.Size, BitDepth.U8, 1);

                imgS = new IplImage(imgSrc.Size, BitDepth.U8, 1);

                imgV = new IplImage(imgSrc.Size, BitDepth.U8, 1);

                imgBackProjection = new IplImage(imgSrc.Size, BitDepth.U8, 1);

                imgFlesh = new IplImage(imgSrc.Size, BitDepth.U8, 1);

                imgHull = new IplImage(imgSrc.Size, BitDepth.U8, 1);

                imgDefect = new IplImage(imgSrc.Size, BitDepth.U8, 3);

                imgContour = new IplImage(imgSrc.Size, BitDepth.U8, 3);               

                //imagmove;              

 

                int WINDOW_WIDTH = imgSrc.Width;

                int WINDOW_HEIGHT = imgSrc.Height;

 

                // RGB -> HSV

                Cv.CvtColor(imgSrc, imgHSV, ColorConversion.BgrToHsv);

                Cv.Split(imgHSV, imgH, imgS, imgV, null);

                hsvPlanes[0] = imgH;

                hsvPlanes[1] = imgS;

                hsvPlanes[2] = imgV;

 

                // 피부색 영역을 구한다

                RetrieveFleshRegion(imgSrc, hsvPlanes, imgBackProjection);

 

                // 최대의 면적의 영역을 남긴다

                FilterByMaximalBlob(imgBackProjection, imgFlesh);

                Interpolate(imgFlesh);

 

                //템플릿 매칭

               

                 //윤곽을 구한다

                CvSeq<CvPoint> contours = FindContours(imgFlesh, storage);

                if (contours != null)

                {

                    Cv.DrawContours(imgContour, contours, CvColor.Red, CvColor.Green, 03LineType.AntiAlias);

                    // 요철을 구한다

                    CvSeq hull = Cv.ConvexHull2(contours, storage, ConvexHullOrientation.Clockwise, false);

                    Cv.Copy(imgFlesh, imgHull);

                     //윤곽을 구합니다.

                    DrawConvexHull(hull, imgHull);

                    //DrawConvexHull(hull, imgBackProjection);

                   

                    // 오목한 상태 결손을 구한다

                    Cv.Copy(imgContour, imgDefect);

                    CvSeq<CvConvexityDefect> defect = Cv.ConvexityDefects(contours, hull, storage);

                    DrawDefects(imgDefect, defect);

                }

                else

                {

                    return;

                }

                imgmove = new IplImage(new CvSize(imgBackProjection.Width - MouseSystem.img_move.Width + 1,

                    imgBackProjection.Height - MouseSystem.img_move.Height + 1), BitDepth.F32, 1);

 

               

 

                //MouseSystem.imgResult[0] = imgSrc;

                tpl = MouseSystem.img_move;

                tm = new IplImage(new CvSize(WINDOW_WIDTH - TPL_WIDTH + 1, WINDOW_HEIGHT - TPL_HEIGHT + 1), BitDepth.F32, 1);

                trackObject(imgBackProjection);

 

                //Point result = getCenter(imgBackProjection);

                //imgDefect.DrawCircle(new CvPoint(result.X,result.Y), 70, new CvScalar(255,255,255) -1);

                MouseSystem.imgResult[0] = imgSrc;

                MouseSystem.imgResult[1] = imgBackProjection;

                MouseSystem.imgResult[2] = imgDefect;

                Cv.WaitKey();               

            }

            catch

            {

            }

        }

     

 

        private void DrawDefects(IplImage img, CvSeq<CvConvexityDefect> defect)

        {

            int count = 0;

            try

            {               

                foreach (CvConvexityDefect item in defect)

                {

                    p1 = item.Start;

                    p2 = item.End;

                    double dist = GetDistance(p1, p2);

                    CvPoint2D64f mid = GetMidpoint(p1, p2);

                    img.DrawLine(p1, p2, CvColor.White, 3);

                    if (count == 1)

                    {

                        img.DrawCircle(item.Start, 10CvColor.Pink, -1);

                        MouseSystem.MousePointStart = item.Start;

                    }

                    else

                    {

                        img.DrawCircle(item.Start, 10CvColor.Green, -1);

                    }

                    img.DrawLine(mid, item.DepthPoint, CvColor.White, 1);

                    count++;             

                }

 

                MouseSystem.str_ControlsCount = (count - 1).ToString();

                switch (count - 1)

                {

                    case 1:

                        MouseSystem.str_MouseState = "한개";

                        //NativeMethod.mouse_event(NativeMethod.WM_LBUTTONDOWN, 0, 0, 0, 0);

                        break;

                    case 2:

                        MouseSystem.str_MouseState = "두개";

                        //NativeMethod.mouse_event(NativeMethod.WM_LBUTTONDOWN, 0, 0, 0, 0);

                        break;

                    case 3:

                        MouseSystem.str_MouseState = "세개";

                        //NativeMethod.mouse_event(NativeMethod.WM_LBUTTONUP, 0, 0, 0, 0);

                        break;

                    case 4:

                        MouseSystem.str_MouseState = "네개";

                        //NativeMethod.mouse_event(NativeMethod.WM_LBUTTONUP, 0, 0, 0, 0);

                        break;

                    case 5:

                        MouseSystem.str_MouseState = "다섯개";

                        //NativeMethod.mouse_event(NativeMethod.WM_LBUTTONUP, 0, 0, 0, 0);

                        break;

                }

            }

            catch

            {

            }

        }      

 

        private CvPoint2D64f GetMidpoint(CvPoint p1, CvPoint p2)

        {

            return new CvPoint2D64f

            {

                X = (p1.X + p2.X) / 2.0,

                Y = (p1.Y + p2.Y) / 2.0

            };

         }

 

        private double GetDistance(CvPoint p1, CvPoint p2)

        {

            return Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2));

        }

 

        void DrawConvexHull(CvSeq hull, IplImage img)

        {

            CvPoint pt0 = Cv.GetSeqElem<Pointer<CvPoint>>(hull, hull.Total - 1).Value.Entity;

            for (int i = 0; i < hull.Total; i++)

            {

                CvPoint pt = Cv.GetSeqElem<Pointer<CvPoint>>(hull, i).Value.Entity;

                Cv.Line(img, pt0, pt, new CvColor(255255255));

                pt0 = pt;

            }

        }

 

        public CvSeq<CvPoint> FindContours(IplImage img, CvMemStorage storage)

        {

            // 윤곽 추출

            CvSeq<CvPoint> contours;

            IplImage imgClone = img.Clone();

            Cv.FindContours(imgClone, storage, out contours);

            if (contours == null)

            {

                return null;

            }

            contours = Cv.ApproxPoly(contours, CvContour.SizeOf, storage, ApproxPolyMethod.DP, 3true);

 

            // 제일   같은 윤곽만을 얻는다

            CvSeq<CvPoint> max = contours;

            for (CvSeq<CvPoint> c = contours; c != null; c = c.HNext)

            {

                if (max.Total < c.Total)

                {

                    max = c;

                }

            }

            return max;

        }

        public void Interpolate(IplImage img)

        {

            Cv.Dilate(img, img, null2);

            Cv.Erode(img, img, null2);

        }

 

        private void FilterByMaximalBlob(IplImage imgSrc, IplImage imgDst)

        {

            using (CvBlobs blobs = new CvBlobs())

            using (IplImage imgLabelData = new IplImage(imgSrc.Size, CvBlobLib.DepthLabel, 1))

            {

                imgDst.Zero();

                blobs.Label(imgSrc, imgLabelData);

                CvBlob max = blobs[blobs.GreaterBlob()];

                if (max == null)

                {

                    return;

                }

                blobs.FilterByArea(max.Area, max.Area);

                blobs.FilterLabels(imgLabelData, imgDst);

                MouseSystem.MousePointEnd = new CvPoint((int)max.Centroid.X, (int)max.MinY);

            }

        }

 

        private void RetrieveFleshRegion(IplImage imgSrc, IplImage[] hsvPlanes, IplImage imgDst)

        {

            int[] histSize = new int[] { 3032 };

            float[] hRanges = { 0.0f20f };

            float[] sRanges = { 50f255f };

            float[][] ranges = { hRanges, sRanges };

 

            imgDst.Zero();

            hist = new CvHistogram(histSize, HistogramFormat.Array, ranges, true);

            hist.Calc(hsvPlanes, falsenull);

            float minValue, maxValue;

            hist.GetMinMaxValue(out minValue, out maxValue);

            hist.Normalize(imgSrc.Width * imgSrc.Height * 255 / maxValue);

            Cv.CalcBackProject(hsvPlanes, imgDst, hist);

        }

 

        private void trackObject(IplImage img_src)

        {

            int WINDOW_WIDTH = img_src.Width;

            int WINDOW_HEIGHT = img_src.Height;

            try

            {

                CvPoint minloc, maxloc;

                double minval, maxval;

                int win_x0 = object_x0 - ((WINDOW_WIDTH - TPL_WIDTH) / 2);

                int win_y0 = object_y0 - ((WINDOW_HEIGHT - TPL_HEIGHT) / 2);

                Cv.SetImageROI(img_src, new CvRect(win_x0, win_y0, WINDOW_WIDTH, WINDOW_HEIGHT));

                Cv.MatchTemplate(img_src, tpl, tm, MatchTemplateMethod.SqDiffNormed);

                Cv.MinMaxLoc(tm, out minval, out maxval, out minloc, out maxloc);

                Cv.ResetImageROI(img_src);

                if (minval <= THRESHOLD)

                {

                    object_x0 = win_x0 + minloc.X;

                    object_y0 = win_y0 + minloc.Y;

                    Cv.DrawRect(img_src, new CvRect(object_x0, object_y0, TPL_WIDTH, TPL_HEIGHT), CvColor.Red, 2);

                }

            }

            catch

            {               

            }

        }

    }

 

'Programing > OpenCV' 카테고리의 다른 글

수직에지기반 차량인식  (0) 2016.11.30
제스쳐 인식  (0) 2016.11.30
플러드필  (0) 2016.11.30
Opencv C# 모폴로지  (0) 2016.11.30
영상 모폴로지 자체 커널 만들기  (0) 2016.11.30





  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);

            pictureBoxIpl1.ImageIpl = src;

        }

 

//픽쳐박스를 클릭 했을 경우 새로 창을 띄워  그림으로 보여준다

        private void pictureBoxIpl2_Click(object sender, EventArgs e)

        {

            if (pictureBoxIpl2.ImageIpl == nullreturn;

 

            using (CvWindow wind = new CvWindow("결과창"))

            {

                wind.Image = result;

                Cv.WaitKey(0);

            }

        }


'Programing > OpenCV' 카테고리의 다른 글

영상처리 컬러모델  (0) 2016.11.30
gray scale  (0) 2016.11.30
Opencv c#  (0) 2016.11.30
SIFT 알고리즘  (0) 2016.11.30
범위 강조 변환  (0) 2016.11.30

SIFT 알고리즘.docx

StartOpenCV.zip



SIFT 알고리즘

(영상 추적)


디지털 영상처리 개요


디지털 영상처리 기술은 영상 개선영상 복원영상 변환영상 분석영상 인식영상 압축으로 분류된다.
 그리고 구현 알고리즘은 화소 점 처리영역 처리기하학적 처리프레임 처리로 분류할 수 있다.

디지털 영상의 내부 

가로 및 세로의 크기가 M  N 픽셀로 이루어져 있다저장된 영상데이터는 차원 배열(array) 형태를 이룬다.영상 데이터의 값은 흑백 영상인 경우 각 픽셀이 0~255의 값을 가지게 되며 각 값들은 픽셀의 밝기값을 표현한다가장 어두운 픽셀은 0의 값을 가지며 255는 가장 밝은 데이터 값을 표현한다밝기를 가지는 이러한 픽셀들이 모여 한장의 그림을 구성하게 된다.

일반적인 물체 추적 시스템의 원리

카메라로부터 영상을 획득하고 필요한 전처리(processing)를 한다.

영상 속에서 물체(object)의 존재를 검출(detection)하고 물체가 존재하는 영역을 배경(background)으로부터 분할(segmentation)한다.(이때 분할된 영역은 대상이 되는 물체가 존재하는 영역과 반드시 일치하지는 않는다.)

이전 영상 프레임까지 얻은 정보로부터 추적중인 각 물체의 상태 정보에 근거하여 2단계에서 분할된 추정 영역에 속한 후보 영역과의 일치도(match)를 판정하고 현재 프레임에서의 각 물체의 상태를 갱신(update)하여 계속적으로 추적한다.

 


SIFT

David G. Lowe  Scale Invariant FeatureTransform(SIFT)라는 알고리즘을 제안했는데 이는객체의 모서리나 꼭지점 등에서 생성되는 특징 점을 벡터로 추출하여영상의 크기변화회전조명변화 등에 의한 변형에 대해 뛰어난 매칭 성능을 가진다하지만 SIFT 알고리즘은 영상을 반복적으로 연산하는 과정이 많아서 처리속도가 좋지 않다.

SIFT  서술자는 영상 변환,  크기,  회전,  노이즈 영향에도 일정한 특징 정합 성능을 유지한다. SIFT 를 이용한 특징 추출 과정은 아래 그림 처럼 크게 특징 점을 찾는 부분과 선택된 특징 점의 서술자(Descriptor)를 생성하는 두단계로 구분할 수 있다.  먼저,  특징 점 추출 단계에서는 스케일 공간상의 후보 특징 점을 추출하고 후보 특징 점의 안정성을 검사하여 안정된 특징 점의 위치를 세부 위치로 보정한다.  서술자 단계에서는 선택된 점들을 중심으로 주변 영역의 그레디언트를 통해 방향 성분을 얻게 되고,  얻어 진 방향 성분을 중심으로 관심 영역을 재설정하여 서술자를 생성하게 된다.

SIFT 알고리즘의 수행시간 및 성능을 좌우하는 요소

SIFT 알고리즘은 특징 점을 추출하기 위해 여러 가지단계를 거치는데첫 번째 단계는 같은 개체가 다른 관점에서라도 반복적으로 추출될 수 있는 크기와 위치의 후보 픽셀들을 뽑는 것이다각각의 후보픽셀에 대하여 더 세밀한 검사를 거쳐 특징 점으로 사용할지를 결정한다첫 번째 검사는 낮은 대비를 가지는 픽셀을 제거한다두 번째 검사는 모서리에 의해 추출된 특징 점을 제거한다.

'Programing > OpenCV' 카테고리의 다른 글

gray scale  (0) 2016.11.30
Opencv c# 2  (0) 2016.11.30
Opencv c#  (0) 2016.11.30
범위 강조 변환  (0) 2016.11.30
이진화  (0) 2016.11.30

범위 강조 변환 이란?

 영상에서 한 부분의 화소는 원 상태를 그대로 유지한 채 일정 범위의 화소만 강조하는 변환

 원하는 부분의 화소 값이 더 커지거나 작아져 다른 부분과 비교해서 더욱 도드라져 보임



기존의 영상을 출력해주고 다시 이진화로 변환된 영상을 출력해준다.

void CImageprocesingView::OnDraw(CDC* pDC)

{

             CImageprocesingDoc* pDoc = GetDocument(); // 도큐먼트클래스참조

             ASSERT_VALID(pDoc);

             int i, j;

             unsigned char R, G, B;

             for(i=0 ; i<pDoc->m_height ; i++){

                           for(j=0 ; j<pDoc->m_width ; j++){

                                        R = G = B = pDoc->m_InputImage[i*pDoc->m_width+j];

                                        pDC->SetPixel(j+5, i+5, RGB(R, G, B));

                           }

             }

             for(i= 0 ; i<pDoc->m_Re_height; i++){

                           for(j = 0 ; j<pDoc->m_Re_width; j++){

                                        R = pDoc->m_OutputImage[i*pDoc->m_Re_width+j];

                                        G = B = R;

                                        pDC->SetPixel(j+pDoc->m_width+10, i+5, RGB(R, G, B));

                           }

             }

}

 

 

범위반전 코드

void CImageprocesingDoc::OnStressTransform2() 

{

             CRangeofstress2 dlg;

             int i;

             m_Re_height = m_height;

             m_Re_width = m_width;

             m_Re_size = m_Re_height * m_Re_width;

             m_OutputImage = new unsigned char[m_Re_size];

             if(dlg.DoModal() == IDOK){

                           for(i=0 ; i<m_size ; i++){

                                        // 입력값이강조시작값과강조종료값사이에위치하면출력

                                        if(m_InputImage[i] >= dlg.m_Start1 && m_InputImage[i] <= dlg.m_End1)

                                                     m_OutputImage[i] = dlg.m_value;

                                        else

                                                     m_OutputImage[i] = m_InputImage[i];

                           }

             }

}



'Programing > OpenCV' 카테고리의 다른 글

gray scale  (0) 2016.11.30
Opencv c# 2  (0) 2016.11.30
Opencv c#  (0) 2016.11.30
SIFT 알고리즘  (0) 2016.11.30
이진화  (0) 2016.11.30

이진화란?

 이진화란 RGB값으로 다양하게 분포되어 있는 색상값을 0 1만의 값으로 표현하는 것이다실제적으로 RGB컬러 영상을 흑백(Gray channel)영상으로 바꾼뒤 특정 임계값을 기준으로 초과 값을 255이하 값은 0으로 변환한다

의도

 에지 검출시 영상의 변화 부분을 강조함으로써 물체의 윤곽선과 영상 신호 분포를 이진화 하여 나타내는 방법이다.

 

기존의 영상을 출력해주고 다시 이진화로 변환된 영상을 출력해준다.

void CImageprocesingView::OnDraw(CDC* pDC)

{

             CImageprocesingDoc* pDoc = GetDocument(); // 도큐먼트클래스참조

             ASSERT_VALID(pDoc);

             int i, j;

             unsigned char R, G, B;

             for(i=0 ; i<pDoc->m_height ; i++){

                           for(j=0 ; j<pDoc->m_width ; j++){

                                        R = G = B = pDoc->m_InputImage[i*pDoc->m_width+j];

                                        pDC->SetPixel(j+5, i+5, RGB(R, G, B));

                           }

             }

             for(i= 0 ; i<pDoc->m_Re_height; i++){

                           for(j = 0 ; j<pDoc->m_Re_width; j++){

                                        R = pDoc->m_OutputImage[i*pDoc->m_Re_width+j];

                                        G = B = R;

                                        pDC->SetPixel(j+pDoc->m_width+10, i+5, RGB(R, G, B));

                           }

             }

}

 

이진화 코드

void CImageProcessingDoc::OnBinarization()

{

             CConstantDlg dlg;

             int i;

             m_Re_height = m_height;

             m_Re_width = m_width;

             m_Re_size = m_Re_height * m_Re_width;

             m_OutputImage = new unsigned char[m_Re_size];

             if(dlg.DoModal() == IDOK){

                           for(i=0 ; i<m_size ; i++){

                                        if(m_InputImage[i] >= dlg.m_Constant)

                                                     m_OutputImage[i] = 255// 임계값보다크면출력

                                        else

                                                     m_OutputImage[i] = 0// 임계값보다작으면출력

                           }

             }

}





'Programing > OpenCV' 카테고리의 다른 글

gray scale  (0) 2016.11.30
Opencv c# 2  (0) 2016.11.30
Opencv c#  (0) 2016.11.30
SIFT 알고리즘  (0) 2016.11.30
범위 강조 변환  (0) 2016.11.30

+ Recent posts