2009年1月10日 星期六

2009年1月6日 星期二

Matrix

CvArr → CvMat → IplImage ( 繼承關係 )
Even though OpenCV is implemented in C, the structures used in OpenCV have an object-oriented design; in effect, IplImage is derived from CvMat, which is derived from CvArr

1.
When CvArr* appears, it is acceptable to pass CvMat* or IplImage* to the routine.

可以用 CvArr * 去接 CvMat 或是 IplImage

上層往下指,上層的每一個成員下層也一定都有,所以一定都會對滿

反之,下層有的上層不見得有,所以下層的指標有些會接不到東西,就錯誤

故可以用上層的指標去接下層的成員函式。

2.
CvArr, can be thought of as an abstract base class from which CvMat is itself derived.

抽象基礎類別

是把最底層的class成員函數都宣告成virtual,本身的class沒辦法實體化

只提供該有哪些function的功能

實體的使用內容卻是由衍生出來的class去各自設計

也就是提供類似模組或樣版

第二點的參考資料來源:奇摩知識+

萍聚

選擇 - 林子祥 葉蒨文

是否 - 葉蒨文



當初我的合唱團老師也有唱過此首的男聲獨唱版

可惜沒找到來源,也很好聽!!

2009年1月5日 星期一

重病

經過了一個周末的煎熬

加上昨晚全身發冷似乎還發燒了 Orz

今天終於去看了校醫

症狀:喉嚨吞嚥會痛、脖子很緊、全身無力、身體發冷

沒想到竟然是扁桃腺發炎加上喉嚨有痰,哭哭

好像好久沒有生這麼重的病了吧

記得高中以來也沒有這樣過

偏偏又發生在期末考前,考試掰掰 = =... 睡覺重要 XD?

校醫還說要開抗生素給我吃= = 偏偏學校的抗生素又只有一種

如果吃了兩天還是有發燒到39度以上或是吞嚥會痛,

就要住院 = =~~~ 很無奈,學校都提供免費的校醫了

醫療資源也不順便升級一些,嘖嘖~~ 有貪污吧 =口=+

A Not-So-Simple Transformation











左為cvPyrDown()兩次的結果,
  右為cvCanny()一次的結果。

// Example 2-5. Using cvPyrDown() to create a new image that is half the width and height of the input image

// Example 2-6. The Canny edge detector writes its output to a single channel (grayscale) image
// Example 2-7. Combining the pyramid down operator (twice) and the Canny subroutine in a simple image pipeline
// Example 2-8. Simplifying the image pipeline of Example 2-7 by making the individual stages release their intermediate memory allocations

#include "highgui.h"
#include "cv.h"

IplImage *doPyrDown( IplImage * , int );
IplImage *doCanny( IplImage * , double , double , double );

int main( int argc , char **argv )
{
 cvNamedWindow( "Input" , CV_WINDOW_AUTOSIZE );
 cvNamedWindow( "Output1" , CV_WINDOW_AUTOSIZE );
 //cvNamedWindow( "Output2" , CV_WINDOW_AUTOSIZE );
 //cvNamedWindow( "Output3" , CV_WINDOW_AUTOSIZE );

 IplImage *image = cvLoadImage( argv[1] , 0);
 IplImage *out1 = doPyrDown( image , IPL_GAUSSIAN_5x5 );
 //IplImage *out2 = doPyrDown( out1 , IPL_GAUSSIAN_5x5 );
 //IplImage *out3 = doCanny( out2 , 10 , 100 , 3 );
 out1 = doPyrDown( out1 , IPL_GAUSSIAN_5x5 );
 cvShowImage( "Input" , out1 );
 out1 = doCanny( out1 , 10 , 100 , 3 );

 //cvShowImage( "Input" , image );
 cvShowImage( "Output1" , out1 );
 //cvShowImage( "Output2" , out2 );
 //cvShowImage( "Output3" , out3 );

 cvWaitKey( 0 );

 cvReleaseImage( &image );
 cvReleaseImage( &out1 );
 //cvReleaseImage( &out2 );
 //cvReleaseImage( &out3 );

 cvDestroyWindow( "Input" );
 cvDestroyWindow( "Output1" );
 //cvDestroyWindow( "Output2" );
 //cvDestroyWindow( "Output3" );
 return 0;
}

// Example 2-5.
IplImage *doPyrDown( IplImage *in , int filter )
{
 // Best to make sure input image is divisible by two.
 //
 assert( in->width%2 == 0 && in->height%2 == 0 );

 IplImage *out = cvCreateImage( cvSize( in->width/2 , in->height/2 ) , in->depth , in->nChannels );
 cvPyrDown( in , out , filter );
 return out;
}

// Example 2-6.
IplImage *doCanny( IplImage *in , double lowThresh , double highThresh , double aperture )
{
 if( in->nChannels != 1 )
  return 0; // Canny only handles gray scale iamges

 IplImage *out = cvCreateImage( cvGetSize( in ) , IPL_DEPTH_8U , 1 );
 cvCanny( in , out , lowThresh , highThresh , aperture );
 return out;
}

2009年1月4日 星期日

Equalization using VB













←開檔













←依序為原圖、灰階、灰階均化、轉回彩色















←存檔


' 背景需要先拉入OpenFileDialog與SaveFileDialog物件

' RGB 轉成 YIQ 並且顯示灰階
  Dim i, j, r, g, b, Y, imgW, imgH As Integer
  Dim bmp As New Bitmap(PictureBox1.Image)
  imgW = bmp.Width
  imgH = bmp.Height
  Dim bmp1 As New Bitmap(imgW, imgH)

  For i = 0 To imgW - 1
   For j = 0 To imgH - 1
    r = bmp.GetPixel(i, j).R
    g = bmp.GetPixel(i, j).G
    b = bmp.GetPixel(i, j).B
    Y = (0.299 * r + 0.587 * g + 0.114 * b)
    If Y < 0 Then
     Y = 0
    ElseIf Y > 255 Then
     Y = 255
    End If
    bmp1.SetPixel(i, j, Color.FromArgb(Y, Y, Y))
   Next
  Next

  PictureBox2.SizeMode = PictureBox1.SizeMode
  PictureBox2.Image = bmp1

' 對灰階影像做亮度均化
  Dim imgW, imgH, i, j, Y As Integer
  Dim bmp As New Bitmap(PictureBox2.Image)

  imgW = bmp.Width
  imgH = bmp.Height
  Dim bmp1 As New Bitmap(imgW, imgH)
  Dim N(255) As Integer

  For i = 0 To imgW - 1
   For j = 0 To imgH - 1
    Y = bmp.GetPixel(i, j).R
    N(Y) = N(Y) + 1
   Next
  Next

  For i = 1 To 255
   N(i) = N(i - 1) + N(i)
  Next

  j = imgW * imgH

  For i = 0 To 255
   ' 四捨五入
   If (N(i) * 255 / j * 10) Mod 10 < 5 Then
    N(i) = N(i) * 255 / j
   Else
    N(i) = N(i) * 255 / j + 1
   End If
   If N(i) > 255 Then
    N(i) = 255
   ElseIf N(i) < 0 Then
   N(i) = 0
   End If
  Next

  For i = 0 To imgW - 1
   For j = 0 To imgH - 1
    Y = N(bmp.GetPixel(i, j).R)
    bmp1.SetPixel(i, j, Color.FromArgb(Y, Y, Y))
   Next
  Next

  PictureBox3.SizeMode = PictureBox2.SizeMode
  PictureBox3.Image = bmp1

' 將均化過的Y與沒變的IQ轉回RGB
  Dim i, j, r, g, b, Y, AI, Q, imgW, imgH As Integer
  Dim bmp As New Bitmap(PictureBox1.Image)
  Dim bmp1 As New Bitmap(PictureBox3.Image)
  imgW = bmp.Width
  imgH = bmp.Height
  Dim bmp2 As New Bitmap(imgW, imgH)

  For i = 0 To imgW - 1
   For j = 0 To imgH - 1
    r = bmp.GetPixel(i, j).R
    g = bmp.GetPixel(i, j).G
    b = bmp.GetPixel(i, j).B
    Y = bmp1.GetPixel(i, j).R
    AI = (0.596 * r - 0.274 * g - 0.322 * b)
    Q = (0.211 * r - 0.522 * g + 0.311 * b)

    r = (1 * Y + 0.956 * AI + 0.632 * Q)
    If r < 0 Then
     r = 0
    ElseIf r > 255 Then
     r = 255
    End If
    g = (1 * Y - 0.272 * AI - 0.648 * Q)
    If g < 0 Then
     g = 0
    ElseIf g > 255 Then
     g = 255
    End If
    b = (1 * Y - 1.105 * AI + 0.705 * Q)
    If b < 0 Then
     b = 0
    ElseIf b > 255 Then
     b = 255
    End If
    bmp2.SetPixel(i, j, Color.FromArgb(r, g, b))
   Next
  Next

  PictureBox4.SizeMode = PictureBox3.SizeMode
  PictureBox4.Image = bmp2

' 讀檔
  Dim openFileDialog1 As New OpenFileDialog()
  openFileDialog1.Filter = "Bmp Files|*.bmp"
  openFileDialog1.Title = "Select a Bitmap File"

  If openFileDialog1.ShowDialog() = DialogResult.OK Then
   PictureBox1.Image = Image.FromFile(openFileDialog1.FileName)
   Button1.Enabled = True
   Label1.Visible = True
  End If

' 存檔
  Dim saveFileDialog1 As New SaveFileDialog()
  saveFileDialog1.Filter = "Bitmap Image|*.bmp"
  saveFileDialog1.Title = "Save an Bitmap File"
  saveFileDialog1.ShowDialog()

  ' If the file name is not an empty string open it for saving.
  If saveFileDialog1.FileName <> "" Then
   ' Saves the Image via a FileStream created by the OpenFile method.
   Dim fs As System.IO.FileStream = CType _ (saveFileDialog1.OpenFile(), System.IO.FileStream)
   ' Saves the Image in the appropriate ImageFormat based upon the
   ' file type selected in the dialog box.
   ' NOTE that the FilterIndex property is one-based.
   Me.PictureBox2.Image.Save(fs, _ System.Drawing.Imaging.ImageFormat.Bmp)

   fs.Close()
  End If

A Simple Transformation

// If the resource is not from bitmap file but from avi file, then each frame of the output
// will up-side down, I still not find out what reason.

// Example 2-4. Loading and then smoothing an image before it is displayed on the screen


#include "cv.h"
#include "highgui.h"

void example2_4( IplImage *);

int main(int argc,char **argv)
{
 IplImage *image = cvLoadImage( argv[1] );
 example2_4( image );
 cvReleaseImage( &image );
 return 0;
}

void example2_4( IplImage *image )
{
 // Create some windows to show the input
 // and output image in.
 //
 cvNamedWindow( "Example4-in" );
 cvNamedWindow( "Example4-out" );

 // Create a window to show our input image
 //
 cvShowImage( "Example4-in" , image );

 // Create an image to hold the smoothed output
 //
 IplImage *out = cvCreateImage( cvGetSize(image) , IPL_DEPTH_8U , 3 );

 // Do the smoothing
 //
 cvSmooth( image , out , CV_GAUSSIAN , 31 , 31);

 // Show the smoothed image in the output window
 //
 cvShowImage( "Example4-out" , out );

 //Be tidy
 //
 cvReleaseImage( &out );

 // Wait for the user to hit a key, then clean up the windows
 //
 cvWaitKey( 0 );
 cvDestroyWindow( "Example4-in" );
 cvDestroyWindow( "Example4-out" );
}

Trackbar Slider

// Example 2-3. Program to add a trackbar slider to the basic viewr window: when the slider is
// moved, the function onTrackbarSlide() is called and then passed to the slider's new value

#include "cv.h"
#include "highgui.h"

void onTrackbarSlide(int);

int g_slider_position = 0;
CvCapture *g_capture = NULL;

int main(int argc, char **argv)
{
 cvNamedWindow("Example3",CV_WINDOW_AUTOSIZE);
 g_capture = cvCreateFileCapture(argv[1]);

 // we use it when we want to query some data from the CvCapture structure
 // it will return how many frames are in the video
 int frames = (int)cvGetCaptureProperty(g_capture,CV_CAP_PROP_FRAME_COUNT);
 IplImage *frame;
 if(frames!=0)
  for(;;g_slider_position++)
  {
   // the last parameter is a callback function that reset the position of trackbar slider
   cvCreateTrackbar("Position","Example3",&g_slider_position,frames,onTrackbarSlide);
   frame = cvQueryFrame( g_capture );
   if( !frame )
    break;
   cvShowImage("Example3",frame);
   char c = cvWaitKey(33);
   if( c==27 )
    break;
   while((c=='p')||(c=='P'))
   {
    c = cvWaitKey(0);
    if( c==27 )
    {
     cvReleaseCapture( &g_capture );
     cvDestroyWindow("Example3");
     return 0;
    }
    if( (c=='c')||(c=='C')||(c==13) )
     break;
    else
     c='p';
   }
  }
 cvReleaseCapture( &g_capture );
 cvDestroyWindow("Example3");
 return 0;
}

void onTrackbarSlide(int pos)
{
 cvSetCaptureProperty(g_capture,CV_CAP_PROP_POS_FRAMES,pos);
}

AVI Video

// Example 2-2. A simple OpenCV program for playing a video file from disk

#include "highgui.h"

int main(int argc, char **argv)
{
 cvNamedWindow("Example2",CV_WINDOW_AUTOSIZE);
 // it will also allocate a memory for the image
 CvCapture *capture = cvCreateFileCapture(argv[1]);
 IplImage *frame;
 while(1)
 {
  frame = cvQueryFrame( capture );
  if( !frame )
   break;
  cvShowImage( "Example2", frame );
  // 30 frames per second = 30 frames / 1000 ms = 1 frame / 33 ms
  // if no stdin then it will return -1

  char c = cvWaitKey(33);
  if(c==27)
   break;
  // pause while pressing p or P
  while((c=='p')||(c=='P'))
  {
   c = cvWaitKey(0);
   if(c==27)
   {
    cvReleaseCapture( &capture );
    cvDestroyWindow( "Example" );
    return 0;
   }
   // continue the video while pressing c, C or enter
   if((c=='c')||(c=='C')||(c==13))
    break;
   else
    c='p';
  }
 }
 // it will also called "cvReleaseImage()" for the "frame" pointer
 cvReleaseCapture( &capture );
 cvDestroyWindow( "Example2" );
 return 0;
}

Babylon - Gregorian Chants

2009年1月2日 星期五

二零零八跨年

今年依舊是在詠寧家跨年

成員:我、Angie、丁丁、左左、殺手、詠寧、啾啾

好不容易熬玩歷史課回家匆匆洗了個澡便趕往中壢

抵達目的地後不久沒想到意外的來了神秘嘉賓:聰明人跟宅豪











←右手邊的看起來不只宅,還呆呆的 XD"


好不容易大家都到齊了,舟車勞苦之後都飢腸轆轆,

便東西先放在一旁沒整頓就整群先去中原夜市覓食了,

找來找去都沒找到詠寧哥哥說的"傻蛋的窩",只好作罷,

走著走著倒是意外的發現了一家"塞納河"的義大利麵店,

感覺裝潢得很溫馨,裡面的服務生也很親切,給人感覺很舒服,

出餐雖然頗久 ( XD" 吃了快兩個小時吧 ) 但是卻是平常所感受不到的悠哉,

跟米卡果然不能比 = =+ 應該說米卡真的是太不好吃了,

大推這家店的手工蛋糕,在中原夜市的三井電腦斜對面巷子進去,











←巧克力部分超美味,吃起來很綿密不會膩


有機會可以再去吃吃看,為了美食到處奔波阿 XDDDD

回去的途中還順手夾了一個長頸鹿充氣娃娃,不過卻花了五十元,

感覺是被騙錢了 =口=... 不過大家卻玩得莫名很high...XD?












←啾啾的牙突











←被小惡魔硬是戴上去的丁丁,可憐的應該是長頸鹿...

中間就是倒數跨年啦,其間還打了蠻久的桌球 XD"

沒辦法,誰叫有一半都是系桌的,哈哈哈

大家都老了 =.=.... 沒辦法通霄到天亮,

不過也可能是因為宵夜吃鐵板燒加上冰火的關係吧,天氣太冷,

/* 家樂福買的澳洲培根肉串,結果是羊肉 = = 黑店 大家以後不要去阿...不爽 */

酒足飯飽之後喝完酒暖暖地好舒服超想睡 XD

隔天中午吃了到中壢一定要吃的牛肉麵!

之前吃過了永川、老師傅牛肉麵之後,這次主打:老三牛肉麵

坦白說,我覺得比老師傅差,且又忘記弄我們點的東西,

讓我們等超久 = =... 不開心~~~~~ 不推! 還是老師傅好吃!

計畫中的重頭戲就是巧克力火鍋啦! 今年突發奇想,繼去年豆漿火鍋之後,

今年特別一點,不過因為有一半的人有事先走,QQ

所以剩下一半的人吃了幾乎全部的東西,吃的超飽,可能一段時間不會吃甜食了吧我猜~










←啾啾(左)跟我(右)的傑作,啾咪跟囧 XDDD 超可愛的啦,棉花糖+巧克力醬愛不釋手












←蘋果麵包做地,也很好吃 >///<














←離開前的KUSO~ 倒掛金鉤 XD" 感覺很蠢 哈哈哈


Ps. 番外篇 ~ 到三峽吃完晚餐之後騎車回宿舍,沒想到紅燈左轉被抓到了 XD
      哭哭,騎車以來第一張紅單,沒想到在元旦來臨了
      XD 噴1,800...唉 Orz 以後的日子怎麼過阿 QQ

2009年1月1日 星期四

Equalization using VC

專案屬性組態屬性連結器輸入其他相依性 加入 gdiplus.dll

按 Enter 會依序出現












← 一開始顯示測試原圖













← 顯示原圖的灰階影像













← 經過亮度均化後的灰階影像













← 將修改過後的YIQ轉回RGB













← 直接對RGB做亮度均化,出現色偏


===========================================================
Header File

#include <windows.h>
#include <gdiplus.h>

using namespace Gdiplus;

#ifndef _CVE_H_
#define _CVE_H_

Graphics* graphics;
Image* image;
Pen* pen;

/* RGB layers of the image */
int** i_R;
int** i_G;
int** i_B;
/* RGB layers of the image */
int** i_Red;
int** i_Green;
int** i_Blue;
/* YIQ layers of the image */
int** iY_Gray;
int** iI_Gray;
int** iQ_Gray;
/* calculation of RGB layers */
int* num_R;
int* num_G;
int* num_B;
/* probability of RGB layers */
double* pro_R;
double* pro_G;
double* pro_B;
/* probability of gray level */
double* pro_Gray;
/* calculation of gray level */
int* num_Gray;

/* decide to take which processing action */
int flag;
/* image height and width */
int i_Height, i_Width;
/* total pixels */
double i_Pixels;

#endif
===========================================================
CPP FILE

#include "CVE.h"

using namespace Gdiplus;

/* function prototype */
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void Clear();
void myKeys(HWND);
void OnPaint(HDC);
void Setup1();
void Setup2(HDC);

/* WinMain , the program entry point */
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, int iCmdShow)
{
 HWND hWnd;
 MSG msg;
 WNDCLASS wndClass;
 GdiplusStartupInput gdiplusStartupInput;
 ULONG_PTR gdiplusToken;

 /* initilize the flag to show the original image at first */
 flag = 1;

 /* Initialize GDI+. */
 GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

 wndClass.style = CS_HREDRAW | CS_VREDRAW;
 wndClass.lpfnWndProc = WndProc;
 wndClass.cbClsExtra = 0;
 wndClass.cbWndExtra = 0;
 wndClass.hInstance = hInstance;
 wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
 wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
 wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
 wndClass.lpszMenuName = NULL;
 wndClass.lpszClassName = TEXT("Equalization");

 RegisterClass(&wndClass);
 Setup1();

 hWnd = CreateWindow(
  TEXT("Equalization"),       // window class name
  TEXT("CVHW Equalization"),     // window caption
  WS_OVERLAPPEDWINDOW,   // window style
  CW_USEDEFAULT,       // initial x position
  CW_USEDEFAULT,         // initial y position
  i_Width * 2,               // initial x size
  i_Height * 2,               // initial y size
  NULL,              // parent window handle
  NULL,              // window menu handle
  hInstance,             // program instance handle
  NULL);              // creation parameters

 HDC hdc = GetDC(hWnd);
 Setup2(hdc);

 ShowWindow(hWnd, iCmdShow);
 UpdateWindow(hWnd);

 while(1)
 {
  if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  {
   if (msg.message == WM_QUIT)
    break;
   TranslateMessage(&msg);
   DispatchMessage(&msg);
  }
  else
   myKeys(hWnd);
 }

 GdiplusShutdown(gdiplusToken);
 Clear();
 return (int)msg.wParam;
}

/* WndProc */
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 HDC hdc;
 PAINTSTRUCT ps;

 switch(message)
 {
  case WM_PAINT:
   hdc = BeginPaint(hWnd, &ps);
   OnPaint(hdc);
   EndPaint(hWnd, &ps);
   return 0;
  case WM_DESTROY:
   PostQuitMessage(0);
   return 0;
  default:
   return DefWindowProc(hWnd, message, wParam, lParam);
 }
}

/* free memory */
void Clear()
{
 delete i_Red;
 delete i_Green;
 delete i_Blue;
 delete i_R;
 delete i_G;
 delete i_B;
 delete iY_Gray;
 delete iI_Gray;
 delete iQ_Gray;

 delete [] num_Gray;
 delete [] pro_Gray;
 delete [] num_R;
 delete [] num_G;
 delete [] num_B;
 delete [] pro_R;
 delete [] pro_G;
 delete [] pro_B;
}

/* keyboard events */
void myKeys(HWND hwnd)
{
 static int count=2;

 /* press ESC to exit program */
 if(GetKeyState(27) & 0x80)
  exit(0);

 /* press enter to continue the next image */
 if(GetKeyState(13) & 0x80)
 {
  flag = (count%=7)++;
  InvalidateRect(hwnd, NULL, FALSE);
 }
}

/* initialize_1 */
void Setup1()
{
 image = new Image(L"test.jpg");
 if(image->GetHeight() == 0 && image->GetWidth() == 0)
  image = new Image(L"test.bmp");
 i_Height = image->GetHeight();
 i_Width = image->GetWidth();
}

/* initialize_2 */
void Setup2(HDC hdc)
{
 graphics = new Graphics(hdc);

 pen = new Pen(Color(0,0,255), 3);

 i_Pixels = (double)(i_Height * i_Width);

 num_Gray = new int[256];
 pro_Gray = new double[256];
 num_R = new int[256];
 num_G = new int[256];
 num_B = new int[256];
 pro_R = new double[256];
 pro_G = new double[256];
 pro_B = new double[256];

 for(int i = 0; i < 256; i++)
 {
  num_Gray[i] = 0;
  pro_Gray[i] = 0;
  num_R[i] = 0;
  num_G[i] = 0;
  num_B[i] = 0;
  pro_R[i] = 0;
  pro_G[i] = 0;
  pro_B[i] = 0;
 }

 i_Red = new int*[i_Height];
 i_Green = new int*[i_Height];
 i_Blue = new int*[i_Height];
 iY_Gray = new int*[i_Height];
 iI_Gray = new int*[i_Height];
 iQ_Gray = new int*[i_Height];
 i_R = new int*[i_Height];
 i_G = new int*[i_Height];
 i_B = new int*[i_Height];

 for(int i = 0; i < i_Height;i++)
 {
  i_Red[i] = new int[i_Width];
  i_Green[i] = new int[i_Width];
  i_Blue[i] = new int[i_Width];
  iY_Gray[i] = new int[i_Width];
  iI_Gray[i] = new int[i_Width];
  iQ_Gray[i] = new int[i_Width];
  i_R[i] = new int[i_Width];
  i_G[i] = new int[i_Width];
  i_B[i] = new int[i_Width];
 }
}

/* image processing */
void OnPaint(HDC hdc)
{
 COLORREF color;
 switch(flag)
 {
  /* show the original image */
  case 1:
   graphics->DrawImage(image, 0, 0, i_Width, i_Height);
   break;
  /* show the gray level of the image */
  case 2:
   for(int i = 0; i < i_Height; i++)
    for(int j = 0; j < i_Width; j++)
    {
     color = GetPixel(hdc, j ,i);

     i_Red[i][j] = i_R[i][j] = GetRValue(color);
     i_Green[i][j] = i_G[i][j] = GetGValue(color);
     i_Blue[i][j] = i_B[i][j] = GetBValue(color);

     iY_Gray[i][j] = (int)(0.299 * i_Red[i][j] + 0.587 * i_Green[i][j] + 0.114 * i_Blue[i][j]);
     iI_Gray[i][j] = (int)(0.596 * i_Red[i][j] - 0.274 * i_Green[i][j] - 0.322 * i_Blue[i][j]);
     iQ_Gray[i][j] = (int)(0.211 * i_Red[i][j] - 0.522 * i_Green[i][j] + 0.311 * i_Blue[i][j]);

     num_Gray[iY_Gray[i][j]]++;
     num_R[i_R[i][j]]++;
     num_G[i_G[i][j]]++;
     num_B[i_B[i][j]]++;

     color = RGB(iY_Gray[i][j], iY_Gray[i][j], iY_Gray[i][j]);
     SetPixel(hdc, j + i_Width, i, color);
    }
   break;
  /* show the gray level of the image after equalizing */
  case 3:
   for(int i = 1; i < 256; i++)
   {
    num_Gray[i] += num_Gray[i-1];
    num_R[i]+=num_R[i-1];
    num_G[i]+=num_G[i-1];
    num_B[i]+=num_B[i-1];
   }

   for(int i = 0; i < 256; i++)
   {
    pro_Gray[i] = double(num_Gray[i]) / i_Pixels;
    pro_R[i] = double(num_R[i]) / i_Pixels;
    pro_G[i] = double(num_G[i]) / i_Pixels;
    pro_B[i] = double(num_B[i]) / i_Pixels;
   }

   for(int i = 0; i < i_Height; i++)
    for(int j = 0; j < i_Width; j++)
    {
     iY_Gray[i][j] = (int)(pro_Gray[iY_Gray[i][j]] * 255);
     i_R[i][j] = (int)(pro_R[i_R[i][j]] * 255);
     i_G[i][j] = (int)(pro_G[i_G[i][j]] * 255);
     i_B[i][j] = (int)(pro_B[i_B[i][j]] * 255);

     color = RGB(iY_Gray[i][j], iY_Gray[i][j], iY_Gray[i][j]);
     SetPixel(hdc, j, i + i_Height, color);
    }
   break;
  /* YIQ→RGB */
  case 4:
   for(int i = 0; i < i_Height; i++)
    for(int j = 0; j < i_Width; j++)
    {
     i_Red[i][j] = (int)(1 * iY_Gray[i][j] + 0.956 * iI_Gray[i][j] + 0.632 * iQ_Gray[i][j]);
     if(i_Red[i][j]>255)
      i_Red[i][j]=255;
     else if(i_Red[i][j]<0)
      i_Red[i][j]=0;

     i_Green[i][j]= (int)(1 * iY_Gray[i][j] - 0.272 * iI_Gray[i][j] - 0.648 * iQ_Gray[i][j]);
     if(i_Green[i][j]>255)
      i_Green[i][j]=255;
     else if(i_Green[i][j]<0)
      i_Green[i][j]=0;

     i_Blue[i][j]= (int)(1 * iY_Gray[i][j] - 1.105 * iI_Gray[i][j] + 0.705 * iQ_Gray[i][j]);
     if(i_Blue[i][j]>255)
      i_Blue[i][j]=255;
     else if(i_Blue[i][j]<0)
      i_Blue[i][j]=0;
     color = RGB(i_Red[i][j], i_Green[i][j], i_Blue[i][j]);
     SetPixel(hdc, j + i_Width, i + i_Height, color);
    }
   break;
  /* equalize directly to each R, G, B layer */
  case 5:
   for(int i = 0; i < i_Height; i++)
    for(int j = 0; j < i_Width; j++)
    {
     color = RGB(i_R[i][j], i_G[i][j], i_B[i][j]);
     SetPixel(hdc, j, i, color);
    }
   break;
  default:
   break;
 }
}
===========================================================