OpenCV实现简单的套索工具

本文介绍了如何利用OpenCV实现一个简单的套索工具,模拟Photoshop中的套索功能。用户可以通过鼠标点击创建多边形区域,右键完成封闭并使用方向键移动选定区域。文章详细讲解了实现过程,包括鼠标事件处理和图像合成步骤。
摘要由CSDN通过智能技术生成

       Photoshop中的套索工具通过鼠标多次点击可以选中一个任意多边形的区域,然后单独对这块区域进行编辑,下面就使用OpenCV实现一个简单的功能,模拟Photoshop中的套索工具。
       这里的套索工具通过鼠标左键在图片上多次点击创建任意多个点,右键点击后将这些点连成封闭的多边形,形成一块待编辑的区域,键盘方向键控制该区域的移动,从而将该区域内的图像复制到原图像的其他地方。
      首先定义下列全局变量

const char* winName = "TaoSuoTool";//窗口名称
cv::Mat resultImg;//最终在OpenCV窗口上显示的图像
cv::Mat foregroundImg;//编辑前的图像
cv::Mat areaMask;//蒙版,多边形区域实际绘制在该蒙版上
cv::Point maskLocation;//蒙版位置,通过方向键移动后蒙版位置随之变化
std::vector<cv::Point> drawingPoints;//区域完成前正在点击的所有点
std::vector<cv::Point> areaPoints;//区域完成后其多边形顶点

       main函数

int main(int argc, char **arv)
{
    foregroundImg = cv::imread("test.jpg");
    foregroundImg.copyTo(resultImg);
    areaMask = cv::Mat::zeros(foregroundImg.size(), CV_8U);
    cv::imshow(winName, resultImg);

    maskLocation.x = maskLocation.y = 0;
    cv::setMouseCallback(winName, OnMouseEvent);
    int key = cv::waitKeyEx(0);
    while (key != VK_ESCAPE)
    {
        key = cv::waitKeyEx(0);
    }
    return 0;
}

       在鼠标回调函数OnMouseEvent中处理三个消息:鼠标左键按下,鼠标右键按下和鼠标移动

void OnMouseEvent(int event, int x, int y, int flags, void* userdata)
{
    if (event == cv::EVENT_LBUTTONDOWN)
    {
        OnLeftMouseButtonDown(x,y);
    }
    else if (event == cv::EVENT_RBUTTONDOWN)
    {
        OnRightMouseButtonDown(x,y);
    }
    if (event == cv::EVENT_MOUSEMOVE)
    {
        OnMouseMove(x,y);
    }
}

       在编写鼠标事件前先定义一个函数

void OnCompleteArea(bool bDrawOutline);

       它表示完成当前区域的编辑,包括右键点击完成封闭多边形、移动区域以及合成最终图片。参数bDrawOutline表示绘制区域多边形的外轮廓,右键点击完成封闭多边形和移动区域过程中都要显示轮廓(bDrawOutline=true),合成最终图片后就不需要显示轮廓了(bDrawOutline=false)。
       鼠标左键按下事件:先判断是否有前一个区域存在,存在则先完成前一个区域并且不显示区域轮廓,然后开始绘制新的区域多边形的点,点与点之间用蓝色线连接,点位置处绘制一个4X4的红色矩形。

void OnLeftMouseButtonDown(int x,int y)
{
    if (drawingPoints.empty() && areaPoints.size() > 0)
    {
        OnCompleteArea(false);
    }
    drawingPoints.push_back(cv::Point(x, y));
    cv::rectangle(resultImg, cv::Rect(x - 2, y - 2, 4, 4), CV_RGB(255, 0, 0), -1);
    if (drawingPoints.size() >= 2)
    {
        cv::line(resultImg, drawingPoints[drawingPoints.size() - 2], cv::Point(x, y), CV_RGB(0, 0, 255), 1);
    }
    cv::imshow(winName, resultImg);
}

       鼠标移动事件:判断drawingPoints是否为空,如果已经存在点则绘制线和点,并且还要绘制一根连接到鼠

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值