C++ 영상처리 예제인데 아무리 해도 그림 하나 밖에 안뜨네요..뭐가틀린...

C++ 영상처리 예제인데 아무리 해도 그림 하나 밖에 안뜨네요..뭐가틀린...

작성일 2007.04.20댓글 1건
    게시물 수정 , 삭제는 로그인 필요

1. RAW파일 RAW파일이란 영상의 어떠한 형식(format)도 가지고 있지 않는 원시영상이다. 영상 데이터는 파일의 고유한 특성을 나타내는 헤더 부분을 가지고 있으나 RAW 데이터 파일은 아무런 데이터 형식을 가지지 않고 파일명과 확장자 RAW(ex: chest.raw)를 가지고 있는 영상을 말한다. RAW데이터 파일을 일반 텍스트 에디터로 읽으면 라인피드나 캐리지 리턴, 파일의 끝정보를 나타내는 정보가 없기 때문에 그냥 일렬로 나열만한다. RAW데이터의 영상 파일은 단순한 화소(pixel)정보의 나열로서 RAW데이터의 파일 이미지를 그대로 재현하기 위해서는 원래의 해상도를 정확히 일치 시킨 상태에서 일어 들여야 한다. 의학 영상 처리의 구현에서 RAW파일 형식을 취하는 것은 일반 영상파일 형식들 예를 들면 BMP, GIF, JPG, TIF등은 헤더 정보를 가지고 있어서 프로그래밍 작업시에 헤더 정보를 분석하는 작업이 별도로 필요하기 때문에 프로그램의 길이가 커지고 복잡하게 되기 때문이다. 그러나 RAW파일 형식의 의학영상은 헤더 정보가 없으므로 영상처리를 위하여 헤더정보의 분석이 필요없이 의학영상의 데이터를 직접 처리하면 상대적으로 간단하게 된다. RAW파일 형식의 데이터는 개발자가 사전에 영상의 크기를 알고 있어야 한다는 것과 프로그램의 유연성이 떨어진다는 단점이 있다. 헤더정보가 없다파일정보비트맵정보컬러테이블헤더 정보데이터RAW파일BMP파일 2. RAW데이터 파일 만들기 일반적인 영상처리에서 특별히 많이 사용되고 있는 영상은 고주파영역과 저주파영역이 적절하게 섞여있는 영상이거나 고주파나 저주파의 한가지 특성이 강한 영상을 사용한다. 페인트샵을 이용하여 RAW파일을 만드는 방법에 대하여 알아보자 (1) 먼저 페인트샵을 실행한다. (2) 메뉴에서 [File]->[Open]에서 원하는 이미지를 불러온다. (3) 불러온 이미지에서 원하는 부분을 잘라내고 메뉴에서 [Image]->[Resize]를 실행시켜 크기를 가로 256 Pixel, 세로 256 Pixel로 지정한다. (4) 컬러 이미지를 그레이(Gray Level)이미지로 바꾸기 위해 메뉴의 [Color]->[Gray Scale]을 선택하여 준다. (5) RAW파일로 저장하기 위해 메뉴에서 [File]->{Save]를 누룬 뒤, 파일형식을 "Raw file format(*.raw)"를 선택한 후 저장한다. 2. Visual C++에 의한 의학영상처리 먼저 이 실험을 위해서 기초적인 C 프로그래밍 문법과 Visual C++을 공부할 것을 권유한다. (1) VC++을 실행시키고 파일에서 [NEW]를 선택하여 새로운 프로젝트를 생성한다. 프로세스의 이름은 원하는 이름을 임의로 사용하면 된다. 여기서는 “Test"라는 이름을 사용한다. Location에는 이 프로젝트가 생성될 곳의 디렉토리를 적어준다. 과정이 끝나면 [OK]버튼을 누른다. (2) Step 1은 여러 개의 창이 존재하는 Multiple Document 프로그램을 설정해주는 단계이다. 지원하는 언어는 한국어를 사용할 것이기 때문에 한국어를 선택한다. [Next]버튼을 누른다. (3) Step 2는 데이터베이스를 선택하기 위한 것인데 이 프로젝트에서는 사용하지 않는다. [Next]버튼을 누른다. (4) Step 3은 OLE와 Active 등에 관한 설정을 하는 곳이다. 이 프로젝트와는 무관함으로 [Next]버튼을 누른다. (5) Step 4는 여러 가지 툴바의 형태와 프린트 관련 설정 등을 하는 단계이다. 그림과 같이 설정한다. [Advanced...] 버튼을 눌러서 아래 그림과 같이 입력한다. Advanced 버튼의 Document Template Strings 탭을 RAW 파일 출력 프로그램에 맞게 기입한 것이다. (1) File Extension : 프로그램에서 사용할 디지털 의학영상의 확장자를 지정한다. 프로젝트에서 사용할 영상의 형식은 RAW파일 임으로 raw를 적었다. (2) File type ID : 시스템 레지스트리에 등록될 문서의 타입 ID를 지정한 것이다. (3) Doc type name : 새로운 도큐멘트 템플릿이 추가되면 File 메뉴의 New 항목을 선택했을 때 다이얼로그가 출력되는데 이때 사용되는 도큐먼트 타입 이름을 지정한다. (4) File new name : OLE 서버 프로그램에서 OLE 객체의 짧은 이름으로 사용된다. OLE 기능을 사용하여 이 프로그램을 다른 프로그램에 객체 삽입을 할 경우 사용되어지는 이름이다. (5) Main frame caption : 프로그램의 타이틀 바에 나타날 캡션을 지정한다. (6) Frame name : OLE 객체의 짧은 이름으로 사용된다. (7) File type name : OLE 서버에서 객체 삽입 다이얼로그의 Object type 리스트 박스에서 사용되는 파일 타입 이름을 지정한다. 설정을 모두 마쳤으면 [Close]버튼을 누르고, 다시 [Next] 버튼을 눌러 다음 단계로 간다. (6) Step 5는 주석과 라이브러리 설정화면이다. 기본적으로 설정되어 있는 대로 두고 [Next] 버튼을 누른다. (7) Step 6은 생성된 클래스들의 기본 클래스와 파일 정보를 표시하는 단계이다. 그림처럼 “Base class:”에서 CScrollView를 선택하여 이미지 영상의 출력될 창이 작아지면 오른쪽과 아래쪽에 스크롤 바가 생겨서 바를 이동 시키면서 볼 수 있게 한다. 모든 설정을 마쳤으면 [Finish]버튼을 누른 후, 설정내용 화면을 확인하고 [OK]버튼을 누른다. 이제 프로그램을 작성하면 된다. 그림의 Workspace에서 보이는 것처럼 프로젝트를 위해 생성된 클래스는 6개를 가지고 있다. 각각의 클래스는 다음과 같은 기능을 하는 클래스이다. CTestDoc 클래스 : 문서구조-> 처리할 의학영상을 Loading해서 영상의 변환이나 분석, 인식 등과 같은 작업을 처리할 클래스 CTestView 클래스 : View 구조-> 처리된 의학영상의 결과를 보여주는 역할을 담당하는 클래스 CTestDoc 클래스에는 의학영상을 읽어오는 기능과 저장하는 기능을 구현할 Serialize함수가있다. VC++은 도큐먼트 클래스인 Doc클래스에서 파일처리를 하기를 권장함으로 파일 입출력은 도큐먼트 클래스의 Serialize 함수에서 작성하기로 한다. 이미 프로젝트 생성시 기본적인 틀이 만들어져 있으므로 필요로하는 세부적인 코딩만 추가하면 된다. 이 프로젝트에서 구현해야 할 것은 의학영상을 읽어오는 기능(File Open)과 저장하는 기능(File Save)이다. 3. 의학영상 파일 열기와 저장을 위한 CTestDoc 클래스 AppWizard를 사용하여 생성된 프로젝트는 그림에 보이는 리스트와 같이 기본적인 코드와 구조를 갖추고 있으며 프로그래머가 코딩할 부분에 대한 설명도 되어있음을 볼 수 있다. 먼저 필요한 변수를 CTestDoc 헤더 파일에 첨가하여 입력과 출력을 위한 메모리를 설계하여야한다. 실험에 사용할 의학영상은 “가로 256 X 세로 256”크기의 순수영상(RAW영상)을 입력과 출력에 이용할 것이다. 이를 위하여 배열 [256][256]의 2차원 배열 형태인 unsigned char m_OpenImg[256][256]을 선언하여야 한다. unsigned char 로 Type을 설정한 이유는 영상 파일은 음수값이 없고 256 그레이 영상(Gray Level)이기 때문이다. unsigned char는 부호가 없는 문자형 변수로 0~255까지의 정보를 표현할 수 있다. 파일을 저장하기 위한 변수는 unsigned char m_ResultImg[256][256]을 선언하기로 한다. Workspace에서 CTestDoc 클래스를 두 번 클릭하면 CTestDoc 클래스의 헤더 파일(testdoc.h)이 오른쪽 코딩영역에 나타난다. [리스트1]과 같이 파일열기와 저장을 위한 메모리를 할당하기로 한다. 헤더 부분에 메모리를 읽고 쓸 수 있는 메모리를 할당하였으면 구현파일(testdoc.cpp)에 파일 열기와 저장하기 부분을 직접 코딩하여야 한다. CTestDoc 클래스 멤버함수인 Serialize함수(1)을 두 번 클릭하면 우측의 코딩 공간인 나타난다. 이제부터 코딩 공간에 코드를 추가하면 된다. [리스트 2]와 같이 파일 입/출력 함수인 Serialize함수를 추가한다. [리스트 2] [리스트 2]에서 (1)은 파일 저장부로 직렬화(ar)를 이용하여 m_ResultImg 메모리에 있는 데이터를 가로 256byte, 세로 256byte 크기로 파일에 저장시키는 역할을 한다. (2)는 파일포인터를 생성하고 파일의 길이를 구해서 256 X 256 의학영상이 아닐 경우를 체크하는 루틴과 파일포인터의 헤더 부분에 잡아준 메모리 영역으로 읽어오는 루틴으로 구성된다. AfxMessageBox 함수는 에러 메시지를 출력시키는 역할을 한다. 파일 열기와 저장 부분이 완성되었다. 다음은 받아들인 의학영상 데이터를 사용자가 볼 수 있게 해주는 CTestView에서 저장공간의 초기화와 출력을 위한 작업이 필요하다. 4. 의학영상 화면 출력을 위한 CTestView 클래스 void CTestView::OnInitialUpdate() { CScrollView::OnInitialUpdate(); CSize sizeTotal; // TODO: calculate the total size of this view sizeTotal.cx = sizeTotal.cy = 100; SetScrollSizes(MM_TEXT, sizeTotal); } [리스트 3] CTestView 클래스는 파일 입력과 출력을 이용해서 파일을 배열로 불러왔을 때 사용자에게 보여주는 클래스로서 여러 함수 중 뷰 클래스의 초기화 함수와 하면을 갱신하고 보여주는 역할을 하는 OnDraw함수를 살펴본다. OnInitialUpdate 함수는 화면에 출력하기 전 저장메모리의 초기화 작업을 수행하며 OnDraw 함수에서는 의학영상 데이터를 화면에 출력해 주는 역할을 하는 함수이다. 기본적으로 생성된 초기화 함수의 코드는 [리스트 3]과 같다. [리스트 3]은 뷰 선택에서 선택한 CScrollView함수이다. 함수의 첫부분에 스크롤 뷰를 선택하였음을 나타내는 “CScrollView :: OnInitialUpdate();"가 나타나 있다. 그리고 영상의 출력시 영상이 화면을 넘어가는 부분이 있을 때 생기는 스크롤 바의 범위를 X축, Y축 각각 100으로 ”sizeTotal,cx = sizeTotal.cy = 100; SetScrollSize(MM_TEXT, sizeTotal);"로 지정해 주었다. 1) 출력변수를 이용한 출력작업의 구현 [리스트 4-1] 좌측의 그림에서 (1) CTestView를 두 번 클릭하면 코딩공간처럼 초기값이 보인다. 우측의 그림 네모상자에 있는 내용으로 CTestView 클래스에서 출력에 사용되어질 멤버 변수를 헤더 파일에 선언한다. [리스트 4-1] [리스트 4-2]는 구현파일 OnInitialUpdate() 함수로서 할당되어진 멤버변수에 출력할 의학영상을 옮기는 초기화 작업을 한 것이다. [리스트 4-2] [리스트 4-2]에서 "CTestDoc* pDoc = GetDocument();"는 Application Program 개발에서 문서/뷰 구조를 사용할 경우에 뷰 객체(CTestView)에서 도큐먼트 객체의 멤버(m_OpenImg[256][256])에 접근하려면 도큐먼트 클래스를 참조해야 한다. 그 때 사용하는 함수가 GetDocument()이고 포인터를 사용하여 참조해온 도큐먼트를 pDoc로 할당하여 준다. 이제 pDoc로부터 CTestDoc 클래스의 멤버에 접근할 수 있게 되었으므로 pDoc을 이용하여 m_OpenImg의 데이터 값을 참조하여 도큐먼트 클래스에서 파일 열기에서 받은 의학영상(m_OpenImg)을 할당 받게된다. 화면 출력을 위한 작업을 위하여 OnDraw 함수에 출력함수를 추가하여야 한다. 출력변수를 사용하지 않고 초기화 작업 없이 화면출력을 하기 위하여 초기화 변수선언과 OnInitialUpadte 함수의 편집 없이 OnDraw 함수만 변경하여 주면 된다. [리스트 5]와 같이 GetDocument() 함수를 이용하여 도큐먼트 클래스의 멤버변수를 직접 참조하여 화면에 그려 준다. [리스트 5] 2) Windows 크기 조정을 위한 CChildFrame 클래스 파일을 읽고 화면에 출력하는 모든 과정이 완성되었다. 만약 읽어들인 의학영상이 화면의 크기보다 크다면 의학영상은 윈도우 창의 일부만 보일 것이다, 이 경우 윈도우 창을 늘려주어야 하는데 “가로 256 X 세로 256” 크기의 영상을 보기 위해서는 윈도우 크기를 “캡션바 크기 + 의학영상의 크기”이상으로 하여야 한다. 출력 윈도우의 설정은 CChildFrame 클래스의 멤버함수인 PreCreateWindow 함수에서 조정해 준다. [리스트 6]은 의학영상 출력을 위하여 적당한 크기의 윈도우 를 설정해주기 위한 것이다. [리스트 6] 이제 프로그램을 실행하기 위하여 컴파일과 링크과정을 통하여 실행 파일을 만들고 실행하면 아래 그림과 같은 결과를 얻을 수 있다. 그림처럼 수행을 하기 위하여 [파일]->[열기]를 수행한 후 이미 만들어 놓은 RAW파일을 읽어 들이면 된다. 지금까지 의학영상을 읽어 들이고 저장한 후 출력하는 과정을 살펴보았다. 이제 본격적인 의학영상처리를 하면 된다. 5. 디지털 의학영상의 픽셀 단위 처리 영상처리에서 점처리는 영상의 픽셀 단위로 연산을 수행하는 것이다. 입력 의학영상의 명암 값의 변화나 영상의 합성, 영상증강 등을 수행하며, DSA(Digital Subtraction Angiography)장비는 픽셀 단위 감산으로 혈관영상만 디스플레이하는 대표적인 점처리 영상처리이다. 1) 픽셀 단위 더하기 구현 (1) 디지털 의학영상 처리 프로그램(CTestView)를 로드한 후 리소스 편집기에서 팝업메뉴(Caption : "PixelOp")를 생성한다. (2) 팝업메뉴 아래와 같이 Caption은 “SUM-Const", ID는 ”ID_CONSTANTSUM"로 기입한 뒤 상태바에 출력될 도움말을 Prompt에 적는다. (3) 생성된 서브메뉴에서 마우스 오른쪽 버튼을 클릭하여 [ClassWizard]를 선택하고 Class name은 "CTestView"로, Object IDs는 “ID_CONSTANTSUM"을 선택한다. (4) [Add Function]버튼을 눌러 함수이름을 “OnConstantSum"으로 바꾼 다음, [OK]버튼을 누른다. (5) 함수를 추가하였으면 [Edit Code]버튼을 눌러 CTestView 클래스의 OnConstantSum()함수로 이동해 코딩을 한다. (6) CTestView 클래스의 OnConstantSum() 함수를 [리스트 7]과 같이 추가하여 코딩한다. 원 의학영상에 100을 더한 후 결과 값이 255를 초과하는 픽셀은 255로 강제 할당하여 Saturation 방법을 선택한다. Saturation 방법으로 계산된 결과 값은 도큐먼트 클래스의 m_ResultImg 변수로 할당하였다. void CTestView::OnConstantSum() { // TODO: Add your command handler code here int data = 0; CTestDoc* pDoc = GetDocument(); // Doc클래스 참조 ASSERT_VALID(pDoc); for(int x=0; x<256; x++) { for(int y=0; y<256; y++) { data = pDoc->m_OpenImg[x][y] + 100; //원영상의 값 + 100 //Saturation 방법선택 if(data>255) { pDoc->m_ResultImg[x][y]=255;//출력값저장 } else { pDoc->m_ResultImg[x][y]=data; // 출력값저장 } } } Invalidate(FALSE);//화면갱신 } [리스트7] (7) 출력함수인 OnDraw 함수를 변경한다. 기존의 원 의학영상이지만 출력하던 방법에 연산 결과 후의 의학영상을 출력할 수 있도록 [리스트 8]과 같이 추가하여 코딩을 한다. 출력방법은 출력변수를 사용하지 않고 도큐먼트 클래스의 멤버함수를 직접 참조하여 출력한다. 원 의학영상 옆에 바로 결과 의학영상을 출력할 수 있도록 코딩한다. ///////////////////////////////////////////////////////////////////////////// // CTestView drawing void CTestView::OnDraw(CDC* pDC) { CTestDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here // Original Image 출력 for(int y=0; y<256; y++) { for(int x=0; x<256; x++) { pDC->SetPixel(x,y,RGB(pDoc->m_OpenImg[y][x], pDoc->m_OpenImg[y][x], pDoc->m_OpenImg[y][x])); } } // Result Image 출력 for(y=0; y<256; y++) { for(int x=0; x<256; x++) { pDC->SetPixel(x+300,y,RGB(pDoc->m_ResultImg[y][x], pDoc->m_ResultImg[y][x], pDoc->m_ResultImg[y][x])); } } } [리스트 8] (8) OnDraw 함수에서 원 의학영상과 결과 의학영상을 한꺼번에 출력하게 설정하였으므로 윈도우의 창 크기도 2배로 커져야만 동시에 출력화면을 볼 수 있게 된다. 윈도우 창 크기를 변경하기 위하여 PreCreateWindow 함수를 사용하였으므로 [리스트 9]와 같이 CChildFrame 클래스의 PreCreateWindow 함수를 변경한다. [리스트 9] [프로그램 수행결과 의학영상]


#c++ 영상처리 #c++ 영상처리 예제 #opencv 영상처리 c++ #opencv 실시간 영상처리 c++

profile_image 익명 작성일 -

책에 다 있음. 숙제는 집에서 혼자의 힘으로!!!

실시간인 asf, wmv형식을 avi, mpg...

... 동영상 파일을 만들어야 하나요? 좀더 빠르고, 쉽게... 흑백처리를 한것과 에펙에서 필터를 써서 흑백처리를... 만드신건데 예제중심으로 설명이 쉽고 팁들이 풍부하며...