绘制矩形的按钮,动态绘制ROI区域并显示在另外的指定区域C#、OpenCVSharp、OpenCV

在加载好的图像上可以用鼠标绘制矩形的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

自我总结点滴,欢迎批评指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值