2010년/6월
6월15일 영상처리(흑백 크기축소확대)
뽀얀햄스터
2010. 6. 16. 09:09
#include<Windows.h>
#include"vfw.h"
#include <math.h>
#include <iostream>
#pragma comment(lib, "vfw32.lib") //vfw32 라이브러리 포함
#define SQRT1_2 0.70710678118654752440
#define PI 3.14159265358979323846
#define WIDTH4(width) ((width+3)>>2)<<2
#define ID_BCAPTURE 101
#define ZOOMSIZE 1
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK FramInfo(HWND, LPVIDEOHDR); // 콜백 함수
BITMAPINFO* ChangeBitmapInfo(LONG width,LONG height,const BITMAPINFO* binfo);
TCHAR str[10]; //정수데이터값 확인을 위한 버퍼
unsigned char Menuflag; //인터페이스 선택
HINSTANCE g_hInst;
HWND hWndMain;
HWND hVFW;
HWND Hwndmain;
HBITMAP hBit;
BITMAPINFO Bm; //비트맵 정보를 가짐
//영상 메모리
int Action;
LPCTSTR lpszClass = TEXT("VFW 기본 예제");
BYTE *imageData;
BITMAPFILEHEADER bmfh;
BITMAPINFO *binfo;
LONG width4;
// 변환할 정보
BITMAPINFO *chbinfo;
BYTE *chData;
BITMAPINFO* ChangeBitmapInfo(LONG width,LONG height,const BITMAPINFO* binfo,int i){
BITMAPINFO* chbinfo;
BITMAPINFO* blbinfo;
LONG width4;
if(i==24){ // 크기를 변환한 bitmapinfo구조체를 리턴해 준다.
chbinfo = (BITMAPINFO *) malloc (sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256);
chbinfo->bmiHeader.biBitCount = 24;
chbinfo->bmiHeader.biClrImportant =binfo->bmiHeader.biClrImportant;
chbinfo->bmiHeader.biClrUsed = binfo->bmiHeader.biClrUsed;
chbinfo->bmiHeader.biCompression = binfo->bmiHeader.biCompression;
chbinfo->bmiHeader.biHeight = height;
chbinfo->bmiHeader.biPlanes = binfo->bmiHeader.biPlanes;
chbinfo->bmiHeader.biSize = binfo->bmiHeader.biSize;
chbinfo->bmiHeader.biWidth = width;
width4 = width *3; //폭 맞춤
width4 = ((width4+3)>>2)<<2;
chbinfo->bmiHeader.biSizeImage = width4 * height;
chbinfo->bmiHeader.biXPelsPerMeter = binfo->bmiHeader.biXPelsPerMeter;
chbinfo->bmiHeader.biYPelsPerMeter = binfo->bmiHeader.biYPelsPerMeter;
return chbinfo;
}
else if(i==8)
{
blbinfo=(BITMAPINFO *) malloc (sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256);
blbinfo->bmiHeader.biBitCount=8;
blbinfo->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
blbinfo->bmiHeader.biWidth=width;
blbinfo->bmiHeader.biHeight=height;
width4=((width+3)>>2)<<2;
blbinfo->bmiHeader.biXPelsPerMeter=0;
blbinfo->bmiHeader.biYPelsPerMeter=0;
blbinfo->bmiHeader.biSizeImage=width4*height;
blbinfo->bmiHeader.biPlanes=1;
blbinfo->bmiHeader.biClrUsed=256;
blbinfo->bmiHeader.biCompression=0;
blbinfo->bmiHeader.biClrImportant=256;
for(i=0;i<256;++i)
{
blbinfo->bmiColors[i].rgbBlue=blbinfo->bmiColors[i].rgbGreen=blbinfo->bmiColors[i].rgbRed=i;
blbinfo->bmiColors[i].rgbReserved=0;
}
return blbinfo;
}
}
BYTE* ReSizeImage(BITMAPINFO *binfo,const BITMAPINFO* cbinfo,const BYTE* Data,int i)
{
BYTE newValue,R,G,B;
BYTE* chData;
int new_height=binfo->bmiHeader.biHeight;//새로운 이미지의 높이 계산
int new_width=binfo->bmiHeader.biWidth;//새로운 이미지의 폭 계산
int heightm1=cbinfo->bmiHeader.biHeight-1;
int widthm1=cbinfo->bmiHeader.biWidth-1;
int where,org_where;
int r,c;//타겟 이미지 좌표
float r_orgr,r_orgc;//원 이미지 상의 해당 좌표 (실수값)
int i_orgr,i_orgc;//원 이미지 상의 해당 좌표 (정수값)
float sr,sc;// 예 1.24-1=0.24
float I1,I2,I3,I4;
float zoominfactor = (float)binfo->bmiHeader.biWidth/cbinfo->bmiHeader.biWidth;
unsigned int count=0;
// long width4 = binfo->bmiHeader.biWidth*3;
// width4 = WIDTH4(width4);
width4 =cbinfo->bmiHeader.biWidth*3;
width4 = WIDTH4(width4);
long width5 = cbinfo->bmiHeader.biWidth;
width5= WIDTH4(width5);
long cwidth4 = binfo->bmiHeader.biWidth*3 ;
cwidth4 = WIDTH4(cwidth4);
//Zoom Image를 위한 동적 메모리 할당
chData=(BYTE* )malloc(cbinfo->bmiHeader.biSizeImage);
memset(chData,254,cbinfo->bmiHeader.biSizeImage);
if(i==8)
{
for(r=0;r<new_height;r++)
{
r =r;
for(c=0;c<new_width;c++)
{
r_orgr=r/zoominfactor;
r_orgc=c/zoominfactor;
i_orgr=floor(r_orgr);//예: floor(2.8)=2.0
i_orgc=floor(r_orgc);
sr=r_orgr-i_orgr;
sc=r_orgc-i_orgc;
//범위 조사
//원이미지의 범위를 벗어나는 경우 0값 할당
if(i_orgr<0 || i_orgr>heightm1 || i_orgc<0 || i_orgc>widthm1)
{
where=r*width5+c;
// chData[where]=0;
// chData[where+1]=0;
// chData[where+2]=0;
}
//원 이미지의 범위 내에 존재 이중 선형 보간 수행
else
{
count++;
where=r*width5+c;
I1=(float)Data[(cwidth4*i_orgr)+i_orgc*3+0]; //(org_r,org_c)
I2=(float)Data[(cwidth4*i_orgr)+(i_orgc+1)*3+0];//(org_r,org_c+1)
I3=(float)Data[(cwidth4*(i_orgr+1))+(i_orgc+1)*3+0];//(org_r+1,org_c+1)
I4=(float)Data[(cwidth4*(i_orgr+1))+(i_orgc+1)*3+0];//(org_r+1,org_c)
//이중 선형 보간을 통한 새로운 밝기값 계산
R=(BYTE)(I1*(1-sc)*(1-sr)+I2*sc*(1-sr)+I3*sc*sr+I4*(1-sc)*sr);
// newValue = (I1+I2+I3+I4)/4;
// chData[where]=newValue;
I1=(float)Data[(cwidth4*i_orgr)+i_orgc*3+1];//(org_r,org_c)
I2=(float)Data[(cwidth4*i_orgr)+(i_orgc+1)*3+1];//(org_r,org_c+1)
I3=(float)Data[(cwidth4*(i_orgr+1))+(i_orgc+1)*3+1];//(org_r+1,org_c+1)
I4=(float)Data[(cwidth4*(i_orgr+1))+(i_orgc+1)*3+1];//(org_r+1,org_c)
//이중 선형 보간을 통한 새로운 밝기값 계산
G=(BYTE)(I1*(1-sc)*(1-sr)+I2*sc*(1-sr)+I3*sc*sr+I4*(1-sc)*sr);
//newValue = (I1+I2+I3+I4)/4;
//chData[where+1]=newValue;
I1=(float)Data[(cwidth4*i_orgr)+i_orgc*3+2];//(org_r,org_c)
I2=(float)Data[(cwidth4*i_orgr)+(i_orgc+1)*3+2];//(org_r,org_c+1)
I3=(float)Data[(cwidth4*(i_orgr+1))+(i_orgc+1)*3+2];//(org_r+1,org_c+1)
I4=(float)Data[(cwidth4*(i_orgr+1))+(i_orgc+1)*3+2];//(org_r+1,org_c)
//이중 선형 보간을 통한 새로운 밝기값 계산
B=(BYTE)(I1*(1-sc)*(1-sr)+I2*sc*(1-sr)+I3*sc*sr+I4*(1-sc)*sr);
//newValue = (I1+I2+I3+I4)/4; //이중 선형 보간을 안할시 test 코드
//chData[where+2]=newValue;
chData[where]=(R+G+B)/3;
}
}
}
}
else if(i==24)
{
for(r=0;r<new_height;r++)
{
r =r;
for(c=0;c<new_width;c++)
{
r_orgr=r/zoominfactor;
r_orgc=c/zoominfactor;
i_orgr=floor(r_orgr);//예: floor(2.8)=2.0
i_orgc=floor(r_orgc);
sr=r_orgr-i_orgr;
sc=r_orgc-i_orgc;
//범위 조사
//원이미지의 범위를 벗어나는 경우 0값 할당
if(i_orgr<0 || i_orgr>heightm1 || i_orgc<0 || i_orgc>widthm1)
{
where=r*width4+c*3;
chData[where]=0;
chData[where+1]=0;
chData[where+2]=0;
}
//원 이미지의 범위 내에 존재 이중 선형 보간 수행
else
{
count++;
where=r*width4+c*3;
I1=(float)Data[(cwidth4*i_orgr)+i_orgc*3+0]; //(org_r,org_c)
I2=(float)Data[(cwidth4*i_orgr)+(i_orgc+1)*3+0];//(org_r,org_c+1)
I3=(float)Data[(cwidth4*(i_orgr+1))+(i_orgc+1)*3+0];//(org_r+1,org_c+1)
I4=(float)Data[(cwidth4*(i_orgr+1))+(i_orgc+1)*3+0];//(org_r+1,org_c)
//이중 선형 보간을 통한 새로운 밝기값 계산
newValue=(BYTE)(I1*(1-sc)*(1-sr)+I2*sc*(1-sr)+I3*sc*sr+I4*(1-sc)*sr);
// newValue = (I1+I2+I3+I4)/4;
chData[where]=newValue;
I1=(float)Data[(cwidth4*i_orgr)+i_orgc*3+1];//(org_r,org_c)
I2=(float)Data[(cwidth4*i_orgr)+(i_orgc+1)*3+1];//(org_r,org_c+1)
I3=(float)Data[(cwidth4*(i_orgr+1))+(i_orgc+1)*3+1];//(org_r+1,org_c+1)
I4=(float)Data[(cwidth4*(i_orgr+1))+(i_orgc+1)*3+1];//(org_r+1,org_c)
//이중 선형 보간을 통한 새로운 밝기값 계산
newValue=(BYTE)(I1*(1-sc)*(1-sr)+I2*sc*(1-sr)+I3*sc*sr+I4*(1-sc)*sr);
//newValue = (I1+I2+I3+I4)/4;
chData[where+1]=newValue;
I1=(float)Data[(cwidth4*i_orgr)+i_orgc*3+2];//(org_r,org_c)
I2=(float)Data[(cwidth4*i_orgr)+(i_orgc+1)*3+2];//(org_r,org_c+1)
I3=(float)Data[(cwidth4*(i_orgr+1))+(i_orgc+1)*3+2];//(org_r+1,org_c+1)
I4=(float)Data[(cwidth4*(i_orgr+1))+(i_orgc+1)*3+2];//(org_r+1,org_c)
//이중 선형 보간을 통한 새로운 밝기값 계산
newValue=(BYTE)(I1*(1-sc)*(1-sr)+I2*sc*(1-sr)+I3*sc*sr+I4*(1-sc)*sr);
//newValue = (I1+I2+I3+I4)/4; //이중 선형 보간을 안할시 test 코드
chData[where+2]=newValue;
}
}
}
}
return chData;
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCndParam, 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_CAPTION,200,200,
300, 300, NULL, (HMENU)NULL, hInstance, NULL);
hWndMain = hWnd;
ShowWindow(hWnd, SW_SHOW);
while(GetMessage(&Message, 0,0,0))
{
TranslateMessage(&Message);
DispatchMessage(&Message);
}
return (int)Message.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
HDC Hdc;
FILE *file;
LONG width, height;
int count=0;
switch(iMessage)
{
case WM_CREATE:
Hwndmain = hWnd;
Hdc = GetDC(hWnd);
file=fopen("test.bmp","rb");
if(file==NULL)
return 0;
//BITMAPINFO
binfo = (BITMAPINFO *)malloc(sizeof(BITMAPINFOHEADER)+(sizeof(RGBQUAD)*256));
//초기화
memset(binfo,0,sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256);
//이미지 데이터가 보관될 메모리 할당
//비트맵 파일 헤더 읽음
fread(&bmfh,sizeof(BITMAPFILEHEADER),1,file);
//비트맵 인포 헤더를 읽음
fread(&(binfo->bmiHeader),sizeof(BITMAPINFOHEADER),1,file);
imageData = (BYTE*)malloc(binfo->bmiHeader.biSizeImage);
//이미지 데이터를 읽음
fread(imageData,sizeof(BYTE),binfo->bmiHeader.biSizeImage,file);
fclose(file);
//변환할 가로 세로의 크기 Width
LONG chwidth,chheight;
chwidth = binfo->bmiHeader.biWidth *ZOOMSIZE;
chheight = binfo->bmiHeader.biHeight *ZOOMSIZE;
//bitmapinfo의 size를 바꾸어서 받아온다.
chbinfo = ChangeBitmapInfo(chwidth,chheight,binfo,8);
//imageData의 사이즈를 바꾸어 준다.
chData = ReSizeImage(chbinfo,binfo,imageData,8);
return 0;
case WM_COMMAND:
return 0;
case WM_LBUTTONDOWN:
Hdc = GetDC(hWnd);
width = (unsigned int)binfo->bmiHeader.biWidth;
height = (unsigned int)binfo->bmiHeader.biHeight;
MoveWindow(hWndMain,200,200,width*2+15,height,true);
SetDIBitsToDevice(Hdc,0,0,width,height,
NULL,NULL,NULL,height,imageData,
binfo,DIB_RGB_COLORS);
if(chData!=NULL){
SetDIBitsToDevice(Hdc,width+5,0,chbinfo->bmiHeader.biWidth,chbinfo->bmiHeader.biHeight,
NULL,NULL,NULL,chbinfo->bmiHeader.biHeight,chData,
chbinfo,DIB_RGB_COLORS);
}
ReleaseDC(hWnd,Hdc);
return 0;
case WM_DESTROY:
if(chData!=NULL){
free(chData);
chData=NULL;
}
if(imageData!=NULL){
free(imageData);
imageData =NULL;
}
free(binfo);
PostQuitMessage(0);
return 0;
}
return (DefWindowProc(hWnd,iMessage,wParam,lParam));
}