- ベストアンサー
C言語での平滑化フィルタ
OPenCVを使わずにC言語で3×3の平滑化フィルタを作成したと思っています。 それで、プログラム例を参考にして作ろうと、googleなどで検索しているのですけれども、なかなかファイルの読み込みから平滑化処理まで全てを書いてくれているプログラム例が見つかりません。 もしご存知の方がいらしたら、コンパイル可能な状態のプログラム例を教えて頂けないでしょうか? 環境はwindows VISTAでVisual Studio2008を使っています。 画像サイズなどはこだわりません。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
こんばんは。 取りあえず読み込み元がDIB24bit前提と言う事で。グレースケールに変換しながら計算しています。全てを9で割って足さず、全て足してから9で割っています。若しかしたら、間違っているかもしれませんが、其処は御勘弁下さい。 #include<windows.h> #include<tchar.h> //固定長配列を数える #define ArrayCount(a) (sizeof(a) / sizeof(a[0])) //プロパティ名 const LPCTSTR TSTR_BITMAP = TEXT("bitmap"); //色彩の構造 struct Colors { long R; long G; long B; }; //グレースケール変換 static long GetY(long R, long G, long B) { return 0.298912 * R + 0.586611 * G + 0.114478 * B; } //色彩を設定する static void SetColor(VOID* p, int x, int y, int strideByte, const Colors* pcolors) { BYTE* pByte = (BYTE*)p; const int pos = (x * 3) + (strideByte * y); pByte[pos] = pcolors->B; pByte[pos + 1] = pcolors->G; pByte[pos + 2] = pcolors->R; } //色彩を取り出す static const Colors GetColor(const VOID* p, int x, int y, int strideByte) { const BYTE* pByte = (BYTE*)p; const int pos = (x * 3) + (strideByte * y); const Colors colors = {pByte[pos + 2], pByte[pos + 1], pByte[pos]}; return colors; } //1スキャン辺りのバイト長を4のn倍調整で計算 static DWORD CalcScanLineByte(const DWORD w, const DWORD bpp) { return ((((bpp * w) + 31) / 32) * 4); } //範囲外確認 static bool IsInRect(const POINT* ppt, int width, int height) { return ppt->x >= 0 && ppt->y >= 0 && ppt->x < width && ppt->y < height; } //近傍の計算 static const Colors CalcFilter(const VOID* p, int x, int y, int width, int height, int strideByte) { const POINT point[] = { {x - 1, y - 1}, {x, y - 1}, {x + 1, y - 1}, {x - 1, y}, {x, y}, {x + 1, y}, {x - 1, y + 1}, {x, y + 1}, {x + 1, y + 1} }; const int KERNEL_SIZE = ArrayCount(point); Colors result = {0}; for(int k = 0; k < KERNEL_SIZE; ++k) { //範囲外にはみ出た時は、着眼点(中心)の色彩を取る const int pos = ::IsInRect(&point[k], width, height) ? k : KERNEL_SIZE / 2; const Colors colors = ::GetColor(p, point[pos].x, point[pos].y, strideByte); const long Y = ::GetY(colors.R, colors.G, colors.B); result.R += Y; result.G += Y; result.B += Y; } //全部足してから9で割る result.R /= KERNEL_SIZE; result.G /= KERNEL_SIZE; result.B /= KERNEL_SIZE; return result; } //滑らかにする static void Softness(HBITMAP hBitmap, int count = 1/*この数だけ繰り返す*/) { BITMAP bitmap = {0}; ::GetObject(hBitmap, sizeof(bitmap), &bitmap); const int strideByte = ::CalcScanLineByte(bitmap.bmWidth, 24); for(int i = 0; i < count; ++i) { for(int y = 0; y < bitmap.bmHeight; ++y) { for(int x = 0; x < bitmap.bmWidth; ++x) { const Colors colors = ::CalcFilter(bitmap.bmBits, x, y, bitmap.bmWidth, bitmap.bmHeight, strideByte); ::SetColor(bitmap.bmBits, x, y, strideByte, &colors); } } } } //ウィンドウクラス登録 static ATOM Regist(LPCTSTR szClassName, WNDPROC wndProc) { WNDCLASSEX wndclass = {sizeof(wndclass)}; wndclass.hCursor = ::LoadCursor(NULL,IDC_ARROW); wndclass.hIcon = NULL; wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szClassName; wndclass.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH); wndclass.hInstance = ::GetModuleHandle(NULL); wndclass.style = 0; wndclass.lpfnWndProc = wndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; return ::RegisterClassEx(&wndclass); } //ウィンドウを作成して開く static HWND OpenWindow(LPCTSTR szClassName, LPCTSTR szTitleName, INT w, INT h) { HINSTANCE hInst = ::GetModuleHandle(NULL); HWND hWnd = ::CreateWindowEx(WS_EX_TOOLWINDOW, szClassName, szTitleName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT, w, h, NULL, NULL, hInst, NULL); return hWnd; } //ウィンドウが作られた static LRESULT OnCreate(HWND hWnd) { HBITMAP hBitmap = (HBITMAP)::LoadImage(NULL, TEXT("test.bmp")/*読み込みたいファイル名を入れる*/, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE | LR_CREATEDIBSECTION); ::Softness(hBitmap, 1); ::SetProp(hWnd, TSTR_BITMAP, hBitmap); return 0; } //xボタン static LRESULT OnClose(HWND hWnd) { HBITMAP hBitmap = (HBITMAP)::GetProp(hWnd, TSTR_BITMAP); ::DeleteObject(hBitmap); ::RemoveProp(hWnd, TSTR_BITMAP); ::DestroyWindow(hWnd); return 0; } //ウィンドウが無くなった static LRESULT OnDestroy(HWND hWnd) { ::PostQuitMessage(0); return 0; } //再描画 static LRESULT OnPaint(HWND hWnd) { HBITMAP hBitmap = (HBITMAP)::GetProp(hWnd, TSTR_BITMAP); BITMAP bitmap = {0}; ::GetObject(hBitmap, sizeof(bitmap), &bitmap); HDC hDC = ::CreateCompatibleDC(NULL); ::SelectObject(hDC, hBitmap); PAINTSTRUCT ps; HDC hPaint = ::BeginPaint(hWnd, &ps); ::BitBlt(hPaint, 0, 0, bitmap.bmWidth, bitmap.bmHeight, hDC, 0, 0, SRCCOPY); ::EndPaint(hWnd, &ps); ::DeleteDC(hDC); return 0; } LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_CREATE: return ::OnCreate(hWnd); case WM_CLOSE: return ::OnClose(hWnd); case WM_DESTROY: return ::OnDestroy(hWnd); case WM_PAINT: return ::OnPaint(hWnd); } return ::DefWindowProc(hWnd, uMsg, wParam, lParam); }; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hInstancePrev, LPSTR lpCmdLine, int nShowCmd) { MSG msg; TCHAR tstrClassName[] = TEXT("test resize frame"); TCHAR tstrTitleName[] = TEXT("title"); //ウィンドウクラスの登録 ::Regist(tstrClassName, &::WndProc); //ウィンドウを作成して開く HWND hWnd = ::OpenWindow(tstrClassName, tstrTitleName, 800, 600); //ウィンドウの表示 ::ShowWindow(hWnd, SW_SHOW); //メッセージ回転 while(::GetMessage(&msg, NULL, 0, 0) == TRUE) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } //終了 return msg.wParam; }
その他の回答 (2)
- machongola
- ベストアンサー率60% (434/720)
こんにちは。補足頂きました。思い当たる事を上げると、 ・ソースファイルの拡張子が.cの場合は関数名に付いている::を消すか、ソースファイルの拡張子を.cppに変更するか(こっちの方が楽)。 ・作成するプロジェクトをwin32アプリケーション(window)にする ・リンクエラー対策に kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib comctl32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib winmm.lib 位までリンクしておく、と言った所でしょうか。
- chie65536(@chie65535)
- ベストアンサー率44% (8740/19838)
>コンパイル可能な状態のプログラム例 そんな都合の良い物はありませんよ。 >プログラム例を参考にして作ろうと、googleなどで検索している googleで探せば、 ・ファイルをメモリに読み込むサンプル ・メモリ上またはファイルにある特定の形式の画像データを展開し、ラスターイメージ(ベタな無圧縮イメージ)のピクセルデータにデコードするサンプル ・2次元配列に格納されたラスターイメージの画像データを平滑化するサンプル ・メモリ上にあるラスターイメージのピクセルデータを、特定の形式の画像データに圧縮してメモリ上またはファイルに保存するサンプル など、さまざまな「部品」のソースコードがいっぱいヒットするので、それらの部品を組み合わせて自分で作りましょう。
補足
丁寧に書いていただいて申し訳ないのですが、コンパイルしてみたら、全く問題がなさそうなコーディング箇所にエラーがたくさんでてでて、自力で直そうとしてみたのですが、訳が分からなくなってしまいました。今後も自力で直してみますが、できればアドバイスいただけないでしょうか?