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
    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;
    
    
    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));
}