事實上索貝爾運算子我之前就有想說要研究,但看到維基百科上的解釋,讓我打退堂鼓。最近有開始研究他,也多虧同學的講義讓我終 於了解,其中要了解的是捲積的概念,還有邊界判定的問題,其他應該都小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);
}
程式執行結果:
文章標籤
全站熱搜
