윈도우즈 디바이스 드라이버 개발 방법

프로그래밍 언어/WinApi 2014. 12. 18. 21:52

윈도우즈 디바이스 드라이버 개발 방법

디바이스 드라이버 개발을 처음 시작하시는 분들이 가장 많이 하시는 질문은 “ 디바이스 드라이버를 개발하려면 무엇을 어떻게 공부해야 하나요 ? 라는 것이다 .

 

일반 애플리케이션 프로그램 개발을 시작하는 경우에는 자료도 많고 , 주변에 개발자들도 많아서 공부 방법이나 자료들을 쉽게 접할 수 있는데 , 디바이스 드라이버 분야는 개발자들이 많은 분야도 아니고 , 자료도 쉽게 찾을 수도 없다 보니 입문자들에게는 어디서부터 어떻게 시작해야 할지 막막해 한다 . 간혹, 디바이스 드라이버에 열정이 있으신 분들중에는 홀로 무수한 나날을 디버깅과 테스트를 통해 개발의 고수가 되는 경우도 있다.

하지만 , 일반 개발자들은 아직도 디바이스 드라이버 개발을 위해 어떻게 준비를 해야 할지 어려워하는게 현실이다. 그래서 이런 컬럼 에서는 필자가 그 동안 경험하고 느낀 것을 토대로 초보자들도 쉽게 접근할 수 있는  개발 방법들을 소개하려고 한다 .

우선 , 디바이스 드라이버 개발 방법의 내용을 언급하기 전에 여러분이 한 가지 알아두어야 할 사항이 있다 . 이전 1 부 컬럼 에서도 언급했듯이 디바이스 드라이버와 운영체제는 서로 밀접한 관계를 맺고 있다 . 그래서 이번 컬럼에서 다루는 윈도우 디바이스 드라이버 개발 방법이 다른 운영체제들에도 동일하게 적용되지 않을 수도 있다는 것을 참고해서 글의 내용을 이해했으면 한다 .

1. 무엇을 공부해야 하나 ?
응용프로그램 , 웹 프로그래밍 , 게임 등의 프로그램들처럼 디바이스 드라이버도 소프트웨어의 한 종류로 볼 수 있다 . 그래서 일반적인 대학교의 컴퓨터 학과들에서 배우는 알고리즘 , 운영체제 , 프로그래밍 언어 , 자료구조 , 컴파일러 등등의 다양한 지식들을 기본적으로 알고 있는 것은 디바이스 드라이버를 공부하는데 하는데 많은 도움이 된다 .

하지만 , 이런 기본적인 내용들 이외에 디바이스 드라이버를 개발하기 위해서 좀 더 알아야 할 지식들이 있다 . 그 내용들에 대해서 간략히 살펴보도록 하자 .

운영체제 아키텍처 : 다른 프로그램들도 마찬가지겠지만 , 프로그램이 동작하는 기반이 되는 운영체제를 이해하지 않고서는 제대로 된 프로그램을 개발 할 수가 없다 . 그 중에서도 디바이스 드라이버는 운영체제의 커널에서 동작 하므로, 운영체제 구조 및 개념들 ( 메모리 관리 , 스케줄링 , I/O 요청의 흐름 , 동기화 등등 ) 을 제대로 이해해야 개발하는데 문제가 없게 있게 된다 . 하지만 , 윈도우는 리눅스와 같은 Open Source 운영체제가 아니고, 내부 구조가  블랙박스처럼 베일에 싸여 있다보니,  O/S 내부 내용을 공부 하려해도 항상 정확한 자료들을 가지고 아니어서 이해하는데 많은 어려움이 있다. 그래서, 이런 경우엔  직접 디버깅을 통해 알아내야 하는데, 이런 부분은 윈도우 운영체제를 이해하는데 어렵게 하는 부분이 되고 있다.

Windows Shared Source programs

( http://www.microsoft.com/resources/sharedsource/Licensing/default.mspx )

Microsoft 에서는 윈도우 소스코드를 공유하는 “ Windows Shared Source programs 제도를 운영하고 있다 . 이 프로그램에 참여방법은 여러 가지 방법이 있는데, 그 중에 Microsoft MVP 자격으로 참여해 볼 수 있는 형태가 있다.  관심 있는 분들은 MVP 에 도전해 보길 바란다.  

•  컴퓨터 구조 및 CPU 아키텍처 : 운영체제 아키텍처를 이해하기 위해서는 먼저 컴퓨터 구조나 CPU 아키텍처의 이해가 필요하다 . 즉 , 넓은 의미로 운영체제도 CPU 및 컴퓨터 구조 기반 위에서 작동하는 프로그램이기 때문에 CPU 및 컴퓨터의 구조를 이해하는 것은 기본 중에 기본이다 . 그래서 기본적인 CPU 동작원리라던지 컴퓨터의 내부 구조에 대한 지식은 운영체제 및 드라이버를 이해하는데 필요하다.

•  C/C++ 언어 : 많이 질문하시는 내용 중에 “ 디바이스 드라이버는 어떤 언어로 개발하나요 ? ” 가 있다 . 윈도우 디바이스 드라이버 개발 시에는 C/C++ 언어 정도를 이해한다면 개발하는데 무리는 없다 . 그리고 , 가끔 디버깅 (Debugging) 이나 리버스 엔지니어링 (Reverse Engineering) 이 필요한 경우에 어셈블리 언어 (Assembly) 의 지식이 필요하다. 그렇다고 어셈블리 언어를 완벽한 이해해야 하는것은 아니다. 대신 남의 코드를 디버깅하는 경우 소스 코드가 어셈블리 코드로 보여 내용을 보고 분석할 줄 알아야 하는데 이때 간단히 코드를 보고 이해할 수 있을 정도의 지식이면 된다.

•  API 프로그래밍 : 디바이스 드라이버는 누군가의 요청에 의해 기능을 하게 된다 . 사용자가 GUI 를 가진 애플리케이션을 통해 I/O 요청을 하면 디바이스 드라이버가 해당 작업을 하게 되고 , 결과는 다시 애플리케이션에게 전달되는 구조를 가진다.  이처럼 디바이스 드라이버는 애플리케이션과 항상 상호작용을 한다.
그래서, API 프로그래밍을 공부할때는 단순 API 사용법의 내용이 아닌 디바이스 드라이버와 애플리케이션 사이의 통신 및 전체 I/O 구조에 대한 내용을 중심으로 공부하길 바라며 이 부분은 추후에 드라이버를 공부하는데도 많은 도움이 된다.

•  H/W 지식 : 디바이스 드라이버는 소프트웨어와 하드웨어 사이에 중간의 다리역할을 하는 프로그램이라 볼 수 있다 . 이러다 보니 디바이스 드라이버를 작성하기 위해서는 소프트웨어 지식 뿐만 아니라 , 하드웨어적인 지식도 필요로 하게 된다. 그렇다고 H/W 스펙의 전기적인 내용이나 물리적인 회로등의 이해를 요구하는 것은 아니다. 대신. 기본적인 H/W 스펙 문서에 나와있는 용어라던지 통신 프로토콜등에 대해 먼저 이해하기 바라며, 드라이버에서 사용되는 H/W 관련 개념들도 같이 공부하길 바란다.  

•  디바이스 드라이버 모델 : 윈도우에서는 디바이스 드라이버를 어떤 방식으로 개발하라는 드라이버 모델들을 제시하고 있으며, 이 모델들을 이용해 드라이버를 좀 더 쉽게 개발할 수 있게 해준다. 현재 윈도우에서 제공하는 드라이버 모델은 10 가지 이상의 방법들을 제시하고 있고 , 개발하려는 장치 및 드라이버 종류에 따라 추천하는 드라이버 모델들이 존재하고 있다 . 하지만 , 이런 다양한 드라이버 모델은 개발자들이 드라이버 종류에 따라 각각 새로운 모델들을 익히기 위해 시간과 노력을 배로 들게 하는 단점이 있다 . 그래서 Microsoft 에서는 이런 어려움을 해결하기 위해 새로운 드라이버 모델을 계속 발전시키고 , 통합하는 과정을 진행하고 있다 .

아래 표는 현재까지의 윈도우 운영체제의 종류에 따른 지원하는 드라이버 모델이다 .

Windows 종류

Driver Model

Windows 95/98/ME

VxD, WDM ( Windows 98/ME 에 해당 )

Windows NT

NT Kernel Mode Driver

Windows 2000/XP/2003/VISTA

NT Kernel Mode Driver, WDM, WDF


아래 표는 Microsoft 에서 디바이스 및 드라이버 종류에 따라 권장하는 드라이버 모델에 대한 설명이다 . ( http://www.microsoft.com/whdc/driver/foundation/DrvRoadmap.mspx# )

Device/Driver Class

Recommended Driver Model

1394 device

Depends on device class : KMDF or WDM

Auxiliary display (SideShow)

Windows Portable Devices (WPD),
which is UMDF-based

Bluetooth L2CAP

Depends on device class : KMDF or device-class-specific model such as AVStream

Bluetooth Radio Frequency Communication (RFCOMM)

UMDF

Cell phone, PDA, portable media player

WPD, which is UMDF-baased

Digital camera

Depends on device characterisitics :
Media Transfer Protocol (MTP)/UMDF or WIA

Display adapter

Windows Display Driver Model

File system filter

FS mini-filter

Generic filter driver

KMDF

Human input device (HID)

UMDF (except for mouse and keyboard) or KMDF

Keyboard/Mouse filter

KMDF

Modem, cable modem

KMDF, WDM, or NDIS-WDM

Network Transport Driver Interface (TDI) client

KMDF

Network-connected device

UMDF

Other

Depends on device class and characteristics : UMSF, KMDF, or WDM

Printer

UniDrv, PScript, XPS

Scanner

WIA

Secure digital (SD)

Depends on device class : KMDF or WDM

Serial and parallel devices (legacy)

UMDF or KMDF

Smart card device

WDM

USB device

Depends on device class : UMDF, KMDF, or WDM

Video capture

AVStream



Port/Adapter Class

Recommended Driver Model

Audio adapter

AVStream, PortCls

HID miniport

Microsoft-supplied or KMDF

Network adapter

NDIS-WDM

Network adapter (USB)

NDIS-KMDF

PC card

Microsoft-supplied or KMDF

PCI

Microsoft-supplied or KMDF

Serial, parallel port

Microsoft-supplied or KMDF

Storage adapter (SCSI and ATA)

Scsiport, Storport, ATA port

USB adapter

Microsoft-supplied or KMDF



VxD ( Virtual Device Driver ) : Windows 95/88/ME 에서 사용되는 드라이버 모델로 디바이스 드라이버를 가상화시킨다는 개념을 적용해 드라이버를 만든다 . 확장자는 vxd 로 만들어진다 .

NT Kernel Mode Driver : Windows NT 용 드라이버를 만들기 위한 드라이버 모델로 드라이버 개발을

WDM ( Windows Driver Model ) : 윈도우 디바이스 드라이버를 어떻게 만들어야 한다는 하나의 스펙이라고 볼 수 있다 . 하나의 드라이버 바이너리 파일을 가지고 다양한 윈도우 에서 사용 할 수 있는 드라이버를 만들기 위한 목적으로 만들어졌으며 , 현재 Windows 98/ME/2000/XP/2003/Vista 에서 사용할 수 있다 . 기본적인 개념은 NT Kernel Mode Driver 구조를 바탕으로 만들어 졌으며 , PnP, Power 관리 , WMI 등을 지원한다 .

WDF ( Windows Driver Foundation ) : Windows Vista 가 출시되면서 만들어진 드라이버모델로 WDM 모델에서 발전된 형태이다 . 윈도우 API 프로그래밍을 WDM 에 비유하면 , MFC 는 WDF 해당한다고 볼 수 있다 . WDF 는 크게 두 가지 종류로 나뉘는데 , KMDF ( Kernel-Mode Driver Framework ) 와 UMDF ( User-Mode Driver Framework ) 가 그에 해당된다 .

NDIS ( Network Driver Interface Specification ) : 윈도우에서 네트워크 관련 드라이버를 개발할 때 사용되는 드라이버 모델로 네트워크 드라이버를 좀 더 모듈화 시켜서 쉽게 만들 수 있는 방법을 제공해준다 .

그럼, 현 시점에서는 이렇게 "다양한 드라이버 모델중에 어떤 모델을 공부해야 하나?" 생각이 들것이다.
필자 생각에는 먼저 WDM 드라이버 모델을 공부하라고 말하고 싶다. 이유는 여러분들이 처음 애플리케이션 만들때를 생각해 보면, 처음엔 쉽게 개발을 하기 위해 라이브러리들이 많이 지원되는 MFC 나 비주얼 베이직, 델파이 등을 이용해 프로그램들을 만들었을 것이다. 하지만 이것의 내부 구조 및 원리들을 이해하기 위해서는 API 를 다시 공부 했어야 했다. 이것은 기본적인 원리를 이해하지 못하고는  발전된 개념들을 이해하기 어렵기 때문이다. 그래서 드라이버 모델에서도 API 와 같은 WDM 를 우선적으로 공부하면 드라이버의 기본적인 개념이나 구조를 이해하는데 많은 도움이 될 것이기 때문이다. 그리고나서, 필요에 따라 WDF 를 공부한다던지, 해당 Device Class에 따른 드라이버 모델들을 공부하는 방법을 권한다.

2. 어떻게 공부해야 하나 ?

프로그래밍을 배울 때 듣는 속담 중 하나가 “ 백문이 불여일견 , 백견이 불여일타 “ 라고 했다 . 그 만큼 실제 책으로 공부하고 눈으로 보는 것 보다는 직접 코딩을 하면서 프로그램을 작성하는 것이 백배 더 효과적이라고 한다 .

디바이스 드라이버도 이런 공부 방법대로 많이 만들어보는 것이 제일 중요하다고 생각한다 . 필자도 처음에는 디바이스 드라이버를 책으로만 볼 때는 무슨 내용들을 말고 있는지 , 어떻게 드라이버가 작동 되는지 이해가 잘 되지 않았지만 , 이것저것 개발을 하면서 조금씩 이해를 한 경험이 있다 .

그러나 , 처음 드라이버를 만들려고 해도 뭔가 이론적인 바탕이 있어야 하는데 이런 부분은 혼자 공부하기에는 어려운 부분이 많다 . 그래서 여러 명이서 스터디 그룹을 만들어 같이 공부하면서 서로 공부한 것들을 공유하는 방법을 생각해 볼 수 있을 것이다 . 그리고 , 개발자 저변은 넓지 않은 분야이다 보니 자료들을 찾아보는데도 한계가 있다 . 그렇기 때문에 다양한 세미나 및 개발자 모임 등에는 적극적으로 참여해서 정보를 얻어야 한다 . 그 다음에는 관심 있는 프로그램이나 분야 중에 디바이스 드라이버가 사용되는 것을 선정해 직접 만들어보면서 실제 이론 내용을 적용해 보는 형태로 공부를 하면 많은 도움이 될 것이다 .

그럼 , 여러분들이 개발하기 전에 몇 가지 고려해야 할 사항들을 소개하겠다 .

•  지원할 운영체제 : 제일 먼저 어떤 운영체제를 지원 할지를 결정해야 한다 . 그래야 지원하는 운영체제에 따른 H/W 지원 유무및 드라이버 모델이 정해지고 , 경우에 따라서는 디바이스 드라이버를 운영체제에서 기본적으로 지원하고 있어서 디바이스 드라이버 개발을 별도로 하지 않아도 되는 경우들이 있다 . 그렇기 때문에 우선 지원할 운영체제를 무엇으로 할지 선택해야 한다 .

•  Device 및 Driver Class : 개발하려는 디바이스 드라이버가 지원하는 장치 종류 및 드라이버가 어떤 종류인지 선택 해야 한다 . 다시 설명하면 , 장치관리자에 올라가는 장치 목록에 어떤 장치로 보이게 할 것인지를 선택해야 한다는 말이다 . 어떤 장치 종류이냐에 따라 앞에서도 언급한 드라이버 모델이 결정되어서 개발 방향이 결정이 되기 때문에 이 부분도 중요하게 결정되어야 한다 .

•  Windows Logo 인증 : 여러분들은 장치를 구매했을 때 박스나 PC 에 Windows Logo 스티커가 있는 걸 보거나 , 드라이버 설치시에 경고창이 나타나는 것을 본 경험이 있을 것이다 . 이 Logo 의 의미는 Microsoft 는 Windows 운영체제에서 하드웨어와 소프트웨어가 안정적으로 동작할 수 있도록 하드웨어와 소프트웨어의 완벽한 호환성에 관한 명확한 기준을 제공하고 있으며 , Microsoft 의 WHQL 에서는 제시한 기준에 적합한지를 시험해서 기준에 적합하면 Windows Logo 인증 마크를 사용할 수 있는 권한을 부여하는 제도 이다 . 이런 인증 제도는 비즈니스적인 측면과 관련된 부분이긴 하지만 , 여러분의 H/W 및 디바이스 드라이버 품질을 검증해 보길 원한다면 한번 인증을 진행해 보는 것도 좋은 방법이 될 거라 본다 . 대신 별도의 인증 비용이 들어가니 이점은 참고하기 바란다 .
( http://www.microsoft.com/whdc/winlogo/default.mspx )

디바이스 드라이버를 개발하기 위해 필요한 지식 및 방법에 대한 내용을 필자의 경험을 토대로 간략히 살펴봤다 . 공부에는 왕도가 없다라는 말이 있다 . 디바이스 드라이버를 공부하는 것도 특별한 비법이 있거나 빨리 실력이 느는 방법이 따로 있는것은 아니다. 특히나 드라이버나 시스템 프로그래밍쪽은 다른 분야보다 공부한 만큼 바로 바로 결과가 나오지 않아 쉽게 포기를 하기도 하는 분야다.  이럴수록 여러분들은 차근차근 기본기부터 다진다는 생각으로 공부을 했으면 한다. 
끝으로, 한 가지 더 부탁을 하자면, 인내와 끈기를 가지고 문제 해결를 끝까지 해결하려는 자세를 가졌으면 한다. 디바이스 드라이버를 개발하면서 느낀것은 쉽게 해결되는 문제가 없다는 것이다. 운영체제와 애플리케이션 , H/W 등의 다양한 구성 요소들 사이에서 동작을 하다 보니, 문제점을 파악하고 디버깅하고  테스트하는 과정은 정말 어려움 고난의 과정이다. 그래서 처음 생각과 달리 디버깅이나 테스트에서 많이들 힘들어하고 어려워한다. 하지만, 이런 과정은 여러분들이 고수로 가게 해주는 밑바탕이 될 것이며, 드라이버 개발을 재미를 느끼게 해주는 기폭제가 될것이라 본다.   

그럼, 이제 디바이스 드라이버 개발을 어렵게 느끼지 말고 바로 지금 공부를 시작해보자. 

 

출처 : http://driveronline.org/bbs/view.asp?tb=begin&no=5

설정

트랙백

댓글

Winapi) tooltip track이 안될 때

프로그래밍 언어/WinApi 2014. 11. 28. 00:16

Windows XP, 7 환경에서

툴팁(tooltip)에 TTF_TRACK 속성을 줬는데도 불과하고

실행되지 않을 때에는 아래와 같이 수정하면 잘 된다.


ti.cbSize  =  sizeof(TOOLINFO);


  ->   ti.cbSize  =  sizeof(TTTOOLINFOA_V2_SIZE);

or

  ->   ti.cbSize  =  sizeof(TTTOOLINFOW_V2_SIZE);

or

  ->   ti.cbSize  =  TTTOOLINFOA_V2_SIZE;

or

  ->   ti.cbSize  =  TTTOOLINFOW_V2_SIZE;


공동 컨트롤러의 옛 버전은 sizeof(TOOLINFO)를 사용하고

5.xx 버전 이상??은 sizeof(TTTOOLINFOA_V2_SIZE)를 사용한다고 한다.

버전이 바뀌면서 크기가 달라져서 그렇다고 한다.

설정

트랙백

댓글

Winapi) 소스에서 lib 추가하기

프로그래밍 언어/WinApi 2014. 11. 27. 23:17
#pragma commnet(lib, "추가할 lib")

ex)
#pragma comment( lib, "comctl32.lib")


설정

트랙백

댓글

영상처리 winapi 소스

프로그래밍 언어/WinApi 2014. 10. 10. 10:20


--------------------------

기상 방송 같은 효과

--------------------------


------- 기상 방송을 보면 아나운서가 파란 뒷 배경에서 설명하는데

방송에서는 아나운서 뒤에 기상 그림이 나온다.

이런 영상 효과를 내는 예제 소스이다. 웹캠이 연결되어 있어야하고

같은 디렉토리 내에 image.bmp 파일이 있어야한다.


#include <windows.h>

#include "vfw.h"

#pragma comment(lib, "vfw32.lib")


#define BITMAP_MAXSIZE (1024*768*3+10)


LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

HINSTANCE g_hInst;

HWND HWndMain;

LPCTSTR lpszClass=TEXT("WiseCat");


int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance

,LPSTR lpszCmdParam,int nCmdShow)

{

HWND hWnd;

MSG Message;

WNDCLASS WndClass;

g_hInst = hInstance;


WndClass.cbClsExtra=0;

WndClass.cbWndExtra=0;

WndClass.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);

WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);

WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);

WndClass.hInstance=hInstance;

WndClass.lpfnWndProc=WndProc;

WndClass.lpszClassName=lpszClass;

WndClass.lpszMenuName=NULL;

WndClass.style=CS_HREDRAW | CS_VREDRAW;

RegisterClass(&WndClass);


hWnd=CreateWindow(  lpszClass

,lpszClass

,WS_OVERLAPPEDWINDOW

,CW_USEDEFAULT

,CW_USEDEFAULT

,CW_USEDEFAULT,CW_USEDEFAULT

,NULL

,(HMENU)NULL

,hInstance

,NULL);        

ShowWindow(hWnd,nCmdShow);


while(GetMessage(&Message,NULL,0,0))

{

TranslateMessage(&Message);

DispatchMessage(&Message);

}


return (int)Message.wParam;

}


LRESULT CALLBACK FramInfo(HWND, LPVIDEOHDR);


HWND vfw;

BITMAPINFO Bm;

HDC hdc;

BITMAPFILEHEADER * stpBFH;

BITMAPINFOHEADER * stpBIH;

unsigned char * BMbuf;

unsigned int uiPad;


LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)

{

HANDLE hFile;

PAINTSTRUCT ps;

static unsigned int uiX;

static unsigned int uiY;

DWORD dwRead;


switch(iMessage)

{

case WM_CREATE:

HWndMain = hWnd;


// Bitmap 열고 처리 //시작---------------------------------------------

hFile = CreateFile(TEXT("image.bmp"),

GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if(INVALID_HANDLE_VALUE != hFile)

{

BMbuf = (unsigned char *)malloc(BITMAP_MAXSIZE);

ReadFile(hFile, BMbuf, BITMAP_MAXSIZE, &dwRead, NULL);

CloseHandle(hFile);


stpBFH = (BITMAPFILEHEADER *)BMbuf;

stpBIH = (BITMAPINFOHEADER *)(BMbuf + sizeof(BITMAPFILEHEADER));


uiX = (unsigned int)(stpBIH->biWidth);

uiPad = uiX%4;

uiY = (unsigned int)(stpBIH->biHeight);

}

// Bitmap 열고 처리 //끝-----------------------------------------------


// 웹캠 설정 // 시작------------------------

vfw = capCreateCaptureWindow(  TEXT("CAM")

,WS_CHILD | WS_VISIBLE

,0

,0

,400

,300

,hWnd

,NULL);


capDriverConnect(vfw,0);

capGetVideoFormat(vfw,&Bm,sizeof(Bm));

Bm.bmiHeader.biWidth  = 320;

Bm.bmiHeader.biHeight = 240;

capSetVideoFormat(vfw,&Bm,sizeof(Bm));

//capDlgVideoFormat(m_capwnd); 

capSetCallbackOnFrame(vfw, FramInfo);

capPreviewRate(vfw, 1);

capPreview(vfw, FALSE);

// 웹캠 설정 // 끝--------------------------

return 0;


case WM_PAINT:

hdc = BeginPaint(hWnd,&ps);

EndPaint(hWnd,&ps);

return 0;


case WM_DESTROY:

free(BMbuf);

PostQuitMessage(0);

return 0;

}

return(DefWindowProc(hWnd,iMessage,wParam,lParam));

}


LRESULT CALLBACK FramInfo(HWND hWnd, LPVIDEOHDR lpData)

{

static int iCntX;

static int iCntY;

static int Jump;

unsigned char * ucpPixel;


// 원본 영상 그리기 // 시작-------------------------------

hdc = GetDC(HWndMain);

StretchDIBits(hdc  , 0

, 0

, Bm.bmiHeader.biWidth

, Bm.bmiHeader.biHeight

, 0

, 0

, Bm.bmiHeader.biWidth

, Bm.bmiHeader.biHeight

, lpData->lpData

, &Bm

, DIB_RGB_COLORS

, SRCCOPY);

// 원본 영상 그리기 // 끝---------------------------------


// 영상 정보 편집 // 시작--------------------------------------------

ucpPixel = BMbuf + stpBFH->bfOffBits - 3;

Jump= 0;

for(iCntY = 0; iCntY < Bm.bmiHeader.biHeight ; ++iCntY)  

{        

for(iCntX = 0; iCntX  < Bm.bmiHeader.biWidth  ; ++iCntX, Jump += 3)

{

ucpPixel = ucpPixel + 3;

if(lpData->lpData[Jump + 2] > 100)

{

continue;

}

else if(lpData->lpData[Jump + 1] > 100)

{

continue;

}

else if(lpData->lpData[Jump + 0] > 50)

{

lpData->lpData[Jump] = *(ucpPixel + 0);  // Blue

lpData->lpData[Jump + 2] = *(ucpPixel + 2);  // Red

lpData->lpData[Jump + 1] = *(ucpPixel + 1);  // Green

}

}

ucpPixel = ucpPixel + uiPad;

}

// 영상 정보 편집 // 끝----------------------------------------------


// 편집된 영상 그리기 // 시작----------------------------

StretchDIBits(hdc  , Bm.bmiHeader.biWidth +20

, 0

, Bm.bmiHeader.biWidth

, Bm.bmiHeader.biHeight

, 0

, 0

, Bm.bmiHeader.biWidth

, Bm.bmiHeader.biHeight

, lpData->lpData

, &Bm

, DIB_RGB_COLORS

, SRCCOPY);

// 편집된 영상 그리기 // 끝------------------------------


ReleaseDC(HWndMain, hdc);


return 0;

}

/*

#include <windows.h>

#include <Vfw.h>

#pragma comment (lib,"vfw32.lib")


#define BITMAP_MAXSIZE (1024*768*3+10)


LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

HINSTANCE g_hInst;

HWND hWndMain;

LPCTSTR lpszClass=TEXT("Class");

//WinMain 시작


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance

,LPSTR lpszCmdParam,int nCmdShow)

{

HWND hWnd;

MSG Message;

WNDCLASS WndClass;

g_hInst=hInstance;

//1. 윈도우 속성값 등록

WndClass.cbClsExtra=0;

WndClass.cbWndExtra=0;

WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);

WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);

WndClass.hIcon=LoadIcon(NULL, IDI_APPLICATION);

WndClass.hInstance=hInstance;

WndClass.lpfnWndProc=WndProc;

WndClass.lpszClassName=lpszClass;

WndClass.lpszMenuName=NULL;

WndClass.style=CS_HREDRAW | CS_VREDRAW;

RegisterClass(&WndClass);  //주소에 Write


//2. 윈도우 생성

hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,

NULL, (HMENU)NULL,hInstance,NULL);

ShowWindow(hWnd,nCmdShow); //화면에 뿌려줌


//3. 메시지 처리(무한 반복)

while (GetMessage(&Message,NULL,0,0))

{

TranslateMessage(&Message);

DispatchMessage(&Message);

}

return (int)Message.wParam;

}


LRESULT CALLBACK FramInfo(HWND hVFW, LPVIDEOHDR VideoHdr);

HBITMAP hBit;

BITMAPINFO Bm;

BITMAPFILEHEADER * stpBFH;

BITMAPINFOHEADER * stpBIH;

unsigned char * BMbuf;

unsigned int uiPad;


LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)

{

HDC hdc;

HWND hVFW;

PAINTSTRUCT ps;

HANDLE hFile;

static unsigned int uiX;

static unsigned int uiY;

DWORD dwRead;


switch(iMessage)

{

case WM_CREATE:

hWndMain=hWnd;

hdc=GetDC(hWndMain);


// Bitmap 열기 //-------------------------------------------------------

hFile = CreateFile(TEXT("image.bmp"),

GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if(INVALID_HANDLE_VALUE != hFile)

{

BMbuf = (unsigned char *)malloc(BITMAP_MAXSIZE);

ReadFile(hFile, BMbuf, BITMAP_MAXSIZE, &dwRead, NULL);

CloseHandle(hFile);


stpBFH = (BITMAPFILEHEADER *)BMbuf;

stpBIH = (BITMAPINFOHEADER *)(BMbuf + sizeof(BITMAPFILEHEADER));


uiX = (unsigned int)(stpBIH->biWidth);

uiPad = uiX%4;

uiY = (unsigned int)(stpBIH->biHeight);

}

// Bitmap 그리기 //끝-----------------------------------------------


hVFW=capCreateCaptureWindow(TEXT("VFW"),WS_CHILD | WS_VISIBLE , 0,0,320,240,hWnd,0);

capDriverConnect(hVFW,0);

capPreviewRate(hVFW,10);

capGetVideoFormat(hVFW,&Bm, sizeof(Bm));

Bm.bmiHeader.biWidth = 320;

Bm.bmiHeader.biHeight = 240;

capSetVideoFormat(hVFW, &Bm, sizeof(Bm));

capPreview(hVFW,TRUE);


hBit = CreateCompatibleBitmap(hdc, Bm.bmiHeader.biWidth,Bm.bmiHeader.biHeight);


if (capSetCallbackOnFrame(hVFW,FramInfo) == FALSE)

{

return FALSE;

}

ReleaseDC(hWndMain, hdc);

return 0;

case WM_PAINT:

hdc = BeginPaint(hWnd, &ps);

EndPaint(hWnd, &ps);

return 0;

case WM_DESTROY:

free(BMbuf);

PostQuitMessage(0);

return 0;

}

return(DefWindowProc(hWnd, iMessage, wParam, lParam));

}

LRESULT CALLBACK FramInfo(HWND hVFW, LPVIDEOHDR VideoHdr)

{

HDC hdc;

HDC hMemDC;

HBITMAP OldBitmap;

int iCntX;

int iCntY;

int Jump;

int avr;

unsigned char * ucpPixel;


hdc = GetDC(hWndMain);

hMemDC = CreateCompatibleDC(hdc);

OldBitmap = (HBITMAP)SelectObject(hMemDC, hBit);


ucpPixel = BMbuf + stpBFH->bfOffBits;

Jump=0;

for (iCntY=0 ; iCntY < Bm.bmiHeader.biHeight ; ++iCntY)

{

//for (iCntX=0 ; iCntX < Bm.bmiHeader.biWidth ; ++iCntX)

for (iCntX=Bm.bmiHeader.biWidth-1 ; 0 <= iCntX ; --iCntX)

{


// 특정 색 전환

if(VideoHdr->lpData[Jump+2] > 150)// && VideoHdr->lpData[Jump+2] > 40)

{

if(VideoHdr->lpData[Jump+1] > 150)// && VideoHdr->lpData[Jump+1] > 70)

{

if(VideoHdr->lpData[Jump+0] > 150)// && VideoHdr->lpData[Jump+0] > 70)

{

VideoHdr->lpData[Jump+2] = *(ucpPixel+2);

VideoHdr->lpData[Jump+1] = *(ucpPixel+1);

VideoHdr->lpData[Jump+0] = *(ucpPixel+0);

}

}

}


//원영상

SetPixel(hMemDC, iCntX,(Bm.bmiHeader.biHeight - iCntY)-1,

RGB(VideoHdr->lpData[Jump+2], VideoHdr->lpData[Jump+1], VideoHdr->lpData[Jump]));

//   SetPixel(hMemDC, iCntX,(Bm.bmiHeader.biHeight - iCntY)-1, RGB(0xC3&(VideoHdr->lpData[Jump+2]), 0xC3&(VideoHdr->lpData[Jump+1]), 0xC3&(VideoHdr->lpData[Jump])));

// avr = (VideoHdr->lpData[Jump+2]+VideoHdr->lpData[Jump+1]+VideoHdr->lpData[Jump])/3;

// if(avr < 200)

// avr = 0;

// SetPixel(hMemDC, iCntX,(Bm.bmiHeader.biHeight - iCntY)-1, RGB(avr, avr, avr));


Jump+=3;

ucpPixel = ucpPixel + 3;

}

ucpPixel = ucpPixel + uiPad;

}


//------------------------------------------------------------------------------

BitBlt(hdc, 320,0,Bm.bmiHeader.biWidth,Bm.bmiHeader.biHeight,hMemDC,0,0,SRCCOPY);

SelectObject(hMemDC,OldBitmap);

ReleaseDC(hWndMain,hdc);

return 0;

}

*/


결과





왼쪽이 원본, 오른쪽이 특정 색은 다른 영상 이미지로 대체












-------------------------

웹캠 영상 처리

-------------------------


------- 웹캠으로 촬영된 영상을 스트레칭, 평활화등 영상 처리한 소스이다.



#include <windows.h>

#include <Vfw.h>

#pragma comment (lib,"vfw32.lib")


#define BITMAP_MAXSIZE (1024*768*3+10)


LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

HINSTANCE g_hInst;

HWND hWndMain;

LPCTSTR lpszClass=TEXT("Class");

//WinMain 시작


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance

,LPSTR lpszCmdParam,int nCmdShow)

{

HWND hWnd;

MSG Message;

WNDCLASS WndClass;

g_hInst=hInstance;

//1. 윈도우 속성값 등록

WndClass.cbClsExtra=0;

WndClass.cbWndExtra=0;

WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);

WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);

WndClass.hIcon=LoadIcon(NULL, IDI_APPLICATION);

WndClass.hInstance=hInstance;

WndClass.lpfnWndProc=WndProc;

WndClass.lpszClassName=lpszClass;

WndClass.lpszMenuName=NULL;

WndClass.style=CS_HREDRAW | CS_VREDRAW;

RegisterClass(&WndClass);  //주소에 Write


//2. 윈도우 생성

hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,

NULL, (HMENU)NULL,hInstance,NULL);

ShowWindow(hWnd,nCmdShow); //화면에 뿌려줌


//3. 메시지 처리(무한 반복)

while (GetMessage(&Message,NULL,0,0))

{

TranslateMessage(&Message);

DispatchMessage(&Message);

}

return (int)Message.wParam;

}


LRESULT CALLBACK FramInfo(HWND hVFW, LPVIDEOHDR VideoHdr);

HBITMAP hBit;

BITMAPINFO Bm;

unsigned char * ucpPixel;

BITMAPFILEHEADER * stpBFH;

BITMAPINFOHEADER * stpBIH;

unsigned char * BMbuf;

unsigned int uiPad;


LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)

{

HDC hdc;

HWND hVFW;

PAINTSTRUCT ps;

HANDLE hFile;

static unsigned int uiX;

static unsigned int uiY;

unsigned int uiXcount;

unsigned int uiYcount;

DWORD dwRead;

HBITMAP OldBitmap;


switch(iMessage)

{

case WM_CREATE:

hWndMain=hWnd;

hdc=GetDC(hWndMain);


// Bitmap 열고 설정 //시작-----------------------------------------------------

hFile = CreateFile(TEXT("image.bmp"),

GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if(INVALID_HANDLE_VALUE != hFile)

{

BMbuf = (unsigned char *)malloc(BITMAP_MAXSIZE);

ReadFile(hFile, BMbuf, BITMAP_MAXSIZE, &dwRead, NULL);

CloseHandle(hFile);


stpBFH = (BITMAPFILEHEADER *)BMbuf;

stpBIH = (BITMAPINFOHEADER *)(BMbuf + sizeof(BITMAPFILEHEADER));


uiX = (unsigned int)(stpBIH->biWidth);

uiPad = uiX%4;

uiY = (unsigned int)(stpBIH->biHeight);

}

// Bitmap 열고 설정 //끝-------------------------------------------------------


    // 웹캠 설정 // 시작----------------------------------------------------------------------

hVFW=capCreateCaptureWindow(TEXT("VFW"),WS_CHILD | WS_VISIBLE , 0,0,320,240,hWnd,0);

capDriverConnect(hVFW,0);

capPreviewRate(hVFW,10);

capGetVideoFormat(hVFW,&Bm, sizeof(Bm));

Bm.bmiHeader.biWidth = 320;

Bm.bmiHeader.biHeight = 240;

capSetVideoFormat(hVFW, &Bm, sizeof(Bm));

capPreview(hVFW,TRUE);


hBit = CreateCompatibleBitmap(hdc, Bm.bmiHeader.biWidth,Bm.bmiHeader.biHeight);


if (capSetCallbackOnFrame(hVFW,FramInfo) == FALSE)

{

return FALSE;

}

    // 웹캠 설정 // 끝------------------------------------------------------------------------


ReleaseDC(hWndMain, hdc);

return 0;

case WM_PAINT:

hdc = BeginPaint(hWnd, &ps);

EndPaint(hWnd, &ps);

return 0;

case WM_DESTROY:

free(BMbuf);

PostQuitMessage(0);

return 0;

}

return(DefWindowProc(hWnd, iMessage, wParam, lParam));

}

LRESULT CALLBACK FramInfo(HWND hVFW, LPVIDEOHDR VideoHdr)

{

HDC hdc;

HDC hMemDC;

HBITMAP OldBitmap;

int iCntX;

int iCntY;

int Jump;

int avr;

int Rhigh, Ghigh, Bhigh;

int Rlow, Glow, Blow;

unsigned int uiXcount;

unsigned int uiYcount;

unsigned int uiRcnt[256];

unsigned int uiGcnt[256];

unsigned int uiBcnt[256];

unsigned int uiRhisto[256];  // 평활화로 사용할 변수

unsigned int uiGhisto[256];  // 평활화로 사용할 변수

unsigned int uiBhisto[256];  // 평활화로 사용할 변수


hdc = GetDC(hWndMain);

hMemDC = CreateCompatibleDC(hdc);

OldBitmap = (HBITMAP)SelectObject(hMemDC, hBit);


// 원본 영상 그리기 // 시작------------------------------------------------------

ucpPixel = BMbuf + stpBFH->bfOffBits;

Jump=0;

for (iCntY=0 ; iCntY < Bm.bmiHeader.biHeight ; ++iCntY)

{

//for (iCntX=0 ; iCntX < Bm.bmiHeader.biWidth ; ++iCntX)    // 좌우 반전

for (iCntX=Bm.bmiHeader.biWidth-1 ; 0 <= iCntX ; --iCntX)

{

// 영상 정보 수집 // 시작-------------

++uiRcnt[VideoHdr->lpData[Jump+2]];

++uiGcnt[VideoHdr->lpData[Jump+1]];

++uiBcnt[VideoHdr->lpData[Jump+0]];

// 영상 정보 수집 // 끝---------------


// 영상 출력

SetPixel(hMemDC, iCntX,(Bm.bmiHeader.biHeight - iCntY)-1,

RGB(VideoHdr->lpData[Jump+2], VideoHdr->lpData[Jump+1], VideoHdr->lpData[Jump]));


// 영상 흑백으로 전환 // 시작----------------------------------------------------------------

// avr = (VideoHdr->lpData[Jump+2]+VideoHdr->lpData[Jump+1]+VideoHdr->lpData[Jump])/3;

// if(avr < 200)

// avr = 0;

// SetPixel(hMemDC, iCntX,(Bm.bmiHeader.biHeight - iCntY)-1, RGB(avr, avr, avr));

// 영상 흑백으로 전환 // 끝------------------------------------------------------------------


Jump+=3;    // 다음 픽셀

ucpPixel = ucpPixel + 3;    // 다음 픽셀

}

ucpPixel = ucpPixel + uiPad;    // 패드만큼 다음 가리킴

}

// 원본 영상 그리기 // 끝--------------------------------------------------------


// 영상 정보 처리 // 시작-----------------------------

for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

if(uiRcnt[uiXcount] != 0)

{

Rlow = uiXcount;

break;

}

}

for(uiXcount = 255; 0 <= uiXcount; --uiXcount)

{

if(uiRcnt[uiXcount] != 0)

{

Rhigh = uiXcount;

break;

}

}


for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

if(uiGcnt[uiXcount] != 0)

{

Glow = uiXcount;

break;

}

}

for(uiXcount = 255; 0 <= uiXcount; --uiXcount)

{

if(uiGcnt[uiXcount] != 0)

{

Ghigh = uiXcount;

break;

}

}


for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

if(uiBcnt[uiXcount] != 0)

{

Blow = uiXcount;

break;

}

}

for(uiXcount = 255; 0 <= uiXcount; --uiXcount)

{

if(uiBcnt[uiXcount] != 0)

{

Bhigh = uiXcount;

break;

}

}


// 누적

uiXcount = 0;

uiRhisto[uiXcount] = uiRcnt[uiXcount];

uiGhisto[uiXcount] = uiGcnt[uiXcount];

uiBhisto[uiXcount] = uiBcnt[uiXcount];

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

uiRhisto[uiXcount] = (uiRhisto[uiXcount-1] + uiRcnt[uiXcount]);

uiGhisto[uiXcount] = (uiGhisto[uiXcount-1] + uiGcnt[uiXcount]);

uiBhisto[uiXcount] = (uiBhisto[uiXcount-1] + uiBcnt[uiXcount]);

}


// 계산

for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

uiRhisto[uiXcount] = (uiRhisto[uiXcount] * 255) / (Bm.bmiHeader.biHeight*Bm.bmiHeader.biWidth);

uiGhisto[uiXcount] = (uiGhisto[uiXcount] * 255) / (Bm.bmiHeader.biHeight*Bm.bmiHeader.biWidth);

uiBhisto[uiXcount] = (uiBhisto[uiXcount] * 255) / (Bm.bmiHeader.biHeight*Bm.bmiHeader.biWidth);

}

// 영상 정보 처리 // 끝-------------------------------


  // 편집된 영상 이미지 정보 수정 // 시작-------------------------------

Jump=0;

for (iCntY=0 ; iCntY < Bm.bmiHeader.biHeight ; ++iCntY)

{

for (iCntX=0 ; iCntX < Bm.bmiHeader.biWidth ; ++iCntX)

{

/*

//평활화 + 스트레칭

VideoHdr->lpData[Jump+2] = uiRhisto[(((VideoHdr->lpData[Jump+2])-Rlow) * 255) / (Rhigh - Rlow)];

VideoHdr->lpData[Jump+1] = uiGhisto[(((VideoHdr->lpData[Jump+1])-Glow) * 255) / (Ghigh - Glow)];

VideoHdr->lpData[Jump] = uiBhisto[(((VideoHdr->lpData[Jump+1])-Blow) * 255) / (Bhigh - Blow)];

*/


//스트레칭

VideoHdr->lpData[Jump+2] = (((VideoHdr->lpData[Jump+2])-Rlow) * 255) / (Rhigh - Rlow);

VideoHdr->lpData[Jump+1] = (((VideoHdr->lpData[Jump+1])-Glow) * 255) / (Ghigh - Glow);

VideoHdr->lpData[Jump] = (((VideoHdr->lpData[Jump+1])-Blow) * 255) / (Bhigh - Blow);


/*

//평활화

VideoHdr->lpData[Jump+2] = uiRhisto[VideoHdr->lpData[Jump+2]];

VideoHdr->lpData[Jump+1] = uiGhisto[VideoHdr->lpData[Jump+1]];

VideoHdr->lpData[Jump] = uiBhisto[VideoHdr->lpData[Jump+1]];

*/

//원영상

//   SetPixel(hMemDC, iCntX,(Bm.bmiHeader.biHeight - iCntY)-1,

// RGB(VideoHdr->lpData[Jump+2], VideoHdr->lpData[Jump+1], VideoHdr->lpData[Jump]));

Jump+=3;

}

}

// 편집된 영상 이미지 정보 수정 // 시작-------------------------------


BitBlt(hdc, 320,0,Bm.bmiHeader.biWidth,Bm.bmiHeader.biHeight,hMemDC,0,0,SRCCOPY);

SelectObject(hMemDC,OldBitmap);

ReleaseDC(hWndMain,hdc);

// Sleep(100);

return 0;

}



/*

// 선생님 소스

#include <windows.h>

#include "vfw.h"

#pragma comment(lib, "vfw32.lib")


LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

LRESULT CALLBACK FramInfo(HWND, LPVIDEOHDR);


HINSTANCE g_hInst;

HWND hWndMain;

HWND hVFW;

HWND Hwndmain;

HBITMAP hBit;

BITMAPINFO Bm;

LPCTSTR lpszClass=TEXT("VFW");



LRESULT CALLBACK WndProc( HWND hWnd

, UINT iMessage

, WPARAM wParam

, LPARAM lParam)

{

HDC Hdc;


switch(iMessage)

{

case WM_CREATE:

Hwndmain = hWnd;

Hdc  = GetDC(hWnd);

hVFW = capCreateCaptureWindow(

TEXT("VFW"),

WS_CHILD | WS_VISIBLE,

0,

0,

1,

1,

hWnd,

0);

capDriverConnect(hVFW, 0);

capPreviewRate(hVFW, 1);

capPreview(hVFW, TRUE);

capGetVideoFormat(hVFW, &Bm, sizeof(Bm));

hBit = CreateCompatibleBitmap( Hdc

, Bm.bmiHeader.biWidth

, Bm.bmiHeader.biHeight);

if (capSetCallbackOnFrame(hVFW, FramInfo) == FALSE)

{

return FALSE;

}

ReleaseDC(hWnd, Hdc);

return 0;


case WM_DESTROY:

PostQuitMessage(0);

return 0;

}

return (DefWindowProc(hWnd, iMessage, wParam, lParam));

}


LRESULT CALLBACK FramInfo(HWND hVFW, LPVIDEOHDR VideoHdr)

{

HDC Hdc;

HDC hMemDC;

HBITMAP OldBitmap;


Hdc = GetDC(Hwndmain);

hMemDC = CreateCompatibleDC(Hdc);

OldBitmap = (HBITMAP)SelectObject(hMemDC, hBit);


BitBlt( Hdc

, 0

, 0

, Bm.bmiHeader.biWidth

, Bm.bmiHeader.biHeight

, hMemDC

, 0

, 0

, SRCCOPY);

SelectObject(hMemDC,OldBitmap);

DeleteDC(hMemDC);

ReleaseDC(Hwndmain, Hdc);


return 0;

}

*/


결과




왼쪽이 원본 영상, 오른쪽이 평활화 & 스트레칭 처리된 영상이다.

원본의 왼쪽에 어두워 잘 안보이는데,

처리된 영상을 보면 어두운 부분이 보이게 처리된 것을 확인할 수 있다.











----------------

이미지 평활화

----------------


------- 비트맵 이미지를 평활화 처리하는 소스


#include <windows.h>


#define BITMAP_MAXSIZE (1024*768*3+10)

#define XOFFSET 280

#define X_WIDTH_SIZE 100

#define ALPA

#define SCREEN_Y_SIZE 270*2

#define SCROLL_SIZE 100*6


LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

HINSTANCE g_hInst;

LPCTSTR lpszClass=TEXT("First");


int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance

 ,LPSTR lpszCmdParam,int nCmdShow)

{

HWND hWnd;

MSG Message;

WNDCLASS WndClass;

g_hInst=hInstance;

WndClass.cbClsExtra=0;

WndClass.cbWndExtra=0;

WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);

WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);

WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);

WndClass.hInstance=hInstance;

WndClass.lpfnWndProc=WndProc;

WndClass.lpszClassName=lpszClass;

WndClass.lpszMenuName=NULL;

WndClass.style=CS_HREDRAW | CS_VREDRAW;

RegisterClass(&WndClass);


hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW | WS_VSCROLL,

100,40,800,660,

NULL,(HMENU)NULL,hInstance,NULL);

ShowWindow(hWnd,nCmdShow);

while (GetMessage(&Message,NULL,0,0)) {

TranslateMessage(&Message);

DispatchMessage(&Message);

}

return (int)Message.wParam;

}


unsigned char * BMbuf;

unsigned int uiRcnt[256];

unsigned int uiGcnt[256];

unsigned int uiBcnt[256];

unsigned int uiRcnt2[256];

unsigned int uiGcnt2[256];

unsigned int uiBcnt2[256];

unsigned int uiRhisto[256];  // 평활화로 사용할 변수

unsigned int uiGhisto[256];  // 평활화로 사용할 변수

unsigned int uiBhisto[256];  // 평활화로 사용할 변수

HBITMAP Screen;

HBITMAP Histo;


LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)

{

HDC hdc;

static HDC MemDC;

PAINTSTRUCT ps;

HANDLE hFile;

DWORD dwRead;

TCHAR str[1024];

static BITMAPFILEHEADER * stpBFH;

static BITMAPINFOHEADER * stpBIH;

static unsigned int uiX;

static unsigned int uiY;

unsigned int uiXcount;

unsigned int uiYcount;

unsigned char * ucpPixel;

static unsigned int uiPad;

HBITMAP OldBitmap;

static int yPos;

int yInc;

int iBorW;

HPEN OldPen, MyPen;

switch (iMessage)

{

case WM_CREATE:

SetScrollRange(hWnd, SB_VERT, 0, SCROLL_SIZE, TRUE);

SetScrollPos(hWnd, SB_VERT, 0, TRUE);

hFile = CreateFile(TEXT("image4.bmp"),

GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);


BMbuf = (unsigned char *)malloc(BITMAP_MAXSIZE);

if(0 == BMbuf)

{

MessageBox(hWnd, TEXT("동적할당을 받을 수 없습니다."), TEXT("오류"), MB_OK);

DestroyWindow(hWnd);

}

if(INVALID_HANDLE_VALUE != hFile)

{

ReadFile(hFile, BMbuf, BITMAP_MAXSIZE, &dwRead, NULL);

CloseHandle(hFile);


stpBFH = (BITMAPFILEHEADER *)BMbuf;

stpBIH = (BITMAPINFOHEADER *)(BMbuf + sizeof(BITMAPFILEHEADER));


// 정보 출력 //시작------------------------------------------------------

wsprintf(str, TEXT("[%c][%c]"), BMbuf[0], BMbuf[1]);

CreateWindow(TEXT("static"), TEXT("파일 타입 : "), WS_CHILD | WS_VISIBLE,

0, 0, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 0, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%d byte]"), stpBFH->bfSize);

CreateWindow(TEXT("static"), TEXT("파일 크기 : "), WS_CHILD | WS_VISIBLE,

0, 20, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 20, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%u]"), stpBIH->biWidth);

CreateWindow(TEXT("static"), TEXT("가로 크기 : "), WS_CHILD | WS_VISIBLE,

0, 40, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 40, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%u]"), stpBIH->biHeight);

CreateWindow(TEXT("static"), TEXT("세로 크기 : "), WS_CHILD | WS_VISIBLE,

0, 60, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 60, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%08X]"), stpBFH->bfOffBits);

CreateWindow(TEXT("static"), TEXT("bfOffbits : "), WS_CHILD | WS_VISIBLE,

0, 80, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 80, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%d bytes]"), stpBIH->biSize);

CreateWindow(TEXT("static"), TEXT("헤더 크기 : "), WS_CHILD | WS_VISIBLE,

0, 100, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 100, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%d bytes]"), stpBIH->biSizeImage);

CreateWindow(TEXT("static"), TEXT("그림 크기 : "), WS_CHILD | WS_VISIBLE,

0, 120, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 120, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%d pixel]"), stpBIH->biXPelsPerMeter);

CreateWindow(TEXT("static"), TEXT("이미지 가로 크기 : "), WS_CHILD | WS_VISIBLE,

0, 140, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 140, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%d pixel]"), stpBIH->biYPelsPerMeter);

CreateWindow(TEXT("static"), TEXT("이미지 세로 크기 : "), WS_CHILD | WS_VISIBLE,

0, 160, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 160, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);

// 정보 출력 //끝-----------------------------------------------------------

uiX = (unsigned int)(stpBIH->biWidth);

uiPad = uiX%4;

uiY = (unsigned int)(stpBIH->biHeight);


hdc = GetDC(hWnd);

MemDC = CreateCompatibleDC(hdc);


Screen = CreateCompatibleBitmap(hdc, uiX, uiY * 2);

OldBitmap = (HBITMAP)SelectObject(MemDC, Screen);

// Bitmap 그리기 //시작---------------------------------------------

ucpPixel = BMbuf + stpBFH->bfOffBits;

for(uiYcount = uiY; 0 < uiYcount; --uiYcount)

{

for(uiXcount = uiX; 0 < uiXcount; --uiXcount)

{

// 흑백 처리 // 시작--------------------------------------

iBorW = ((*(ucpPixel+2)) + (*(ucpPixel+1)) + (*ucpPixel))/3;

*(ucpPixel+2)= iBorW;

*(ucpPixel+1)= iBorW;

*(ucpPixel+0)= iBorW;

// 흑백 처리 // 끝----------------------------------------

++uiRcnt[*(ucpPixel+2)];

++uiGcnt[*(ucpPixel+1)];

++uiBcnt[*ucpPixel];


SetPixel(MemDC, uiXcount-1, uiYcount-1,

RGB(*(ucpPixel+2), *(ucpPixel+1), *ucpPixel));

ucpPixel = ucpPixel + 3;

}

ucpPixel = ucpPixel + uiPad;

}



// Bitmap 그리기 //끝-----------------------------------------------


uiYcount = 0;

for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

if(uiYcount < uiRcnt[uiXcount])

{

uiYcount = uiRcnt[uiXcount];

}

if(uiYcount < uiGcnt[uiXcount])

{

uiYcount = uiGcnt[uiXcount];

}

if(uiYcount < uiBcnt[uiXcount])

{

uiYcount = uiBcnt[uiXcount];

}

}


// 히스토그램 세로축 값 변환 //시작----------------------------------

// 평활화 누적값 // 시작--------------------------------------------


// 누적

uiXcount = 0;

uiRhisto[uiXcount] = uiRcnt[uiXcount];

uiGhisto[uiXcount] = uiGcnt[uiXcount];

uiBhisto[uiXcount] = uiBcnt[uiXcount];

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

uiRhisto[uiXcount] = (uiRhisto[uiXcount-1] + uiRcnt[uiXcount]);

uiGhisto[uiXcount] = (uiGhisto[uiXcount-1] + uiGcnt[uiXcount]);

uiBhisto[uiXcount] = (uiBhisto[uiXcount-1] + uiBcnt[uiXcount]);

}

// 계산

for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

uiRhisto[uiXcount] = (uiRhisto[uiXcount] * 255) / (uiX*uiY);

uiGhisto[uiXcount] = (uiGhisto[uiXcount] * 255) / (uiX*uiY);

uiBhisto[uiXcount] = (uiBhisto[uiXcount] * 255) / (uiX*uiY);

}


//n[i]=sum[i]*(1/16)*7 


// 평활화 누적값 // 끝----------------------------------------------


for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

uiRcnt[uiXcount] = (uiRcnt[uiXcount] * 255) / uiYcount;//(uiX*uiY);

uiGcnt[uiXcount] = (uiGcnt[uiXcount] * 255) / uiYcount;//(uiX*uiY);

uiBcnt[uiXcount] = (uiBcnt[uiXcount] * 255) / uiYcount;//(uiX*uiY);

}

// 히스토그램 세로축 값 변환 //끝------------------------------------


// 편집된 Bitmap 그리기 //시작---------------------------------------------

ucpPixel = BMbuf + stpBFH->bfOffBits;

for(uiYcount = uiY*2; uiY < uiYcount; --uiYcount)

{

for(uiXcount = uiX; 0 < uiXcount; --uiXcount)

{

++uiRcnt2[uiRhisto[*(ucpPixel+2)]];

++uiGcnt2[uiGhisto[*(ucpPixel+1)]];

++uiBcnt2[uiBhisto[*ucpPixel]];


SetPixel(MemDC, uiXcount-1, uiYcount-1,

RGB(uiRhisto[*(ucpPixel+2)], uiGhisto[*(ucpPixel+1)], uiBhisto[*ucpPixel]));

ucpPixel = ucpPixel + 3;

}

ucpPixel = ucpPixel + uiPad;

}

// 편집된 Bitmap 그리기 //끝-----------------------------------------------


uiYcount = 0;

for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

if(uiYcount < uiRcnt2[uiXcount])

{

uiYcount = uiRcnt2[uiXcount];

}

if(uiYcount < uiGcnt2[uiXcount])

{

uiYcount = uiGcnt2[uiXcount];

}

if(uiYcount < uiBcnt2[uiXcount])

{

uiYcount = uiBcnt2[uiXcount];

}

}


for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

uiRcnt2[uiXcount] = (uiRcnt2[uiXcount] * 255) / uiYcount;//(uiX*uiY);

uiGcnt2[uiXcount] = (uiGcnt2[uiXcount] * 255) / uiYcount;//(uiX*uiY);

uiBcnt2[uiXcount] = (uiBcnt2[uiXcount] * 255) / uiYcount;//(uiX*uiY);

}


//히스토그램 그리기 //시작-------------------------------------------

Histo = CreateCompatibleBitmap(hdc, 260, SCREEN_Y_SIZE);

SelectObject(MemDC, Histo);

/*

SetBkColor(MemDC, RGB(100,100,100));

aaa = GetBkColor(MemDC);

wsprintf(str, TEXT("[%08X]"), aaa);

MessageBox(hWnd, str, TEXT("hi"), MB_OK);

*/

// SCREEN 바탕 흰색으로 그리기// 시작--------------------------------

for(uiYcount = 0; SCREEN_Y_SIZE > uiYcount; ++uiYcount)

{

for(uiXcount = 0; 260 > uiXcount; ++uiXcount)

{

SetPixel(MemDC, uiXcount, uiYcount, RGB(255, 255, 255));

}

}

// SCREEN 바탕 흰색으로 그리기// 끝----------------------------------


MyPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));

OldPen = (HPEN)SelectObject(MemDC, MyPen);

MoveToEx(MemDC, 0, 0, NULL);

LineTo(MemDC, 0, 256);

LineTo(MemDC, 259, 256);


MoveToEx(MemDC, 0, 270, NULL);

LineTo(MemDC, 0, 270+256);

LineTo(MemDC, 259, 270+256);

// 빨강색 그래프

MoveToEx(MemDC, 3, 256-uiRcnt[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 256-uiRcnt[uiXcount]);

}


// 초록색 그래프

MoveToEx(MemDC, 3, 256-uiGcnt[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(0, 255, 0));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 256-uiGcnt[uiXcount]);

}


// 파랑색 그래프

MoveToEx(MemDC, 3, 256-uiBcnt[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 256-uiBcnt[uiXcount]);

}




MoveToEx(MemDC, 3, 270+256-uiRcnt2[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 270+256-uiRcnt2[uiXcount]);

}


MoveToEx(MemDC, 3, 270+256-uiGcnt2[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(0, 255, 0));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 270+256-uiGcnt2[uiXcount]);

}


MoveToEx(MemDC, 3, 270+256-uiBcnt2[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 270+256-uiBcnt2[uiXcount]);

}

//히스토그램 그리기 //끝---------------------------------------------


SelectObject(hdc, OldPen);

SelectObject(MemDC, OldBitmap);

DeleteDC(MemDC);

DeleteObject(MyPen);

ReleaseDC(hWnd, hdc);

free(BMbuf);

}

else

{

MessageBox(hWnd, TEXT("파일을 열 수 없습니다."), TEXT("오류"), MB_OK);

DestroyWindow(hWnd);

}

return 0;

case WM_PAINT:

hdc = BeginPaint(hWnd, &ps);

MemDC = CreateCompatibleDC(hdc);

OldBitmap = (HBITMAP)SelectObject(MemDC, Screen);


BitBlt(hdc, XOFFSET, -yPos, uiX, uiY*2, MemDC, 0, 0, SRCCOPY);


(HBITMAP)SelectObject(MemDC, Histo);


BitBlt(hdc, 5, 180-yPos, 260, SCREEN_Y_SIZE, MemDC, 0, 0, SRCCOPY);


SelectObject(MemDC, OldBitmap);

DeleteDC(MemDC);

EndPaint(hWnd, &ps);

return 0;

case WM_VSCROLL:

yInc = 0;

switch(LOWORD(wParam))

{

case SB_LINEUP:

yInc = -40;

break;

case SB_LINEDOWN:

yInc = 40;

break;

case SB_PAGEUP:

yInc = -200;

break;

case SB_PAGEDOWN:

yInc = 200;

break;

case SB_THUMBTRACK:

yInc = HIWORD(wParam)-yPos;

break;

}

if(yPos+yInc < 0)

yInc = -yPos;

if(yPos+yInc > SCROLL_SIZE)

yInc = SCROLL_SIZE - yPos;


yPos = yPos + yInc;

ScrollWindow(hWnd, 0, -yInc, NULL, NULL);

SetScrollPos(hWnd, SB_VERT, yPos, TRUE);

return 0;

case WM_KEYDOWN:

yInc = 0;

switch(wParam)

{

case VK_UP:

yInc = -40;

break;

case VK_DOWN:

yInc = 40;

break;

}

if(yPos+yInc < 0)

yInc = -yPos;

if(yPos+yInc > SCROLL_SIZE)

yInc = SCROLL_SIZE - yPos;


yPos = yPos + yInc;

ScrollWindow(hWnd, 0, -yInc, NULL, NULL);

SetScrollPos(hWnd, SB_VERT, yPos, TRUE);

return 0;

case WM_DESTROY:

DeleteObject(Screen);

DeleteObject(Histo);

PostQuitMessage(0);

return 0;

}

return(DefWindowProc(hWnd,iMessage,wParam,lParam));

}




결과


흑백이미지일 경우,

위에 그림이 원본, 밑에 그림이 평활화된 이미지.





색깔이미지일 경우,

위에 그림이 원본, 밑에 그림이 평활화된 이미지.












--------------------

이미지 스트레칭

--------------------


------- 비트맵 이미지를 스트레칭 처리하는 소스



#include <windows.h>


#define BITMAP_MAXSIZE (1024*768*3+10)

#define XOFFSET 280

#define X_WIDTH_SIZE 100

#define ALPA

#define SCREEN_Y_SIZE 270*2

#define SCROLL_SIZE 100*6


LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

HINSTANCE g_hInst;

LPCTSTR lpszClass=TEXT("First");


int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance

 ,LPSTR lpszCmdParam,int nCmdShow)

{

HWND hWnd;

MSG Message;

WNDCLASS WndClass;

g_hInst=hInstance;

WndClass.cbClsExtra=0;

WndClass.cbWndExtra=0;

WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);

WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);

WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);

WndClass.hInstance=hInstance;

WndClass.lpfnWndProc=WndProc;

WndClass.lpszClassName=lpszClass;

WndClass.lpszMenuName=NULL;

WndClass.style=CS_HREDRAW | CS_VREDRAW;

RegisterClass(&WndClass);


hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW | WS_VSCROLL,

100,40,800,660,

NULL,(HMENU)NULL,hInstance,NULL);

ShowWindow(hWnd,nCmdShow);

while (GetMessage(&Message,NULL,0,0)) {

TranslateMessage(&Message);

DispatchMessage(&Message);

}

return (int)Message.wParam;

}


unsigned char * BMbuf;

unsigned int uiRcnt[256];

unsigned int uiGcnt[256];

unsigned int uiBcnt[256];

unsigned int uiRcnt2[256];

unsigned int uiGcnt2[256];

unsigned int uiBcnt2[256];

unsigned int uiRStretch[256];  // 스트레칭으로 사용할 변수

unsigned int uiGStretch[256];  // 스트레칭으로 사용할 변수

unsigned int uiBStretch[256];  // 스트레칭으로 사용할 변수

HBITMAP Screen;

HBITMAP Stretch;


LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)

{

HDC hdc;

static HDC MemDC;

PAINTSTRUCT ps;

HANDLE hFile;

DWORD dwRead;

TCHAR str[1024];

static BITMAPFILEHEADER * stpBFH;

static BITMAPINFOHEADER * stpBIH;

static unsigned int uiX;

static unsigned int uiY;

unsigned int uiXcount;

unsigned int uiYcount;

unsigned char * ucpPixel;

static unsigned int uiPad;

HBITMAP OldBitmap;

static int yPos;

int yInc;

int iBorW;

HPEN OldPen, MyPen;

int Rhigh, Ghigh, Bhigh;

int Rlow, Glow, Blow;

switch (iMessage)

{

case WM_CREATE:

SetScrollRange(hWnd, SB_VERT, 0, SCROLL_SIZE, TRUE);

SetScrollPos(hWnd, SB_VERT, 0, TRUE);

hFile = CreateFile(TEXT("image6.bmp"),

GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);


BMbuf = (unsigned char *)malloc(BITMAP_MAXSIZE);

if(0 == BMbuf)

{

MessageBox(hWnd, TEXT("동적할당을 받을 수 없습니다."), TEXT("오류"), MB_OK);

DestroyWindow(hWnd);

}

if(INVALID_HANDLE_VALUE != hFile)

{

ReadFile(hFile, BMbuf, BITMAP_MAXSIZE, &dwRead, NULL);

CloseHandle(hFile);


stpBFH = (BITMAPFILEHEADER *)BMbuf;

stpBIH = (BITMAPINFOHEADER *)(BMbuf + sizeof(BITMAPFILEHEADER));


// 정보 출력 //시작------------------------------------------------------

wsprintf(str, TEXT("[%c][%c]"), BMbuf[0], BMbuf[1]);

CreateWindow(TEXT("static"), TEXT("파일 타입 : "), WS_CHILD | WS_VISIBLE,

0, 0, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 0, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%d byte]"), stpBFH->bfSize);

CreateWindow(TEXT("static"), TEXT("파일 크기 : "), WS_CHILD | WS_VISIBLE,

0, 20, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 20, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%u]"), stpBIH->biWidth);

CreateWindow(TEXT("static"), TEXT("가로 크기 : "), WS_CHILD | WS_VISIBLE,

0, 40, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 40, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%u]"), stpBIH->biHeight);

CreateWindow(TEXT("static"), TEXT("세로 크기 : "), WS_CHILD | WS_VISIBLE,

0, 60, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 60, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%08X]"), stpBFH->bfOffBits);

CreateWindow(TEXT("static"), TEXT("bfOffbits : "), WS_CHILD | WS_VISIBLE,

0, 80, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 80, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%d bytes]"), stpBIH->biSize);

CreateWindow(TEXT("static"), TEXT("헤더 크기 : "), WS_CHILD | WS_VISIBLE,

0, 100, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 100, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%d bytes]"), stpBIH->biSizeImage);

CreateWindow(TEXT("static"), TEXT("그림 크기 : "), WS_CHILD | WS_VISIBLE,

0, 120, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 120, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%d pixel]"), stpBIH->biXPelsPerMeter);

CreateWindow(TEXT("static"), TEXT("이미지 가로 크기 : "), WS_CHILD | WS_VISIBLE,

0, 140, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 140, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%d pixel]"), stpBIH->biYPelsPerMeter);

CreateWindow(TEXT("static"), TEXT("이미지 세로 크기 : "), WS_CHILD | WS_VISIBLE,

0, 160, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 160, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);

// 정보 출력 //끝-----------------------------------------------------------

uiX = (unsigned int)(stpBIH->biWidth);

uiPad = uiX%4;

uiY = (unsigned int)(stpBIH->biHeight);


hdc = GetDC(hWnd);

MemDC = CreateCompatibleDC(hdc);


Screen = CreateCompatibleBitmap(hdc, uiX, uiY * 2);

OldBitmap = (HBITMAP)SelectObject(MemDC, Screen);

// Bitmap 그리기 //시작---------------------------------------------

ucpPixel = BMbuf + stpBFH->bfOffBits;

for(uiYcount = uiY; 0 < uiYcount; --uiYcount)

{

for(uiXcount = 0; uiX > uiXcount; ++uiXcount)

{

/*iBorW = ((*(ucpPixel+2)) + (*(ucpPixel+1)) + (*ucpPixel))/3;

*(ucpPixel+2)= iBorW;

*(ucpPixel+1)= iBorW;

*(ucpPixel+0)= iBorW;*/

++uiRcnt[*(ucpPixel+2)];

++uiGcnt[*(ucpPixel+1)];

++uiBcnt[*ucpPixel];


SetPixel(MemDC, uiXcount, uiYcount-1,

RGB(*(ucpPixel+2), *(ucpPixel+1), *ucpPixel));

ucpPixel = ucpPixel + 3;

}

ucpPixel = ucpPixel + uiPad;

}



// Bitmap 그리기 //끝-----------------------------------------------


// 히스토그램 세로축 값 변환 //시작----------------------------------



for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

if(uiRcnt[uiXcount] != 0)

{

Rlow = uiXcount;

break;

}

}

for(uiXcount = 255; 0 <= uiXcount; --uiXcount)

{

if(uiRcnt[uiXcount] != 0)

{

Rhigh = uiXcount;

break;

}

}

// wsprintf(str, TEXT("Rhigh : %d, Rlow : %d"), Rhigh, Rlow);

// MessageBox(hWnd, str, TEXT("test"), MB_OK);



for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

if(uiGcnt[uiXcount] != 0)

{

Glow = uiXcount;

break;

}

}

for(uiXcount = 255; 0 <= uiXcount; --uiXcount)

{

if(uiGcnt[uiXcount] != 0)

{

Ghigh = uiXcount;

break;

}

}

// wsprintf(str, TEXT("Ghigh : %d, Glow : %d"), Ghigh, Glow);

// MessageBox(hWnd, str, TEXT("test"), MB_OK);



for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

if(uiBcnt[uiXcount] != 0)

{

Blow = uiXcount;

break;

}

}

for(uiXcount = 255; 0 <= uiXcount; --uiXcount)

{

if(uiBcnt[uiXcount] != 0)

{

Bhigh = uiXcount;

break;

}

}

// wsprintf(str, TEXT("Bhigh : %d, Blow : %d"), Bhigh, Blow);

// MessageBox(hWnd, str, TEXT("test"), MB_OK);


/*

for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

uiRStretch[uiXcount] = ((uiRcnt[uiXcount]-Rlow) * 255) / (Rhigh - Rlow);

uiGStretch[uiXcount] = ((uiGcnt[uiXcount]-Glow) * 255) / (Ghigh - Glow);

uiBStretch[uiXcount] = ((uiBcnt[uiXcount]-Blow) * 255) / (Bhigh - Blow);

}*/



uiYcount = 0;

for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

if(uiYcount < uiRcnt[uiXcount])

{

uiYcount = uiRcnt[uiXcount];

}

if(uiYcount < uiGcnt[uiXcount])

{

uiYcount = uiGcnt[uiXcount];

}

if(uiYcount < uiBcnt[uiXcount])

{

uiYcount = uiBcnt[uiXcount];

}

}


for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

uiRcnt[uiXcount] = (uiRcnt[uiXcount] * 255) / uiYcount;//(uiX*uiY);

uiGcnt[uiXcount] = (uiGcnt[uiXcount] * 255) / uiYcount;//(uiX*uiY);

uiBcnt[uiXcount] = (uiBcnt[uiXcount] * 255) / uiYcount;//(uiX*uiY);

}

// 히스토그램 세로축 값 변환 //끝------------------------------------


// Bitmap 그리기 //시작---------------------------------------------

ucpPixel = BMbuf + stpBFH->bfOffBits;

for(uiYcount = uiY*2; uiY < uiYcount; --uiYcount)

{

for(uiXcount = 0; uiX > uiXcount; ++uiXcount)

{

*(ucpPixel+2) = (((*(ucpPixel+2))-Rlow) * 255) / (Rhigh - Rlow);

*(ucpPixel+1) = (((*(ucpPixel+1))-Glow) * 255) / (Ghigh - Glow);

*(ucpPixel+0) = (((*(ucpPixel+0))-Blow) * 255) / (Bhigh - Blow);


++uiRcnt2[*(ucpPixel+2)];

++uiGcnt2[*(ucpPixel+1)];

++uiBcnt2[*ucpPixel];


SetPixel(MemDC, uiXcount, uiYcount-1,

RGB(*(ucpPixel+2), *(ucpPixel+1), *ucpPixel));

ucpPixel = ucpPixel + 3;

}

ucpPixel = ucpPixel + uiPad;

}

// Bitmap 그리기 //끝-----------------------------------------------


uiYcount = 0;

for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

if(uiYcount < uiRcnt2[uiXcount])

{

uiYcount = uiRcnt2[uiXcount];

}

if(uiYcount < uiGcnt2[uiXcount])

{

uiYcount = uiGcnt2[uiXcount];

}

if(uiYcount < uiBcnt2[uiXcount])

{

uiYcount = uiBcnt2[uiXcount];

}

}


for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

uiRcnt2[uiXcount] = (uiRcnt2[uiXcount] * 255) / uiYcount;//(uiX*uiY);

uiGcnt2[uiXcount] = (uiGcnt2[uiXcount] * 255) / uiYcount;//(uiX*uiY);

uiBcnt2[uiXcount] = (uiBcnt2[uiXcount] * 255) / uiYcount;//(uiX*uiY);

}


//히스토그램 그리기 //시작-------------------------------------------

Stretch = CreateCompatibleBitmap(hdc, 260, SCREEN_Y_SIZE);

SelectObject(MemDC, Stretch);

/*

SetBkColor(MemDC, RGB(100,100,100));

aaa = GetBkColor(MemDC);

wsprintf(str, TEXT("[%08X]"), aaa);

MessageBox(hWnd, str, TEXT("hi"), MB_OK);

*/

// SCREEN 바탕 흰색으로 그리기// 시작--------------------------------

for(uiYcount = 0; SCREEN_Y_SIZE > uiYcount; ++uiYcount)

{

for(uiXcount = 0; 260 > uiXcount; ++uiXcount)

{

SetPixel(MemDC, uiXcount, uiYcount, RGB(255, 255, 255));

}

}

// SCREEN 바탕 흰색으로 그리기// 끝----------------------------------


MyPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));

OldPen = (HPEN)SelectObject(MemDC, MyPen);

MoveToEx(MemDC, 0, 0, NULL);

LineTo(MemDC, 0, 256);

LineTo(MemDC, 259, 256);


MoveToEx(MemDC, 0, 270, NULL);

LineTo(MemDC, 0, 270+256);

LineTo(MemDC, 259, 270+256);

// 빨강색 그래프

MoveToEx(MemDC, 3, 256-uiRcnt[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 256-uiRcnt[uiXcount]);

}


// 초록색 그래프

MoveToEx(MemDC, 3, 256-uiGcnt[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(0, 255, 0));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 256-uiGcnt[uiXcount]);

}


// 파랑색 그래프

MoveToEx(MemDC, 3, 256-uiBcnt[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 256-uiBcnt[uiXcount]);

}



MoveToEx(MemDC, 3, 270+256-uiRcnt2[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 270+256-uiRcnt2[uiXcount]);

}


MoveToEx(MemDC, 3, 270+256-uiGcnt2[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(0, 255, 0));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 270+256-uiGcnt2[uiXcount]);

}


MoveToEx(MemDC, 3, 270+256-uiBcnt2[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 270+256-uiBcnt2[uiXcount]);

}

//히스토그램 그리기 //끝---------------------------------------------


SelectObject(hdc, OldPen);

SelectObject(MemDC, OldBitmap);

DeleteDC(MemDC);

DeleteObject(MyPen);

ReleaseDC(hWnd, hdc);

free(BMbuf);

}

else

{

MessageBox(hWnd, TEXT("파일을 열 수 없습니다."), TEXT("오류"), MB_OK);

DestroyWindow(hWnd);

}

return 0;

case WM_PAINT:

hdc = BeginPaint(hWnd, &ps);

MemDC = CreateCompatibleDC(hdc);

OldBitmap = (HBITMAP)SelectObject(MemDC, Screen);


BitBlt(hdc, XOFFSET, -yPos, uiX, uiY*2, MemDC, 0, 0, SRCCOPY);


(HBITMAP)SelectObject(MemDC, Stretch);


BitBlt(hdc, 5, 180-yPos, 260, SCREEN_Y_SIZE, MemDC, 0, 0, SRCCOPY);


SelectObject(MemDC, OldBitmap);

DeleteDC(MemDC);

EndPaint(hWnd, &ps);

return 0;

case WM_VSCROLL:

yInc = 0;

switch(LOWORD(wParam))

{

case SB_LINEUP:

yInc = -40;

break;

case SB_LINEDOWN:

yInc = 40;

break;

case SB_PAGEUP:

yInc = -200;

break;

case SB_PAGEDOWN:

yInc = 200;

break;

case SB_THUMBTRACK:

yInc = HIWORD(wParam)-yPos;

break;

}

if(yPos+yInc < 0)

yInc = -yPos;

if(yPos+yInc > SCROLL_SIZE)

yInc = SCROLL_SIZE - yPos;


yPos = yPos + yInc;

ScrollWindow(hWnd, 0, -yInc, NULL, NULL);

SetScrollPos(hWnd, SB_VERT, yPos, TRUE);

return 0;

case WM_KEYDOWN:

yInc = 0;

switch(wParam)

{

case VK_UP:

yInc = -40;

break;

case VK_DOWN:

yInc = 40;

break;

}

if(yPos+yInc < 0)

yInc = -yPos;

if(yPos+yInc > SCROLL_SIZE)

yInc = SCROLL_SIZE - yPos;


yPos = yPos + yInc;

ScrollWindow(hWnd, 0, -yInc, NULL, NULL);

SetScrollPos(hWnd, SB_VERT, yPos, TRUE);

return 0;

case WM_DESTROY:

DeleteObject(Screen);

DeleteObject(Stretch);

PostQuitMessage(0);

return 0;

}

return(DefWindowProc(hWnd,iMessage,wParam,lParam));

}



결과



위에 이미지가 원본영상으로 전체적으로 어둡다.

밑에 이미지가 스트레칭 처리된 이미지로 밝아졌다.





전체적으로 밝기만 올렸을 경우,





설정

트랙백

댓글

Java 설치 및 기본 설정

프로그래밍 언어/Java 2014. 9. 27. 07:57

1. 다음 사이트에 접속

http://www.oracle.com/us/downloads/index.html 



2. 아래 그림따라 클릭




3. 아래 그림따라 클릭




4.사용할 플랫폼에 맞는 버전 설치







5. 선택사항


source는 필요없다. (뭔지는 아직 모르겠음)

설치가 끝나면 "C:\Program Files\Java" 아마 이 경로에 아래와 같이 있을 것이다.







6. "C:\Program Files\Java\jdk1.8.0_20\bin" 이 경로를 PATH 환경변수에 추가해 주어야 한다.


Windows 7 경우 "윈도우"키 + "Pause break" 키  -> 왼쪽란에 "고급 시스템 설정" -> "환경 변수"

-> path 변수에 경로 추가.







7. 실행 화면



type 명령어는 텍스트 파일 내용을 읽는 명령어이다.

javac 명령어는 .java 소스 파일을 컴파일 명령어인데, 주의해야할 것은 class 이름이랑 파일 이름이랑 같아야 한다.

'프로그래밍 언어 > Java' 카테고리의 다른 글

Java SE, EE, ME 차이점  (0) 2014.09.27

설정

트랙백

댓글

Java SE, EE, ME 차이점

프로그래밍 언어/Java 2014. 9. 27. 07:52

JAVA SE (Java Platform Standard Edition)

데스크톱, 서버, 임베디드시스템을 위한 표준 자바 플랫폼. 자바 가상머신 규격 및 API집합을 포함

JAVA EE,ME는 목적에 따라 SE를 기반으로 기존의 일부를 택하거나 API를 추가하여 구성된다.

SE는 가장 일반적으로 사용된다. JDBC나 기본적인 기능이 모두 포함되어 있기 때문에 Android개발할때 주로 SE를 사용한다.

예전에는 J2SE로 불리어쓰나 버전 6.0 이후에는 Java SE로 변경되었다. 이전에는 썬 마이크로 시스템즈에서 관리하였으나 J2EE 1.4 이후는 JCP(Java Community Process)주도하에 개발되고 있다.


JDBC, Javadoc 도구, RMI, JNDI등을 포함.



 

JAVA EE (Java Platform EnterPrise Edition)

자바를 이용한 서버측 개발을 위한 플랫폼. 기존 SE에 웹 애플리케이션 서버에서 동작하는 분산 멀티미디어를 제공하는 자바의 기능을 추가한 서버를 위한 플랫폼.

JAVA SE에 서버측을 위한 기능을 부가하였기 때문에 SE기능을 모두 포함한다.

이전에는 J2EE로 불리었으나 버전 5.0 이후로는 Java EE로 개칭되었다.

기업용 분산 API를 개발할 때 사용하므로, 서버측의 서블릿(servlets), JTA, JMS, XML 등을 다룰 수 있는 API 제공.



 

JAVA ME (Java Platform Micro Edition)

이름에서 알 수 있듯이 임베디드를 위한 자바 플랫폼이다.

'프로그래밍 언어 > Java' 카테고리의 다른 글

Java 설치 및 기본 설정  (0) 2014.09.27

설정

트랙백

댓글

[WinApi]VFW함수 자료정리

프로그래밍 언어/WinApi 2014. 9. 18. 12:08

비디오 캡쳐를 하기 위해서 먼저 vfw32.lib 를 프로젝트에서 포함 해주어야 하며 작성 소스 상단에 Vfw.h를

include 해주어야 한다.

 

비디오 캡쳐를 위한 작업 순서를 간단히 다음과 같다.

 

캡쳐 윈도우를 생성

윈도우와 캡쳐 드라이버를 연결

캡쳐된 비디오 프레임을 캡쳐 윈도우를 통해서 출력

캡쳐된 비디오 프레임을 캡쳐 윈도우에 보여주기 위해서는 한 프레임이 캡쳐 될 때마다 특정 함수를 호출하도록 한 다음에 호출된 함수에서 그 프레임을 화면에 출력한다.

이러한 작업을 수행하기 위해서는 VFW 라이브러리 중에서 다음과 같은 함수들을 사용해야 한다.

capGetDriverDescription()

CapCreateCaptureWindow()

capDriverConnect()

capPreviewRate()

capSetVideoFormat()

capDriverDisconnect()

capSetCallbackOnFrame()

 

 - 함수의 원형

 

HWND VFWAPI capCreateCaptureWindowW (
        LPCWSTR lpszWindowName,
        DWORD dwStyle,
        int x, int y, int nWidth, int nHeight,
        HWND hwndParent, int nID);

이 함수는 캡쳐 윈도우를 생성한다. name 에는 윈도우위 이름을 지정한다. style 윈도우위 스타일을 지정한다. (x,y)에는 캡쳐 윈도우의 좌측 상단의 좌표를 지정한다. width height에는 캡쳐 윈도우의 크기를 지정한다. hWnd에는 부모윈도우의 핸들값을 입력한다. id에는 윈도우의 식별 번호를 입력한다. 캡쳐 윈도우가 정상적으로 생성되면 캡쳐 윈도우의 핸들의 함수 결과값으로 반환되고 그렇지 않으면 NULL값이 반환된다.

 

 

BOOL VFWAPI capGetDriverDescriptionW (UINT wDriverIndex,
        LPWSTR lpszName, int cbName,
        LPWSTR lpszVer, int cbVer);

이 함수는 캡쳐 드라이버의 이름 및 버전 정보를 검색한다. 첫 번째 매개변수인 index는 검색하고자 하는 드라이버의 번호를 나타내는데, 0부터 9까지의 값을 가질 수 있다.

즉, 한 컴퓨터에서 9대의 캡쳐 장치가 사용될 수 있다고 가정하고 있다. 검색하고자 하는 번호의 드라이버가 존재하면 이 함수는 name에 드라이버의 이름을 저장하고 version에 드라이버 버전을 저장한 다음에 함수 결과값으로 TURE 값을 반환한다. 

 

capDriverConnect(hWnd, index);

이 함수는 아래 처럼 디파인 되어 있으며

#define capDriverConnect(hwnd, i)          ((BOOL)AVICapSM(hwnd, WM_CAP_DRIVER_CONNECT, (WPARAM)(i), 0L))

AVICapSM 역시 아래 처럼 디파인 되어 있다.( 윈도우 메시지인 WM_CAP_DRIVER_CONNECT 를 사용 하는듯 하다.)

#define AVICapSM(hwnd,m,w,l) ( (::IsWindow(hwnd)) ? ::SendMessage(hwnd,m,w,l) : 0)

이 함수는 캡쳐 윈도우를 캡쳐 드라이버에 연결한다. hWnd는 캡쳐 윈도우의 핸들을 나타내고 index는 캡쳐 드라이버의 번호를 나타낸다. 이 함수는 캡쳐 장치가 정상적으로 작동하여 연결이 성공되면 TURE 값을 반환하고 그렇지 않으면 FALSE 값을 반환한다.

 

 

capPreviewRate(hWnd, rate);

이 함수는 아래 처럼 디파인 되어 있으며

#define capPreviewRate(hwnd, wMS)   ((BOOL)AVICapSM(hwnd, WM_CAP_SET_PREVIEWRATE, (WPARAM)(wMS), 0))

AVICapSM 역시 아래 처럼 디파인 되어 있다.( 윈도우 메시지인 WM_CAP_SET_PREVIEWRATE를 사용 하는듯 하다.)

#define AVICapSM(hwnd,m,w,l) ( (::IsWindow(hwnd)) ? ::SendMessage(hwnd,m,w,l) : 0)

이 함수는 미리보기 (preview)모드에서의 프레임 재생 속도를 설정한다. 여기에서 미리보기란 카메라에서 입력된 비디오를 파일에 저장하는 것이 아니라 화면에 보여준다는 것을 의미한다. hWnd는 캡쳐 윈도우의 핸들 값으로 설정하고 rate는 밀리초(ms) 단 위의 시간으로 설정한다. 예를 들어, rate 값을 66으로 설정하면 0.066초마다 새로운 비디오 프레임을 캡쳐해서 디스플레이 하게 도니다. 이와 같은 속도로 재생을 하면 1초에 15개의 비디오 프레임이 디스플레이된다.

 

capSetVideoFormat(hWnd, videoFormat, videoFormat_size);

#define capSetVideoFormat(hwnd,s,wSize)          ((BOOL)AVICapSM(hwnd,WM_CAP_SET_VIDEOFORMAT, (WPARAM)(wSize), (LPARAM)(LPVOID)(s)))

AVICapSM 역시 아래 처럼 디파인 되어 있다.( 윈도우 메시지인 WM_CAP_SET_VIDEOFORMAT를 사용 하는듯 하다.)

#define AVICapSM(hwnd,m,w,l) ( (::IsWindow(hwnd)) ? ::SendMessage(hwnd,m,w,l) : 0)

이 함수는 캡쳐된 비디오 데이터 형식을 설정한다. 사용자가 원하는 비디오 데이터형식이 캡쳐 장치에서 지원이 되면 이 함수는 TRUE 값을 반환하고 그렇지 않으면 FALSE 값을 반환하므로 반드시 이 함수의 결과값이 TRUE 인지 검사한 다음에 다음단계로 넘어가야 한다.

hWnd는 캡쳐 윈도우의 핸들 값으로 설정한다. videoFormat은 설정하고자 하는 비디오 데이터 형식을 나타내는데, 비디오 데이터의 각 프레임에 대한 비트맵 형식을 BITMAPINFO 구조로 기술한다.

 

BITMAPINFO 구조는 다음과 같다.

typedef struct tagBITMAPINFO{

BITMAPINFOHEADER bmiHeader;

RGBQUAD bmiColrs[1];

BITMAPINFO;  

BITMAPINFO는 BITMAPINFOHEADER와 RGBQUAD로 구성되는데, 여기에서는 다음과 같이 정의되는 BITMAPINFOHEADER 구조체의 값만 사용하면 된다.


pBmiInfo->bmiHeader.biSize = 40;  //BITMAPINFOHEADER 구조체의 크기

pBmiInfo->bmiHeader.biHeight = 480; //영상의 가로크기

pBmiInfo->bmiHeader.biWidth = 640;

//영상의 세로크기(양수:좌측 하단이 원점   음수:좌측 상단이 원점)

pBmiInfo->bmiHeader.biPlanes = 1; //목표 장치의 플레인 수(1로 설정해야함)

pBmiInfo->bmiHeader.biBitCount = (short) 24; //각 픽셀의 비트수

pBmiInfo->bmiHeader.biCompression = 0; //압축 방법(bi_rgb 또는 0:무압축 비트맵)

pBmiInfo->bmiHeader.biSizeImage =0; //비트맵 영상 크기(무압축인 경우 0으로 설정)

pBmiInfo->bmiHeader.biClrImportant = 0; // 비트맵 디스플레이에 사용되는 컬러수

pBmiInfo->bmiHeader.biClrUsed = 0; // 사용된 컬러의 수

pBmiInfo->bmiHeader.biXPelsPerMeter = 10000; //수평 해상도 (미터당 픽셀수)

pBmiInfo->bmiHeader.biYPelsPerMeter = 10000; //수직 해상도 (미터당 픽셀 수)

}BITMAPINFOHEADER;

비디오 캡쳐를 위해서는 다음과 같이 BITMAPINFOHEADER 구조체에서 biSize,biWidth, biHeight, biPlanes, biBitCount 값을 설정하고 나머지 값을은 0으로 설정하면된다.

BITMAPINFO bmi;

memset(&bmi.bmiHeader, 0, sizeof(bmiHeader));

pBmiInfo->bmiHeader.biSize = sizeof(bmi.bmiHeader);

pBmiInfo->bmiHeader.biWidth = 640;//영상의 세로크기(양수:좌측 하단이 원점

pBmiInfo->bmiHeader.biHeight = 480;//영상의 가로크기

pBmiInfo->bmiHeader.biPlanes = 1;//목표 장치의 플레인 수(1로 설정해야함)

pBmiInfo->bmiHeader.biBitCount =  24;//각 픽셀의 비트수

 

capDriverDisconnect(hWnd);

#define capDriverDisconnect(hwnd)       ((BOOL)AVICapSM(hwnd, WM_CAP_DRIVER_DISCONNECT, (WPARAM)0, 0L))

AVICapSM 역시 아래 처럼 디파인 되어 있다.( 윈도우 메시지인 WM_CAP_DRIVER_DISCONNECT를 사용 하는듯 하다.)

#define AVICapSM(hwnd,m,w,l) ( (::IsWindow(hwnd)) ? ::SendMessage(hwnd,m,w,l) : 0)

이 함수는 carDriverConnect() 함수에 의하여 연결한 캡쳐 윈도우와 캡쳐 장치를 분리하는 함수이다. hWnd에는 분리하고자 하는 캡쳐 윈도우의 핸들 값을 설정한다.

 

BOOL capSetCallbackOnFrame(hWnd, func);

#define capSetCallbackOnFrame(hwnd, fpProc)        ((BOOL)AVICapSM(hwnd,WM_CAP_SET_CALLBACK_FRAME, 0, (LPARAM)(LPVOID)(fpProc)))

AVICapSM 역시 아래 처럼 디파인 되어 있다.( 윈도우 메시지인 WM_CAP_SET_CALLBACK_FRAME를 사용 하는듯 하다.)

#define AVICapSM(hwnd,m,w,l) ( (::IsWindow(hwnd)) ? ::SendMessage(hwnd,m,w,l) : 0)

VFW 라이브러리에서는 캡쳐된 비디오 프레임을 화면에 보여주는 작업을 callback함수를 사용해서 처리하도록 하고 있다. capSetCallbackOnFrame()함수는 캡쳐 장치로부터 비디오 프레임이 캡쳐되었을때에 이를 화면에 보여주기 위해서 호출되는 callback 함수를 설정한다. hWnd는 캡쳐 윈도우의 핸들 값으로 설정하고 func는 호출될 함수 이름으로 설정한다.  

 

 

BOOL capOverlay(hWnd, f);
#define capOverlay(hwnd, f)          ((BOOL)AVICapSM(hwnd, WM_CAP_SET_OVERLAY, (WPARAM)(BOOL)(f), 0L))

#define AVICapSM(hwnd,m,w,l) ( (::IsWindow(hwnd)) ? ::SendMessage(hwnd,m,w,l) : 0)

이 함수는 비디오 오버레이를 사용 할것인지 아닌지를 설정한다. 설정 성공시 TRUE, 그렇지 않을경우 FALSE를 반환.
매개변수는 순서대로 윈도우 핸들, 설정시-true 미설정시 -false
비디오 오버레이를 사용하면 CPU자원이 요구 되지 않아 효과적이라고 한다. 
 
BOOL capPreview(hWnd, f);
#define capPreview(hwnd, f)       ((BOOL)AVICapSM(hwnd, WM_CAP_SET_PREVIEW, (WPARAM)(BOOL)(f), 0L))

#define AVICapSM(hwnd,m,w,l) ( (::IsWindow(hwnd)) ? ::SendMessage(hwnd,m,w,l) : 0)

이 함수는 미리보기 모드를 동작 시킬 것인지 아닌지를 설정한다. 설정을 하게 되면 영상 프레임이 시스템의 메모리로 전달되어 GDI함수를 사용하여 캠처 윈도우에 영상을 출력하게 된다.
매개 변수는 순서대로 윈도우 핸들, 설정시 -true, 미설정시 -false 










예제 소스>


#include "windows.h"
#include "Vfw.h"
#pragma comment (lib,"vfw32.lib")
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
LRESULT CALLBACK FramInfo(HWND hVFW, LPVIDEOHDR VideoHdr);
HINSTANCE g_hInst;
HWND hWndMain;
HBITMAP hBit;
BITMAPINFO Bm;
LPCSTR lpszClass=TEXT("Class");
//WinMain 시작
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance
      ,LPSTR lpszCmdParam,int nCmdShow)
{
 HWND hWnd;
 MSG Message;
 WNDCLASS WndClass;
 g_hInst=hInstance;
 //1. 윈도우 속성값 등록
 WndClass.cbClsExtra=0;
 WndClass.cbWndExtra=0;
 WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
 WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
 WndClass.hIcon=LoadIcon(NULL, IDI_APPLICATION);
 WndClass.hInstance=hInstance;
 WndClass.lpfnWndProc=WndProc;
 WndClass.lpszClassName=lpszClass;
 WndClass.lpszMenuName=NULL;
 WndClass.style=CS_HREDRAW | CS_VREDRAW;
 RegisterClass(&WndClass);  //주소에 Write
 
 //2. 윈도우 생성
 hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,
  CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
  NULL, (HMENU)NULL,hInstance,NULL);
 ShowWindow(hWnd,nCmdShow); //화면에 뿌려줌
 
 //3. 메시지 처리(무한 반복)
 while (GetMessage(&Message,NULL,0,0))
 {
  TranslateMessage(&Message);
  DispatchMessage(&Message);
 }
 return (int)Message.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
 HDC hdc;
 HWND hVFW;
 PAINTSTRUCT ps;
 switch(iMessage)
 {
 case WM_CREATE:
  hWndMain=hWnd;
  hdc=GetDC(hWndMain);
  hVFW=capCreateCaptureWindow(TEXT("VFW"),WS_CHILD | WS_VISIBLE , 0,0,1,1,hWnd,0);
  capDriverConnect(hVFW,0);
  capPreviewRate(hVFW,1);
  capPreview(hVFW,TRUE);
  capGetVideoFormat(hVFW,&Bm, sizeof(Bm));
  hBit=CreateCompatibleBitmap(hdc, Bm.bmiHeader.biWidth,Bm.bmiHeader.biHeight);
  if (capSetCallbackOnFrame(hVFW,FramInfo)==FALSE)
  {
   return FALSE;
  }
  ReleaseDC(hWndMain, hdc);
  return 0;
 case WM_PAINT:
  hdc = BeginPaint(hWnd, &ps);
  EndPaint(hWnd, &ps);
  return 0;
 case WM_DESTROY:
  PostQuitMessage(0);
  return 0;
 }
 return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
LRESULT CALLBACK FramInfo(HWND hVFW, LPVIDEOHDR VideoHdr)
{
 HDC hdc;
 HDC hMemDC;
 HBITMAP OldBitmap;
 int iCntX;
 int iCntY;
 int Jump;
 
 hdc = GetDC(hWndMain);
 hMemDC = CreateCompatibleDC(hdc);
 OldBitmap = (HBITMAP)SelectObject(hMemDC, hBit);
 
 Jump=0;
 for (iCntY=0 ; iCntY < Bm.bmiHeader.biHeight ; ++iCntY)
 {
  for (iCntX=0 ; iCntX < Bm.bmiHeader.biWidth ; ++iCntX)
  {
   //원영상
   SetPixel(hMemDC, iCntX,(Bm.bmiHeader.biHeight - iCntY)-1, RGB(VideoHdr->lpData[Jump+2],VideoHdr->lpData[Jump+1],VideoHdr->lpData[Jump]));
   Jump+=3;
  }
 }
 BitBlt(hdc, 0,0,Bm.bmiHeader.biWidth,Bm.bmiHeader.biHeight,hMemDC,0,0,SRCCOPY);
 SelectObject(hMemDC,OldBitmap);
 ReleaseDC(hWndMain,hdc);
 return 0;
}

설정

트랙백

댓글

윈도우즈 API 정복 예제 소스

프로그래밍 언어/WinApi 2014. 7. 13. 02:02

http://kikillers.tistory.com/2

설정

트랙백

댓글

c언어 ms-dos 문자 색깔, 배경 색깔, 커서 위치 변경(gotoxy, settextcolor, getcolor, getbgcolor)

프로그래밍 언어/WinApi 2014. 5. 20. 16:10



ms-dos에서

문자, 배경색 바꾸기

커서 위치 변경






헤더파일 windows.h 를 찾지 못하는 경우

C:\Program Files\Microsoft SDKs\Windows\v7.0A\Include

위치에 windows.h 가 있는지 확인하고 환경변수에 추가.



소스)


#include <stdio.h>

#include <windows.h>


void gotoxy(int, int);

void settextcolor(int, int);

int getcolor();

int getbgcolor();


int main()

{

int color;

int bgcolor;


color = getcolor();

bgcolor = getbgcolor();


gotoxy(5, 5);

settextcolor(10, 0);

printf("hello\n");


gotoxy(5, 6);

settextcolor(12, 0);

printf("hello\n");


settextcolor(color, bgcolor);


return 0;

}



// 커서 위치 변경

void gotoxy(int x, int y)

{

COORD Pos = {x, y};

SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),Pos);

}



// 문자색, 배경색 변경.

void settextcolor(int color, int bgcolor)

{

color &= 0xF;

bgcolor &=0xF;

SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), (bgcolor<<4|color));

}



// 문자색 얻기

int getcolor()

{

CONSOLE_SCREEN_BUFFER_INFO info;

int color;


GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);

color = info.wAttributes & 0xf;

return color;

}



// 배경색 얻기

int getbgcolor()

{

CONSOLE_SCREEN_BUFFER_INFO info;

int color;


GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);

color = (info.wAttributes & 0xf0) >> 4;

return color;

}

'프로그래밍 언어 > WinApi' 카테고리의 다른 글

Winapi) tooltip track이 안될 때  (0) 2014.11.28
Winapi) 소스에서 lib 추가하기  (0) 2014.11.27
영상처리 winapi 소스  (0) 2014.10.10
[WinApi]VFW함수 자료정리  (0) 2014.09.18
윈도우즈 API 정복 예제 소스  (0) 2014.07.13

설정

트랙백

댓글