영상처리 winapi 소스
--------------------------
기상 방송 같은 효과
--------------------------
------- 기상 방송을 보면 아나운서가 파란 뒷 배경에서 설명하는데
방송에서는 아나운서 뒤에 기상 그림이 나온다.
이런 영상 효과를 내는 예제 소스이다. 웹캠이 연결되어 있어야하고
같은 디렉토리 내에 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));
}
결과
위에 이미지가 원본영상으로 전체적으로 어둡다.
밑에 이미지가 스트레칭 처리된 이미지로 밝아졌다.
전체적으로 밝기만 올렸을 경우,