Category
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
エクスプローラや画像処理ソフトでよくある、マウスで選択した領域を四角で囲むというイメージです。


ソース

ソースは以下のようになります。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace SelectRegion
{
    public partial class Form1 : Form
    {
        Point MD = new Point();
        Point MU = new Point();
        Bitmap bmp;
        bool view = false;
        
        public Form1()
        {
            InitializeComponent();

            //描画先とするImageオブジェクトを作成する
            bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
        }

        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            // 描画フラグON
            view = true;
            
            // Mouseを押した座標を記録
            MD.X = e.X;
            MD.Y = e.Y;
        }

        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            Point start = new Point();
            Point end = new Point();
            
            // Mouseを離した座標を記録
            MU.X = e.X;
            MU.Y = e.Y;

            //System.Diagnostics.Debug.WriteLine("MouseUp({0},{1})->({2},{3})", MD.X, MD.Y, MU.X, MU.Y);
            
            // 座標から(X,Y)座標を計算
            GetRegion(MD, MU, ref start, ref end);
            
            // 領域を描画
            DrawRegion(start, end);
            
            //PictureBox1に表示する
            pictureBox1.Image = bmp;

            // 描画フラグOFF
            view = false;
        }

        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            Point p = new Point();
            Point start = new Point();
            Point end = new Point();

            // 描画フラグcheck
            if (view == false)
            {
                return;
            }
            
            // カーソルが示している場所の座標を取得
            p.X = e.X;
            p.Y = e.Y;

            // 座標から(X,Y)座標を計算
            GetRegion(MD, p, ref start, ref end);

            //System.Diagnostics.Debug.WriteLine("Move ({0},{1})", e.X, e.Y);

            // 領域を描画
            DrawRegion(start, end);
            
            //PictureBox1に表示する
            pictureBox1.Image = bmp;
        }

        private void GetRegion(Point p1, Point p2, ref Point start, ref Point end)
        {
            start.X = Math.Min(p1.X, p2.X);
            start.Y = Math.Min(p1.Y, p2.Y);

            end.X = Math.Max(p1.X, p2.X);
            end.Y = Math.Max(p1.Y, p2.Y);
        }

        private int GetLength(int start, int end)
        {
            return Math.Abs(start - end);
        }

        private void DrawRegion(Point start, Point end)
        {
            Pen blackPen = new Pen(Color.Black);
            Graphics g = Graphics.FromImage(bmp);

            // 描画する線を点線に設定
            blackPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;

            // 画面を消去
            g.Clear(SystemColors.Control);
            
            // 領域を描画
            g.DrawRectangle(blackPen, start.X, start.Y, GetLength(start.X, end.X), GetLength(start.Y, end.Y));
            
            g.Dispose();
        }
    }
}


【pictureBox1_MouseUp】
マウスをクリックした瞬間にコールされます。
押した瞬間の座標を取得するのと、描画用のフラグをONにしています。

【pictureBox1_MouseDown】
マウスをクリックを離した瞬間にコールされます。
離した場所の座標を取得するのと、描画用のフラグをOFFにしています。

【pictureBox1_MouseMove】
マウスが移動中は常にコールされます。
描画用のフラグがONになっていないと以降の処理をしないようにしています。



個人的にはGetRegionの関数で複数の戻り値ができるよう実装したかったのですが、挫折・・・orz

結果

結果はわかりずらいですが、以下のようになります。


1_20120917192150.png


ドラッグするときちんと四角の領域もマウスに追随していきます。
画像処理のソフトなどで、領域拡大をさせるときにマウスで選択したい場合に視覚的にわかりやすくなるのかなと・・・

今までblogにアップしていた、画像ファイルのサイズが大きすぎたのでまとめてリサイズするプログラムがほしかったので作ってみました。
まとめて処理できたら楽なのでドラッグ&ドロップできるように。。。
Drag&Dropされたファイルのファイル名を取得する

listBox1_DragDropとlistBox1_DragEnterは上記ページからの丸写しです(汗
listboxのAllowDropTrueにしておかないとダメです。



ソース


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DragDropAPP
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void listBox1_DragDrop(object sender, DragEventArgs e)
        {
            //コントロール内にドロップされたとき実行される
            //ドロップされたすべてのファイル名を取得する
            string[] fileName =
                (string[])e.Data.GetData(DataFormats.FileDrop, false);
            //ListBoxに追加する
            listBox1.Items.AddRange(fileName);
        }

        private void listBox1_DragEnter(object sender, DragEventArgs e)
        {
            //コントロール内にドラッグされたとき実行される
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                //ドラッグされたデータ形式を調べ、ファイルのときはコピーとする
                e.Effect = DragDropEffects.Copy;
            else
                //ファイル以外は受け付けない
                e.Effect = DragDropEffects.None;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < listBox1.Items.Count; i++)
            {
                //ファイル名をフルパスで取得
                String str = listBox1.Items[i].ToString();

                //拡張子を取得
                String ext = System.IO.Path.GetExtension(str);
                if (ExtentionCheck(ext) == true)
                {
                    //画像を半分のサイズに
                    ConvertBmp(str);
                }                
            }
        }

        private bool ExtentionCheck(String ext)
        {
            //拡張子に一致するか
            return System.Text.RegularExpressions.Regex.IsMatch(ext, ".bmp|.png|.jpeg|.jpg");
        }

        private void ConvertBmp(String str)
        {
            Bitmap bitmap = new Bitmap(str);
            Bitmap halfbmp = new Bitmap(bitmap, bitmap.Width / 2, bitmap.Height / 2);

            //ディレクトリ名の取得
            String dir = System.IO.Path.GetDirectoryName(str);
            //ファイル名の取得
            String fname = System.IO.Path.GetFileName(str);
            //新規ファイル名
            String halfname = "half" + fname;
            //新規ファイル名をフルパスで保存
            halfbmp.Save(dir + "\\" +halfname);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            //リストをすべてクリア
            listBox1.Items.Clear();
        }
    }
}



C#でスクリーンキャプチャする方法があったのでφ(`д´)メモメモ...


下記サイトを参考にさせていただきましたm(_ _)m



ソース

御覧の通り(?)、画面をキャプチャした後に、Formのサイズへ全体をリサイズしてから表示してます。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Runtime.InteropServices;//for screen capture

namespace ScreenCapture
{
    public partial class Form1 : Form
    {
        private Bitmap myBitmap;//for screen capture
        public Form1()
        {
            InitializeComponent();

            pictureBox1.Height = this.Height;
            pictureBox1.Width = this.Width;
        }

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            // スクリーンキャプチャーする
            myBitmap = Win32APICall.GetDesktop();

            // キャプチャーした画面をFormのサイズへリサイズ
            myBitmap = ResizeImage(myBitmap, this.Width, this.Height);

            pictureBox1.Image = myBitmap;
        }

        public static Bitmap ResizeImage(Bitmap image, double dw, double dh)
        {
            double hi;
            double imagew = image.Width;
            double imageh = image.Height;

            if ((dh / dw) <= (imageh / imagew))
            {
                hi = dh / imageh;
            }
            else
            {
                hi = dw / imagew;
            }
            int w = (int)(imagew * hi);
            int h = (int)(imageh * hi);

            Bitmap result = new Bitmap(w, h);
            Graphics g = Graphics.FromImage(result);
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            g.DrawImage(image, 0, 0, result.Width, result.Height);

            return result;
        }
    }
    public class Win32APICall
    {
        [DllImport("gdi32.dll", EntryPoint = "DeleteDC")]
        public static extern IntPtr DeleteDC(IntPtr hdc);

        [DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
        public static extern IntPtr DeleteObject(IntPtr hObject);

        [DllImport("gdi32.dll", EntryPoint = "BitBlt")]
        public static extern bool BitBlt(IntPtr hdcDest, int nXDest,
            int nYDest, int nWidth, int nHeight, IntPtr hdcSrc,
            int nXSrc, int nYSrc, int dwRop);

        [DllImport("gdi32.dll", EntryPoint = "CreateCompatibleBitmap")]
        public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc,
            int nWidth, int nHeight);

        [DllImport("gdi32.dll", EntryPoint = "CreateCompatibleDC")]
        public static extern IntPtr CreateCompatibleDC(IntPtr hdc);

        [DllImport("gdi32.dll", EntryPoint = "SelectObject")]
        public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobjBmp);

        [DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]
        public static extern IntPtr GetDesktopWindow();

        [DllImport("user32.dll", EntryPoint = "GetDC")]
        public static extern IntPtr GetDC(IntPtr hWnd);

        [DllImport("user32.dll", EntryPoint = "GetSystemMetrics")]
        public static extern int GetSystemMetrics(int nIndex);

        [DllImport("user32.dll", EntryPoint = "ReleaseDC")]
        public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);

        public static Bitmap GetDesktop()
        {
            int screenX;
            int screenY;
            IntPtr hBmp;
            IntPtr hdcScreen = GetDC(GetDesktopWindow());
            IntPtr hdcCompatible = CreateCompatibleDC(hdcScreen);

            screenX = GetSystemMetrics(0);
            screenY = GetSystemMetrics(1);
            hBmp = CreateCompatibleBitmap(hdcScreen, screenX, screenY);

            if (hBmp != IntPtr.Zero)
            {
                IntPtr hOldBmp = (IntPtr)SelectObject(hdcCompatible, hBmp);
                BitBlt(hdcCompatible, 0, 0, screenX, screenY, hdcScreen, 0, 0, 13369376);

                SelectObject(hdcCompatible, hOldBmp);
                DeleteDC(hdcCompatible);
                ReleaseDC(GetDesktopWindow(), hdcScreen);

                Bitmap bmp = System.Drawing.Image.FromHbitmap(hBmp);

                DeleteObject(hBmp);
                GC.Collect();

                return bmp;
            }
            return null;
        }
    }
}


結果

再起的に画面が取り込まれてるみたいですね(;´Д`)
Paintのイベント時にキャプチャしているので、ウィンドウが移動してもForm内の画像も更新されていきます 。

capture.png


いわゆる、K-MeansをC#で実装してみました。 PictureBoxに点を貼りつけて実装しています。

停止条件である重心の位置が更新されなくなったら分類停止っていうのは実装していません。


ソース

実装したものは以下のようになります。

例外などエラー時の処理は考慮していないのであしからずm(_ _)m
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace K_Means
{
    public partial class Form1 : Form
    {
        struct Cluster
        {
            public Point Point;    // 座標
            public int Pattern;    // 色のパターン
        }

        public static int POINT_SIZE = 70;  //分類する点の数
        public static int CLUSTER_SIZE = 5; //分類するクラスターの数

        Cluster[] kernel = new Cluster[POINT_SIZE];   //分類する点
        Cluster[] cluster = new Cluster[CLUSTER_SIZE];//分類するクラスター
        Color[] myColor = new Color[] {               //色
            Color.Red,
            Color.Blue, 
            Color.Brown,
            Color.Cyan,
            Color.Yellow,
            Color.DarkGray,
            Color.DarkSlateBlue,
            Color.DarkGoldenrod,
            Color.DarkGreen,
            Color.DarkRed
        };

        public Form1()
        {
            InitializeComponent();

            // コンボボックスの初期位置
            comboBox1.SelectedIndex = 4;

            pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);
            Graphics g = Graphics.FromImage(pictureBox1.Image);
            if (comboBox1.SelectedIndex != -1)
            {
                // 洗濯されている要素を取得
                int index = comboBox1.SelectedIndex;
                string Text = comboBox1.Items[index].ToString();
                Console.WriteLine(int.Parse(Text));

                // クラスターの配列数を変更
                CLUSTER_SIZE = int.Parse(Text);
                Array.Resize(ref cluster, CLUSTER_SIZE);
            }

            // 任意の点を生成
            int seed = Environment.TickCount;
            for (int i = 0; i < POINT_SIZE; i++)
            {
                Random rnd = new Random(seed++);
                kernel[i].Point.X = rnd.Next(pictureBox1.Width);
                kernel[i].Point.Y = rnd.Next(pictureBox1.Height);
                kernel[i].Pattern = 0;
                
                // 描画
                g.FillEllipse(Brushes.Black, kernel[i].Point.X, kernel[i].Point.Y, 10, 10);
            }

            // clusterの初期位置を決定
            for (int i = 0; i < CLUSTER_SIZE; i++)
            {
                Random rnd = new Random(seed++);
                cluster[i].Point.X = rnd.Next(pictureBox1.Width);
                cluster[i].Point.Y = rnd.Next(pictureBox1.Height);
                cluster[i].Pattern = i;
            }
            // 描画
            DrawCluster(g, cluster, CLUSTER_SIZE, 20);
            //DrawCluster(g, kernel, POINT_SIZE, 10);

            g.Dispose();
            pictureBox1.Refresh();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);
            Graphics g = Graphics.FromImage(pictureBox1.Image);

            // 各点がどのクラスターに属するか判定
            for (int i = 0; i < POINT_SIZE; i++)
            {
                double temp = 2000;
                double dist = 2000;
                int pat = 0;

                for (int j = 0; j < CLUSTER_SIZE; j++)
                {
                    // 距離を計算
                    temp = Distance(cluster[j], kernel[i]);
                    if (dist > temp)
                    {
                        dist = temp;
                        pat = j;
                    }
                }
                kernel[i].Pattern = pat;
            }
            // クラスターの重心位置を計算し移動させる
            for (int j = 0; j < CLUSTER_SIZE; j++)
            {
                double sum_x = 0;
                double sum_y = 0;
                int num = 0;
                for (int i = 0; i < POINT_SIZE; i++)
                {
                    if (cluster[j].Pattern == kernel[i].Pattern)
                    {
                        sum_x += kernel[i].Point.X;
                        sum_y += kernel[i].Point.Y;
                        num = num + 1;
                    }
                }
                //System.Diagnostics.Debug.WriteLine("sum_x:{0},sum_y:{1}, Pattern{2}", sum_x, sum_y, j);
                cluster[j].Point.X = (int)sum_x / num;
                cluster[j].Point.Y = (int)sum_y / num;
            }
            // 描画
            DrawCluster(g, cluster, CLUSTER_SIZE, 20);
            DrawCluster(g, kernel, POINT_SIZE, 10);

            g.Dispose();
            pictureBox1.Refresh();
        }

        // 各座標にPatternにて指定されたカラーで描画
        private void DrawCluster(Graphics g, Cluster[] p, int Num_Point, int radius)
        {
            for (int i = 0; i < Num_Point; i++)
            {
                Brush brush = new SolidBrush(myColor[p[i].Pattern]);
                g.FillEllipse(brush, p[i].Point.X, p[i].Point.Y, radius, radius);
            }
        }

        // 2点間の距離を計算
        private double Distance(Cluster a, Cluster b)
        {
            double dx = a.Point.X - b.Point.X;
            double dy = a.Point.Y - b.Point.Y;

            return Math.Sqrt(dx * dx + dy * dy);
        }
    }
}




結果

コンボボックスで分類できる数を変更できるようにしています。


【初期位置】
kmeans1.png

【5個分類時】
kmeans2.png

【9個分類時】
kmeans3.png

【3個分類時】
kmeans4.png

C#でコンボボックスを使ったので、忘れそうなことをメモ


初期位置の設定

何も設定しておかないとコンボボックスに選択されていない状態になるので、 以下のようにして、初期位置を設定しておきます。
// コンボボックスの初期位置
comboBox1.SelectedIndex = 4;
ちなみに、これで初期位置が5番目の要素になります。

選択位置・要素の取得

もちろん、コンボボックスで何が選択されているか必要な場合があります。
int index = comboBox1.SelectedIndex;
string Text = comboBox1.Items[index].ToString();
お分かりのように、
comboBox1.SelectedIndexで何番目が選択されているかが取得でき、
comboBox1.Items[index].ToString()で選択されているアイテムを文字列にして取得してます。

FC2カウンター
プロフィール

詠み人知らず

Author:詠み人知らず
プログラム好きな名もなき凡人がお送りしています。(得意とは言っていない
最近の興味はPython、C#、Matlab(Octave)、画像処理、AR(拡張現実)、統計などなど・・・

気分で思いついたことを書くため話題に一貫性がないかもしれません。

カレンダー
08 | 2017/03 | 09
- - - 1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31 -
最新記事
タグクラウドとサーチ

カテゴリ
最新コメント
最新トラックバック
月別アーカイブ
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。