영상처리 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));

}



결과



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

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





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





설정

트랙백

댓글