close

以下是我研究這篇技術文件的筆記 Emgu CV -Select ROI (Region Of Interest) With Mouse C#


修改部分

1. 多了一個影像備份(Clone), 加快裁剪的速度; 原作者是從檔案直接再讀一次,

當載入的圖片比較大(如8192x8192)時就會發現速度超慢!

2. 下圖中最右邊, 裁剪的影像外框會有紅色ROI, 已經拿掉

image

展示

image_thumb3

人機介面如下:

1. 先拉一個splitContainer(水平), 在拉兩個splitContainer(垂直)

2. 拉三個EmguCV元件ImageBox, 並將Dock屬性值Filled

image

3. 加入tableLayoutPanel

4. 加入label1   1) Select Region of Interest with Mouse

5. 加入labelPostionXY   Last Position: X:0   Y:0

image

為了取消zoom in/zoom out

請將imageBoxInput和imageBoxOutputROI的FunctionMode設定成Minimum, 預設值為Everything

image

加入3個參考 C:\Emgu\emgucv-windows-universal-cuda 3.0.0.2158\bin

Emgu.CV   Emgu.CV.UI      Emgu.Util

image

建置->平台目標 x64

image

變數宣告

   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

image

檔案名稱: Utilities.cs

image

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事件撰寫

image

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: }

操考資料:

Emgu CV -Select ROI (Region Of Interest) With Mouse - C#

arrow
arrow
    全站熱搜

    me1237guy 發表在 痞客邦 留言(9) 人氣()