반응형

State Pattern(상태 패턴)?

상태변화를 가지는 주요 객체를 다룰 때 유용하게 적용해 볼 수 있는 패턴이다.

의도

객체의 내부 상태에 따라 스스로 행동을 변경할 수 있게 허가하는 패턴으로 이렇게 하면 개체는 마치 자신의 클래스를 바꾸는 것처럼 보인다.

 


 

서브클래스들이 상속 받을 State를 다음과 같이 만든다.

모두 가상 메서드로 이루어지고 각 가상 메서드는 에러처리만 하도록 만든다. 후손개체의 메서드가 사용되지 않고, 조상 개체의 메서드가 사용되면 자동으로 에러가 나도록 만든다.

State.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace StatePattern

{

    class State

    {

        public virtual bool Attack(Character character)

        {

            Console.WriteLine("공격 오류!");

            return false;

        }

        public virtual bool Move(Character character)

        {

            Console.WriteLine("이동 오류 !");

            return false;

        }

        public virtual bool Lucky(Character character)

        {

            Console.WriteLine("행운 오류!");

            return false;

        }

        public virtual void CountDown(Character character)

        {

        }

    }

}

 

 

싱글톤패턴 적용하여 시스템에 하나의 개체만 존재하도록 하였고, 생성자 캐릭터 개체를 입력 받도록 만들어주어, 나중에 상태개체를 변경해야 할 때 사용한다

 

Normal.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace StatePattern

{

    class Normal : State

    {

        private static Normal this_object;

        public static Normal get_object

        {

            get

            {

                if (this_object == null)

                {

                    this_object = new Normal();

                }

                return this_object;

            }

        }

        public override bool Attack(Character character)

        {

            Console.WriteLine("100% 공격력!!");

            character.Hp -= 40;

            if (character.Hp < 30)

            {

                character.chageState(Emergency.get_object);

            }

            return true;

        }

        public override bool Move(Character character)

        {

            Console.WriteLine("100% 이동!!");

            //character.chageState(Superman.get_object);

            return true;

        }

      

    }

}

 

 

Emergency.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace StatePattern

{

    class Emergency : State

    {

        Random rand = new Random();

        private static Emergency this_object;

        public static Emergency get_object

        {

            get

            {

                if (this_object == null)

                {

                    this_object = new Emergency();

                }

                return this_object;

            }

        }

        public override bool Attack(Character character)

        {

            int luck=0;

            Console.WriteLine("공격 75 %!!");

            luck = rand.Next(3);

            if (luck == 2)

            {

                character.chageState(Immortal.get_object);

                Immortal.before_state = this;

            }

            return true;

        }

        public override bool Move(Character character)

        {

            Console.WriteLine("이동 50%!!");

            return true;

        }

        public override bool Lucky(Character character)

        {           

            Console.WriteLine("행운 15!");

            return true;

        }

    }

}

 

 

 

※ 캐릭터를 담당 하게 될 Character  클래스를 보도록 하자Character Class 내부에 State 개체를 가지게 되는데, 이 개체는 수시로 각 상태를 담당하는 개체로 형 변환을 하게 된다.

 

Character.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace StatePattern

{

    class Character

    {

        int hp;

        private State state;

        public Character()

        {

            hp = 100;

            chageState(Normal.get_object);

        }

        public int Hp

        {

            get

            {

                return hp;

            }

            set

            {

                hp = value;

            }

        }

        public void chageState(State state)

        {

            this.state = state;

        }

        public void Move()

        {

            state.Move(this);      

        }

        public void Attack()

        {

            state.Attack(this);           

        }

        public void Lucky()

        {

            state.Lucky(this);

        }

        public void CountDown()

        {

            state.CountDown(this);

        }

        public void SuperItem()

        {

            chageState(Superman.get_object);

        }

    }

}

 

 

마지막으로 파일관리 개체를 활용하는 모듈을 작성한다. 이때 모듈은 파일관리 개체의 상태에 전혀 신경을 쓰지 않아도 된다. 그냥 메서드를 호출하여 사용하기만 하면 된다.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace StatePattern

{

    class Program

    {

        static void Main(string[] args)

        {

            Character c = new Character();

           

            c.Attack();

            c.Attack();

            c.Attack();

            c.Move();

           

            c.Attack();

            c.Attack();

            c.Attack();

            c.Attack();

            c.Attack();

            c.SuperItem();

            c.Attack();

            c.Attack();

        }

    }

}

 





반응형

'Programing > Design Pattern' 카테고리의 다른 글

State Pattern (상태패턴)  (0) 2016.11.30
템플릿 메서드  (0) 2016.11.30
전략패턴,Strategy patterns  (0) 2016.11.30
반응형



우리는 게임이든다른 것이든 이런 객체의 상태에 대해서 많이 접하게 됩니다상태에 따라서 같은 기능도 다르게 작동해야 하는데 위 그림도 그것을 나타내고 있습니다만약 우리가 상태 패턴을 모른다면 두가지 방법밖에 없습니다상태가 정수로 표현된다면switch 문으로 case를 상태로 하여 쭈욱 늘어 뜨릴 수 있고상태가 정수가 아닌 문자열이나 기타 다른 조건이라면 if, else if로 복잡하게 코딩할 수 밖에 없습니다.






캐릭터 클래스의 모든 매서드의 처리를 상태객체에게 위임합니다위임된 기능은 상태 객체의 현재 타입에 따라 다르게 처리됩니다현재 타입이란 서브클래스 타입을 말하는 것이죠. 이 자체가 상태가 됩니다위임된 처리를 수행하는 방법은 캐릭터 클래스내에서 상태 객채를 접근 가능하게 한뒤상태 객체는 캐릭터 객체를 매개변수로 받아서 처리를 구현합니다이것은 마치 캐릭터 객체를 대신 해서 동작하는 느낌입니다상태를 바꿀때도 이런 방법을 사용합니다상태 객체는 내부 데이터 변수가 없기 때문에 싱글톤으로 만들어 여러 캐릭터 객체가 이 상태객체의 기능을 공유할 수 있습니다.*플라이급 패턴



반응형

'Programing > Design Pattern' 카테고리의 다른 글

상태패턴 예제  (0) 2016.11.30
템플릿 메서드  (0) 2016.11.30
전략패턴,Strategy patterns  (0) 2016.11.30
반응형

템플릿 메서드


 객체의 연산에는 알고리즘의 뼈대만을 정의하고 각 단계에서 수행할 구체적 처리는 서브클래스 쪽으로 미룹니다. 알고리즘의 구조 자체는 그대로 놔둔 채 알고리즘 각 단계처리를 서브클래스에서 재정의할 수 있게 합니다.


-GOF의 디자인패턴 중-











예를 들어 기존 커피와 차를 만드는 코드가 있는데 코코아를 만드는 코드를 만들게 되었습니다.이럴 경우 만드는 순서, 물을 끓이고 컵에 담는 동일 공정이 해야 할 것입니다.



하지만 템플릿 메서드를 사용 할 경우 동일 공정을 부모 클래스에 정의함으로써 코드의 중복과 하드 코딩을 방지 할 수 있습니다. 클래스는 부모클래스인 비버리지와 서브클래스인 커피와 티로 구성되며, 템플릿 메서드로는 음료제작에 대한 알고리즘의 골격을 정의하는 프리퍼레시피가 있습니다. 우선 부모클래스인 비버리지가 서브클래스인 커피와 티에 공통적인 행위에 대하여 정의하면, 자식클래스인 커피와 티는 서로 공통되지 않는 부분에 대하여 정의하고 있습니다. 또한 프로퍼레시피의 코디먼트는 첨가물여부에 대한 훅메소드로 구성되어 있습니다.


여기서 훅메소드는 부모 클래스에 선언되는 메소드이기는 하지만 기본적인 내용만 구현되어 있거나 아무 코드도 들어있지 않은 메소드 입니다. 이를 서브 클래스에서 선택적으로 오버라이드 하여 사용하며, 오버라이드 하지 않으면 부모클래스에서 기본으로 제공한 코드가 실행됩니다.


이러한 템플릿 메서드는 코드의 재사용성을 높일수 있다는점과 일부행동만 지정하는 프레임웍을 만다는데 유용하지만, 서브클래스가 꼭 구현해야할 매서드의 개수가 많아질수록 설계가 복잡해지고, 상속에 의존적이기 때문에 유연성이 떨어지는 단점이 있습니다.


관련패턴으로는 전략패턴이 있는데, 템플릿메서드는 동일알고리즘의 일부분이 다양한 형태를 띄도록 하기 위해 서브클래스에서 처리하고, 

전략패턴은 바꿔쓸수 있는 행동을 캡슐화하고, 어떤행동을 사용할지는 서브클래스에게 위임한다는 차이점이 있습니다. 


#include <iostream> 

 



using std::cout; 

using std::cin; 

using std::endl; 



class Beverage 

public: 

// 템플릿(틀) 메소드. 

// 알고리즘의 각 단계가 파생 클래스에서 수정되는 것을 방지하기 위해 비가상으로 선언.

// 비가상인터페이스 :  private 가상 함수를 감싸는 publice 비가상 함수(비가상 인터페이스)를 만들어 

// 인터페이스를 단일화하는 것을 의미

// 템플릿 메소드 패턴으로 구현

void PrepareRecipe() 

BoilWater(); 

Brew(); 

PourInCup(); 

if ( Condiments() ) // 후킹! 

AddCondiments(); 

}

}

private: 

// 모든 가상 메소드를 정의 해야만 한다.

//가상메소드 정의 (Brew & AddCondiments)

virtual void Brew()=0;

virtual void AddCondiments()=0;

// 후크연산 기본적으로 부모연산은 아무행동도 정의하지 않는다.

// 기본 클래스에 있는 템플릿 메소드의 알고리즘 단계에 파생 클래스가 여러가지 방식으로 개입할 수 있게 된다. 

virtual const bool  Condiments() 

{

return true; 

} //기본값 : 첨가물추가


void BoilWater() { cout << "물 끓이는 중" << endl; } 

void PourInCup() { cout << "컵에 따르는 중" << endl; } 

}; 



class Coffee: public Beverage 

private: 

// 가상메소드 재정의 (Brew & AddCondiments)

void Brew()

{

cout << "커피 우려내는중~"<<endl;

}


//행동확장을 위해 후크연산을 재정의한다.

virtual const bool Condiments() // 후크

cout << "설탕과 우유를 넣으시겠습니까? : 1. 네, 2. 아니오" << endl; 

int answer=0; 

bool res=0;


cin >>answer; 

if (answer ==1)

res = true; 

else if (answer ==2)

res = false;

return res; 

}

void AddCondiments()

{

cout << "우유와 설탕을 추가하는중~"<<endl; 

}

};



class Tea: public Beverage 

private: 

// 가상메소드 재정의 (Brew & AddCondiments)

void Brew()

{

cout << "티백 우려내는중~"<<endl;

}

void AddCondiments()

{

cout << "레몬을 추가하는중~"<<endl; 

}

};



void main()

{

Beverage *cafe = new Coffee();

cafe->PrepareRecipe();


delete cafe;


cout<<"\n\n"<<endl;


cafe = new Tea();

cafe->PrepareRecipe();


delete cafe;


cout<<"\n\n"<<endl;

cafe = new Coffee();

cafe->PrepareRecipe();


delete cafe;

}


반응형

'Programing > Design Pattern' 카테고리의 다른 글

상태패턴 예제  (0) 2016.11.30
State Pattern (상태패턴)  (0) 2016.11.30
전략패턴,Strategy patterns  (0) 2016.11.30
반응형

전략패턴



전략패턴의 핵심은 객체의 내부에서 나타날 수 있는 행동을 따로 분리하여 여러개로 확장하여 일일이 서브클래스마다 행동에 대한 하드코딩을 피한다는 것입니다.

하드코딩을 하지않는 대신생성자를 통해 매뉴얼(전략)을 선택하여 집어넣으면

끝입니다.


위 상황은 단순한 상황입니다이전 설계 할 때 모든 유닛 오브젝트는Att을 할꺼로 예상하고 베이스 오브젝트에 그 가상함수를 넣어놨습니다.

그리고 3개의 하위 클래스를 설계합니다. Marin,Medic,Tank 근데 문제가하나 있습니다. Medic은 예상을 벗어나 Att에 대한 행동을 정의할 수 없게 되었습니다해병은 총을 쏘고탱크는 캐논샷을 쏘지만 메딕은 공격을 하지 못합니다그래서 설계한 방법으로 베이스 클래스의 Att함수를 오버라이딩해서 {} 이렇게 빈칸으로 두기로 했습니다하지만 이런식으로 베이스 클래스의 가상함수가 늘어날수록 동작을 하지 않아야 되는 함수들을 일일이 오버라이딩으로 처리하여 코딩하는 것은 상당히 귀찮은 일입니다문법때문에 어쩔수 없다는 생각을 가져도 만약 1000개의 오브젝트에서 그런 하드코딩을 하라면….. 더불어 코딩이 실제로 들어가므로 유지보수때도 신경쓸 수 밖에 없습니다예를들어 베이스클래스의 기능이 10가지 인데 메딕은 그중에 3가지 밖에 쓰지 않는다고 가정해 봅시다그럼 나머지 7개를 빈칸으로 오버라이딩 할 수 밖에 없는 것이죠

이때 전략패턴을 사용하면 이런 수고를 덜 수 있을 뿐더러 다른 행동까지도 동적으로 정의할 수 있는 유연성이 생깁니다


위 그림에서 같이 전략패턴에서 전략을 나타내는 객체를 매뉴얼이라고 표현했습니다제가 생각하기에는 매뉴얼이 전략패턴의 컨셉과 잘 맞는것 같습니다전략 패턴의 핵심은 객체의 내부에서나타날 수 있는 행동을 따로 분리하여 여러 개로 확장하여 일일이 서브클래스마다 행동에 대한 하드코딩을 피한다는 것입니다하드코딩을 하지 않는 대신생성자를 통해 매뉴얼(전략)을 선택하여 집어넣으면 끝입니다위에서 Att함수는 그 내부에서 매뉴얼을 참조해서 행동하므로 다른 Att행동을 취할 수 있습니다만약 생성자에 매뉴얼을 넣지 않을때 Att함수는 아무일도 하지않게 설계하면 메딕을 생성하는데 문제가 없습니다





하나는 매개변수를 직접 마련하여 전달하는 형식이고 다른 하나는 객체 자신을 매개변수로 넘겨 접근권한을 주고 처리하게 하는 형식입니다전자는 매개변수 인터페이스에 맞춰서 전략객체의 기능을 사용하기때문에 매개변수를 위한 준비가 필요합니다그 인터페이스가 많은 서브클래스들을 고려하여 너무 복잡하다면 어떤 서브 객체에게는 쓰이지 않게 되는 매개변수가 생길 수도 있습니다.

후자는 매개변수에 객체 자신의 참조자를 넘겨 처리하는 방법입니다이는 상태패턴과 동일한 방법이라고 하는데요 본객체와 전략객체간의 겹합도가 높아지게 되는 방법이기도 한데 강결합으로해야 효율이 나올 수 밖에 없는 경우외에는 별로임

 

구구단 2 2단노트

 

– 결론-

 

전략패턴은 말그대로 객체의 전략을 런타임에 다르게 설정할 수 있게 해주는 패턴입니다.

객체안의 여러 매서드들에 대한 행동을 무한한 형태로 전략을 조합하여 변경할 수 있습니다.

행동 전체를 변경할 수도 있지만 행동에 쓰이는 알고리즘 하나만 변형하게 하여 성능의

향상을 꾀할 수도있습니다.


예제)

 #include <iostream>

using namespace std;

#define interface struct

interface Manual

{

virtual void Att() = 0;

};


class GunShot :public Manual

{

public : void Att()

{

cout << "따다다다당"<<endl;

}

};


class CanonShot : public Manual

{

public :

void Att()

{

cout <<"푸학 폭~!"<<endl;

}

};


class SteamPack : public Manual

{

public :

void Att()

{

cout <<"따다다다당 따다다다당 따다다다당~!"<<endl;

}

};


class Unit

{

Manual *_strategy;

public :

Unit(Manual *strategy=0)

{

_strategy = strategy;

}

virtual ~Unit() { }

void Att()

{

if(_strategy)

{

_strategy->Att();

}

}

virtual void Display() =0;

};

//*************************Marin*****************************

class Marine :public Unit

{

SteamPack *sp;

public :

Marine(Manual *ma) : Unit(ma)

{

sp = 0;

}

void SteamPackUpGrade()

{

if(sp == 0)

{

sp = new SteamPack();

}

}

void SteamPackAttack()

{

if(sp)

{

sp->Att();

}

}

~Marine()

{

if(sp)

{

delete sp;

}

}

public:

void Display()

{

}

};

//*************************Enginneer*****************************

class Medic :

public Unit

{

public:

Medic(Manual *ma=0) : Unit(ma){ }

public :

void Display()

{

}

};

//*************************Tank*****************************

class Tank:

public Unit

{

public :

Tank(Manual *ma) : Unit(ma) { }

public:

void Display()

{

}

};


void main()

{

Unit *unit = new  Marine(new GunShot);

unit->Att();


Marine *marine = dynamic_cast<Marine*>(unit);

marine->SteamPackUpGrade();

marine->SteamPackAttack();


Unit *unit2 = new  Tank(new CanonShot);

unit2->Att();


Unit *unit3 = new  Medic();

unit3->Att();

delete unit;

delete unit2;

delete unit3;

}


반응형

'Programing > Design Pattern' 카테고리의 다른 글

상태패턴 예제  (0) 2016.11.30
State Pattern (상태패턴)  (0) 2016.11.30
템플릿 메서드  (0) 2016.11.30
반응형

차량의 뒷모양은 매우 복잡하여서 영상에서도 매우 복잡한 화소 변화로 인해 에지 특징이 잘 나타난다특히 수직 방향의 화소 변화가 두드러지기 때문에 수직 에지 성분이 잘 나타난다.  아래 그림은 수직 에지를 분석한 부분이다.


수직 방향 에지를 분석하여 전체 영역에서 흰색 부분만 추출하기 위해 침식 팽창 연산을 하여 차량 뒷부분을 뚜렷하게 강조 하였다.

 


해당 부분에서 가장 흰색영역이 큰 부분이 우리와 가장 인접한 차량이 된다해당 프로젝트에서 필요한 정보는 앞차와의 거리를 인식하기 위함 이기 때문에 앞차만을 위한 관심 영역을 지정하여 진행 하였다.



이 부분에서 차선을 기반으로 관심영역을 지정해 주면 앞차만을 인식 할 수 있다.


 

 첫번째 결과 이다차량을 정확하게 잡아주기는 하나 앞차선에 대한 관심영역 설정이 잘못되어 앞차량 보다 엣지성분이 많은 트럭을 잡게 되었다.




반응형

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

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


반응형

'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
반응형

플러드필은 영상에서 특정 영역을 고립시키거나 구분할 때 사용되는 기능이며영상 처리 및 영상 분석 등의 전처리 과정으로 널리 사용된다플러드필은 입력 영상으로부터 마스크를 만드는 용도로 사용될 수 있는데이러한 마스크는 추후 제한된 영역에서만 연산을 수행하도록 하여 전체 연산 속도를 향살시키는 용도로 사용될 수 있다.마스트는 Cv.FloodFill() 함수의 인자로도 사용될  있으며 경우 채우기가 완료된 곳을 제어하는 용도로 사용된다.

 

OpenCV에서 제공하는 플러드필은 다른 페인팅 프로그램에서 채우기 기능의 일반적인 형태이다일단 영상에서 씨앗점을 선택해 주어야 하고 점과 유사한 이웃 점들이 모두같은 색깔로 칠해진다다른 페인팅 프로그램과 조금 다른 점은 OpenCV 플러드필은 주변 픽셀과 색상이 완전히 똑같을 필요가 없다는 점이다Cv.FloodFill() 함수는 주변 픽셀값이 이미 색칠되어 있는 인접한 픽셀값 또는 씨앗점 픽셀값과 비교하여 특정 범위 안에 있으면 색을 칠한다플러드필은 선택적으로 전달되는 mask 인자에 의해 동작이 제한될 있다.

 

FloodFill(CvArr image, CvPoint seed_point, CvScalar new_val, CvScalar lo_diff, CvScalar up_diff, out CvConnectedComp comp, int flags, CvArr mask);



첫 번째 인자 image는 입력 영상이며, 8비트 또는 실수형이고, 1또는 3채널 영상이다플러드필은 씨앗점에서 시작하고추후 선택된 영역은 newVal값으로 색칠한다특정 픽셀값이 이미 색칠되어 있는 이웃 픽셀의 밝기값에서 lo_diff를 뺀 값보다 같거나 크고, up_Diff를 더한 값보다는 같거나 작을 경우이 픽셀을 newVal 값으로 색칠한다만약flags 인자에 CV_FLOODFILL_FIXED_RANGE 값이 포함되어 있따면인접한 이웃 픽셀과 값을 비교하지 않고 씨앗점의 픽셀값과 비교한다. comp인자가 null이 아니면채워진 영역에 대한 통계 정보를 담고 있는 CvConnectedComp 구조체를 가리킨다.                  

씨앗점으로 (흰색)지정

 



mask 인자는 cvFloodFill() 함수의 입력으로도 작용하고출력으로도 사용된다입력으로 사용될 경우에는 채우기가 적용될 영역을 제한하는 역할을 담당하고출력으로 사용될 경우에는 실제 채워진 영역을 가리키는 용도로 사용된다. Mask null이 아니라면입력 영상보다 가로세로 방향으로 2픽셀 더 큰, 8비트 1채널 영상이어야 한다입력영상보다 큰 영상으로 mask를 설정하는 이유는 내부 작업을 쉽고 빠르게 수행하기 위함이다. Mask 영상에서(x+1,y+1)위치의 픽셀은 입력 영상의 (x,y)좌표의 픽셀과 대응된다.  Flags의 하위 8비트는 4또는 8값을 가질 수 있다이 값은 채우기 알고리즘에서 연결성을 제어하는 용도로 사용된다이 값이 8이면양쪽 대각선 방향으로 인접한 픽셀들도 이웃 픽셀로 간주도니다상위 8비트(16~23) CV_FLOODFILL_FIXED_RANGE 또는 CV_FLOODFILL_MASK_ONLY 값을 가질 수 있다. CV_FLOODFILL_FIXED_RANGE가 설정되면채우기 알고리즘에서 이웃 픽셀의 값과 비교하는 대신 씨앗점 픽셀값과 비교한다. CV_FLOODFILL_MASK_ ONLY가 설정되면 원본 영상에 채우기 결과를 설정하는 대신mask 영상에만 결과를 표현한다. CV_FLOODFILL_MASK_ONLY를 설정하는 경우 반드시 mask 인자값을 설정해 주어야 한다.


if (src == nullreturn;

            IplImage dst = Cv.CreateImage(src.Size, BitDepth.U8, 3);

 

            IplImage tempimage = src.Clone();            

 

            //Cv.FloodFill(src, new CvPoint(3, 240),0,7.0,7.0);

            //Cv.FloodFill(src,new CvPoint(0,255), 255, 7.0, 7.0);

            CvConnectedComp aa = new CvConnectedComp();

            

 

            Cv.FloodFill(src, Cv.Point(10255), Cv.RGB(255255255), Cv.ScalarAll(25.0),Cv.ScalarAll(25.0));

            

            resultwb = new WriteableBitmap(src.Width, src.Height, 9696PixelFormats.Bgr24, null);

 

            WriteableBitmapConverter.ToWriteableBitmap(src, resultwb);

 

            image2.Source = resultwb;


 

반응형

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

제스쳐 인식  (0) 2016.11.30
제스쳐 인식  (0) 2016.11.30
Opencv C# 모폴로지  (0) 2016.11.30
영상 모폴로지 자체 커널 만들기  (0) 2016.11.30
영상 모폴로지  (0) 2016.11.30
반응형

이진 영상의 모폴로지는 기본적인 침식과 팽창 연산만 알고 있어도 충분하다그러나 그레이스케일 또는 컬러 영상의 경우유용한 모폴로지 연산들이 더 존재한다모폴로지 연산들은 모두 하나의 함수 Cv.MorphologyEx()를 이용한다.

 

public static void MorphologyEx(CvArr src, CvArr dst, CvArr temp, IplConvKernel element, MorphologyOperation operation, int iterations);

 

Cv.MorphologyEx() 함수는 두개의 새로운 매개변수를  받는다하나는 temp 배열이고다른 하나는 operation이다. Temp 배열이 선택적으로 사용된다, temp 배열이 사용되는 경우 배열은 입력 영상과동일한 크기여야 한다.

 

Operation 인자에 지정할  있는 

Operation

모폴로지 연산

Temp 영상의 필요 유무

MorphologyOperation.Open

열기

불필요

MorphologyOperation.Close

닫기

불필요

MorphologyOperation.Gradient

모폴로지 그래디언트

항상필요

MorphologyOperation.Tophat

탑 

바꿔치기 전용(src = dst)

MorphologyOperation.Blackhat

블랙 

바꿔치기 전용(src = dst)


열기와 닫기 연산

열기와 닫기 연산은 침식과 팽창 연산을 조합하여 사용함으로써 이루어진다열기 연산의 경우침식 연산을 수행한 후 팽창 연산을 수행한다열기 연산은 종종 이진 영상에서 독립된 영역들의 개수를 세기 위해서 사용된다예를 들어현미경으로 관찰한 세포 영상을 임계값을 이용하여 이진화한 후열기 연산을 수행하여 가까이 붙어 있는 세포들을 서로 떨어뜨리려 놓고 나서 세포의 수를 세곤 한다닫기 연산은 팽창을 먼저 하고 침식 연산을 수행한다닫기 연산은 연결된 구성 요소 알고리즘 등에서 잡음에 의한 원치 않은 분할을 최소한으로 줄이고자 사용한다연결된 구성 요소 레이블링을 수행하기 위해 보통 침식 또는 닫기 연산을 수행하여 잡음을 먼저 제거하고열기 연산을 수행하여 다시 가까이 인접한 큰 영역들을 합쳐준다열기 또는 닫기 연산의 결과는 침식 또는 팽창 연산의 결과와 유사하지만열기 및 닫기 연산이 연결된 영역을 보다 정확하게 보존해준다.

 

IplImage tempimage = src.Clone();

 

            IplConvKernel element = Cv.CreateStructuringElementEx(3,322ElementShape.Rect, null);

 

            Cv.MorphologyEx(src, dst, tempimage, element, MorphologyOperation.Open, 3);



모폴로지 열기 연산의 결과작은 크기의 밝은 영역은 사라지고남아 있는 밝은 역역의 크기는 유지된채 고립되어 있다.


모폴로지 닫기 연산의 결과밝은 영역들이 서로 합쳐졌지만 기본 크기는 유지하고 있다.

 

Iterations 2를 전달하여 닫기 연산을 두 번 수행하는 것은 팽창-침식-팽창-침식 연산을 수행하는 것 같은 효과를 나타낸다그러나 이러한 연산은 그다지 유용하지 않다보통의 경우팽창-팽창-침식-침식 같은 연산을 원할 것이다팽창-팽창-침식-침식과 같은 방식으로 모폴로지 연산을 수행해야 팽창-침식을 한 번 수행하는 것보다 더 큰 잡을을 제거하는 효과가 있다.

 

모폴로지 그래디언트

이 연산을 이진 영상에 적용하면 영역의 외곽선만 남기는 효과가 있다.

Gradient(src) = dilate(src) - erdoe(src)



모폴로지 그래디언트 연산의 결과주변부 엣지가 밝게 표현된다.

 

그래이스케일 영상에 대한 모폴로지 그래디언트 연산 결과는 영상에서 밝기값 변화량의 정도를 알려준다모폴로지 그래디언트는 밝은 영역 주위를 고립시켜서 이를 하나의 객체로써 다룰 수 있도록 해준다영역의 완전한 외곽선은 확정된 영역으로부터 수축된 영역을 빼는 차연산을 통해 쉽게 구할 수 있다이는 객체의 그래디언트를 계산 하는 것과는 다르다.(그래디언트 관한 소벨샤르 연산)

 

-햇 연산과 블랙-햇 연산

이들 연산은 주변보다 밝거나 어두운 영역을 고립시키는 효과가 있기 때문에 특정 객체 내부에서 밝기 변화가 두드러진 부분을 찾아내기 위해 사용된다예를 들어생체조직 또는 세포를 촬영한 현미경 영상을 다룰 때 사용되기도 한다.

TopHat(src) = src - open(src)

BlackHat(src) = close(src) - src

 

-햇 연산은 입력 영상에서 열기 연산이 수행된 영상을 빼는 연산이다열기 연산은 영상에서 밝기값이 크게 튀는 작은 덩어리를 제거하는 효과가 있다그러므로 src에서open(src)를 빼게 되면 결과적으로 원본 src영상에서 주변보다 밝았던 부분만 남아서 강조되어 보인다이러한 효과는 커널의 크기에 의존적이다이와 반대로 블랙-햇 연산은 원본 영상에서 주변보다 어두운 영역만 강조한다.


모폴로지 탑-햇 연산의 결과주변보다 밝은 영역들이 강조되었다.


모폴로지 블랙-햇 연산 결과주변보다 어두운 영역들이 강조되었다.

반응형

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

제스쳐 인식  (0) 2016.11.30
플러드필  (0) 2016.11.30
영상 모폴로지 자체 커널 만들기  (0) 2016.11.30
영상 모폴로지  (0) 2016.11.30
스무딩(블러링)  (0) 2016.11.30
반응형

OpenCV에서는 IplConvKernel 구조체를 사용하여 자체적인 모폴로지 커널을 사용할 수 있다이 커널은 Cv.CreateStructuringElementEx() 함수를 통해서 생성하고,ReleaseStructuringElement() 함수를 이용하여 해제한다

 

public static IplConvKernel CreateStructuringElementEx(int cols, int rows, int anchor_x, int anchor_y, ElementShape shape, int[,] values);

모폴로지 커널은 컨볼루션 커널과 달리 수치값을 필요로 하지 않는다모폴로지 커널의 모양은 커널이 영상을 스캔하는 동안 최대값 또는 최소값 계산에 필요한 픽셀 위치를 알려주는 역할만 할 뿐이다고정점은 커널이 원본 영상에 어떻게 정렬되어야 하는지 알려주는 역할을 하고또한 모폴로지 연산의 결과값이 원본 영상의 어느 픽셀에 대입되어야 하는지 알려준다커널을 새로 생성하려면 구성요소를 감싸는 사각형을 표현하는 cols rows를 지정해주어야 한다그 다음으로 고정점의 좌표 (x,y)를 나타내는 anchor_xanchor_y를 지정한다. CV_SHAPE_CUSTOM 값이 사용되면 정수형 배열 values에 의해 지정된 형태의 커널이 생성된다이 배열은 rows x cols 크기의 1차원 배열이며 0이 아닌 값으로 지정된 위치의 원소는 커널에서 사용되는 픽셀이다. Values null이면 모든 원소값이 0이 아닌 것으로 간주되어 사각형 형태의 커널이 생성된다.

 

다섯 번째 인자 shape 

Shape 

의미

CV_SHAPE_RECT

사각형 커널

CV_SHAPE_CROSS

십자 모양의 커널

CV_SHAPE_ELLIPSE

타원형 커널

CV_SHAPE_CUSTOM

Values 값으로 지정하는 사용자 정의 커널


반응형

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

플러드필  (0) 2016.11.30
Opencv C# 모폴로지  (0) 2016.11.30
영상 모폴로지  (0) 2016.11.30
스무딩(블러링)  (0) 2016.11.30
영상 파일 포맷의 종류  (0) 2016.11.30

+ Recent posts