6월16일 영상처리(흑백크기)

2010. 6. 16. 09:572010년/6월




영상의 크기를 축소하거나 확대할경우 기본적으로 필요한 부분은 여러가지가 있지만 특히 기본적인
BITMAPFILEHEADER나 BITMAPINFO부분을 설정해주고 그리고 평안화를 해야한다. 그리고 방법이외에 약간 수학적 공식을 첨가해서 쓰는것인데 그것이 선형보간이다.
수학을 잘몰라서 내용은 잘모르겠지만 대충 평안화할때 보다 조금더 범위가 크게해서 사람이 각지게 울퉁불퉁하지않고 부드럽게 하려고하는것 같다.

#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 0.8    //크기설정

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //윈도우창 콜백 함수 
LRESULT CALLBACK FramInfo(HWND, LPVIDEOHDR); // 콜백 함수

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;  //파일open한 이미지정보 받을 포인터
BITMAPFILEHEADER bmfh;  // 파일open한 비트맵파일해더 정보 
BITMAPINFO *binfo;    //파일open한 비트맵인포정보 
LONG width4;      //폭설정값 

// 변환할 정보
BITMAPINFO *chbinfo;  //크기 변경된 비트맵인포정보 
BYTE *chData;      //크기 변경된 비트맵DATA값 

BITMAPINFO* ChangeBitmapInfo(LONG width,LONG height,const BITMAPINFO* binfo,int i){
  
  BITMAPINFO* chbinfo; //24비트 용 비트맵인포 
  BITMAPINFO* blbinfo; //8비트 용 비트맵인포 
  LONG width4;
  
  if(i==24){ // 크기를 변환한 bitmapinfo구조체를 리턴해 준다.
    
    chbinfo = (BITMAPINFO *) malloc (sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256);
    //24비트 정보로 bitmapinfo를 설정
    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);
    //8비트 정보로 bitmapinfo를설정 
    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=0;
    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;
  } 
  else 
  {
    MessageBox(0,"error","error",0);

  }
  return 0;
  
}
//선형보간으로 이미지 크기 변경 
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;
  
  //Zoom Image를 위한 동적 메모리 할당
  // 원본이미지 폭 
  long width4 = binfo->bmiHeader.biWidth*3;
  width4 = WIDTH4(width4);
  
  // 수정되는 이미 폭 
  long cwidth4 = cbinfo->bmiHeader.biWidth * 3;
  cwidth4 = WIDTH4(cwidth4);
  
  //동적할당 
  chData=(BYTE* )malloc(binfo->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*width4/3+c;
          chData[where]=0;
          //  chData[where+1]=0;
          //  chData[where+2]=0;
          
        }
        //원 이미지의 범위 내에 존재 이중 선형 보간 수행 
        else
        { 
          count++;
          where=r*width4/3+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;
        }
      }
    }
  }
  //24비트 칼라일경우 
  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
    300300, 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;
    
    //window창 위치와 크기 설정 
    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));
}


======================================================================
우리가 배우는것은 영상이기때문에 기존의 비트맵을 바꾸는것을 영상으로 바꾸는것이다.

그래서 간단하게 바꾸었다.

크기는 1.5배로 크게 키운것이고 마찬가지로 숫자는 0.5든 0.1이든 마음대로 바꿀수가있다.


#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.5    //크기설정

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //윈도우창 콜백 함수 
LRESULT CALLBACK FramInfo(HWND, LPVIDEOHDR); // 콜백 함수

TCHAR str[10];    //정수데이터값 확인을 위한 버퍼
unsigned char Menuflag;  //인터페이스 선택 

HINSTANCE g_hInst; //핸들
HWND hWndMain;  
HWND hVFW;
HWND Hwndmain;
HBITMAP hBit;    
BITMAPINFO Bm;    //비트맵 정보를 가짐
LPVIDEOHDR VideoHdr_1;
//영상 메모리
int Action;

LPCTSTR lpszClass = TEXT("VFW 기본 예제");

BYTE *imageData;  //파일open한 이미지정보 받을 포인터
BITMAPFILEHEADER bmfh;  // 파일open한 비트맵파일해더 정보 
BITMAPINFO *binfo;    //파일open한 비트맵인포정보 
LONG width4;      //폭설정값 

// 변환할 정보
BITMAPINFO *chbinfo;  //크기 변경된 비트맵인포정보 
BYTE *chData;      //크기 변경된 비트맵DATA값 

BITMAPINFO* ChangeBitmapInfo(LONG width,LONG height,const BITMAPINFO* binfo,int i){
  
  BITMAPINFO* chbinfo; //24비트 용 비트맵인포 
  BITMAPINFO* blbinfo; //8비트 용 비트맵인포 
  LONG width4;
  
  if(i==24){ // 크기를 변환한 bitmapinfo구조체를 리턴해 준다.
    
    chbinfo = (BITMAPINFO *) malloc (sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256);
    //24비트 정보로 bitmapinfo를 설정
    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);
    //8비트 정보로 bitmapinfo를설정 
    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=0;
    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;
  } 
  else 
  {
    MessageBox(0,"error","error",0);
    
  }
  return 0;
  
}
//선형보간으로 이미지 크기 변경 
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;
  
  //Zoom Image를 위한 동적 메모리 할당
  // 원본이미지 폭 
  long width4 = binfo->bmiHeader.biWidth*3;
  width4 = WIDTH4(width4);
  
  // 수정되는 이미 폭 
  long cwidth4 = cbinfo->bmiHeader.biWidth * 3;
  cwidth4 = WIDTH4(cwidth4);
  
  //동적할당 
  chData=(BYTE* )malloc(binfo->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*width4/3+c;
          chData[where]=0;
          //  chData[where+1]=0;
          //  chData[where+2]=0;
          
        }
        //원 이미지의 범위 내에 존재 이중 선형 보간 수행 
        else
        { 
          count++;
          where=r*width4/3+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;
        }
      }
    }
  }
  //24비트 칼라일경우 
  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
    300300, 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);
    hVFW = capCreateCaptureWindow(TEXT("VFW"), WS_CHILD|WS_VISIBLE,0,0,1,1,hWnd,0);
    //(캡쳐될 윈도우 이름 생성, 윈도우 스타일, 시작점x좌표, 시작점y좌표, 넓이, 높이, 부모윈도우 핸들, window ID)
    
    capDriverConnect(hVFW,0);  //캡쳐윈도우와 드라이버 연결(캡쳐윈도우 핸들, 캡쳐드라이버의 인덱스)
    capPreviewRate(hVFW,1);  //프리뷰모드에서 보여질 프레임 속도(rate)설정 
    //capPreview(hVFW,TRUE);   //프리뷰모드 사용여부
    capGetVideoFormat(hVFW, &Bm, sizeof(Bm)); //영상복사를 위해 사용, 포맷의 크기를 바이트로 전환
    //(캡쳐윈도우 핸들, bitmapinfo 구조체 포인터, 구조체 크기)
    
    hBit = CreateCompatibleBitmap(Hdc, Bm.bmiHeader.biWidth, Bm.bmiHeader.biHeight);
    //DC에 호환하는 비트맵을 생성하여 반환(dc의 핸들, 비트맵의가로 사이즈, 비트맵의 세로 사이즈)
    
    // 비디오 프레임이 캡쳐되었을 경우 처리하기 위한 함수를 설정해주는 매크로 함수
    if(capSetCallbackOnFrame(hVFW, FramInfo)==FALSE)
      //(캡쳐 윈도우 핸들, 콜백함수에 의해 호출되는 함수 포인터)
    {
      return FALSE;
    }
    
    
    
    ReleaseDC(hWnd, Hdc);
    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;
    
    //window창 위치와 크기 설정 
    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));
}
LRESULT CALLBACK FramInfo(HWND hVFW, LPVIDEOHDR VideoHdr)
{
  
  
  HDC Hdc;
  HDC hMemDC;    //메모리DC
  HBITMAP OldBitmap;
  
  int height, width;
  //비트맵 영상 정보
  //영상출력을 위한 변수
  
  capPreviewRate(hVFW, 0);   //프리뷰모드에서 보여질 프레임 속도를 0으로 설정함
  
  // 즉 어떠한 처리가 다 끝나기 전에는 다시 콜백함수가 호출되게 하지 않는다
  LONG chwidth,chheight;
  
  //수정할 이미지 크기 
  chwidth = Bm.bmiHeader.biWidth *ZOOMSIZE;
  chheight = Bm.bmiHeader.biHeight *ZOOMSIZE;
  
  
  //bitmapinfo의 size를 바꾸어서 받아온다.
  chbinfo = ChangeBitmapInfo(chwidth,chheight,&Bm,8);
  chData = ReSizeImage(chbinfo,&Bm,VideoHdr->lpData,8);   
  

  
  height = Bm.bmiHeader.biHeight;  //캡쳐영상의 세로
  width = Bm.bmiHeader.biWidth;  //캡쳐영상의 가로
  
  Hdc=GetDC(Hwndmain);
  hMemDC = CreateCompatibleDC(Hdc);
  OldBitmap = (HBITMAP)SelectObject(hMemDC,hBit);
  MoveWindow(hWndMain,200,200,width+200,height*2+80,true);
  
  SetDIBitsToDevice(Hdc,0,0,width,height,NULL,NULL,NULL,height,VideoHdr->lpData,&Bm,DIB_RGB_COLORS);
    SetDIBitsToDevice(Hdc,0,height,width,height,NULL,NULL,NULL,height,chData,chbinfo,DIB_RGB_COLORS);
  
  
  SelectObject(hMemDC, OldBitmap);
  DeleteDC(hMemDC);
  ReleaseDC(Hwndmain, Hdc); 
  capPreviewRate(hVFW,1); //다음 프레임에는 다시 영상처리를 시작 하게 된다.
  
  return 0;

}