//★ Win32 API で Edge を検出 前田 稔
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
struct BITMAPINFOHEADER
{
・・・ Image Guid を参照 ・・・
};
public class MyForm : Form
{ Face App;
int val= 3000;
public MyForm()
{
App = new Face();
Width = App.m_bmp.Width;
Height = App.m_bmp.Height+32;
App.InitDib();
App.CopyBmp(App.m_DibDC);
App.CopyBmp(App.m_MaskDC);
Paint += new PaintEventHandler(MyHandler);
MouseDown += new MouseEventHandler(OnMyMouseDown);
}
private void MyHandler(object sender, PaintEventArgs e)
{
Graphics g;
g = e.Graphics;
if (App.m_bmp == null) Application.Exit();
App.ViewMask(g,0,0);
}
private void OnMyMouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left) //マウスの左ボタン
{ val+= 1000;
VerMsg("val: ", val);
App.Edge(val);
}
if (e.Button == MouseButtons.Right) //マウスの右ボタン
{ val = 5000;
App.CopyBmp(App.m_MaskDC);
}
Invalidate();
}
public void VerMsg(string msg, int v)
{
string wstr;
wstr = msg + v.ToString();
this.Text = wstr;
}
}
//☆ Face Object Class
unsafe class Face
{
public Bitmap m_bmp; // 入力画像
public IntPtr m_Dib; // DIB 画像
public IntPtr m_DibDC; // DIB DC
public byte *dat; // DIB ピクセルデータ
public IntPtr m_Mask; // Mask 画像
public IntPtr m_MaskDC; // Mask DC
public byte *msk; // Mak ピクセルデータ
string ImgFile = "";
public const int BI_RGB = 0;
public const int DIB_RGB_COLORS = 0;
public const int SRCCOPY = 0xcc0020;
int[,] vect = new int[9,2] //エッジ検出テーブル
{ {-1,-1}, {-1,0}, {-1,1}, {0,-1}, {0,0}, {0,1}, {1,-1}, {1,0}, {1,1} };
int[] hCoef = new int[9]{ 1, 0, -1, 2, 0, -2, 1, 0, -1 };
int[] vCoef = new int[9]{ 1, 2, 1, 0, 0, 0, -1, -2, -1 };
[DllImport("gdi32.dll")]
・・・ Image Guid を参照 ・・・
// Constructor
public Face()
{
OpenFileDialog opendlg = new OpenFileDialog();
opendlg.Filter = "画像ファイル (*.bmp)|*.bmp|すべてのファイル (*.*)|*.*";
if (opendlg.ShowDialog() == DialogResult.OK)
{ ImgFile = opendlg.FileName; }
try
{ m_bmp = new Bitmap(ImgFile); }
catch
{ MessageBox.Show("画像ファイルが読めません!", ImgFile);
return;
}
}
// Destructor
~Face()
{ DeleteDC(m_DibDC);
DeleteObject(m_Dib);
DeleteDC(m_MaskDC);
DeleteObject(m_Mask);
}
// m_MaskDC の画像を描画する
public void ViewMask(Graphics g, int x, int y)
{
if (m_MaskDC == null) return;
IntPtr hDC = g.GetHdc();
BitBlt(hDC, x, y, m_bmp.Width, m_bmp.Height, m_MaskDC, 0, 0, SRCCOPY);
g.ReleaseHdc(hDC);
}
// hDC ← Bitmap m_bmp イメージデータの転送
public void CopyBmp(IntPtr hDC)
{
IntPtr hBmpSrc = m_bmp.GetHbitmap();
Graphics gdraw = Graphics.FromImage(m_bmp);
IntPtr srcHDC = gdraw.GetHdc();
SelectObject(srcHDC, hBmpSrc);
BitBlt(hDC, 0, 0, m_bmp.Width, m_bmp.Height, srcHDC, 0, 0, SRCCOPY);
DeleteObject(hBmpSrc);
gdraw.ReleaseHdc(srcHDC);
}
//☆ DIB の初期化
unsafe public void InitDib()
{
・・・ Image Guid を参照 ・・・
fixed (void* ppvBits2 = &msk)
{ m_Mask = CreateDIBSection(hdc, bi, 0, (IntPtr)ppvBits2, (IntPtr)null, 0);
if (m_Mask == null) MessageBox.Show("CreateDIBSection error");
}
m_MaskDC = CreateCompatibleDC(hdc);
SelectObject(m_MaskDC, m_Mask);
ReleaseDC(IntPtr.Zero, hdc);
}
// *dat を参照して *msk にエッジ画像を作成
public void Edge(int val)
{
if (m_DibDC == null) return;
for(int y=1; y<m_bmp.Height-1; y++)
for(int x=1; x<m_bmp.Width-1; x++)
{
if (Sobel(x, y, val)) MASK(x,y,0,0,0);
else MASK(x,y,255,255,255);
}
}
// 座標[x,y]周辺のピクセル(*dat)を調べてエッジを検出する
public bool Sobel(int x, int y, int val)
{ int[] fx = new int[3]; //横3色分
int[] fy = new int[3]; //縦3色分
int dx, dy;
byte *pt;
fx[0]= fx[1]= fx[2]= 0;
fy[0]= fy[1]= fy[2]= 0;
for(int i=0; i<9; i++)
{
dx = x + vect[i,0];
dy = y + vect[i,1];
pt = dat+(dy*m_bmp.Width+dx)*4;
for(int c=0; c<3; c++)
{ fx[c] += *(pt+c) * hCoef[i];
fy[c] += *(pt+c) * vCoef[i];
}
}
for(int c=0; c<3; c++)
if (fx[c]*fx[c]+fy[c]*fy[c] > val) return true;
return false;
}
// *msk(y, x) に R,G,B を設定(A はそのまま)
public void MASK(int x, int y, byte r, byte g, byte b)
{
byte *pt;
pt = msk+(y*m_bmp.Width+x)*4;
*pt = b;
*(pt+1)= g;
*(pt+2)= r;
}
}
class image01
{
[STAThread]
public static void Main()
{
MyForm mf = new MyForm();
Application.Run(mf);
}
}
|