事實上索貝爾運算子我之前就有想說要研究,但看到維基百科上的解釋,讓我打退堂鼓。最近有開始研究他,也多虧同學的講義讓我終 於了解,其中要了解的是捲積的概念,還有邊界判定的問題,其他應該都小Case。

程式碼如下:

Sobel.rc

LENA          BITMAP          "lena.bmp"

Sobel.cpp

#include<windows.h>
#include<math.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
ATOM InitApp(HINSTANCE);
BOOL InitInstance(HINSTANCE, int);
void bmpToMemoryDC(LPCTSTR, HDC* );
void dcToGray(HDC* , HDC);
void grayToSobel(HDC* , HDC);
TCHAR szClassName[]=TEXT("sobel");
HINSTANCE hInst;
int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow)
{
    MSG msg;
    BOOL bRet;
    hInst = hCurInst;
    if (!InitApp(hCurInst))
       return FALSE;
    if (!InitInstance(hCurInst, nCmdShow))
       return FALSE;
    while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
          if (bRet ==-1)
             break;
          else {
               TranslateMessage(&msg);
               DispatchMessage(&msg);
          }
    }
    return (int)msg.wParam;      
}

ATOM InitApp(HINSTANCE hInst)
{
     WNDCLASSEX wc;
     
     wc.style = CS_VREDRAW | CS_HREDRAW;
     
     wc.cbSize = sizeof(WNDCLASSEX);
     wc.cbClsExtra = 0;
     wc.cbWndExtra = 0;
     
     wc.lpszClassName = szClassName;
     wc.lpszMenuName = NULL;
     wc.lpfnWndProc = WndProc;
     
     wc.hInstance = hInst;
     wc.hIcon = (HICON)LoadImage(NULL,
                MAKEINTRESOURCE(IDI_APPLICATION),
                IMAGE_ICON,
                0,
                0,
                LR_DEFAULTSIZE | LR_SHARED);
     wc.hIconSm = NULL;
     wc.hCursor = (HCURSOR)LoadImage(NULL,
                  MAKEINTRESOURCE(IDC_ARROW),
                  IMAGE_CURSOR,
                  0,
                  0,
                  LR_DEFAULTSIZE | LR_SHARED);
     wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
     
     return (RegisterClassEx(&wc));     
}

BOOL InitInstance(HINSTANCE hInst, int nCmdShow)
{
     HWND hWnd = CreateWindow(szClassName,
                 TEXT("索貝爾算子"),
                 WS_OVERLAPPEDWINDOW,
                 CW_USEDEFAULT,
                 CW_USEDEFAULT,
                 CW_USEDEFAULT,
                 CW_USEDEFAULT,
                 NULL,
                 NULL,
                 hInst,
                 NULL);
     if (!hWnd)
        return FALSE;
     ShowWindow(hWnd, nCmdShow);
     UpdateWindow(hWnd);
     return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
        HDC hdc;
        PAINTSTRUCT ps;
        HDC src_mdc;
        HDC gray_mdc;
        HDC sobel_mdc;
        RECT rc;
        switch (msg) {
               case WM_PAINT:
                    hdc = BeginPaint(hWnd, &ps);
                    src_mdc = CreateCompatibleDC(hdc);
                    gray_mdc = CreateCompatibleDC(hdc);
                    sobel_mdc = CreateCompatibleDC(hdc);
                    bmpToMemoryDC(TEXT("LENA"), &src_mdc);
                    GetClipBox(src_mdc, &rc);
                    dcToGray(&gray_mdc, src_mdc);
                    grayToSobel(&sobel_mdc, gray_mdc);
                    BitBlt(hdc, 0, 0, rc.right, rc.bottom, sobel_mdc, 0, 0, SRCCOPY);
                    EndPaint(hWnd, &ps);
                    break;
               case WM_DESTROY:
                    PostQuitMessage(0);                    
                    break;
               default:
                    return (DefWindowProc(hWnd, msg, wp, lp));
        }
}
        
void bmpToMemoryDC(LPCTSTR path, HDC* mdc)
{
     HBITMAP hBmp = (HBITMAP)LoadImage(hInst,
                    path,
                    IMAGE_BITMAP,
                    0,
                    0,
                    LR_DEFAULTCOLOR | LR_DEFAULTSIZE);
     SelectObject(*mdc, hBmp);
     DeleteObject(hBmp);
}

void dcToGray(HDC* dest_mdc, HDC src_mdc)
{
     COLORREF Pixel;
     int r, g, b;
     RECT rc;
     GetClipBox(src_mdc, &rc);
     HBITMAP hBmp = CreateCompatibleBitmap(src_mdc, rc.right, rc.bottom);
     SelectObject(*dest_mdc, hBmp);
     for (int Y_POS = 0; Y_POS < rc.bottom; Y_POS++) {
         for (int X_POS = 0; X_POS < rc.bottom; X_POS++) {
             Pixel = GetPixel(src_mdc, X_POS, Y_POS );
             //取出原圖rgb值
             r = GetRValue(Pixel);
             g = GetGValue(Pixel);
             b = GetBValue(Pixel);
             //將每個像素作灰階處理
             SetPixel(*dest_mdc, X_POS, Y_POS, RGB(0.3 * r + 0.59 *g + 0.11 * b, 0.3 * r + 0.59 *g + 0.11 * b, 0.3 * r + 0.59 *g + 0.11 * b));
         }
     }
     DeleteObject(hBmp);
}

void grayToSobel(HDC* dest_mdc, HDC src_mdc)
{
     RECT rc;
     GetClipBox(src_mdc, &rc);
     HBITMAP hBmp = CreateCompatibleBitmap(src_mdc, rc.right, rc.bottom);
     SelectObject(*dest_mdc, hBmp);
     
     COLORREF Pixel;
     int result[rc.bottom][rc.right];
     //x遮罩矩陣
     int x_mark[3][3] = { {-1, 0, 1},
                          {-2, 0, 2},
                          {-1, 0, 1}};
     //與x遮罩運算結果
     int x_result[3][3];
     //x遮罩矩陣
     int y_mark[3][3] = { { 1, 2, 1},
                          { 0, 0, 0},
                          {-1,-2,-1}};
     //與y遮罩運算結果                           
     int y_result[3][3];
     int sampleValue;
     int sum;
     int sum_x;
     int sum_y;
     int threshold;
     TCHAR str[6];
     for (int Y_POS = 0; Y_POS < rc.bottom; Y_POS++) {
         for (int X_POS = 0; X_POS < rc.right; X_POS++) {
             
             for (int ROW = 0; ROW < 3; ROW++) {
                 for (int COL = 0; COL < 3; COL++) {
                     if ((X_POS+COL) < rc.right &&  (Y_POS+ROW) < rc.bottom)
                     {
                        //判斷沒超出邊界將取樣值作運算
                        Pixel = GetPixel(src_mdc, X_POS + COL , Y_POS + ROW);
                        sampleValue =(int)GetRValue(Pixel);
                        x_result[ROW][COL] = sampleValue * x_mark[ROW][COL];
                        y_result[ROW][COL] = sampleValue * y_mark[ROW][COL];   
                        
                     } else {
                        //超出邊界設為0
                        x_result[ROW][COL] = 0;
                        y_result[ROW][COL] = 0;
                     }      
                 }
             }
             sum=0;
             sum_x= 0;
             sum_y= 0;
             for (int ROW = 0; ROW < 3; ROW++) {
                 for (int COL = 0; COL < 3; COL++) {
                     sum_x+= x_result[ROW][COL];//將矩陣加總,得到該像素x邊界運算結果
                     sum_y+= y_result[ROW][COL];//將矩陣加總,得到該像素y邊界運算結果
                 }
             }    
             sum = abs(sum_x)+abs(sum_y);//將x遮罩與y遮罩運算結果取绝對值加總
             result[Y_POS][X_POS] = sum;    
         }
     }
     sum = 0;
     for (int Y_POS = 0; Y_POS < rc.bottom; Y_POS++)
         for (int X_POS = 0; X_POS < rc.right; X_POS++)
             sum += result[Y_POS][X_POS];
     threshold = sum /(rc.bottom*rc.right);

     for (int Y_POS = 0; Y_POS < rc.bottom; Y_POS++) {
         for (int X_POS = 0; X_POS < rc.right; X_POS++) {
             if (result[Y_POS][X_POS]>=threshold)
                SetPixel(*dest_mdc, X_POS, Y_POS, RGB(255, 255, 255));
             else
                SetPixel(*dest_mdc, X_POS, Y_POS, RGB(0, 0, 0));
         }
     }
     DeleteObject(hBmp);
}

程式執行結果:

文章標籤
全站熱搜
創作者介紹
創作者 jeff810123 的頭像
jeff810123

在我心中有一個夢

jeff810123 發表在 痞客邦 留言(0) 人氣(699)