以下是我研究這篇技術文件的筆記 Emgu CV -Select ROI (Region Of Interest) With Mouse C#
修改部分
1. 多了一個影像備份(Clone), 加快裁剪的速度; 原作者是從檔案直接再讀一次,
當載入的圖片比較大(如8192x8192)時就會發現速度超慢!
2. 下圖中最右邊, 裁剪的影像外框會有紅色ROI, 已經拿掉
展示
人機介面如下:
1. 先拉一個splitContainer(水平), 在拉兩個splitContainer(垂直)
2. 拉三個EmguCV元件ImageBox, 並將Dock屬性值Filled
3. 加入tableLayoutPanel
4. 加入label1 1) Select Region of Interest with Mouse
5. 加入labelPostionXY Last Position: X:0 Y:0
為了取消zoom in/zoom out
請將imageBoxInput和imageBoxOutputROI的FunctionMode設定成Minimum, 預設值為Everything
加入3個參考 C:\Emgu\emgucv-windows-universal-cuda 3.0.0.2158\bin
Emgu.CV Emgu.CV.UI Emgu.Util
建置->平台目標 x64
變數宣告
1: private bool m_img_loaded = false;
2: private string m_img_filename = "";
3: private Image<Bgr, byte> m_img = null; // 載入圖片
4: private Image<Bgr, byte> m_img_cpy = null; // 載入圖片備份
5:
6: private Point RectStartPoint; // imageBoxInput's ROI 起始點 (picture coordinates)
7: private Rectangle Rect = new Rectangle(); // imageBoxInput's ROI (picture coordinates)
8: private Rectangle RealImageRect = new Rectangle(); // imageBoxOuputROI's ROI (image coordinates)
9: private Brush selectionBrush = new SolidBrush(Color.FromArgb(128, 64, 64, 64)); // 128: 透明度
10: private int thickness = 5;
載入圖片
1: private void loadToolStripMenuItem_Click(object sender, EventArgs e)
2: {
3: using(OpenFileDialog ofd = new OpenFileDialog())
4: {
5: if (ofd.ShowDialog() == DialogResult.OK)
6: {
7: m_img_filename = ofd.FileName;
8: m_img = new Image<Bgr, byte>(m_img_filename);
9: m_img_cpy = m_img.Clone();
10: imageBoxOutputROI.Image = imageBoxInput.Image = m_img;
11: m_img_loaded = true;
12: }
13: }
14: }
加入Utilities.cs
檔案名稱: Utilities.cs
Utilities.cs定義Utilities類別: Picture to image coordinates transformation
(xp,yp): picture coordinates
(xi, yi): image coordinates
1: class Utilities
2: {
3: /* Picture to image coordinates transformation
4: * 輸入 picture coordinates (xp, yp)
5: * 輸出 image coordinates (xi, yi)
6: */
7: public static void ConvertCoordinates(PictureBox pic,
8: out int xi, out int yi, int xp, int yp)
9: {
10: int pic_hgt = pic.ClientSize.Height;
11: int pic_wid = pic.ClientSize.Width;
12: int img_hgt = pic.Image.Height;
13: int img_wid = pic.Image.Width;
14:
15: xi = xp;
16: yi = yp;
17: switch (pic.SizeMode)
18: {
19: case PictureBoxSizeMode.AutoSize:
20: break;
21: case PictureBoxSizeMode.Normal:
22: break;
23: case PictureBoxSizeMode.CenterImage:
24: xi = xp - (pic_wid - img_wid) / 2;
25: yi = yp - (pic_hgt - img_hgt) / 2;
26: break;
27: case PictureBoxSizeMode.StretchImage: // 目前使用中
28: // image coordinates(xi, yi), picture coordinates(xp, yp)
29: xi = (int)(img_wid * xp / (float)pic_wid);
30: yi = (int)(img_hgt * yp / (float)pic_hgt);
31: break;
32: case PictureBoxSizeMode.Zoom:
33: float pic_aspect = pic_wid / (float)pic_hgt;
34: float img_aspect = img_wid / (float)img_wid;
35: if (pic_aspect > img_aspect)
36: {
37: // The PictureBox is wider/shorter than the image.
38: yi = (int)(img_hgt * yp / (float)pic_hgt);
39:
40: // The image fills the height of the PictureBox.
41: // Get its width.
42: float scaled_width = img_wid * pic_hgt / img_hgt;
43: float dx = (pic_wid - scaled_width) / 2;
44: xi = (int)((xp - dx) * img_hgt / (float)pic_hgt);
45: }
46: else
47: {
48: // The PictureBox is taller/thinner than the image.
49: xi = (int)(img_wid * xp / (float)pic_wid);
50:
51: // The image fills the height of the PictureBox.
52: // Get its height.
53: float scaled_height = img_hgt * pic_wid / img_wid;
54: float dy = (pic_hgt - scaled_height) / 2;
55: yi = (int)((yp - dy) * img_wid / pic_wid);
56: }
57: break;
58: }
59: }
60: }
接下來開始針對imageBoxInput事件撰寫
pictureBox_MouseDown
1: private void imageBoxInput_MouseDown(object sender, MouseEventArgs e)
2: {
3: RectStartPoint = e.Location;
4: Invalidate();
5: }
pictureBox_MouseMove
1: private void imageBoxInput_MouseMove(object sender, MouseEventArgs e)
2: {
3: if (!m_img_loaded) return;
4: #region 設定imageBoxInput's Rect感興趣座標(picture coordinates), SETS COORDINATES AT INPUT IMAGE BOX
5: int X0, Y0;
6: /* 滑鼠座標: picture coordinates(e.X, e.Y)
7: * 影像座標: image coordinates(X0, Y0)
8: */
9: Utilities.ConvertCoordinates(imageBoxInput, out X0, out Y0, e.X, e.Y);
10: labelPostionXY.Text = "影像座標: X:" + X0.ToString() + " Y:" + Y0.ToString();
11: labelPicPosXY.Text = "圖片座標: X:" + e.X.ToString() + " Y:" + e.Y.ToString();
12: //Coordinates at input picture box
13: if (e.Button != MouseButtons.Left) // 如果移動中同時按下左鍵繼續往下, 否則離開
14: return;
15: Point tempEndPoint = e.Location;
16: // ROI左上角座標 (picture coordinates)
17: Rect.Location = new Point(
18: Math.Min(RectStartPoint.X, tempEndPoint.X),
19: Math.Min(RectStartPoint.Y, tempEndPoint.Y));
20: // ROI寬度和高度 (picture coordinates)
21: Rect.Size = new Size(
22: Math.Abs(RectStartPoint.X - tempEndPoint.X),
23: Math.Abs(RectStartPoint.Y - tempEndPoint.Y));
24: #endregion
25: #region 設定imageBoxOutputROI's RealImageRect感興趣座標(image coordinates), SETS COORDINATES AT REAL IMAGE
26: /* (1) picture coordinates: RectStartPoint.X, RectStartPoint.Y
27: * image coordinates: X0, Y0
28: * (2) picture coordinates: tempEndPoint.X, tempEndPoint.Y
29: * image coordinates: X1, Y1
30: */
31: //Coordinates at real image - Create ROI
32: Utilities.ConvertCoordinates(imageBoxInput, out X0, out Y0, RectStartPoint.X, RectStartPoint.Y);
33: int X1, Y1;
34: Utilities.ConvertCoordinates(imageBoxInput, out X1, out Y1, tempEndPoint.X, tempEndPoint.Y);
35: RealImageRect.Location = new Point(
36: Math.Min(X0, X1),
37: Math.Min(Y0, Y1));
38: RealImageRect.Size = new Size(
39: Math.Abs(X0 - X1),
40: Math.Abs(Y0 - Y1));
41: m_img_cpy.ROI = System.Drawing.Rectangle.Empty;
42: m_img = m_img_cpy.Clone();
43: m_img.Draw(RealImageRect, new Bgr(Color.White), thickness); // 在image上繪製ROI, 並顯示在imageBoxOutputROI
44: imageBoxOutputROI.Image = m_img;
45:
46: #endregion
47: ((PictureBox)sender).Invalidate();
48: }
imageBoxInput_MouseUp
1: private void imageBoxInput_MouseUp(object sender, MouseEventArgs e)
2: {
3: if (!m_img_loaded) return;
4: //Define ROI. Valida altura e largura para evitar index range exception.
5: if (RealImageRect.Width > 0 && RealImageRect.Height > 0)
6: {
7: m_img_cpy.ROI = RealImageRect;
8: imageBoxROI.Image = m_img_cpy;
9: }
10: }
imageBoxInput_Paint
1: private void imageBoxInput_Paint(object sender, PaintEventArgs e)
2: {
3: //if (!m_img_loaded) return;
4: // Draw the rectangle...
5: if (imageBoxInput.Image != null)
6: {
7: if (Rect != null && Rect.Width > 0 && Rect.Height > 0)
8: {
9: //Seleciona a ROI
10: e.Graphics.SetClip(Rect, System.Drawing.Drawing2D.CombineMode.Exclude);
11: e.Graphics.FillRectangle(selectionBrush, new Rectangle(0, 0, ((PictureBox)sender).Width, ((PictureBox)sender).Height));
12: //e.Graphics.FillRectangle(selectionBrush, Rect);
13: }
14: }
15: }
imageBoxInput_DoubleClick
1: private void imageBoxInput_DoubleClick(object sender, EventArgs e)
2: {
3: Rect = new Rectangle();
4: ((PictureBox)sender).Invalidate();
5: }
操考資料:
留言列表