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
// 创建一个画笔工具,红色,画笔的粗细是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图形的 参数,要调用第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 10
m_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;
else
this.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 10
m_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;
else
this.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为的RGB
System.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;
}
}
}
}
}