HALCON_C#_交互ROI

article/2025/9/22 6:28:16

GDI+知识讲解
GDI+英文全称:Graphics Device Interface Plus, GDI+是对GDI的扩展。
一. GDI概述

 二.Graphics类介绍
Graphics 类封装了很多GDI+绘图对象,并将这些对象显示到设备上。创建Graphics对象也被称为创建一个画板,创建画板一共有3种方式:
1. 利用控件或窗体的Paint事件中参数PaintEventArgs来创建画板
    private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
    {
        }
2. 利用控件和窗体的CreateGraphics方法创建画板
      This. CreateGraphics或者 控件名. CreateGraphics()
3. 调用Graphics的FromImage函数创建画板。
      Image  im= Image. FromImage(“1.jpg”);
      Graphics  g=Graphics. FromImage(im);
三.GDI+相关命名空间

 四. Graphics支持的画图方法

创建 C# 的 winform程序
这个 form窗口的属性 事件 Paint 添加事件
这个 paint 事件

   private void OnPaint(object sender, PaintEventArgs e){// Create pens & points// 创建一个画笔工具,红色,画笔的粗细是1Pen redPen = new Pen(Color.Red, 1);// Draw rectangles to screen.// 画笔工具的构造函数// 矩形 ,矩形左上角坐标 XY  矩形的宽高Rectangle rect = new Rectangle(20, 20, 80, 40);// 创建画板e.Graphics.DrawRectangle(redPen, rect);// DisposeredPen.Dispose();}

注意
当我们 使用鼠标移动事件,绘画图形。 其实这个只是设置ROI图形的 参数,要调用第80行指向的这个函数,通知picturebox控件绘图。

 这个才是真正的绘图

第3
用鼠标在界面画一个矩形
添加一个 picture box 控件
改名DisplayImage_pictureBox   
不是改控件的 text
 
再绑定这几个事件  form_load    OnMouseDown  OnMouseMove  OnMouseUp OnPaint

只能画一个 ROI区域,当画完一个,再画另外一个时,前一个RO区域将消失

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;namespace GDI_Text
{public partial class Form1 : Form{// 位图对象private Bitmap OriginImage;// 定义鼠标按下的点private Point MouseDownPoint;// 定义 鼠标移动的点private Point MouseMovePoint;// 鼠标弹起的点private Point MouseUpPoint;// 为true表示在画的状态private bool StartDraw;// 矩形private Rectangle CaptureRectangle;public Form1(){InitializeComponent();MouseDownPoint = new Point(0, 0);MouseMovePoint = new Point(0, 0);MouseUpPoint = new Point(0, 0);StartDraw = false;}private void Form1_Load(object sender, EventArgs e){// 位图对象实例化LoadImage("demo.png");SetDoubleBuffering();}/// <summary>/// 设置双缓存,防止图片闪烁/// </summary>private void SetDoubleBuffering(){this.SetStyle(ControlStyles.ResizeRedraw, true);this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);this.SetStyle(ControlStyles.UserPaint, true);this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);this.UpdateStyles();}/// <summary>/// 加载图像/// </summary>/// <param name="ImagePath"></param>private void LoadImage(string ImagePath){OriginImage = new Bitmap(ImagePath);this.DisplayImage_pictureBox.Image = OriginImage;}/// <summary>///  鼠标左键按下 触发/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void OnMouseDown(object sender, MouseEventArgs e){// 如果是鼠标左键 按下if (e.Button == MouseButtons.Left){// 设置为true 表示开始要画矩形了StartDraw = true;// 记录 鼠标左键按下的坐标MouseDownPoint = new Point(e.X, e.Y);}}/// <summary>/// 鼠标移动/// 实时记录移动的坐标/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void OnMouseMove(object sender, MouseEventArgs e){// 实时记录移动的坐标MouseMovePoint = e.Location;// 判断是否开始画矩形if (StartDraw){// 设置 矩形的左上角 XY坐标,和 长宽CaptureRectangle.X = MouseDownPoint.X - MouseMovePoint.X < 0 ? MouseDownPoint.X : MouseMovePoint.X;CaptureRectangle.Width = Math.Abs(MouseDownPoint.X - MouseMovePoint.X);CaptureRectangle.Y = MouseDownPoint.Y - MouseMovePoint.Y < 0 ? MouseDownPoint.Y : MouseMovePoint.Y;CaptureRectangle.Height = Math.Abs(MouseDownPoint.Y - MouseMovePoint.Y);// 促使图像失效,重新绘制图像this.DisplayImage_pictureBox.Invalidate();}}private void OnMouseUp(object sender, MouseEventArgs e){StartDraw = false;}/// <summary>/// 重新绘制/// 可以防止 在快速拖动 FORM窗口时 绘画的图像抖动/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void OnPaint(object sender, PaintEventArgs e){if (StartDraw){Pen p = new Pen(Color.YellowGreen, 1);p.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;e.Graphics.DrawRectangle(p, CaptureRectangle);}//Create pens &points// 创建一个画笔工具,红色,画笔的粗细是1//Pen redPen = new Pen(Color.Red, 1);//Draw rectangles to screen.// 画笔工具的构造函数// 矩形 ,矩形左上角坐标 XY  矩形的宽高//Rectangle rect = new Rectangle(20, 20, 80, 40);//创建画板//e.Graphics.DrawRectangle(redPen, rect);//Dispose//redPen.Dispose();}}
}

移动 ROI 区域
第4

要增加一个 按钮

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;namespace GDI_Text
{public partial class Form1 : Form{private Bitmap OriginImage;            //原始位图private Point MouseDownPoint;         //鼠标按下坐标private Point MouseMovePoint;         //鼠标移动坐标private Point MouseUpPoint;           //鼠标弹起坐标private Point TempStart_Point;        //记录下矩形当前位置private bool IsMoving;               //移动状态private bool StartDraw;              //开始画ROI对象private bool FinishedDraw;           //完成画ROI对象private bool BlockWidth;             //锁定ROI宽度private bool BlockHeight;            //锁定ROI高度private Rectangle CaptureRectangle;       //当前ROI对象    // 为了改变矩形大小的时候用得到private Rectangle[] m_OperateRectangle;     //ROI周边8个小矩形框private SolidBrush SolidBrushObject;       //画刷对象public Form1(){InitializeComponent();// 类的成员初始化MouseDownPoint = new Point(0, 0);MouseMovePoint = new Point(0, 0);MouseUpPoint = new Point(0, 0);TempStart_Point = new Point(0, 0);StartDraw = false;IsMoving = false;BlockWidth = false;BlockHeight = false;FinishedDraw = false;SolidBrushObject = new SolidBrush(Color.YellowGreen);// 对数组的初始化赋值,这是8个小矩形的m_OperateRectangle = new Rectangle[8];for (int i = 0; i < 8; i++){// 矩形的 X Y 坐标是 0  0 ,矩形的宽高是 10  10m_OperateRectangle[i] = new Rectangle(0, 0, 10, 10);}}private void Form1_Load(object sender, EventArgs e){// 位图对象实例化LoadImage("demo.png");// 设置双缓冲SetDoubleBuffering();}/// <summary>/// 设置双缓存,防止图片闪烁/// </summary>private void SetDoubleBuffering(){this.SetStyle(ControlStyles.ResizeRedraw, true);this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);this.SetStyle(ControlStyles.UserPaint, true);this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);this.UpdateStyles();}/// <summary>/// 改变鼠标样式/// </summary>private void ChangeCursor(Point loc, bool DrawOrMove){if (DrawOrMove){if (m_OperateRectangle[0].Contains(loc) || m_OperateRectangle[7].Contains(loc))this.Cursor = Cursors.SizeNWSE;else if (m_OperateRectangle[1].Contains(loc) || m_OperateRectangle[6].Contains(loc))this.Cursor = Cursors.SizeNS;else if (m_OperateRectangle[2].Contains(loc) || m_OperateRectangle[5].Contains(loc))this.Cursor = Cursors.SizeNESW;else if (m_OperateRectangle[3].Contains(loc) || m_OperateRectangle[4].Contains(loc))this.Cursor = Cursors.SizeWE;else if (CaptureRectangle.Contains(loc))this.Cursor = Cursors.SizeAll;elsethis.Cursor = Cursors.Default;}}/// <summary>/// 加载图像/// </summary>/// <param name="ImagePath"></param>private void LoadImage(string ImagePath){OriginImage = new Bitmap(ImagePath);this.DisplayImage_pictureBox.Image = OriginImage;}/// <summary>/// MouseEventArgs e 当前鼠标/// MouseState=1:当鼠标双击ROI之外的图像区域时候,保留已存在ROI区域;/// MouseState=2:根据鼠标在8个矩形框位置来确定是改变宽度还是高度;/// /// 这个 8个小矩形的布局,从上到下,从左到右,每一层一层的数/// 0  1  2/// 3     4/// 5  6  7/// /// 鼠标在 这个 3  和4  是锁定了 高度/// 鼠标在 这个 1 和 6 是锁定宽度/// /// /// </summary>private void KeepMouseState(int MouseState, MouseEventArgs e){// 这个m_OperateRectangle 表示那8个小矩形// 鼠标左键按下的时候位置在不在这8个小矩形的哪个的框里if (m_OperateRectangle[0].Contains(e.Location)){//这个 CaptureRectangle 是当前ROI对象,把X Y 坐标 给别人// 这个 MouseMovePoint 是鼠标移动坐标MouseMovePoint.X = this.CaptureRectangle.Right;MouseMovePoint.Y = this.CaptureRectangle.Bottom;}else if (m_OperateRectangle[1].Contains(e.Location)){MouseMovePoint.Y = this.CaptureRectangle.Bottom;BlockWidth = true;}else if (m_OperateRectangle[2].Contains(e.Location)){MouseMovePoint.X = this.CaptureRectangle.X;MouseMovePoint.Y = this.CaptureRectangle.Bottom;}else if (m_OperateRectangle[3].Contains(e.Location)){MouseMovePoint.X = this.CaptureRectangle.Right;BlockHeight = true;}else if (m_OperateRectangle[4].Contains(e.Location)){MouseMovePoint.X = this.CaptureRectangle.X;BlockHeight = true;}else if (m_OperateRectangle[5].Contains(e.Location)){MouseMovePoint.X = this.CaptureRectangle.Right;MouseMovePoint.Y = this.CaptureRectangle.Y;}else if (m_OperateRectangle[6].Contains(e.Location)){MouseMovePoint.Y = this.CaptureRectangle.Y;BlockWidth = true;}else if (m_OperateRectangle[7].Contains(e.Location)){MouseMovePoint = this.CaptureRectangle.Location;}else if (this.CaptureRectangle.Contains(e.Location)){// 这里啥也不干,才能表示要移动ROI的位置}else{//当在ROI矩形外按下鼠标,保留现有的ROI,防止ROI被刷掉if (MouseState == 1){StartDraw = false;}}}/// <summary>///  鼠标左键按下 触发/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void OnMouseDown(object sender, MouseEventArgs e){if (e.Button == MouseButtons.Left){StartDraw = true;// 不锁定 宽高,矩形在调整大小的时候BlockWidth = false;BlockHeight = false;KeepMouseState(1, e);MouseDownPoint = new Point(e.X, e.Y);//通过鼠标移动坐标位置来判断是改变ROI大小还是移动ROI操作// 这个 FinishedDraw 为true 表示矩形已经画了,if (FinishedDraw){// 判断鼠标的位置是否在矩形里面,是的话表示要移动if (this.CaptureRectangle.Contains(e.Location)){IsMoving = true;}else{IsMoving = false;}}}}/// <summary>/// 鼠标移动/// 实时记录移动的坐标/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void OnMouseMove(object sender, MouseEventArgs e){// 改变鼠标的样式,分鼠标在ROI的范围内还是外ChangeCursor(e.Location, true);// 表示鼠标正在画if (StartDraw){// 判断鼠标移动的位置是否在8个矩形框里,还是在大ROI里KeepMouseState(2, e);}// 得出矩形的实时的大小if (StartDraw){// 移动状态的矩形的 位置if(IsMoving){this.CaptureRectangle.X = TempStart_Point.X + e.X - MouseDownPoint.X;this.CaptureRectangle.Y = TempStart_Point.Y + e.Y - MouseDownPoint.Y;if (this.CaptureRectangle.X < 0) this.CaptureRectangle.X = 0;if (this.CaptureRectangle.Y < 0) this.CaptureRectangle.Y = 0;if (this.CaptureRectangle.Right > OriginImage.Width) this.CaptureRectangle.X = OriginImage.Width - this.CaptureRectangle.Width - 1;if (this.CaptureRectangle.Bottom > OriginImage.Height) this.CaptureRectangle.Y = OriginImage.Height - this.CaptureRectangle.Height - 1;}else { // 鼠标不是在移动中,就要改变矩形的大小if (Math.Abs(e.X - MouseMovePoint.X) > 1 || Math.Abs(e.Y - MouseMovePoint.Y) > 1){if ((e.X >= 0 && e.X <= this.OriginImage.Width) && (e.Y >= 0 && e.Y <= this.OriginImage.Height)){//当前坐标在图像区域}else{//当前坐标不在图像区域return;}// 锁定宽if (!BlockWidth){CaptureRectangle.X = MouseMovePoint.X - e.X < 0 ? MouseMovePoint.X : e.X;//以CaptureRectangle的Left或Right为正负分界线,//MouseMovePoint.X - e.X < 0:正向方向改变大小,MouseMovePoint.X - e.X > 0:负向方向改变大小CaptureRectangle.Width = Math.Abs(MouseMovePoint.X - e.X);}// 锁定高if (!BlockHeight){CaptureRectangle.Y = MouseMovePoint.Y - e.Y < 0 ? MouseMovePoint.Y : e.Y;//以CaptureRectangle的Top或Bttom为正负分界线,//MouseMovePoint.Y - e.Y < 0:正向方向改变大小,MouseMovePoint.Y - e.Y > 0:负向方向改变大小CaptureRectangle.Height = Math.Abs(MouseMovePoint.Y - e.Y);}}}this.DisplayImage_pictureBox.Invalidate();}}/// <summary>///  鼠标左键弹起,表示ROI画好了,置为 false/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void OnMouseUp(object sender, MouseEventArgs e){if (e.Button == MouseButtons.Left){StartDraw = false;//记录下鼠标弹起时,ROI当前位置TempStart_Point = CaptureRectangle.Location;}}/// <summary>/// 重新绘制/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void OnPaint(object sender, PaintEventArgs e){if (FinishedDraw){Pen p = new Pen(Color.YellowGreen, 1);p.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;e.Graphics.DrawRectangle(p, CaptureRectangle);DrawOperationBox(e.Graphics);}}/// <summary>/// 绘制8个小矩形框/// </summary>/// <param name="g"></param>protected virtual void DrawOperationBox(Graphics g){m_OperateRectangle[0].X = this.CaptureRectangle.X - 5;m_OperateRectangle[0].Y = this.CaptureRectangle.Y - 5;m_OperateRectangle[1].X = this.CaptureRectangle.X + this.CaptureRectangle.Width / 2 - 5;m_OperateRectangle[1].Y = m_OperateRectangle[2].Y = this.CaptureRectangle.Y - 7;m_OperateRectangle[2].X = this.CaptureRectangle.Right - 5;m_OperateRectangle[2].Y = this.CaptureRectangle.Y - 5;m_OperateRectangle[3].X = this.CaptureRectangle.X - 7;m_OperateRectangle[3].Y = this.CaptureRectangle.Y + this.CaptureRectangle.Height / 2 - 5;m_OperateRectangle[4].X = this.CaptureRectangle.Right - 2;m_OperateRectangle[4].Y = this.CaptureRectangle.Y + this.CaptureRectangle.Height / 2 - 5;m_OperateRectangle[5].X = this.CaptureRectangle.X - 5;m_OperateRectangle[5].Y = this.CaptureRectangle.Bottom - 5;m_OperateRectangle[6].X = this.CaptureRectangle.X + this.CaptureRectangle.Width / 2 - 5;m_OperateRectangle[6].Y = this.CaptureRectangle.Bottom - 2;m_OperateRectangle[7].X = this.CaptureRectangle.Right - 5;m_OperateRectangle[7].Y = this.CaptureRectangle.Bottom - 5;if (this.CaptureRectangle.Width > 10 && this.CaptureRectangle.Height > 10){SolidBrushObject.Color = Color.YellowGreen;foreach (Rectangle rect in m_OperateRectangle){g.FillRectangle(SolidBrushObject, rect);}}}/// <summary>/// 用鼠标在图像上一点,画一个默认的矩形
这个是一个 按钮的点击事件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void OnDrawRectangle(object sender, EventArgs e){// 设定矩形的参数CaptureRectangle.X = OriginImage.Width / 2;CaptureRectangle.Width = OriginImage.Width / 4;CaptureRectangle.Y = OriginImage.Height / 2;CaptureRectangle.Height = OriginImage.Height / 4;TempStart_Point = CaptureRectangle.Location;FinishedDraw = true;  // 表示 开始画8个小矩形IsMoving = false;  // 画矩形的时候,不是移动状态this.DisplayImage_pictureBox.Invalidate();}}
}

剪切 画好的ROI

增加一个 picture box
小窗口的属性设置为这个

增加了一个函数

        /// <summary>/// 剪切图像/// </summary>private void CutImage(){// 创建位图Bitmap CutBitmap = new Bitmap(CaptureRectangle.Width, CaptureRectangle.Height);// 创建画板 ,空的位图Graphics GraphicsObject = Graphics.FromImage(CutBitmap);// 向画板 画一张图像,原始图是OriginImage,把原始图像中的ROI区域,画进去GraphicsObject.DrawImage(OriginImage, new Rectangle(0, 0, CaptureRectangle.Width, CaptureRectangle.Height), CaptureRectangle, GraphicsUnit.Pixel);// 小的 picture 控件this.CutImage_pictureBox.Image = CutBitmap;this.CutImage_pictureBox.Width = CutBitmap.Width;this.CutImage_pictureBox.Height = CutBitmap.Height;GraphicsObject.Dispose();}

在鼠标弹起的时候调用

把 ROI 剪切的图像,转为 HALCON 变量

增加一个 按钮, 转halcon 变量
在 项目 的引用里 添加 halcon的dll文件

这个 项目属性  生成 要配置成  X64 才行

using System;
using System.IO;
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;
using HalconDotNet;namespace GDI_Text
{public partial class Form1 : Form{private Bitmap OriginImage;            //原始位图private Point MouseDownPoint;         //鼠标按下坐标private Point MouseMovePoint;         //鼠标移动坐标private Point MouseUpPoint;           //鼠标弹起坐标private Point TempStart_Point;        //记录下矩形当前位置private bool IsMoving;               //移动状态private bool StartDraw;              //开始画ROI对象private bool FinishedDraw;           //完成画ROI对象private bool BlockWidth;             //锁定ROI宽度private bool BlockHeight;            //锁定ROI高度private Rectangle CaptureRectangle;       //当前ROI对象    // 为了改变矩形大小的时候用得到private Rectangle[] m_OperateRectangle;     //ROI周边8个小矩形框private SolidBrush SolidBrushObject;       //画刷对象public Form1(){InitializeComponent();// 类的成员初始化MouseDownPoint = new Point(0, 0);MouseMovePoint = new Point(0, 0);MouseUpPoint = new Point(0, 0);TempStart_Point = new Point(0, 0);StartDraw = false;IsMoving = false;BlockWidth = false;BlockHeight = false;FinishedDraw = false;SolidBrushObject = new SolidBrush(Color.YellowGreen);// 对数组的初始化赋值,这是8个小矩形的m_OperateRectangle = new Rectangle[8];for (int i = 0; i < 8; i++){// 矩形的 X Y 坐标是 0  0 ,矩形的宽高是 10  10m_OperateRectangle[i] = new Rectangle(0, 0, 10, 10);}}private void Form1_Load(object sender, EventArgs e){// 位图对象实例化LoadImage("demo.png");// 设置双缓冲SetDoubleBuffering();}/// <summary>/// 设置双缓存,防止图片闪烁/// </summary>private void SetDoubleBuffering(){this.SetStyle(ControlStyles.ResizeRedraw, true);this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);this.SetStyle(ControlStyles.UserPaint, true);this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);this.UpdateStyles();}/// <summary>/// 改变鼠标样式/// </summary>private void ChangeCursor(Point loc, bool DrawOrMove){if (DrawOrMove){if (m_OperateRectangle[0].Contains(loc) || m_OperateRectangle[7].Contains(loc))this.Cursor = Cursors.SizeNWSE;else if (m_OperateRectangle[1].Contains(loc) || m_OperateRectangle[6].Contains(loc))this.Cursor = Cursors.SizeNS;else if (m_OperateRectangle[2].Contains(loc) || m_OperateRectangle[5].Contains(loc))this.Cursor = Cursors.SizeNESW;else if (m_OperateRectangle[3].Contains(loc) || m_OperateRectangle[4].Contains(loc))this.Cursor = Cursors.SizeWE;else if (CaptureRectangle.Contains(loc))this.Cursor = Cursors.SizeAll;elsethis.Cursor = Cursors.Default;}}/// <summary>/// 加载图像/// </summary>/// <param name="ImagePath"></param>private void LoadImage(string ImagePath){OriginImage = new Bitmap(ImagePath);this.DisplayImage_pictureBox.Image = OriginImage;}/// <summary>/// MouseEventArgs e 当前鼠标/// MouseState=1:当鼠标双击ROI之外的图像区域时候,保留已存在ROI区域;/// MouseState=2:根据鼠标在8个矩形框位置来确定是改变宽度还是高度;/// /// 这个 8个小矩形的布局,从上到下,从左到右,每一层一层的数/// 0  1  2/// 3     4/// 5  6  7/// /// 鼠标在 这个 3  和4  是锁定了 高度/// 鼠标在 这个 1 和 6 是锁定宽度/// /// /// </summary>private void KeepMouseState(int MouseState, MouseEventArgs e){// 这个m_OperateRectangle 表示那8个小矩形// 鼠标左键按下的时候位置在不在这8个小矩形的哪个的框里if (m_OperateRectangle[0].Contains(e.Location)){//这个 CaptureRectangle 是当前ROI对象,把X Y 坐标 给别人// 这个 MouseMovePoint 是鼠标移动坐标MouseMovePoint.X = this.CaptureRectangle.Right;MouseMovePoint.Y = this.CaptureRectangle.Bottom;}else if (m_OperateRectangle[1].Contains(e.Location)){MouseMovePoint.Y = this.CaptureRectangle.Bottom;BlockWidth = true;}else if (m_OperateRectangle[2].Contains(e.Location)){MouseMovePoint.X = this.CaptureRectangle.X;MouseMovePoint.Y = this.CaptureRectangle.Bottom;}else if (m_OperateRectangle[3].Contains(e.Location)){MouseMovePoint.X = this.CaptureRectangle.Right;BlockHeight = true;}else if (m_OperateRectangle[4].Contains(e.Location)){MouseMovePoint.X = this.CaptureRectangle.X;BlockHeight = true;}else if (m_OperateRectangle[5].Contains(e.Location)){MouseMovePoint.X = this.CaptureRectangle.Right;MouseMovePoint.Y = this.CaptureRectangle.Y;}else if (m_OperateRectangle[6].Contains(e.Location)){MouseMovePoint.Y = this.CaptureRectangle.Y;BlockWidth = true;}else if (m_OperateRectangle[7].Contains(e.Location)){MouseMovePoint = this.CaptureRectangle.Location;}else if (this.CaptureRectangle.Contains(e.Location)){// 这里啥也不干,才能表示要移动ROI的位置}else{//当在ROI矩形外按下鼠标,保留现有的ROI,防止ROI被刷掉if (MouseState == 1){StartDraw = false;}}}/// <summary>///  鼠标左键按下 触发/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void OnMouseDown(object sender, MouseEventArgs e){if (e.Button == MouseButtons.Left){StartDraw = true;// 不锁定 宽高,矩形在调整大小的时候BlockWidth = false;BlockHeight = false;KeepMouseState(1, e);MouseDownPoint = new Point(e.X, e.Y);//通过鼠标移动坐标位置来判断是改变ROI大小还是移动ROI操作// 这个 FinishedDraw 为true 表示矩形已经画了,if (FinishedDraw){// 判断鼠标的位置是否在矩形里面,是的话表示要移动if (this.CaptureRectangle.Contains(e.Location)){IsMoving = true;}else{IsMoving = false;}}}}/// <summary>/// 鼠标移动/// 实时记录移动的坐标/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void OnMouseMove(object sender, MouseEventArgs e){// 改变鼠标的样式,分鼠标在ROI的范围内还是外ChangeCursor(e.Location, true);// 表示鼠标正在画if (StartDraw){// 判断鼠标移动的位置是否在8个矩形框里,还是在大ROI里KeepMouseState(2, e);}// 得出矩形的实时的大小if (StartDraw){// 移动状态的矩形的 位置if (IsMoving){this.CaptureRectangle.X = TempStart_Point.X + e.X - MouseDownPoint.X;this.CaptureRectangle.Y = TempStart_Point.Y + e.Y - MouseDownPoint.Y;if (this.CaptureRectangle.X < 0) this.CaptureRectangle.X = 0;if (this.CaptureRectangle.Y < 0) this.CaptureRectangle.Y = 0;if (this.CaptureRectangle.Right > OriginImage.Width) this.CaptureRectangle.X = OriginImage.Width - this.CaptureRectangle.Width - 1;if (this.CaptureRectangle.Bottom > OriginImage.Height) this.CaptureRectangle.Y = OriginImage.Height - this.CaptureRectangle.Height - 1;}else{// 鼠标不是在移动中,就要改变矩形的大小if (Math.Abs(e.X - MouseMovePoint.X) > 1 || Math.Abs(e.Y - MouseMovePoint.Y) > 1){if ((e.X >= 0 && e.X <= this.OriginImage.Width) && (e.Y >= 0 && e.Y <= this.OriginImage.Height)){//当前坐标在图像区域}else{//当前坐标不在图像区域return;}// 锁定宽if (!BlockWidth){CaptureRectangle.X = MouseMovePoint.X - e.X < 0 ? MouseMovePoint.X : e.X;//以CaptureRectangle的Left或Right为正负分界线,//MouseMovePoint.X - e.X < 0:正向方向改变大小,MouseMovePoint.X - e.X > 0:负向方向改变大小CaptureRectangle.Width = Math.Abs(MouseMovePoint.X - e.X);}// 锁定高if (!BlockHeight){CaptureRectangle.Y = MouseMovePoint.Y - e.Y < 0 ? MouseMovePoint.Y : e.Y;//以CaptureRectangle的Top或Bttom为正负分界线,//MouseMovePoint.Y - e.Y < 0:正向方向改变大小,MouseMovePoint.Y - e.Y > 0:负向方向改变大小CaptureRectangle.Height = Math.Abs(MouseMovePoint.Y - e.Y);}}}//使画布无效,从而执行OnPaint()this.DisplayImage_pictureBox.Invalidate();}}/// <summary>///  鼠标左键弹起,表示ROI画好了,置为 false/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void OnMouseUp(object sender, MouseEventArgs e){if (e.Button == MouseButtons.Left){StartDraw = false;//记录下鼠标弹起时,ROI当前位置TempStart_Point = CaptureRectangle.Location;// 鼠标左键 弹起的时候,在小窗口显示ROI区域中间的图像CutImage();}}/// <summary>/// 剪切图像/// </summary>private Bitmap CutImage(){// 创建位图Bitmap CutBitmap = new Bitmap(CaptureRectangle.Width, CaptureRectangle.Height);// 创建画板 ,空的位图Graphics GraphicsObject = Graphics.FromImage(CutBitmap);// 向画板 画一张图像,原始图是OriginImage,把原始图像中的ROI区域,画进去GraphicsObject.DrawImage(OriginImage, new Rectangle(0, 0, CaptureRectangle.Width, CaptureRectangle.Height), CaptureRectangle, GraphicsUnit.Pixel);// 小的 picture 控件this.CutImage_pictureBox.Image = CutBitmap;this.CutImage_pictureBox.Width = CutBitmap.Width;this.CutImage_pictureBox.Height = CutBitmap.Height;GraphicsObject.Dispose();return CutBitmap;}/// <summary>/// 重新绘制/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void OnPaint(object sender, PaintEventArgs e){if (FinishedDraw){Pen p = new Pen(Color.YellowGreen, 1);p.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;e.Graphics.DrawRectangle(p, CaptureRectangle);//绘制8个小矩形框DrawOperationBox(e.Graphics);}}/// <summary>/// 绘制8个小矩形框/// </summary>/// <param name="g"></param>protected virtual void DrawOperationBox(Graphics g){m_OperateRectangle[0].X = this.CaptureRectangle.X - 5;m_OperateRectangle[0].Y = this.CaptureRectangle.Y - 5;m_OperateRectangle[1].X = this.CaptureRectangle.X + this.CaptureRectangle.Width / 2 - 5;m_OperateRectangle[1].Y = m_OperateRectangle[2].Y = this.CaptureRectangle.Y - 7;m_OperateRectangle[2].X = this.CaptureRectangle.Right - 5;m_OperateRectangle[2].Y = this.CaptureRectangle.Y - 5;m_OperateRectangle[3].X = this.CaptureRectangle.X - 7;m_OperateRectangle[3].Y = this.CaptureRectangle.Y + this.CaptureRectangle.Height / 2 - 5;m_OperateRectangle[4].X = this.CaptureRectangle.Right - 2;m_OperateRectangle[4].Y = this.CaptureRectangle.Y + this.CaptureRectangle.Height / 2 - 5;m_OperateRectangle[5].X = this.CaptureRectangle.X - 5;m_OperateRectangle[5].Y = this.CaptureRectangle.Bottom - 5;m_OperateRectangle[6].X = this.CaptureRectangle.X + this.CaptureRectangle.Width / 2 - 5;m_OperateRectangle[6].Y = this.CaptureRectangle.Bottom - 2;m_OperateRectangle[7].X = this.CaptureRectangle.Right - 5;m_OperateRectangle[7].Y = this.CaptureRectangle.Bottom - 5;if (this.CaptureRectangle.Width > 10 && this.CaptureRectangle.Height > 10){SolidBrushObject.Color = Color.YellowGreen;foreach (Rectangle rect in m_OperateRectangle){g.FillRectangle(SolidBrushObject, rect);}}}/// <summary>/// 用鼠标在图像上一点,画一个默认的矩形/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void OnDrawRectangle(object sender, EventArgs e){// 设定矩形的参数CaptureRectangle.X = OriginImage.Width / 2;CaptureRectangle.Width = OriginImage.Width / 4;CaptureRectangle.Y = OriginImage.Height / 2;CaptureRectangle.Height = OriginImage.Height / 4;TempStart_Point = CaptureRectangle.Location;FinishedDraw = true;  // 表示 开始画8个小矩形IsMoving = false;  // 画矩形的时候,不是移动状态this.DisplayImage_pictureBox.Invalidate();}private void pictureBox1_Click(object sender, EventArgs e){}/// <summary>/// 转换 按钮事件/// 这个 ROI 剪切的图像 转HALCON 变量/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void ConvertHalcon(object sender, EventArgs e){Bitmap CutBitmap = CutImage();HObject Image = BitmapToHobject(CutBitmap.Width, CutBitmap.Height, CutBitmap);string FileName = DateTime.Now.ToString("yyyy年MM月dd日HH时mm分ss秒fff毫秒");HOperatorSet.WriteImage(Image, "bmp", 0, Directory.GetCurrentDirectory() + "/" + FileName + ".bmp");}/// <summary>/// Bitmap位图转halcon Hobject图像类型///  4通道/// </summary>/// <param name="Width"></param>/// <param name="Height"></param>/// <param name="MyBitmap"></param>/// <returns></returns>public HObject BitmapToHobject(int Width, int Height, System.Drawing.Bitmap MyBitmap){HObject Image;// 锁住内存 ,Format32bppRgb 是32为的RGBSystem.Drawing.Imaging.BitmapData BitmapData = MyBitmap.LockBits(new Rectangle(0, 0, Width, Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppRgb);// 在C#里使用 C++的代码// 在属性里设置,生成 ,允许不安全代码unsafe{//图像数据排列BGR// 这个 Scan0 表示位图的第一个像素的地址byte* Inptr = (byte*)(BitmapData.Scan0.ToPointer());// 三个数组表示 RGB 三个通道,还有一个通道不用管byte[] R_OutBuffer = new byte[Width * Height];byte[] G_OutBuffer = new byte[Width * Height];byte[] B_OutBuffer = new byte[Width * Height];// 三个通道 指针 初始化fixed (byte* R_Outptr = R_OutBuffer, G_Outptr = G_OutBuffer, B_Outptr = B_OutBuffer){// 将图像数据里的像素,依次放到 RGB 三个数组for (int i = 0; i < Height; i++){for (int j = 0; j < Width; j++){// 这个 乘4 ,是表示4个通道int Index = (i * Width + j) * 4;B_OutBuffer[Index / 4] = (byte)Inptr[Index + 0];G_OutBuffer[Index / 4] = (byte)Inptr[Index + 1];R_OutBuffer[Index / 4] = (byte)Inptr[Index + 2];}}// 解除锁定MyBitmap.UnlockBits(BitmapData);//将 RGB 三通道转为 HALCON 的图像HOperatorSet.GenImage3(out Image, "byte", Width, Height, new IntPtr(R_Outptr), new IntPtr(G_Outptr), new IntPtr(B_Outptr));return Image;}}}}
}


 


http://chatgpt.dhexx.cn/article/7whkJ3Jk.shtml

相关文章

OpenCV之图像ROI与ROI操作

python代码&#xff1a; import cv2 as cv import numpy as npsrc cv.imread("./test.png") cv.namedWindow("input", cv.WINDOW_AUTOSIZE) cv.imshow("input", src) h, w src.shape[:2]# 获取ROI cy h//2 cx w//2 roi src[cy-100:cy100,c…

ROI Pooling和ROI Align、ROI Warp解析

文中很多内容来源于其他博客&#xff0c;较为详细&#xff0c;有需要可直接按目录跳选到自己需要的部分。 目录 简单介绍 实验比较 ROI理解 ROI Pooling ROI Pooling理解 ROI Pooling example ROI Pooling局限性 ROI Align理解 双线性插值法 ROI Align的反向传播 R…

RoI Pooling 和 RoI Align

RoI Pooling 和 RoI Align 一、背景和基本概念1.背景2.基本概念 二、RoI Pooling原理1.目的2.步骤&#xff08;以输出RoI feature大小为225为例&#xff09;Step1Step2Step3Step4 三、RoI Align原理1.目的2.步骤&#xff08;以输出RoI feature大小为225为例&#xff09;step1St…

ROI Pooling解析

ROI Pooling最早由Ross Girshick在2015年的论文fast rcnn中提出&#xff0c;是对ROI(Region of Interest)的Pooling操作&#xff0c;广泛应用于物体检测的研究领域。该操作旨在对输入特征图中不同大小的ROI利用池化方法获得固定大小的输出特征图。 ROI Pooling层的输入&#x…

ROI

栗子&#xff1a; #include<cv.h> #include<highgui.h> using namespace cv; //方法1&#xff0c;假如区域为长方形&#xff0c;使用MAT 构造函数设置区域内的值为255 int main() {Mat imageimread("boldt.jpg");//初始化掩模矩阵Mat mask Mat::zeros(…

OpenCV--0016:图像ROI与ROI操作

文章目录 一、图像ROI1. 概念2. 图像ROI操作2.1 矩形感兴趣区域2.1.1 使用Rect函数2.1.2 使用Range2.1.3 应用实例 2.2 不规则ROI区域2.2.1 通过inRange函数生成mask2.2.2 通过“与”操作提取ROI 一、图像ROI 1. 概念 图像ROI&#xff08;region of interest&#xff09;是指…

ROI pooling 和 ROI Align详解

ROI Align 是在Mask-RCNN这篇论文里提出的一种区域特征聚集方式, 很好地解决了ROI Pooling操作中两次量化造成的区域不匹配(mis-alignment)的问题。实验显示&#xff0c;在检测测任务中将 ROI Pooling 替换为 ROI Align 可以提升检测模型的准确性。 ROI Pooling 的局限性分析 …

【深度学习】ROI Pooling 和 ROI Align 计算机视觉 目标检测

文章目录 ROI Pooling和ROI Align&#xff1a;一篇好的文章ROI Pooling 如何计算&#xff1f;AdaptiveMaxPool2d 在做啥Fast RCNN或者Faster RCNN中都使用了ROI PoolingROI Align ROI Pooling和ROI Align&#xff1a; &#xff08;1&#xff09;ROI Pooling 是为了让特征图输出…

ROI Pooling

RCNN ref 1 步骤: 1.使用Selective Search方法生成候选区域 2.对每一个候选区域使用CNN进行特征提取 3.对提取到的特征送入到每一类的SVM分类器 判断该区域是否属于该类特征 4.使用回归器精修候选框的位置 候选框搜索阶段: 使用selective search方法生成候选框,由于CNN提取…

ROI 详解

SPPNet、roi pooling 和 average pooling之间的区别&#xff0c;都是起到对任意大小的输入产生固定的输出的作用。其中SPPNet、roi pooling是一样的。 下面对ROI Pooling 进行详解&#xff1a; ROI是Region of Interest的简写&#xff0c;指的是在“特征图上的框”&#xff1…

【深度学习小知识】ROI到ROI pooling 再到ROI Align

ROI&#xff01;RoI Pooling&#xff01; ROI详解RoI Pooling详解Pooling操作ROI pooling ROI Align详解 ROI详解 Region of interest(ROI),中文译为感兴趣区域。在计算机视觉领域&#xff0c;从输入的图像中框选处理待处理的区域就是ROI。 ROI / Region proposals大致过程&am…

MD5密钥

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

漫画戏说:如何破解MD5加密算法

本文将通过漫画的形式来解释&#xff1a;如何破解MD5加密算法。其中包括了暴力枚举法、字典法、彩虹表法三种破解MD5加密算法的方法。MD5破解原理都是利用了&#xff0c;被加密的数据与MD5加密算法所生成的哈希值并不是一一对应的关系&#xff0c;而是多对一&#xff0c;也就是…

基于量子计算的md5密码哈希破解方法

基于量子计算的md5密码哈希破解方法 背景 Md5密文破解&#xff08;解密&#xff09;可以说是网络攻击中的一个必不可少的环节&#xff0c;是黑客工具中的一个重要“辅助工具”。md5解密主要用于网络攻击&#xff0c;在对网站等进行入侵过程&#xff0c;有可能获得管理员或者其…

MD5与SHA

不管是MD5还是SHA&#xff0c;这一切的根本都是哈希算法&#xff0c;即单向函数 MD5 全称为 消息摘要算法版本5 &#xff08;Message Digest Algorithm 5&#xff09; 首先我要强调的是&#xff0c;MD5并不是加密算法&#xff0c;它是一种哈希散列算法。 但是其往往可以应用…

使用rainbowcrack破解md5密文

文章目录 1、rainbowcrack下载2、文件说明3、使用流程3.1 生成彩虹表3.2 排序彩虹表3.3 使用刚生成的彩虹表破解密文 4、实例4.1 生成彩虹表4.2 彩虹表排序4.3 破解密文 1、rainbowcrack下载 下载链接 2、文件说明 3、使用流程 环境&#xff1a;windows 前提&#xff1a;进入…

MD5算法破解思路

https://blog.csdn.net/wufaliang003/article/details/79794982 小明&#xff1a;老师&#xff0c;上次您讲了MD5算法。用它生成的信息摘要&#xff0c;真的可以被破解吗&#xff1f; 老师&#xff1a;有很多种方法可以破解&#xff0c;不过需要明确一点&#xff0c;这里所谓的…

MD5密文破解实验

实验目的与要求 1、 了解MD5加密的基本原理 2、 使用MD5Crack工具进行MD5解密 3、 使用网络资源对密文进行在线破解 4、 认真阅读并掌握本实验相关的知识点 5、上机实现实验所提到的工具和操作&#xff0c;得到实验结果&#xff0c;并填写实验报告 预备知识 MD5介绍 199…

破解MD5加密

本文摘自漫画戏说&#xff1a;如何破解MD5加密算法TOMORROW星辰 前言 这里所谓的破解并非是要把摘要还原成原文。因为MD5算法是用有穷的128位表示无穷的原文。对于MD5的破解&#xff0c;实际上都属于碰撞&#xff0c;比如原文A可以 通过MD5生成摘要M&#xff0c;我们只要找到…

MD5摘要算法的几种破解方法!

你知道的越多&#xff0c;不知道的就越多&#xff0c;业余的像一棵小草&#xff01; 你来&#xff0c;我们一起精进&#xff01;你不来&#xff0c;我和你的竞争对手一起精进&#xff01; 编辑&#xff1a;业余草 推荐&#xff1a;https://www.xttblog.com/?p5259 MD5 算法暴力…