--------SDI----------------

1.애플리케이션 클래스의 포인터를 얻을 때

CWinApp* AfxGetApp()

함수를 사용합니다.

2.메인 프레임 클래스의 포인터를 얻을 때

CWnd* AfxGetMainWnd()

함수를 사용합니다.

 이들 두 함수는 MFC의 전역함수로써 프로그램을 작성하는 도중 어디에서나 사용할 수 있습니다. MFC에서는 Afx~로 시작하는 함수들은 모두 전역함수를 의미합니다.

 물론 타입 캐스팅을 해야 하구요. 사용법은 다음과 같습니다.

    CTestApp *pApp = (CTestApp *)AfxGetApp();
    CMainFrame *pFr = (CMainFrame *)AfxGetMainWnd();

이렇게 써준 다음에는 pApp와 pFr은 각각 애플리케이션 클래스와 메인 프레임 클래스의 인스턴스 포인터를 가리키게 됩니다.

 이 외에 뷰 클래스에서 그 뷰를 둘러싸고 있는 프레임 윈도우를 참조할 때는

    CFrameWnd* GetParentFrame() const

함수를 사용할 수 있습니다. 물론 뷰 클래스뿐만이 아니라 일반적인 윈도우를 둘러싸는 틀로써 프레임 윈도우가 사용될 수 있기 때문에 GetParentFrame() 함수는 CWnd() 클래스의 멤버함수로 되어있습니다.

 이 함수와 AfxGetMainWnd() 함수는 SDI에서는 같은 기능을 하지만, MDI에서는 메인 프레임 윈도우와 뷰를 둘러싸고 있는 프레임 윈도우가 다르기 때문에 그 각각을 구하는 역할을 합니다.

3.도큐먼트 클래스의 포인터를 얻을 때는 몇 가지 경우가 있습니다.

    (a) 뷰 클래스에서 도큐먼트 클래스에 접근할 때.

      이때는 말할 필요도 없이 GetDocument() 함수를 쓰면 됩니다. 뷰에 이미 정의되어 있는 함수죠. 하지만 사용자가 임의로 뷰를 추가한 경우에는 이 GetDocument() 함수가 포함되어 있지 않습니다. 이럴 경우 기존에 있는 뷰에서 GetDocument() 함수 부분을 복사해다가 넣으면 됩니다. 이 부분은 Debug 모드와 Release 모드 두 가지의 함수가 있으므로 모두 복사해 넣아야 합니다.

    (b) 임의의 클래스에서 도큐먼트 클래스에 접근할 때.

       CMainFrame *pFr = (CMainFrame *)AfxGetMainWnd();
       CTestDoc *pDoc = (CTestDoc *)pFr->GetActiveDocument();

    위와 같이 두 줄에 걸쳐 써도 되고 다음처럼 한 줄로 줄여써도 됩니다.

    CTestDoc *pDoc = (CTestDoc *) ((CMainFrame *)AfxGetMainWnd())->GetActiveDocument();

4. 뷰 클래스의 포인터를 얻을 경우.

    (a) 임의의 클래스에서 뷰 클래스에 접근할 때

     뷰 클래스의 포인터를 얻어야 하는 경우는 대부분 다이얼로그에서 뷰에 접근하거나, 스플릿을 사용한 경우 다른 뷰 클래스에서 접근하는 경우가 대부분일 겁니다. 뭐 어떻든 상관없이 다음과 같이 하면 어디서든 뷰에 접근할 수 있습니다.

    CTestView *pView = (CTestView *) ((CMainWnd *)AfxGetMainWnd())->GetActiveView();

     물론 위의 3번의 경우처럼 두 줄로 나누어 써도 상관이 없습니다.

    (b) 도큐먼트 클래스에서 뷰 클래스에 접근을 할 때

    도 큐먼트 클래스에서 뷰 클래스의 인스턴스 포인터를 얻으려면 GetFirstViewPosition() 함수와 GetNextView() 함수를 조합하여 사용해야 합니다. 이렇게 복잡해지는 이유는 도큐먼트 하나에 여러개의 뷰가 연결될 수 있기 때문입니다.

    도큐먼트에는 이에 연결된 뷰가 연결 리스트 형태로 관리되고 있기 때문에 몇 번째 뷰를 얻을 것인지 선택하고 나서 위의 함수를 조합하여 사용하면 됩니다.

    다음은 도큐먼트와 연결된 모든 뷰 클래스를 차례로 얻어 뷰 클래스의 멤버함수인 UpdateWindow() 함수를 호출하는 예제입니다.

      POSITION pos = GetFirstViewPosition();

      while(pos != NULL) {
           CView *pView = GetNextView(pos);
           pView->UpdateWindow();
      }

    물 론 이와 같은 효과를 내기 위해서 도큐먼트 클래스의 멤버함수인 UpdateAllViews(NULL) 함수를 호출해도 됩니다. 여기서 쓰이는 인자인 NULL 은 모든 뷰를 업데이트하는 것이고, NULL 대신, 신호를 보내는 뷰의 포인터를 넣어주면 신호를 보내는 뷰는 빼고 나머지 뷰만 업데이트를 합니다.

      도큐먼트에 뷰가 오직 하나만 연결되어 있는 경우에는 다음과 같이 간단하게 뷰 클래스의 인슽턴스 포인터를 얻어낼 수도 있습니다. m_viewList 는 CDocument 클래스의 멤버변수로서, 뷰를 관리하는 연결 리스트입니다. 이것을 이용하여 GetHead() 함수를 호출하면 리스트에 들어있는 첫 번째 뷰가 얻어집니다.

      void CTestDoc::OnRepaintViews()
      {
           CView *pView = m_viewList.GetHead();
           pView->UpdateWindows();
      }

 

    (c) 스플리트 윈도우에서의 각 뷰 클래스에 접근할 때

      동적 스플리트 윈도우라면 모든 페인에서 같은 뷰를 사용하므로 별 문제가 되지 않는데, 정적 스플리트 윈도우라면 각 페인마다 다른 뷰를 사용할 수 있으므로 각 페인별로 뷰의 인스턴스 포인터를 얻는 것이 문제가 되는 경우가 생길 수 있습니다.

     이렇때는 메인 프레임 클래스에서 정의한 CSplitterWnd 클래스의 변수인 m_wndSplitter 의 멤버함수 GetPane()을 사용하면 각 페인의 뷰에 접근할 수 있습니다.

      우선 메인 프레임에서 정의된 m_wndSplitter 변수를 public: 속성으로 바꾸고(외부에서 접근해야 하므로) 메인 클래스의 인스턴스 포인터를 얻은 다음, 다시 여기서 m_wndSplitter 변수에 접근하여 이 멤버변수의 멤버함수 GetPane()을 이용하면 됩니다. 다음은 GetPane()의 함수 원형입니다. 리턴값은 대부분의 경우 CView에서 파생된 클래스의 인스턴스 포인터가 됩니다.

    CWnd* GetPane( int row, int col );

    임의의 클래스에서 다음과 같이 사용하면 페인에 연결된 뷰의 포인터를 얻을 수 있습니다.

        CTestView *pView = (CTestView *)((CMainFrame *)AfxGetMainWnd())->m_wndSplitter.GetPane(0,1);

-------- MDI ---------------

1.애플리케이션 클래스의 포인터를 얻을 때

    CWinApp* AfxGetApp()

함수를 사용합니다. 이것은 SDI에서와 동일합니다. App 클래스는 MDI든 SDI든 프로그램 내에서는 하나뿐이니까요. 다음처럼 사용하면 pApp는 애플리케이션 클래스의 인스턴스 포인터를 가리키게 됩니다.

    CTestApp *pApp = (CTestApp *)AfxGetApp();

2. CMDIFrameWnd의 파생클래스인 메인 프레임 클래스의 포인터를 얻을 때

    CWnd* AfxGetMainWnd()

함수를 사용합니다. 사용법은 SDI에서와 동일합니다.

    CMainFrame *pFr = (CMainFrame *)AfxGetMainWnd();

이렇게 써준 다음에는 pFr은 메인 프레임 클래스의 인스턴스 포인터를 가리키게 됩니다.

3. CMDIChildWnd의 파생클래스인 자식 프레임 윈도우의 포인터를 얻을 때

    (a) 활성화된 자식 프레임 윈도우의 포인터를 얻을 때

      virtual CFrameWnd* GetActiveFrame( );

    함수를 사용합니다. MSDN에 실려있는 이 함수의 리턴값에 대한 설명을 보면, 애플리케이션이 SDI이거나 MDI 프레임 윈도우에 활성화된 도큐먼트가 없을 때, 리턴값은 묵시적인 this 포인터가 된다고 하네요.

    사용법은 다음과 같습니다.

    CMDIChildWnd* pChild = (CMDIChildWnd *)AfxGetMainWnd()->GetActiveFrame();

4. 뷰 / 도큐먼트 클래스의 포인터를 얻을 때

 SDI 에서 구한 것과 마찬가지 방법을 사용한다. SDI에서는 메인 프레임의 포인터를 얻어 GetActiveView() 또는 GetActiveDocument() 함수를 사용했지만, MDI에서는 차일드 프레임의 포인터를 얻어 거기서 GetActiveView() / GetActiveDocument() 함수를 사용하면 된다. 사용법은 거의 동일하다.

 MDI에서도 SDI와 마찬가지로 도큐먼트나 뷰가 여러 개가 연결될 수 있으므로 그점만 주의해 주면 된다.

 사용법은 다음과 같다.

    CMDIChildWnd* pChild = (CMDIChildWnd *)AfxGetMainWnd()->GetActiveFrame();

    // 뷰 클래스의 포인터 얻기
    CTestView *pView = (CTestView *)pChild->GetActiveView();  

    // 도큐먼트 클래스의 포인터 얻기
    CTestDoc *pDoc = (CTestDoc *)pChild->GetActiveDocument();


'1.소프트웨어 이야기 > 01.MFC(Visual Studio)' 카테고리의 다른 글

[펌] DialogBar 구현  (0) 2008.08.07
클래스간 포인터 얻기  (0) 2007.12.06
MFC Socket 사용시 유의점  (0) 2007.12.06
MFC Socket 사용시 유의점

socket.IOCtl( FIONREAD, &avail ); // avail에 읽을 수 있는 양이 들어간다.
socket.Receive( pBuf, avail ) // 하지만 avail 만큼 다 못 읽을 경우가 있다.

따라서

MFC CAsyncSocket 사용시 유의사항

1. 소켓 API를 이용하여 특정 크기의 데이터를 보내면 나눠지거나 합쳐지는 경우가 있는가?

2. 송신자가 100바이트를 전송하여 수신자의 OnReceive함수가 호출 되었다.
그러나 그 함수 에서 50 바이트만 Receive했을 경우 다시 OnReceive함수가 호출되는가?

3. 위와 같은 경우에서 50 바이트가 아니라 아예 Receive를 하지 않은 경우는 어떻게 되는가?

4. 특정 데이터 크기 단위로 받아서 처리하는 로직을 구성하려 한다.
송신자는 데이터 단위당 그 크기를 4바이트 정수로 데이터 앞에 붙여서 보낸다.
다음과 같이 구성하여 완전한 길이의 데이터가 들어왔을때만 메세지를 보내도록 하였다.
이것이 잘 동작하는가? 문제가 있다면 무엇인가?
5. 소켓버퍼에 데이터가 있더라도 인위적으로 OnReceive가 호출 되지 않도록 할 수 있는가?

6. 데이터 크기를 명시하여 잘 동작하는 패킷 전송 프레임웍을 구현해보라.
원문 :   D 프로그래밍 언어 소개
D 프로그래밍 언어 소개


음.. 요즘 D언어에 관심을 가지고 있습니다. 이름에서 알수 있듯이... B다음에 C다음에 C++다음에 만들어진 D언어입니다. 1.0이 나온게 몇년전이고 지금은 상당히 완성도를 가지고 있다고 하더군요.

그리고 예상과는 달리 사용자층도 꽤 만고 해서, D언어를 함 사용해 보기로 마음 먹고 위키를 만들었습니다.
위키의 주소는 http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/D 이고 앞으로 계속 수정되어 나갈 겁니다.




C 언어가 B 언어로부터 나왔다는 얘기는 아마 언뜻 들어서 다들 알고 있을 것 같다. 언어의 역사가 궁금하다면 언어의 역사 문서를 한번 보기 바란다.

C 도 나왔고, 객체지향을 적용한 C++도 나왔으니 이제 D 언어도 나오지 않을까 ? 라는 생각이 들어봄직도 할 거 같은데, 정말 D 언어가 나왔다. 물론 나온지는 꽤 되었고, 예전 부터 써봐야지 써봐야지 하면서 차일피일 미루어왔는데, 이번참에 직접 사용해 보기로 했다. 이 위키는 D언어를 잘 배워서 한번 써먹어 보자라는 취지로 만들었다.

관련기사
지 금, 세계는 대화 언어보다 프로그램 언어를 더 많이 가지고 있으나 프로그램 언어들은 계속 만들어지고 있다. 금주에 Digital Mars는 C/C++의 문제점과 약점을 해결한 D 언어를 발표했다. D는 C++ 컴파일러, Zortech C++의 자손이다. D는 무료이며 윈도우와 리눅스를 위한 표준 라이브러리이며 오픈 소스이다.

C/C++의 개선으로 D는 C 코드와 호환되며 콜 인터페이스 없이 어떠한 C API와도 인터페이스 가능하다. 그러나 D는 C 코드와 완전하게 후향적 호환은 안되며 자바와 Microsoft C#의 많은 기능을 추가로 한다. D는 2001년 이후 개발되었으며 오픈 소스 공동체의 입력물을 많이 사용하였으며 http://dmoz.org/Computers/Programming/Languages/D/에 자료가 많이 있다.

브라이트는 “D는 C++ 프로그래머의 경험에 의해 개발되었으며 많은 새로운 언어처럼 어느 특정한 플랫폼을 목적으로 설계되지 않았다. D의 개념은 빠르게 배우고 코딩하고 빠르게 디버깅하며 유지 보수하는 것”이라고 말했다.

Forrester Research 분석가인 제프 함몬드는 “D가 기반을 얻기까지에는 약간의 시간이 걸릴 것이다. D 언어가 성공하려면 D 언어 기술이 좋은 것 이외에도 그에 맞는 비즈니스 모델이 있어야 될 것”이라고 말했다. 마치 리눅스가 성공한 이유가 그 당시 다른 OS 가격이 너무 고가이어서 고객들이 선택했기 때문인 것처럼 필요한 비즈니스 모델이 중요하다.

출처 : http://www.internetnews.com

D 언어 소개

http://www.digitalmars.com/

C와 C++은 시스템프로그래밍에 있어서 강력함을 발휘 한다. 특유의 단순함과 중급언어라고 분류할 만큼 시스템에 가깝다는게 그 이유인데, 이 단순함은 요즘 같은 시대에 단점이기도 하다.

암 튼 이 두언어는 최신언어의 유행에 한참이나 뒤 떨어져 있다. 절차지향적이고 그다지 깔끔하지도 않으며, C++은 객체지향 적이긴 하지만 업계표준이며 모태라고 할 수 있는 C언어와의 호환성유지등의 문제로 현대언어들의 유행을 쫓아가지 못하고 있다.

물 론 현대언어의 유행이란 것이 모든 면에 있어서 좋은 쪽으로 흘러간다고 할 수는 없다. 그렇다면 C와 C++이라는 언어자체가 필요 없어질 것 아닌가. C와 C++이 유행을 따르지 않음으로써 구식언어라는 멍에를 지기는 했지만 여전히 시스템/네트워크 프로그래밍에 있어서, 속도와 성능,신뢰도 측면에서 높은 점수를 받고 있으며 실제로 널리 사용되고 있다.
Position
Dec 2007
Position
Dec 2006
Delta in PositionProgramming LanguageRatings
Dec 2007
Delta
Dec 2006
Status
1 1 Java 20.049% +0.14%   A
2 2 C 13.173% -3.44%   A
3 4 (Visual) Basic 10.219% +1.31%   A
4 5 PHP 8.393% -0.14%   A
5 3 C++ 7.871% -2.54%   A
6 7 Python 4.697% +0.93%   A
7 6 Perl 4.383% -2.01%   A
8 8 C# 3.994% +0.82%   A
9 11 Ruby 3.089% +0.76%   A
10 10 JavaScript 2.733% +0.17%   A
11 9 Delphi 2.673% +0.10%   A
12 14 D 1.633% +0.66%   A
13 13 PL/SQL 1.394% +0.05%   A
14 12 SAS 1.393% -0.84%   A
15 18 COBOL 0.894% +0.29%   A-
16 15 ABAP 0.875% -0.03%   A-
17 17 Lisp/Scheme 0.841% +0.20%   A-
18 20 Transact-SQL 0.817% +0.35%   A--
19 19 Pascal 0.791% +0.23%   A--
20 46 Lua 0.771% +0.67%   A-
출처 : http://www.tiobe.com/tpci.htm

D언어는 즉 시스템 프로그래밍을 위한 C/C++의 강력함과 최근의 언어들이 가지고 있는 Object orinted, template metaprogramming style 등의 multiparadigm을 지원하는 언어다.

D언어는 statically type를 지원하며 native 코드로 컴파일 되어서 실행된다.

D 언어 설치

Windows, Linux 모두에 대한 버젼이 있는데, 환경이 Linux인 관계로 Linux를 기준으로 설명하도록 하겠다.

  • http://www.digitalmars.com/d/download.html 에서 d 언어 컴파일러를 다운로드 받을 수 있다.
  • D언어 전용컴파일인 dmd와 GCC를 위한 GDC두가지 버젼이 있다.
  • gcc의 프론트엔드인 GDC를 받아서 테스트를 하기로 했다.
  • 다운로드 받은 다음에 /usr/local/gdc 에 압축을 풀었다.
  • 다음과 같이 LD_LIBRARY_PATHPATH 환경변수를 수정했다.

    # export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/gdc/lib
    # export PATH=$PATH:/usr/local/gdc/bin

이제 wc의 d버젼을 가지고 테스트 해보았다.
import std.stdio;
import std.stream;
import std.date;

int main (char[][] args)
{
int w_total;
int l_total;
ulong c_total;
int[char[]] dictionary;

writefln(" lines words bytes file");
foreach (arg; args[1 .. args.length])
{
int w_cnt, l_cnt;
bool inword;

auto c_cnt = std.file.getSize(arg);
if (c_cnt < 10_000_000)
{
size_t wstart;
auto input = cast(char[])std.file.read(arg);

foreach (j, c; input)
{
if (c == '\n')
++l_cnt;
if (c >= '0' && c <= '9')
{
}
else if (c >= 'a' && c <= 'z' ||
c >= 'A' && c <= 'Z')
{
if (!inword)
{
wstart = j;
inword = true;
++w_cnt;
}
}
else if (inword)
{ auto word = input[wstart .. j];

dictionary[word]++;
inword = false;
}
}
if (inword)
{ auto w = input[wstart .. input.length];
dictionary[w]++;
}
}
else
{
auto f = new BufferedFile(arg);
char[] buf;

while (!f.eof())
{ char c;

f.read(c);
if (c == '\n')
++l_cnt;
if (c >= '0' && c <= '9')
{
if (inword)
buf ~= c;
}
else if (c >= 'a' && c <= 'z' ||
c >= 'A' && c <= 'Z')
{
if (!inword)
{
buf.length = 1;
buf[0] = c;
inword = 1;
++w_cnt;
}
else
buf ~= c;
}
else if (inword)
{
if (++dictionary[buf] == 1)
buf = null;
inword = 0;
}
}
if (inword)
{
dictionary[buf]++;
}
}
writefln("%8s%8s%8s %s\n", l_cnt, w_cnt, c_cnt, arg);
l_total += l_cnt;
w_total += w_cnt;
c_total += c_cnt;
}

if (args.length > 2)
{
writefln("--------------------------------------\n%8s%8s%8s total",
l_total, w_total, c_total);
}

writefln("--------------------------------------");

foreach (word1; dictionary.keys.sort)
{
writefln("%3s %s", dictionary[word1], word1);
}
writefln(toDateString(getUTCtime()));
return 0;
}

컴파일과 실행은 매우 간단했다.
# gdc -o wc wc.d
# ./wc wc.d
lines words bytes file
114 234 2922 wc.d

--------------------------------------
2 A
1 BufferedFile
2 Z
....
Mon Jan 29 2007

'1.소프트웨어 이야기 > 09.ETC' 카테고리의 다른 글

URL Helper  (0) 2007.12.06
Manifest 적용하기..  (0) 2007.12.06
두 점 사이의 각도 구하기  (0) 2007.12.06
히스토그램에 대하여 궁금해하시는 회원님들이 계셔서 이두형과장께 허락받고 옮겨왔습니다. 도움이 되었으면 합니다.
출처:  http://www.zuikouser.com/bbs/zboard.php?id=pds&page=1&sn1=&divpage=1&sn=off&ss=on&sc=on&select_arrange=headnum&desc=asc&no=134

DSLR카메라로 촬영을 한 다음 촬영한 이미지를 보면서 info를 클릭하면 그 이미지의 농도분포를 알려주는 그래프가 보입니다.
이 것을 히스토그램이라고 하는데 이를 지원하는 이유는 LCD에 출력된 화상이 절대 결과물의 상태와 상이하기 때문에 이미지를 보며노출 적용 여부를 확인하기 위함입니다. 즉 시각적인 판단 보다는 원본의 물리적인 데이터를 보여준다고 보면 되겠죠.

1. 아래 첫번째 이미지와 같이 가로는 밝고 어두운 농도 구역을 의미하고 세로축은 분포량을 의미합니다.
두번째 코스모스 이미지를 보면 전체적으로 눈에 띠는 검은색이나 흰색이 별로 없고 전반적으로 중간색조의 농도들이 많이 분포되어 있음을 알 수 있습니다. 그러나 자세히 보면 완전 검은색과 완전 흰색이 있긴 하죠?
그렇다면 그래프는 첫 이미지와 같게 형성될겁니다. 왼쪽 하단부는 완전 검은색 존이고 오른쪽 끝은 완전 하얀색 존이므로 분포 곡선은 좌우에 양 끝에서부터 형성됩니다.
또 전체적으로 중간색조가 많으니까 중간색 영역부분으로 갈 수록 분포도가 크게 형성되겠죠.
이제 이해하셨는지요...


2. 파도치는 장면을 찍은 두 사진의 분포를 보면 밝은 쪽의 그래프가 높고 두껍게 형성되어 있습니다. 눈으로 봐도 밝은 색조의 농도가 많은 사진이쟎아요...
단지 차이가 있다면 오른쪽 사진에는 암부의 농도분포도 크게 자리잡고 있습니다.
그게 당연하다고 느끼신 회원님들은 이미 히스토그램에 대하여 이해를 하신 것입니다.


3. 이번 경우는 상대적으로 암부에 톤이 집중되는 이미지 입니다. 이미지를 볼 때 밝은 영역과 어두운 영역이 어느 정도 일까?하고 살펴보시기 바랍니다.
왼쪽의 단풍 이미지의 오른쪽 끝엔 약간의 빈 공간이 있습니다. 이는 제일 하얀색이 이미지에 없다는 것을 의미합니다. 오른쪽 송수관쪽엔 끝에 하얀색 농도가 분포되어 있는 것을 알 수 있지요?
이제 그래프의 느낌이 이미지와 통하는지요?


4. 지금까지의 설명을 토대로 아래 이미지를 보면서 다시 한번 분석해 봅시다.
왼쪽의 사진은 노츨이 약간 부족되어 있습니다. 빛이 부족하게 들어가니까 이미지에 하얀색이 없어 오른쪽 끝부분이 빈공간으로 남겠죠.
그래서 이를 카메라에서 확인한 다음 노출을 더 주어 두번째 사진을 찍습니다.
그리고 히스토그램을 보니 이전 이미지보다 오른쪽 밝은 부분이 더 늘어나 있습니다.
전 여기까지 만족을 했구요...만일 더 밝은 부분이 있기를 바란다면 좀더 노출을 주어야갰지요.
그러나 너무 과도하게 노출을 더하면 반대로 이미지에 검은색이 없어지겠죠.
그렇게 되면 사진이 밋밋해 질꺼라고 판단했기에 그 정도로 만족을 한겁니다.


5. 마지막 이미지들도 같은 이야기 인데 왼쪽은 본래 피사체의 암부와 명부의 차이가 약했고 노출도 약간 부족되어 칙칙합니다. 그래서 콘트라스트를 강하게 +2로 증가시켰습니다.
그리고 노출도 약간 늘려줬구요. 이렇게 하니 원래 밋밋했던 피사체의 톤이 확장되면서 그래프의 좌우에 모두 분포된 이미지를 만들 수 있었습니다.


여기까지 응용할 수 있다면 히스토그램이 왜 필요한지 아셨을 꺼예요...

원래 피사체 상태가 검은색은 없거나 흰색이 없는데 노출만으로 그래프 분포를 모두 확장할 수는 없습니다.
콘트라스, 채도까지도 관계가 있거든요.

정리하면 히스토그램은 피사체와 노출의 상호 관계를 그래픽적으로 판단하게 해주는 도구일 뿐입니다.
그래서 LCD를 믿지 못해도 그래프로 노출 상태를 어찌할 것인지 방향을 잡을 수 있게해주는 것이죠.

전 가끔은 흰색을 질감이 존재하면서 가장 밝게 묘사하기를 바랄 때가 있습니다.
이때 노출을 조절한 다음 힛스토그램으로 확인을 합니다. 가장 밝은 영역이 오른쪽 끝에서부터 시작되도록요.....
오른쪽 끝부분의 농도분포가 너무 커지면 지나쳐 하얀색의 질감이 날라갈 수 있겠죠...
[초급] OpenCV 를 이용한 영상 이진화(Binarization) 강좌
 
오 늘은 손쉽게 구현할 수 있는 영상 이진화(Binarization)에 대해서 설명해 드리도록하겠습니다. 영상 이진화란 RGB 값으로 다양하게 분포되어 있는 색상값을 0 과 1 만의 값으로 표현하는 것 입니다.실제적으로는 RGB 컬러 영상에을 흑백(Gray channel)영상으로 바꾼뒤 특정 임계값(Threshold)을 기준으로 초과값은 255 로, 이하 값은 0 변환하게 되지요. 아래 T9-camera 윈도우 영상과 T9-output 윈도우 영상을 보시면쉽게 이해가 가실 겁니다. T 값 128 을 기준으로 초과값은 255 로 변환되어 흰색으로 보여지고 있고 이하 값은 0 으로변환되어 검은색으로 보여지고 있습니다.
 
 
- 실행 결과

소 스 코드가 다소 길어 졌지만 크게 보면 카메라를 입력 받는 소스에서 이진화 함수인 cvThreshold() 함수가 추가된 것 밖에는 없습니다. 이 함수를 사용할 때 주의해야 할 것은 항상 흑백 이미지로 변환해서 넣어 주어야 한다는 것.

  cvThreshold(gray, output, threshold, 255, CV_THRESH_BINARY); 

위 함수는 입력된 gray 이미지에서 threshold 값을 초과한 값은 255 로 변환하고 이하는 0 으로 변환하여output 이미지를 만들어 냅니다. 이와는 반대로 적용되게 한다거나 일정 값 이하는 0 으로 변환하고 초과되는 값만 보여주는등의 옵션이 있습니다. 옵션을 변화 시켜가며 변화되는 모습을 익혀 보도록 합시다.

  CV_THRESH_BINARY        : threshold 값 초과는 255, 이하는 0

  CV_THRESH_BINARY_INV  : threshold 값 초과는 0, 이하는 255

  CV_THRESH_TRUNC         : threshold 값 초과는 threshold, 이하는 그대로

  CV_THRESH_TOZERO       : threshold 값 초과는 그대로, 이하는 0

  CV_THRESH_TOZERO_INV : threshold 값 초과는 0, 이하는 그대로

이 번 프로그램에는 Trackbar 가 추가되었는데 이는 나중에도 유용하게 쓰이므로 잘 익혀 두시기 바랍니다. 아래 함수는"T9-camera" 이름의 윈도우에 0 부터 255 범위를 같는 "T" 이름의 Trackbar 를 붙입니다. Trackbar의 초기 위치는 threshold 값이 결정하며 bar 를 조절하여도 그 값은 threshold 변수에 들어가게 됩니다. 그리고현재는 NULL 로 되어 있지만 이부분에 함수명을 적으면 bar 가 변경될 때마다 해당하는 함수를 호출하게 됩니다. 이 함수는반드시 int 형 변수 하나를 가지고 있어야 하고 이 변수에 Trackbar 의 값이 넘어 오므로 함수에서 값을 가지고영상처리를 해주면 됩니다.

  cvCreateTrackbar("T", "T9-camera", &threshold, 255, NULL);

cvCvtColor() 함수는 Color 변환을 해주는 함수입니다. 아래 함수는 RGB 채널을 가지고 있는 image 를Gray 채널로 바꾸어서 gray 에 넣어주는 역할을 합니다. 마지막 인자는 Color 변환 모드인데 여기에도 다양한 옵션이존재하므로 필요한 모델을 사용하시면 됩니다.

  cvCvtColor(image, gray, CV_RGB2GRAY);

  CV_RGB2GRAY  : 흑백으로 변환
  CV_RGB2YCrCb : 주로 Skin Color 모델을 할때 변환( 손 제스쳐 인식, 얼굴 인식 )
  CV_RGB2HLS
  CV_RGB2HSV
  CV_RGB2Lab
  CV_RGB2Luv
 

- 소스 코드(압축 파일 첨부)

 
#include <cv.h>
#include <highgui.h>

 
void main()
{
    int i, threshold = 128;
// 임계값(Threshold) 설정

    IplImage* image = 0;
    IplImage* output = 0;
    IplImage* gray = 0;
 
    CvCapture* capture = cvCaptureFromCAM(0);
// 카메라 연결

    cvNamedWindow( "T9-camera", 0 ); // 원본 영상을 띄울 윈도우
    cvNamedWindow( "T9-output", 0 );
// 결과 영상을 띄울 윈도우

    cvCreateTrackbar("T", "T9-camera", &threshold, 255, NULL); // "T9-camera" 윈도우에 bar 를 붙이고 threshold 값을 변화 시킴
                                                                                         
// 이름은 "T" 를 붙이고 0 부터 255 사이의 범위값을 가짐

    while(1) {
        cvGrabFrame( capture );
        image = cvRetrieveFrame( capture );
        cvShowImage( "T9-camera", image );

        if(!output){
            gray = cvCreateImage( cvGetSize(image), IPL_DEPTH_8U, 1); // 흑백 이미지 생성
            output = cvCreateImage( cvGetSize(image), IPL_DEPTH_8U, 1); // 흑백 이미지 생성
        }

        cvCvtColor(image, gray, CV_RGB2GRAY); // 컬러를 흑백으로 변환
 
        if( cvWaitKey(10) >= 0 )
            break;

        // 영상의 각 픽셀(x,y) 값이 threshold 값의 초과는 255 로, 그 이하는 0 으로 변환

        cvThreshold(gray, output, threshold, 255, CV_THRESH_BINARY);
        output->origin = image->origin; // 방향이 뒤집어 진것을 바로 잡아줌
 
        cvShowImage( "T9-output", output );
    }
    cvReleaseImage( &gray );
    cvReleaseImage( &output );
    cvReleaseCapture( &capture );
    cvDestroyWindow( "T9-output" );
    cvDestroyWindow( "T9-camera" );
}

초급] OpenCV 초보를 위한 강좌 - 2편 : 카메라 입력받기

이번 강좌에서는 OpenCV 를 이용하여 간단하게 카메라 영상을 입력받아 IplImage 형 구조체에 넣고 출력 윈도우의크기를 조절해서 화면에 보여주는 작업을 할 것입니다. 1편을 통하여 기본적인 셋팅 방법은 습득 하셨을테니 바로 아래와 같은소스코드를 작성한 후 컴파일 해 봅시다.

 
- 소스 코드(압축 파일 첨부)
 
#include <cv.h>
#include <highgui.h>

void main()
{
    IplImage* image = 0;
    CvCapture* capture = cvCaptureFromCAM(0);
    cvNamedWindow( "T9-camera", 0 );

    cvResizeWindow( "T9-camera", 320, 240 );

       
    while(1) {
        cvGrabFrame( capture );
        image = cvRetrieveFrame( capture );

        cvShowImage( "T9-camera", image );
 
        if( cvWaitKey(10) >= 0 )
            break;
    }

    cvReleaseCapture( &capture );
    cvDestroyWindow( "T9-camera" );
}

 
- 소스 설명

일 단 OpenCV 를 사용하기 위하여 영상처리 관련 라이브러리를 사용하기 위해 <cv.h> 를 include하고 영상을 캡쳐 받고 윈도우로 보여주기 위해 <highgui.h> 를 include 하지만 사실 카메라 영상만 입력받아 화면에 보여줄 것이라면 <highgui.h> 만 include 해도 됩니다.

  #include <cv.h>         // 영상 처리를 위한 header
  #include <highgui.h> 
// 카메라로 영상을 입력받거나 이미지를 읽어들이고 화면에 보여주기 위한 header

 다음은 IplImage 구조체로 image라는 포인터를 생성하여 앞으로 이 것으로 이미지를 받고 처리하게 됩니다. IplImage 의 구조체는 이미지에 관련된 다양한정보를 가지고 있으며 char 형 imageData 를 가지고서 이미지에 직접적인 접근을 할 수 도 있습니다.

 
  IplImage* image = 0;

cvCaptureCAM() 함수를 이용 0번째 연결된 카메라로부터 컨트롤을 얻어 옵니다. 숫자를 넣는 부분에 카메라의 인덱스 번호를 넣으면 현재 2 대 까지 연결이가능하며 이렇게 연결된 capture 는 끝나기 전에 cvReleaseCapture() 함수로 release 해 주어야 합니다.

  CvCapture* capture = cvCaptureFromCAM(0);  // 0 번째 연결된 카메라로부터 컨트롤을 얻어 옵니다.

 cvNamedWindow() 함수는 "T9-camera" 라는 타이틀의 윈도우를 생성합니다. 두번째 인자 값은 고정된 윈도우(0)를 생성 하거나 보여질 이미지의 크기에 맞게 자동 조절 윈도우(1)를 생성 할 수 있습니다. 두 번째 인자를 0 으로 하고 아래 문장을 추가하면 윈도우 크기를 자유롭게 조절 할 수 있습니다. 이것은 입력 소스를 조절하는 것이아니라 출력 창의 크기를 조절 하는 것이므로 화면의 크기를 키울 경우 사각 픽셀이 보이는 현상이 나타납니다.

  cvNamedWindow( "T9-camera", 0 );            // T9-camera 라는 이름의 윈도우를 생성, 0 은 고정된 윈도우를 생성
  cvResizeWindow( "T9-camera", 320, 240 );  // T9-camera 라는 이름의 윈도우 크기를 조절 width = 320, height = 240

 그리고카메라로 부터 매 프레임을 받아오기 위해서 while(1) 문으로 무한 loop 을 돌립니다. 이 무한 loop 는 if(cvWaitKey(10) >= 0 ) 문장을 통해 'ESC' 키가 눌려지면 종료하게 되고 종료되지 않는다면 다음과같은 작업을 반복하게 됩니다. cvGrabFrame( capture ) 함수는 카메라로 부터 입력된 영상의 한 프레임을 잡고,cvRetrieveFrame( capture ) 함수는 잡은 프레임으로부터 이미지를 얻어 냅니다. 이 두 함수는 함께 쓰이며카메라로부터 영상을 받아 이미지에 넣는 과정이라고 보시면 됩니다. 다음으로 cvShowImage( "T9-camera",image ) 함수는 image 를 "T9-camera" 라는 타이틀의 윈도우에 뿌려주게 되는데 해당 타이틀의 윈도우는cvNamedWindow() 함수로 이전에 미리 만들어 두어야 합니다.

  while(1) {
      cvGrabFrame( capture );                    // 카메라로부터 한 프레임을 잡습니다.

      image = cvRetrieveFrame( capture );    // 잡은 프레임으로부터 IplImage 형 구조를 리턴 받아 image 에 넣습니다.

      cvShowImage( "T9-camera", image );  // "T9-camera" 윈도우에 image 를 보여줍니다.
 

      if( cvWaitKey(10) >= 0 )
          break;
  }

 

마지막으로 capture 를 release 하여 카메라와의 연결을 종료하고 윈도우를 소멸시키면 프로그램은 안정적으로 종료됩니다.

  cvReleaseCapture( &capture );
  cvDestroyWindow( "T9-camera" );

다음은 cvNamedWindow() 함수와 cvResizeWindow() 함수를 이용하여 윈도우 창의 크기를 변화 시켜 출력한 결과 화면입니다.

>> 소스코드 결과 화면

     cvNamedWindow( "T9-camera", 0 ) 함수에서 두번째 인자가 '0' 이고
     cvResizeWindow( "T9-camera", 320, 240 ) 함수를 추가 한 경우

>> cvNamedWindow( "T9-camera", 0 ) 함수에서 두번째 인자가 '0' 일 경우

>> cvNamedWindow( "T9-camera", 1 ) 함수에서 두번째 인자가 '1' 일 경우


- 주요 함수

A.윈도우 관련

  cvNamedWindow( "T9-camera", 0 );
  cvShowImage( "T9-camera", image );
  cvDestroyWindow( "T9-camera" );

 
B.카메라 영상 캡쳐 관련

  CvCapture* capture = cvCaptureFromCAM(0);
  cvGrabFrame( capture );
  image = cvRetrieveFrame( capture );

  cvReleaseCapture( &capture );

Copyrights (c) 2005 OpenCV.co.kr. All rights reserved.

Media System Lab., Yonsei University
by Dong-Chul Kim, e-mail: opencv at opencv.co.kr

- T9T9.com

OpenCV 초보를 위한 강좌 1편

OpenCV 는 인텔에서 만든 강력한 영상처리 라이브러리입니다.

강력한 기능과 성능에도 불구하고 3D 의 오픈소스라이브러리인 OpenGL 처럼 알려지지도 않고,

활발하게 개발되지도 않고, 자주 쓰이지도 않아 안타까운 심정입니다.

더욱이 국내에는 아직 활성화된 커뮤니티가 없어 자료를 구하기도 어려운 실정입니다.

그리하여 본인이 자료를 수집하고 공부하는 과정에서부딪친 문제점들의 해결방법들과

습득한 지식들을 강좌를 통해 풀어나가 보려고 합니다.

강좌는 다음과 같은 목차로 진행될 예정이며예제 위주와 간결한 문체를 사용하여 정리 하도록 하겠습니다.

개발 환경은 별도로 거론하지 않는다면 다음과 같습니다.


- Windows XP Platform

- Visual C++ 6.0

- OpenCV beta 5.0a



- 목 차 -

1. OpenCV 란 무엇인가?

2. OpenCV 설치하기

3. OpenCV 셋팅

 

- 본 문 -

1. OpenCV 란 무엇인가?

- OpenCV(Open Source Computer Vision) 인텔에서 만든 강력한 영상처리 라이브러리입니다.

- 기초 영상처리서부터 고급 수준의 영상처리 까지 상당한 량의 알고리즘들이 함수로 구현되어 있습니다.

- Binarization, Noise, Motion Detect, Edge Detect, Pattern Recognition, Hidden Markov Model 등등

- 오픈소스로서 스펙만 맞추면 자신의 알고리즘도 라이브러리에 등록 시킬 수 있습니다.

- 인텔의 OpenCV 사이트 http://www.intel.com/technology/computing/opencv/index.htm



2. OpenCV 설치하기

- OS Platform 에 맞게 OpenCV 라이브러리 다운받아 설치합니다.

- Linux 와 Windows 용이 있고 Mac OS 에서도 돌아간다고 합니다.

- 최신 OpenCV 가 Release 되는 곳

    http://sourceforge.net/projects/opencvlibrary


- 다운받기 OpenCV beta 5.0a for Window platform

    http://nchc.dl.sourceforge.net/sourceforge/opencvlibrary/OpenCV_b5a.exe

    http://keihanna.dl.sourceforge.net/sourceforge/opencvlibrary/OpenCV_b5a.exe



3. OpenCV 셋팅

기본적을 OpenCV 를 돌아가게 하려면 크게 4가지 작업을 해주어야 합니다.


1. 첫번째, Visual Studio 셋팅에서 디렉토리 추가하기

  개발 환경에서 컴파일러가 헤더 및 라이브러리 파일들을 찾을 수 있도록 한번만 셋팅해 주면 됩니다.


  - Include files

    C:\PROGRAM FILES\OPENCV\CXCORE\INCLUDE
    C:\PROGRAM FILES\OPENCV\CV\INCLUDE
    C:\PROGRAM FILES\OPENCV\OTHERLIBS\HIGHGUI
    C:\PROGRAM FILES\OPENCV\OTHERLIBS\CVCAM\INCLUDE


  - Library files

    C:\PROGRAM FILES\OPENCV\LIB


2. 두번째, 프로젝트에 Link 하기

  라이브러리 파일들을 링크 해 줍니다.

  원칙적으로는 소스 코드에 쓰인 라이브러리만 링크 해주면 되지만 일일이 어디에 속해 있는 함수인지 알기가 번거로움으로 일반적으로는 앞에 세가지를 기본적으로 링크하면 됩니다.

  cxcore.lib, cv.lib, highgui.lib, cvcam.lib


3. 세번째, 소스파일에 header 파일 include 하기

  #include <cv.h>

  #include <cxcore.h>

  #include <highgui.h>


4. 네번째, dll 파일 복사하기

  C:\Program Files\OpenCV\bin 폴더에서 다음과 같은 파일들을 Workspace 파일이 있는 폴더에 복사 합니다.

  만약에 라이브러리를 사용하지 않았을 경우에는 필요한 파일만 복사하면 됩니다.

    cv097.dll, cxcore097.dll, cvcam097.dll, highgui097.dll

아래 내용을 파일로 만들어 실행 파일에 있는곳에 집어 넣으면 간단히 해결된다...

VC에서 몇개 설정해야 되던걸 이렇게 간단히 해결할 수 있다니... ㅠㅠ...

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
-     <assemblyxmlns="urn:schemas-microsoft-com:asm.v1"manifestVersion="1.0">
      <assemblyIdentity processorArchitecture="*"version="5.1.0.0"type="win32"name="Microsoft.Windows.Shell.shell32"/>
      <description>Windows Shell</description>
-     <dependency>
-     <dependentAssembly>
      <assemblyIdentity type="win32"name="Microsoft.Windows.Common-Controls"version="6.0.0.0"publicKeyToken="6595b64144ccf1df"language="*"processorArchitecture="*"/>
  </dependentAssembly>
   </dependency>
</assembly>

이 내용을 복사해서 "실행파일.exe.manifest"로 만들어 실행파일이 있는곳에 집어 넣으면 끝....
-------------------------------------------------------------------------------------
이런 소스가 귀찮다면... 볼랜드의 컴포넌트중.. XP Manifest 클래스를 떨어뜨려주기만해도.. 됨...
활성화만 시켜주면 바로 적용됨...

'1.소프트웨어 이야기 > 09.ETC' 카테고리의 다른 글

D 언어 소개  (0) 2007.12.06
두 점 사이의 각도 구하기  (0) 2007.12.06
문자열 처리 함수  (0) 2007.12.06

+ Recent posts