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();
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM