在加载好的图像上可以用鼠标绘制矩形的ROI区域,结束绘制后可以将“抠”出来的区域呈现在另外一个控件上。
开始绘制时判断是否有图像,因为是在图像上绘制;启用编辑模式和绘画状态下才能绘画;按钮或者右键结束绘制。
// 开始绘制按钮
private void BtnDrawing_Click(object sender, EventArgs e)
{
if (src.Empty())
{
MessageBox.Show("请先选择图像文件!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
try
{
BtnDrawing.Enabled = false;
pictureBox1.Invalidate(); // 刷新以触发重绘
MessageBox.Show("请开始绘制,右键结束绘制!");
}
catch (Exception ex)
{
string msg = ex.Message;
}
isEditMode = true;
BtnDrawing.Enabled = false;
isDrawing = false;
}
// 结束绘制
private void BtnEndDrawing_Click(object sender, EventArgs e)
{
EndDrawing();
return;
}
#region 画矩形框动作
private Mat src = new Mat(); // 存储加载的图像
private Point sp = new Point(-1, -1); // 矩形的起点
private Point ep = new Point(-1, -1); // 矩形的终点
private bool isDrawing = false; // 标记是否正在绘制矩形
private bool isEditMode = false; // 是否允许绘制和编辑(以防任意时候按右键都会弹出"绘制结束")
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (!isEditMode) return;
if (src.Empty())
{
MessageBox.Show("请先选择图像文件!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
Point point = new Point(e.Location.X, e.Location.Y);// 重新建立存储点的容器,point存放的的是鼠标在pictureBox中的坐标,要存点了
// 开始绘制矩形框
isDrawing = true; // 点的一瞬间要把绘画标识的旗子电亮
sp = TranslateToImageCoordinates(point);// 转化成图片中的坐标
ep = sp;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (!isEditMode) return;
Point point = new Point(e.Location.X, e.Location.Y);
if (isDrawing)
{
ep = TranslateToImageCoordinates(point);
pictureBox1.Invalidate(); // 刷新以触发重绘
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if (!isEditMode) return;
BtnEndDrawing.Enabled = true;
//if (e.Button == MouseButtons.Right)
//{
// // 右键点击结束绘制模式
// EndDrawing();
// return;
//}
Point point = new Point(e.Location.X, e.Location.Y);
if (isDrawing)
{
isDrawing = false;
ep = TranslateToImageCoordinates(point);
// 获取ROI区域并在pictureBox2中显示
var x1 = Math.Min(sp.X, ep.X);
var y1 = Math.Min(sp.Y, ep.Y);
var x2 = Math.Max(sp.X, ep.X);
var y2 = Math.Max(sp.Y, ep.Y);
if (x2 > x1 && y2 > y1)
{
var roi = new Rect(x1, y1, x2 - x1, y2 - y1);
Mat roiMat = new Mat(src, roi);
pictureBox2.Image = roiMat.ToBitmap(); // 将ROI区域显示在pictureBox2中
}
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (isDrawing)
{
// 将矩形框的图像坐标转换为PictureBox坐标
var spBox = TranslateToPictureBoxCoordinates(sp);
var epBox = TranslateToPictureBoxCoordinates(ep);
// 绘制当前的矩形框
int x1 = Math.Min(spBox.X, epBox.X);
int y1 = Math.Min(spBox.Y, epBox.Y);
int width = Math.Abs(epBox.X - spBox.X);
int height = Math.Abs(epBox.Y - spBox.Y);
using (var pen = new Pen(Color.Red, 2))
{
e.Graphics.DrawRectangle(pen, x1, y1, width, height);
}
}
}
// 将PictureBox坐标转换为图像实际坐标
private Point TranslateToImageCoordinates(Point pbCoordinates)
{
//if (pictureBox1.Image == null) return Point.Empty;
var imgWidth = src.Width;
var imgHeight = src.Height;
var pbWidth = pictureBox1.ClientSize.Width;
var pbHeight = pictureBox1.ClientSize.Height;
// 计算缩放比例(Zoom模式下,长边先达到,所以用min)
float scale = Math.Min((float)pbWidth / imgWidth, (float)pbHeight / imgHeight);
// 计算图片在PictureBox居中时的偏移量
int offsetX = (int)((pbWidth - imgWidth * scale) / 2);
int offsetY = (int)((pbHeight - imgHeight * scale) / 2);
// 将PictureBox坐标转换为图像坐标
int imgX = (int)((pbCoordinates.X - offsetX) / scale);
int imgY = (int)((pbCoordinates.Y - offsetY) / scale);
// 限制坐标范围
imgX = Math.Max(0, Math.Min(imgX, imgWidth - 1));
imgY = Math.Max(0, Math.Min(imgY, imgHeight - 1));
return new Point(imgX, imgY);
}
// 将图像坐标转换为PictureBox的坐标
private Point TranslateToPictureBoxCoordinates(Point imgCoordinates)
{
var imgWidth = src.Width;
var imgHeight = src.Height;
var pbWidth = pictureBox1.ClientSize.Width;
var pbHeight = pictureBox1.ClientSize.Height;
// 计算缩放比例
float scale = Math.Min((float)pbWidth / imgWidth, (float)pbHeight / imgHeight);
// 计算图片在PictureBox居中时的偏移量
int offsetX = (int)((pbWidth - imgWidth * scale) / 2);
int offsetY = (int)((pbHeight - imgHeight * scale) / 2);
// 将图像坐标转换为PictureBox坐标
int pbX = (int)(imgCoordinates.X * scale + offsetX);
int pbY = (int)(imgCoordinates.Y * scale + offsetY);
return new Point(pbX, pbY);
}
// 右键触发的具体动作方法实现
private void EndDrawing()
{
MessageBox.Show("绘制模式已关闭");
isEditMode = false; // 禁用编辑模式
BtnDrawing.Enabled = true;// 将开始绘制按钮置为可用
}
#endregion
自我总结点滴,欢迎批评指正。