Color Spectral theory of light 1672 Issac Newton



































- Slides: 35
Color 개요 • Spectral theory of light (1672, Issac Newton) – Color is a single frequency or wavelength of electro-magnetic radiations – Wavelength of visible light: 400 ~ 700 nm
Color 개요 Human eye Cone Tristimulus 4
색상 모델 • HSI 모델 원본 hue saturation intensity 13
색상 모델 void CColor. Conv: : RGB_To_HSI(float r, float g, float b, float *h, float *s, float *i) { float minc; // minimum and maximum RGB values float angle; // temp variable used to compute Hue // r, g, b = 0~1 사이값 minc = MIN(r, g); minc = MIN(minc, b); // 밝기값(Intensity) 의 계산: 밝기값은 r, g, b, 의 평균을 취함 �*i=(r + g + b) / 3. 0 f; // 색상(Hue)과 채도(staturation)값의 계산 �if((r==g) && (g==b)) /// gray-scale { *s = 0. 0 f; // 채도 *h = 0. 0 f; // 색상 return; } else { � *s= 1. 0 f - (3. 0 f / (r + g + b)) * minc; � angle = (r - 0. 5 f * g - 0. 5 f * b) / (float)sqrt((r - g) * (r - g)+(r - b) * (g - b)); // 기하변환 적용 *h = (float)acos(angle); *h *= 57. 29577951 f; /// 각도값으로 전환 (180 o/phi) } if(b>g) *h = 360. 0 f - *h; } 15
컬러영상처리 • RGB 채널 분리 void CWin. Color. View: : On. Channelsplit. Rgb() { // TODO: Add your command handler code here CWin. Color. Doc* p. Doc = Get. Document(); ASSERT_VALID(p. Doc); int index, i, j; for(int k=2; k>=0; k--) { for(i=0; i<height*rwsize; i++) p. Doc->m_Out. Img[i]=0; for(i=0; i<height; i++) { index = (height-i-1)*rwsize; for(j=0; j<width; j++) p. Doc->m_Out. Img[index+3*j+k]= p. Doc->m_In. Img[index+3*j+k]; //k=0(R), 1(G), 2(B) } p. Doc->Copy. Clipboard(p. Doc->m_Out. Img, height, width, 24); Afx. Get. Main. Wnd()->Send. Message(WM_COMMAND, ID_FILE_NEW); } } 16
컬러영상처리 void CWin. Color. Doc: : m_Color. Embossing(unsigned char *In. Img, unsigned char *Out. Img, int height, int width) { int rwsize = WIDTHBYTES(24*width); // convolution MASK int i, j, k, l, index 1, index 2, index 3, winsize=3; float *Mask =new float [winsize*winsize]; for(i=0; i<winsize*winsize; i++) Mask[i]=0. 0 f; Mask[0]=-1. 0 f; Mask[8]=1. 0 f; int n=(winsize-1)>>1; // winsize offset for(i=n; i<height-n; i++) { index 1 =i*rwsize; for(j=n; j<width-n; j++) { float sum 1=0. 0 f; float sum 2=0. 0 f; float sum 3=0. 0 f; for(k=-n; k<=n; k++) { index 2 = (i+k)*rwsize; index 3 = (k+n)*winsize; for(l=-n; l<=n; l++) { sum 1 +=In. Img[index 2+3*(j+l) ]*Mask[index 3+l+n]; //R sum 2 +=In. Img[index 2+3*(j+l)+1]*Mask[index 3+l+n]; //G sum 3 +=In. Img[index 2+3*(j+l)+2]*Mask[index 3+l+n]; //B } } sum 1 += 128; sum 2 += 128; sum 3 += 128; CLIP(sum 1, 0, 255); CLIP(sum 2, 0, 255); CLIP(sum 3, 0, 255); Out. Img[index 1+3*j ] = (unsigned char)sum 1; Out. Img[index 1+3*j+1] = (unsigned char)sum 2; Out. Img[index 1+3*j+2] = (unsigned char)sum 3; } } delete []Mask; } 18
컬러 영상분리 • Segmentation in HSI Color Space 문제: 원 영상에서 붉은색 영역 추출 H(hue) image * binary S(saturation) mask 22
실습 1: 칼라영상 출력 New Project: Win. Color. Doc. h • 데이터 멤버 추가 #define WIDTHBYTES(bits) • 멤버 함수 추가: On. Open. Document (((bits)+31)/32*4) class CWin. Color. Doc : public CDocument { …… public: int width; int height; unsigned char *m_In. Img; unsigned char *m_Out. Img 1; unsigned char *m_Out. Img 2; unsigned char *m_Out. Img 3; RGBQUAD pal. RGB[256]; BITMAPINFOHEADER dib. Hi; BITMAPFILEHEADER dib. Hf; }; 27
Win. Color. Doc. cpp CWin. Color. Doc: : CWin. Color. Doc() { m_In. Img = NULL; m_Out. Img 1 = m_Out. Img 2 = m_Out. Img 3 = NULL; for(int i=0; i<256; i++) { pal. RGB[i]. rgb. Blue= pal. RGB[i]. rgb. Green= pal. RGB[i]. rgb. Red= i; pal. RGB[i]. rgb. Reserved = 0; } } CWin. Color. Doc: : ~CWin. Color. Doc() { if(m_In. Img) delete[] m_In. Img; if(m_Out. Img 1) delete[] m_Out. Img 1; if(m_Out. Img 2) delete[] m_Out. Img 2; if(m_Out. Img 3) delete[] m_Out. Img 3; } 28
Win. Color. Doc. cpp BOOL CWin. Color. Doc: : On. Open. Document(LPCTSTR lpsz. Path. Name) { if (!CDocument: : On. Open. Document(lpsz. Path. Name)) return FALSE; // TODO: 여기에 특수화된 작성 코드를 추가합니다. CFile h. File; h. File. Open(lpsz. Path. Name, CFile: : mode. Read | CFile: : type. Binary); h. File. Read(&dib. Hf, sizeof(BITMAPFILEHEADER)); // 파일 헤드를 읽음 if(dib. Hf. bf. Type!=0 x 4 D 42) { Afx. Message. Box("Not BMP file!!"); return FALSE; } //이 파일이 BMP파일인지 검사. 0 x 4 d 42=='BM' h. File. Read(&dib. Hi, sizeof(BITMAPINFOHEADER)); //"영상정보의 Header"를 읽는다. if(dib. Hi. bi. Bit. Count!=8 && dib. Hi. bi. Bit. Count!=24) { Afx. Message. Box("Gray/True Color Possible!!"); return FALSE; } if(dib. Hi. bi. Bit. Count==8) h. File. Read(pal. RGB, sizeof(RGBQUAD)*256); // 메모리 할당 (바뀐 부분) int Img. Size; if(dib. Hi. bi. Bit. Count==8) Img. Size = (int)h. File. Get. Length()-sizeof(BITMAPFILEHEADER)-sizeof(BITMAPINFOHEADER)-256*sizeof(RGBQUAD); else if(dib. Hi. bi. Bit. Count==24) Img. Size = (int)h. File. Get. Length()-sizeof(BITMAPFILEHEADER)-sizeof(BITMAPINFOHEADER); m_In. Img = new unsigned char [Img. Size]; //dib. Hi. bi. Size. Image m_Out. Img 1 = new unsigned char [Img. Size]; m_Out. Img 2 = new unsigned char [Img. Size]; m_Out. Img 3 = new unsigned char [Img. Size]; h. File. Read(m_In. Img, Img. Size); h. File. Close(); height = dib. Hi. bi. Height; width = dib. Hi. bi. Width; if(dib. Hi. bi. Bit. Count==24) return TRUE; // True color 이면 리턴 // True color 가 아니면 팔레트값 대입 int i, j, index; int rwsize = WIDTHBYTES(dib. Hi. bi. Bit. Count*width); for(i=0; i<height; i++) { index = i*rwsize; for(j=0; j<width; j++) m_In. Img[index+j] = (unsigned char)pal. RGB[(int)m_In. Img[index+j]]. rgb. Blue; } } return TRUE; 29
Win. Color. View. h class CWin. Color. View : public CView { …… public: int rwsize; int width; int height; BITMAPINFO *Bm. Info; }; Win. Color. View. cpp CWin. Color. View: : CWin. Color. View() { // TODO: add construction code here Bm. Info = (BITMAPINFO*)malloc(sizeof(BITMAPINFO)+256*sizeof(RGBQUAD)); for(int i=0; i<256; i++) { Bm. Info->bmi. Colors[i]. rgb. Red= Bm. Info->bmi. Colors[i]. rgb. Green = Bm. Info->bmi. Colors[i]. rgb. Blue = i; Bm. Info->bmi. Colors[i]. rgb. Reserved = 0; } } CWin. Color. View: : ~CWin. Color. View() { if(Bm. Info) delete Bm. Info; } 30
Win. Color. View. cpp void CWin. Color. View: : On. Draw(CDC* p. DC) { CWin. Color. Doc* p. Doc = Get. Document(); ASSERT_VALID(p. Doc); if (!p. Doc) return; // TODO: 여기에 원시 데이터에 대한 그리기 코드를 추가합니다. if(p. Doc->m_In. Img==NULL) return; height = p. Doc->dib. Hi. bi. Height; width = p. Doc->dib. Hi. bi. Width; rwsize = WIDTHBYTES(p. Doc->dib. Hi. bi. Bit. Count*p. Doc->dib. Hi. bi. Width); Bm. Info->bmi. Header = p. Doc->dib. Hi; } Set. DIBits. To. Device(p. DC->Get. Safe. Hdc(), 0, 0, width, height, 0, 0, 0, height, p. Doc->m_In. Img, Bm. Info, DIB_RGB_COLORS); Set. DIBits. To. Device(p. DC->Get. Safe. Hdc(), width+10, 0, width, height, 0, 0, 0, height, p. Doc->m_Out. Img 1, Bm. Info, DIB_RGB_COLORS); Set. DIBits. To. Device(p. DC->Get. Safe. Hdc(), 2*width+20, 0, width, height, 0, 0, 0, height, p. Doc->m_Out. Img 2, Bm. Info, DIB_RGB_COLORS); Set. DIBits. To. Device(p. DC->Get. Safe. Hdc(), 3*width+30, 0, width, height, 0, 0, 0, height, p. Doc->m_Out. Img 3, Bm. Info, DIB_RGB_COLORS); 31
실습 3: HSI 모델로 변환하여 출력 Win. Color. Doc. h #define MIN(a, b) (((a) < (b)) ? (a) : (b)) class CWin. Color. Doc : public CDocument { …… public: void m_Rgb 2 Hsi(); }; 32
Win. Color. Doc. cpp #include "math. h" void RGB_To_HSI(float r, float g, float b, float *h, float *s, float *i) { float minc; /// minimum and maximum RGB values float angle; /// temp variable used to compute Hue void CWin. Color. Doc: : m_Rgb 2 Hsi() { int rwsize = WIDTHBYTES(24*width); int i, j, index, ih; float r, g, b, h, s, iv; for(i=0; i<height; i++) { index = (height-i-1)*rwsize; for(j=0; j<width; j++) { r = (float)m_In. Img[index+3*j+2]/255. 0 f; g = (float)m_In. Img[index+3*j+1]/255. 0 f; b = (float)m_In. Img[index+3*j ]/255. 0 f; minc = MIN(r, g); minc = MIN(minc, b); /// compute intensity *i=(r + g + b) / 3. 0 f; } /// compute hue and saturation if((r==g) && (g==b)) /// gray-scale { *s = 0. 0 f; *h = 0. 0 f; return; } else { *s= 1. 0 f - (3. 0 f / (r + g + b)) * minc; angle = (r - 0. 5 f * g - 0. 5 f * b) / (float)sqrt((r - g) * (r - g)+(r - b) * (g - b)); *h = (float)acos(angle); *h *= 57. 29577951 f; /// convert to degrees } if(b>g) *h = 360. 0 f - *h; } } } RGB_To_HSI(r, g, b, &h, &s, &iv); ih = (int)(h*255. 0/360. 0); m_Out. Img 1[index+3*j]= m_Out. Img 1[index+3*j+1]=m_Out. Img 1[index+3*j+2]=(unsigned char)ih; m_Out. Img 2[index+3*j] = m_Out. Img 2[index+3*j+1]=m_Out. Img 2[index+3*j+2]=(unsigned char)(s*255. 0); m_Out. Img 3[index+3*j] = m_Out. Img 3[index+3*j+1]=m_Out. Img 3[index+3*j+2]=(unsigned char)(iv*255. 0); 33
IDM_RGB 2 HSI void CWin. Color. View: : On. Rgb 2 hsi() { // TODO: 여기에 명령 처리기 코드를 추가합니다. CWin. Color. Doc* p. Doc = Get. Document(); ASSERT_VALID(p. Doc); p. Doc->m_Rgb 2 Hsi(); Invalidate(FALSE); } 34
35