zoukankan      html  css  js  c++  java
  • ROI多区域选择

      学习图像处理时,为了快速验证处理效果,经常需要手动选取ROI区域。其中,多边形区域是最具普适性的,而有时候我们可能还有一次性提取多个区域的需求。本文实现了该过程,先上效果图。

    鼠标交互

      鼠标交互使用OpenCV函数setMouseCallback:

    void cv::setMouseCallback(const cv::String &winname, cv::MouseCallback onMouse, void *userdata = (void *)0)

      主要实现的就是回调函数onMouse,以下是我实现的回调,用于监听鼠标滑动和左键点击事件。在左键点击后在图上绘制出该角点以及末两点的连线;在鼠标滑动时绘制当前位置点和轮廓始末点的两条连线,作为效果预估。

    //鼠标交互相应
    void polygonCallback(int EVENT, int x, int y, int flags, void* userdata)
    {
        //获取窗口显示图像
        Mat img = *(Mat*) userdata;
        Mat dst;
        img.copyTo(dst);
        //获取坐标
        Point pos(x,y);
        switch (EVENT)
        {
            //鼠标左键点击确认角点
            case CV_EVENT_LBUTTONDOWN:
            {
                mousePoints.push_back(pos);
                //绘制点以反馈
                circle(img, pos, 4, Scalar(255, 0, 0), -1);
                size_t end = mousePoints.size();
                if (end > 1)
                {
                    //将轮廓的最后两个点进行连线
                    line(img, mousePoints[end - 2], mousePoints[end - 1], Scalar(255, 0, 0));
                    line(dst, mousePoints[end - 2], mousePoints[end - 1], Scalar(255, 0, 0));
                }
                break;
            }
            //鼠标滑动时可以进行预估
            case CV_EVENT_MOUSEMOVE:
            {
                size_t end = mousePoints.size();
                if (end > 1)
                {
                    //当前位置点和轮廓始末点的连线
                    line(dst, mousePoints[end - 1], pos, Scalar(255, 0, 0));
                    line(dst, mousePoints[0], pos, Scalar(255, 0, 0));
                }
            }
    
        }
        //展示dst,而img不含预估线
        imshow(windowName, dst);
    }

    掩码获取

      这个步骤主要是用一个二维的vector存储多个历史轮廓,然后使用OpenCV函数drawContours绘制掩码区域:

    void cv::drawContours(cv::InputOutputArray image, cv::InputArrayOfArrays contours, int contourIdx, const cv::Scalar &color, int thickness = 1, int lineType = 8, cv::InputArray hierarchy = noArray(), int maxLevel = 2147483647, cv::Point offset = cv::Point())

      具体函数如下:

    //ROI多边形区域选择
    void selectPolygon(const Mat &srcMat, Mat &dstMat)
    {
        if (srcMat.empty())
        {
            std::cerr << "srcMat is empty!" << std::endl;
            return;
        }
    
        imshow(windowName, srcMat);
        Mat selectMat;
        char key;
        srcMat.copyTo(selectMat);
        std::vector<std::vector<Point>> contours;
        do{
            //鼠标左键选择角点,任意非q按键新建选区,q按键退出ROI选择
            setMouseCallback(windowName, polygonCallback, &selectMat);
            key = waitKey(0);
            //判断是否能构成多边形,不能则忽略本次选择
            if (mousePoints.size() < 3)
            {
                std::cout << "points are too little!:" << std::endl;
                mousePoints.clear();
            }
            else
            {
                //补出轮廓始末点连线
                line(selectMat, mousePoints[0], mousePoints[mousePoints.size() - 1], Scalar(255, 0, 0));
                //存储边界
                contours.push_back(mousePoints);
                //清空本次轮廓点,准备接收下一个区域
                mousePoints.clear();
            }
        }while (key != 'q');
    
        destroyAllWindows();
    
        //实心roi掩码
        //掩码图像
        Mat mask(srcMat.rows, srcMat.cols, CV_8UC1, Scalar(0));
        for (size_t i = 0; i < contours.size(); i++)
        {
            drawContours(mask, contours, i, Scalar(255), -1);
        }
        mask.copyTo(dstMat);
        mousePoints.clear();
    }
  • 相关阅读:
    Python pip – error: invalid command ‘bdist_wheel’
    css实现文字两端对齐(兼容所有浏览器)
    webpack中的require.context
    node 的path模块中 path.resolve()和path.join()的区别
    react-native项目中遇到的问题
    react-native针对android改变状态栏样式
    createBottomTabNavigator: 怎么在切换tab的时候让页面重新渲染
    当vue页面异步加载的数据想在页面上渲染怎么办
    git分布式版本控制系统
    $router和$route的区别,路由跳转方式name 、 path 和传参方式params 、query的区别
  • 原文地址:https://www.cnblogs.com/kensporger/p/12903121.html
Copyright © 2011-2022 走看看