Learning opencv续不足(二)显示一幅bmp图像和感兴趣区域(ROI)图像截取(非常重要)

假定你有一定的C#编程基础。下面代码是显示一幅bmp图像(默认是8位灰度图像,即0-255灰度的黑白色)

 string path = Environment.CurrentDirectory;//获取debug路径

 Bitmap curBitmap = (Bitmap)Bitmap.FromFile(path + "\\contour2.bmp");//debug路径下有图像contour2.bmp

 pictureBox1.Image = curBitmap;//在图像控件显示contour2.bmp

以上三句话,放在form()中。想要得到这幅图的像素颜色灰度buffer,在formload()中执行以下操作: 

    int ww = curBitmap.Width;//此处又用到位图,所以位图声明全局
    int hh = curBitmap.Height;
    int bytes = ww * hh ;

     byte[] rgbValues = new byte[bytes];
     byte[]  glob_buffer8 = new byte[ww * hh];//此变量也要声明全局

  Rectangle rc = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
  System.Drawing.Imaging.BitmapData bmpdata =   curBitmap.LockBits(rc, System.Drawing.Imaging.ImageLockMode.ReadWrite,curBitmap.PixelFormat);
  IntPtr imageptr = bmpdata.Scan0;                                                                   System.Runtime.InteropServices.Marshal.Copy(imageptr, rgbValues, 0, bytes);//像素颜色灰度在rgbValues中
  curBitmap.UnlockBits(bmpdata);
  glob_buffer8 = rgbValues;//给全局

完成以上两步,然后制作感兴趣区域(ROI),大家都有这样的体验,在windows窗口,按着鼠标不放,拖动一下,就会出现一个矩形虚线框,没错,就是他,他就是感兴趣区域(roi),我们经常什么也没圈到,晃一下就没了,或许叫无聊区更合适,因为大家经常对着电脑窗口发呆无聊时,经常这样搞。事情往往就是这样,无发现,无作为,一旦发现,便拥有了世界
       我们让图像控件pictureBox1出现一个可操作感兴趣区域(ROI),实质就是一个矩形,有两个操作,左键按下拖住中心移动,左键按下拖住矩形右下角改变大小。我们截图全靠它了。步骤如下:

一,  public ROIsimple m_cutImageRoi;//声明感兴趣区域(ROI)

二,form()中初始化,m_cutImageRoi = new ROIsimple();

三, private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            PointF point = new PointF(e.X, e.Y);          
            bool status = false;
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                status = true;
            }
            m_cutImageRoi.DrawRectFrame(status, point);//用来感知两个操作

            this.Cursor = m_cutImageRoi.m_cur;//改变鼠标的样子
            pictureBox1.Invalidate(false);

         }

四,m_cutImageRoi.m_RoiBase1.Draw(g, p,"ROI",true);//在paint()函数中画出感兴趣区域(ROI)

ROIsimple 是个什么鬼?我们来看一看,

 public class ROIsimple
    {
        public RoiBase1 m_RoiBase1;//封装了一个矩形及对矩形的操作
        public E_HANDLES m_eHandle;//鼠标位置
        public Cursor m_cur;//改变鼠标形状
        public ROIsimple()
        {
            m_RoiBase1 = new RoiBase1();
            m_cur = Cursors.Arrow;//鼠标通用箭形状
        }
        public void DrawRectFrame(bool lbtn, PointF point)//用来感知两个操作
        {
            if (lbtn)
            {
                switch (m_eHandle)
                {
                    case E_HANDLES.E_HANDLE_INSIDE:
                        m_RoiBase1.Drag(point);//左键按下拖住中心移动
                        break;

                    case E_HANDLES.E_HANDLE_SOUTH_EAST:
                        {
                            m_RoiBase1.DragTolerance(point);//左键按下拖住矩形右下角改变大小
                        }
                        break;
                    default:
                        break;
                }
            }
            else
            {
                m_eHandle = (E_HANDLES)m_RoiBase1.IsPointInRect(point);
            }
            Insteadof((int)m_eHandle);//改变鼠标的样子

            return;
        }
        private void Insteadof(int intcursor)//改变鼠标的样子
        {
            switch (intcursor)
            {
                case (int)E_HANDLES.E_HANDLE_INSIDE:

                    m_cur = Cursors.SizeAll;
                    break;

                case (int)E_HANDLES.E_HANDLE_NORTH:
                case (int)E_HANDLES.E_HANDLE_SOUTH:

                    m_cur = Cursors.SizeNS;
                    break;

                case (int)E_HANDLES.E_HANDLE_EAST:
                case (int)E_HANDLES.E_HANDLE_WEST:

                    m_cur = Cursors.SizeWE;

                    break;

                case (int)E_HANDLES.E_HANDLE_NORTH_WEST:
                case (int)E_HANDLES.E_HANDLE_SOUTH_EAST:

                    m_cur = Cursors.SizeNWSE;
                    break;

                case (int)E_HANDLES.E_HANDLE_NORTH_EAST:
                case (int)E_HANDLES.E_HANDLE_SOUTH_WEST:

                    m_cur = Cursors.SizeNESW;
                    break;
                default:
                    m_cur = Cursors.Arrow;//鼠标通用箭形状
                    break;
            }
            return;
        }
    }

  public enum E_HANDLES//矩形框的八个方向和中心
    {
        E_HANDLE_NONE,//0
        E_HANDLE_INSIDE,//1
        E_HANDLE_NORTH,//2
        E_HANDLE_EAST,//3
        E_HANDLE_SOUTH,//4
        E_HANDLE_WEST,//5
        E_HANDLE_NORTH_WEST,//6
        E_HANDLE_SOUTH_WEST,//7
        E_HANDLE_NORTH_EAST,//8
        E_HANDLE_SOUTH_EAST,//9
        E_HANDLE_UNKNOWN = 65535
    };

m_RoiBase1是个什么鬼?我们来看一看, 

 public class RoiBase1//实质就是画了一个矩形
    {

        public RectangleF rcWin;
        public PointF m_Center;
        public RoiBase1()
        {
            rcWin = new RectangleF(100, 100, 100, 100);//矩形框初始化的位置

            m_Center.X = rcWin.Left + rcWin.Width / 2;//矩形框的中心
            m_Center.Y = rcWin.Top + rcWin.Height / 2;
        }
        public void ResetRc(RectangleF rc)
        {
            rcWin = rc;
            m_Center.X = rcWin.Left + rcWin.Width / 2;
            m_Center.Y = rcWin.Top + rcWin.Height / 2;
        }
        public void Draw(Graphics g, Pen p, string labelstr, bool b_minRc)
        {//可以在矩形框上写字,譬如“ROI”,作为标签
            g.DrawRectangle(p, rcWin.Left, rcWin.Top, rcWin.Width, rcWin.Height);
            if (b_minRc)//鼠标形状改变区域画了两个10*10小矩形
            {
                g.DrawRectangle(p, (int)m_Center.X - 5, (int)m_Center.Y - 5, 10, 10);
                g.DrawRectangle(p, (int)rcWin.Left + rcWin.Width - 5, (int)rcWin.Top + rcWin.Height - 5, 10, 10);
            }         
            Font drawfont = new Font("Arial", 9);
            g.DrawString(labelstr, drawfont, Brushes.Brown, rcWin.Left, (float)(rcWin.Top / 2.0 + rcWin.Bottom / 2.0) - 10);
        }
        public int IsPointInRect(PointF point)//判断鼠标位置
        {
            if (point.X <= m_Center.X + 5 && point.X >= m_Center.X - 5
               && point.Y >= m_Center.Y - 5 && point.Y <= m_Center.Y + 5)
            {
                return (int)E_HANDLES.E_HANDLE_INSIDE;//经过判断在矩形中心位置//1
            }
            else if (point.X <= rcWin.Left + rcWin.Width + 5 && point.X >= rcWin.Left + rcWin.Width - 5
                  && point.Y >= rcWin.Top + rcWin.Height - 5 && point.Y <= rcWin.Top + rcWin.Height + 5)
            {
                return (int)E_HANDLES.E_HANDLE_SOUTH_EAST;// E_HANDLE_SOUTH_EAST,//9   

            }//经过判断在矩形右下角位置
            else
            {
                return 0;
            }
        }
        public void Drag(PointF point)//左键按下拖住中心移动
        {
            float tempX = 0, tempY = 0;

            tempX = point.X - m_Center.X;
            tempY = point.Y - m_Center.Y;

            m_Center.X = (float)point.X;
            m_Center.Y = (float)point.Y;

            rcWin = new RectangleF(rcWin.Left + tempX, rcWin.Top + tempY, rcWin.Width, rcWin.Height);
        }
        public void DragTolerance(PointF point)//左键按下拖住矩形右下角改变大小
        {
            rcWin.Width = point.X - rcWin.Left;
            rcWin.Height = point.Y - rcWin.Top;
            rcWin = new RectangleF(rcWin.Left, rcWin.Top, rcWin.Width, rcWin.Height);

            m_Center.X = rcWin.Left + rcWin.Width / 2;
            m_Center.Y = rcWin.Top + rcWin.Height / 2;
        }
    }

以上完成了图像上画一个可以互动的感兴趣区域(ROI),现在添加一个按钮,来截取感兴趣区域(ROI)图像放入pictureBoxRoiImg图像控件。

    private void cutroi_Click(object sender, EventArgs e)
        {                                
                _RoiW = Convert.ToInt32(textBoxW.Text);//感兴趣区域的宽度
                int mod = _RoiW % 4;//解决四位对齐问题20150716
                _RoiW = _RoiW + (4 - mod) % 4;

                _RoiH = Convert.ToInt32(textBoxH.Text);//感兴趣区域的高度
                _RoiX = Convert.ToInt32(textBoxX.Text);////感兴趣区域的坐标(x,y)在图像中位置
                _RoiY = Convert.ToInt32(textBoxY.Text);
                tempImage3 = new byte[_RoiW * _RoiH];  //截取的感兴趣图像          
                int H =  curBitmap.Height;//加载bmp图像的高和宽
                int W = curBitmap.Width;
                  for (int i = 0; i < _RoiH; i++)
                      for (int j = 0; j < _RoiW; j++)
                      {                        
                          tempImage3[i * _RoiW + j] = glob_buffer8[((i + _RoiY) * W + j + _RoiX)];
                      }
            
               //显示截取的感兴趣图像
                byte[] cutvalues = new byte[_RoiW * _RoiH * 3];

                int bytes = _RoiW * _RoiH * 3;

                Bitmap cutPic24 = new Bitmap(_RoiW, _RoiH, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

                BitmapData _cutPic = cutPic24.LockBits(new Rectangle(0, 0, _RoiW, _RoiH), ImageLockMode.ReadWrite,
                                                     cutPic24.PixelFormat);

                IntPtr ptr = _cutPic.Scan0;//得到首地址

                for (int i = 0; i < _RoiH; i++)//图像复原,即由8位图变成24位图像
                {
                    for (int j = 0; j < _RoiW; j++)
                    {
                        int n = i * _RoiW + j;
                        int m = 3 * n;
                        cutvalues[m] = tempImage3[n];
                        cutvalues[m + 1] = tempImage3[n];
                        cutvalues[m + 2] = tempImage3[n];

                    }
                }
                //把cutvalues数组给ptr
                System.Runtime.InteropServices.Marshal.Copy(cutvalues, 0, ptr, _RoiH * _RoiW * 3);
                cutPic24.UnlockBits(_cutPic);
                pictureBoxRoiImg.Image = cutPic24;
            ///////////////////////////////////////////////////////////////////
              
        }

(待续......................)

猜你喜欢

转载自blog.csdn.net/ganggangwawa/article/details/89021175
今日推荐