2010. 6. 17. 09:47ㆍ2010년/6월
히스토그램이라고하면 기본적으로 색상의 분포도라고 생각하면된다.
검은색이 많으면 그래프가 왼쪽으로 그려지고
반대로 화면에 흰색이많으면 오른쪽으로 그래프가 그려진다.
그래서 여러색상이 잇는 화면인경우 그래프가 골고루 그려진다
여기서 오른쪽으로 하나 치솟은 그래프는 내머리털 때문이다 -_-;;;
================================================================
================================================================
#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;
int buf[256]={0,};
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=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;
}
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,
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);
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)
{
int i;
int j;
int sel;
HDC Hdc;
HDC hMemDC; //메모리DC
HBITMAP OldBitmap;
int height, width;
//비트맵 영상 정보
//영상출력을 위한 변수
capPreviewRate(hVFW, 0); //프리뷰모드에서 보여질 프레임 속도를 0으로 설정함
// 즉 어떠한 처리가 다 끝나기 전에는 다시 콜백함수가 호출되게 하지 않는다
LONG chwidth,chheight;
//수정할 이미지 크기
chwidth = 256;
chheight = Bm.bmiHeader.biHeight;
//bitmapinfo의 size를 바꾸어서 받아온다.
chbinfo = ChangeBitmapInfo(chwidth,chheight,&Bm,8);
// chData = ReSizeImage(chbinfo,&Bm,VideoHdr->lpData,8);
width4=Bm.bmiHeader.biWidth*3;
width4=WIDTH4(width4);
for(i=0;i<Bm.bmiHeader.biHeight;++i)
{
for(j=0;j<Bm.bmiHeader.biWidth;++j)
{
sel=((VideoHdr->lpData[i*width4+j*3])+(VideoHdr->lpData[i*width4+j*3+1])+(VideoHdr->lpData[i*width4+j*3+2]))/3;
buf[sel]++;
}
}
width4=chbinfo->bmiHeader.biWidth;
width4=WIDTH4(width4);
chData =(BYTE *)malloc(chbinfo->bmiHeader.biSizeImage);
for(i=0;i<chwidth;++i)
{
for(j=0;j<chbinfo->bmiHeader.biHeight;++j)
{
if(buf[i]==0)
{
chData[j*width4+i]=255;
}
else
{
chData[j*width4+i]=0;
}
buf[i]--;
}
}
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,256,height,NULL,NULL,NULL,height,chData,chbinfo,DIB_RGB_COLORS);
SelectObject(hMemDC, OldBitmap);
DeleteDC(hMemDC);
ReleaseDC(Hwndmain, Hdc);
capPreviewRate(hVFW,1); //다음 프레임에는 다시 영상처리를 시작 하게 된다.
return 0;
}
===================================================================
===================================================================
영상의 2진화
프로그램을 영상의 값을 128보다 크면 검은색 128보다 작으면 0의 값을 넣어준다.
이경우 색은 흰색과 검은색으로 나온다. 바로 2진화라고 한다.
결국에 두색으로 보여주기때문에 0아니면 1 값같이 나와서 영상을 간단하게 본다.
#include "soullex.h"
#pragma comment(lib, "vfw32.lib") //vfw32 라이브러리 포함
#define SQRT1_2 0.70710678118654752440 //제곱근설정
#define PI 3.14159265358979323846 //파이설정
#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;
int buf[256]={0,};
LPCTSTR lpszClass = TEXT("VFW 기본 예제");
BYTE *imageData; //파일open한 이미지정보 받을 포인터
BITMAPFILEHEADER bmfh; // 파일open한 비트맵파일해더 정보
BITMAPINFO *binfo; //파일open한 비트맵인포정보
LONG width4; //폭설정값
// 변환할 정보
BITMAPINFO *chbinfo; //크기 변경된 비트맵인포정보
BYTE *chData; //크기 변경된 비트맵DATA값
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;
LONG chwidth,chheight;
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의 핸들, 비트맵의가로 사이즈, 비트맵의 세로 사이즈)
chwidth = Bm.bmiHeader.biWidth;
chheight = Bm.bmiHeader.biHeight;
chbinfo = ChangeBitmapInfo(chwidth,chheight,&Bm,8);
chData =(BYTE *)malloc(chbinfo->bmiHeader.biSizeImage);
// 비디오 프레임이 캡쳐되었을 경우 처리하기 위한 함수를 설정해주는 매크로 함수
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)
{
int i;
int j;
int sel;
long width5;
HDC Hdc;
HDC hMemDC; //메모리DC
HBITMAP OldBitmap;
int height, width;
//비트맵 영상 정보
//영상출력을 위한 변수
capPreviewRate(hVFW, 0); //프리뷰모드에서 보여질 프레임 속도를 0으로 설정함
// 즉 어떠한 처리가 다 끝나기 전에는 다시 콜백함수가 호출되게 하지 않는다
//수정할 이미지 크기
//bitmapinfo의 size를 바꾸어서 받아온다.
width4=Bm.bmiHeader.biWidth*3;
width4=WIDTH4(width4);
width5=chbinfo->bmiHeader.biWidth;
width5=WIDTH4(width5);
for(i=0;i<Bm.bmiHeader.biHeight;++i)
{
for(j=0;j<Bm.bmiHeader.biWidth;++j)
{
sel=((VideoHdr->lpData[i*width4+j*3])+(VideoHdr->lpData[i*width4+j*3+1])+(VideoHdr->lpData[i*width4+j*3+2]))/3;
if(sel<128)
{
chData[i*width5+j]=0;
}
else
{
chData[i*width5+j]=255;
}
}
}
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;
}
==================================================================
==================================================================
soullex.h 부분
#include <math.h>
#include <iostream>
#include<Windows.h>
#include"vfw.h"
#define WIDTH4(width) ((width+3)>>2)<<2 // 폭설정
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=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;
}
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;
}
======================================================================
=====================================================================
RGB=>YIQ로
==================================================================
==================================================================
'2010년 > 6월' 카테고리의 다른 글
6월23일 영상처리(프로젝트시작 ) RFID(Scanner) (0) | 2010.06.23 |
---|---|
6월21일 영상처리 (YIQ) RFID( JAVA설치 (0) | 2010.06.21 |
6월16일 영상처리(흑백크기) (0) | 2010.06.16 |
6월15일 영상처리(흑백 크기축소확대) (0) | 2010.06.16 |
6월14일 영상처리(선형보간 영상 축소/확대) (0) | 2010.06.14 |