以下是我研究這篇技術文件的筆記 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 IMAGE26: /* (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: }操考資料:










留言列表
