2016年12月28日 星期三

02360635 鄭瑞銘 Homework 2

直方圖
直方圖所要做的事情是統計一張圖片的藍、綠、紅,各色彩從0255的使用量,所以我宣告了以下二維陣列:

int iHistogram[3][256]; // 直方圖數據


然後用兩層for迴圈統計圖片的藍、綠、紅色彩值,最外圈代表走訪到圖片的第i列像素、內圈則走訪圖片的第i列第j排像素,藍、綠、紅色的統計依序執行。

統計用的程式碼:

// 初始化色彩統計
for (i = 0; i < 3; i++)
    for (j = 0; j < 256; j++)
        iHistogram[i][j] = 0;

for (i = 0; i < iImageHeight; i++)
{
    bPictureImageShowRow = (Byte*)imgShow->Picture->Bitmap->ScanLine[i];
    for (j = 0; j < iImageWidth; j++)
    {
        //藍色值
        iHistogram[0][ int(bPictureImageShowRow[3*j+0]) ] += 1;
        //綠色值
        iHistogram[1][ int(bPictureImageShowRow[3*j+1]) ] += 1;
        //紅色值
        iHistogram[2][ int(bPictureImageShowRow[3*j+2]) ] += 1;
    }
}
//將結果繪製出來
DrawHistogram(imgHistogram,chkRed,chkGreen,chkBlue);


繪製直方圖
繪製直方圖的部分我是將藍、綠、紅三種結果表示在同一個TImage(imgHistogram)元件內,使用三個TCheckBox(chkRedchkGreenchkBlue)元件來自訂輸出哪幾個顏色的統計結果。

在這裡遇到的問題是我剛開始把函式宣告成這樣:
void DrawHistogram(  );

想說四個元件都有宣告在標頭檔(Unit1.h)裡面,但是執行時它看不懂我寫在函式裡面的那四個變數名稱:imgHistogramchkRedchkGreenchkBlue
所以才將函式改寫成接收了四個元件的變數名稱,如下:

void DrawHistogram(
    TImage *imgHistogram,
    TCheckBox *chkRed,
    TCheckBox *chkGreen,
    TCheckBox *chkBlue)
{
// 畫布清空
imgHistogram->Canvas->Brush->Color = clWhite;
imgHistogram->Canvas->FillRect( Rect(0,0,imgHistogram->Width,imgHistogram->Height) );

// 顯示紅色
if (chkRed->Checked == True)
    for (j = 0; j < 256; j++)
    {
        imgHistogram->Canvas->Pen->Color = clRed;
        imgHistogram->Canvas->Pen->Width = 1;
        imgHistogram->Canvas->MoveTo( j*3, 0 );
        imgHistogram->Canvas->LineTo( j*3, int(float(iHistogram[2][j]) / fTotal * 5000) );
    }
// 顯示綠色
if (chkGreen->Checked == True)
    for (j = 0; j < 256; j++)
    {
        imgHistogram->Canvas->Pen->Color = clGreen;
        imgHistogram->Canvas->Pen->Width = 1;
        imgHistogram->Canvas->MoveTo( j*3+1, 0 );
        imgHistogram->Canvas->LineTo( j*3+1, int(float(iHistogram[1][j]) / fTotal * 5000) );
    }
// 顯示藍色
if (chkBlue->Checked == True)
    for (j = 0; j < 256; j++)
    {
        imgHistogram->Canvas->Pen->Color = clBlue;
        imgHistogram->Canvas->Pen->Width = 1;
        imgHistogram->Canvas->MoveTo( j*3+2, 0 );
        imgHistogram->Canvas->LineTo( j*3+2, int(float(iHistogram[0][j]) / fTotal * 5000) );
        }
}



累積直方圖
使用前面直方圖的數據(iHistogram),利用兩層迴圈來製作累積直方圖的值,本來是使用整數型態(iCumulativeHistogram)來貯存,但之後要進行直方圖均化的處理,所以改為使用浮點數型態(fCumulativeHistogram),是將每個從iHistogram計算來的值除以圖片像素總數,像素總數在載入圖片時計算完成。
繪製的方法和直方圖相似。

宣告的變數如下:

float fCumulativeHistogram[3][256]; // 累積直方圖數據
float fTotal; // 圖片像素總數


計算累積直方圖的函式:

// 初始化色彩累積統計
for (i = 0; i < 3; i++)
        {
        fCumulativeHistogram[i][0] = float( iHistogram[i][0] ) / fTotal;
        for (j = 1; j < 256; j++)
                fCumulativeHistogram[i][j] = 0;
        }

for ( i = 0; i < 3; i++ )
        for ( j = 1; j < 256; j++ )
                fCumulativeHistogram[i][j] = fCumulativeHistogram[ i ][ j - 1 ]
                              + ( float( iHistogram[ i ][ j - 1 ] ) / fTotal );
//繪製累積直方圖
DrawCumulativeHistogram(imgCumulativeHistogram,chkRed,chkGreen,chkBlue);


繪製累積直方圖的函式:
void DrawCumulativeHistogram(
    TImage *imgCumulativeHistogram,
    TCheckBox *chkRed,
    TCheckBox *chkGreen,
    TCheckBox *chkBlue)
{
// 畫布清空
imgCumulativeHistogram->Canvas->Brush->Color = clWhite;
imgCumulativeHistogram->Canvas->FillRect( Rect(0,0,imgCumulativeHistogram->Width,imgCumulativeHistogram->Height) );


// 顯示紅色
if (chkRed->Checked == True)
    for (j = 0; j < 256; j++)
    {
        imgCumulativeHistogram->Canvas->Pen->Color = clRed;
        imgCumulativeHistogram->Canvas->Pen->Width = 1;
        imgCumulativeHistogram->Canvas->MoveTo( j*3, 0 );
        imgCumulativeHistogram->Canvas->LineTo( j*3, int(fCumulativeHistogram[2][j] * 100) );
    }
// 顯示綠色
if (chkGreen->Checked == True)
    for (j = 0; j < 256; j++)
    {
        imgCumulativeHistogram->Canvas->Pen->Color = clGreen;
        imgCumulativeHistogram->Canvas->Pen->Width = 1;
        imgCumulativeHistogram->Canvas->MoveTo( j*3+1,0 );
        imgCumulativeHistogram->Canvas->LineTo( j*3+1, int(fCumulativeHistogram[1][j] * 100) );
    }
// 顯示藍色
if (chkBlue->Checked == True)
    for (j = 0; j < 256; j++)
    {
        imgCumulativeHistogram->Canvas->Pen->Color = clBlue;
        imgCumulativeHistogram->Canvas->Pen->Width = 1;
        imgCumulativeHistogram->Canvas->MoveTo( j*3+2,0 );
        imgCumulativeHistogram->Canvas->LineTo( j*3+2, int(fCumulativeHistogram[0][j] * 100) );
    }
}



直方圖均化的程式碼:

for (i = 0; i < iImageHeight; i++)
{
    bPictureImageShowRow = (Byte*)imgShow->Picture->Bitmap->ScanLine[i];
    bPictureImageOriginRow = (Byte*)imgOrigin->Picture->Bitmap->ScanLine[i];
    for (j =0; j < iImageWidth; j++)
    {
        bPictureImageShowRow[3*j+0] = int(fCumulativeHistogram[0][ int(bPictureImageShowRow[3*j+0]) ] * 255);
        // 防止單一像素色彩值溢位
        if ( bPictureImageShowRow[3*j+0] > 255 )
            bPictureImageShowRow[3*j+0] = 255;

        bPictureImageShowRow[3*j+1] = int(fCumulativeHistogram[1][ int(bPictureImageShowRow[3*j+1]) ] * 255);
        // 防止單一像素色彩值溢位
        if ( bPictureImageShowRow[3*j+1] > 255 )
            bPictureImageShowRow[3*j+1] = 255;

        bPictureImageShowRow[3*j+2] = int(fCumulativeHistogram[2][ int(bPictureImageShowRow[3*j+2]) ] * 255);
        // 防止單一像素色彩值溢位
        if ( bPictureImageShowRow[3*j+2] > 255 )
            bPictureImageShowRow[3*j+2] = 255;
    }
}
imgShow->Refresh();



部分程式執行畫面:


開啟圖片後的畫面,第二次作業的結果輸出,我放在「Color Statistics」的分頁


直方圖(Histogram)、累積直方圖(Cumulative Histogram)、直方圖均化(Histogram Equalization)的功能建在Image->Calculate的選單下


直方圖的結果,預設是藍、綠、紅都輸出,可以在下方勾選想觀看的顏色,再按下Reset按鍵重新輸出結果。



累積直方圖的結果


直方圖均化後的圖片,若要觀看均化後的直方圖和累積直方圖,則要再到選單操作兩個功能。


均化後的直方圖



均化後的累積直方圖


沒有留言:

張貼留言