1. 程式人生 > >OpenCV2.4.13 中 選取roi區域,任意形狀(矩形,不規則多邊形,圓形,橢圓,手動指定形狀)

OpenCV2.4.13 中 選取roi區域,任意形狀(矩形,不規則多邊形,圓形,橢圓,手動指定形狀)

在利用OpenCV對影象進行處理時,通常會遇到一個情況,就是隻需要對部分感興趣區域進行處理。
因此,如何選取感興趣區域(其實就是“摳圖”)。
下面給出一個例子:

    Mat img = imread(IMG_PATH);
    Mat cat = imread(CAT_PATH);
    if (img.empty()|| cat.empty())
        cerr << "can not read image."<<endl;

    // 指定感興趣區域,兩種方法
    Mat ROI =  img(Rect(40,40,cat.cols,cat.rows
)); Mat ROI2(img,Rect(40,40,cat.cols,cat.rows)); // 展示 roi 區域 imshow("roi",ROI); cout<<endl <<"將貓放到感興趣區域,兩種方法"<<endl; //cat.copyTo(ROI); cat.copyTo(ROI,cat); imshow("lotus with cat",img); // 在影象中畫出 矩形 rectangle(img,Rect(240,240,cat.cols,cat.rows
),Scalar(0,0,255)); imshow("with rectangle box",img); // 另一種方法 cout <<endl << "利用 Rect 儲存方框,然後使用"<<endl; Rect r1 = Rect(100,0,200,200); rectangle(img,r1,Scalar(255,0,0)); imshow("with rectangle box 2",img);

下面是程式最終的結果:
這裡寫圖片描述

  • 問題:如果感興趣區域不是方形的怎麼辦?
    答:參考這裡的程式碼,也就是說,使用 contour (輪廓)來指定roi。
    其程式碼如下:
    Mat img = imread(IMG_PATH);
    Mat dst;
    Mat roi = Mat::zeros(img.size(),CV_8U);

    vector<vector<Point>> contour;
    vector<Point> pts;
    pts.push_back(Point(30,45));
    pts.push_back(Point(100,15));
    pts.push_back(Point(300,145));
    pts.push_back(Point(330,240));
    pts.push_back(Point(50,250));
    contour.push_back(pts);

    drawContours(roi,contour,0,Scalar::all(255),-1);
    img.copyTo(dst,roi);

    imshow("roi",roi);
    imshow("img",img);
    imshow("dst",dst);

效果圖:這裡寫圖片描述

  • 問題:我不想要這麼複雜的區域,只是想要一個圓形區域呢?
    答:經過參考這裡的回答,給出其中回答中的程式碼,可以畫出圓形區域的roi。
    Mat image = imread(IMG_PATH);
    Mat dst = Mat::zeros(image.size(), image.type());
    Mat mask = Mat::zeros(image.size(),CV_8U);

    Point circleCenter(mask.cols / 2, mask.rows / 2);
    int radius = min(mask.cols, mask.rows)/2;
    // 畫圓
    circle(mask, circleCenter, radius, Scalar(255),-1);

    image.copyTo(dst, mask);

    imshow("mask",mask);
    imshow("image",image);
    imshow("dst",dst);

效果如下:這裡寫圖片描述
- 問題:我想要個橢圓區域呢?
答:將上面程式碼中畫圓的那一句替換為:

ellipse(mask,circleCenter,Size(240,146),10,-180,180,Scalar(255),-1);

效果如下:
這裡寫圖片描述
- 問題:說了這麼多,有什麼規律麼?
答:有啊。
其實主要用到了一個函式:copyTo,先看手冊中 它的定義:
這裡寫圖片描述
給出一個例子:

src.copyTo(dst, mask);

這裡解釋一下:將 src 的位於 mask 中的部分,拷貝到 dst 中。
這裡,mask是一個“掩膜”, 其中非零的位置既是指定了 src 中的那些需要拷貝的部分。

上面才是整個方法的核心部分。

  • 問題:我想手動,用滑鼠選取感興趣區域,怎麼辦麼?
    答:額,這個我還沒用到,不過幫你搜到了一個相關的部落格,在這裡。具體效果如何,我沒有實驗,實在需要的話,可以自己折騰一下。
    不過,這裡貌似只能手動選擇方形區域。

放大招:整體程式碼如下:

// csdn_code.cpp : 定義控制檯應用程式的入口點。
//

#include "stdafx.h"
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;



//#define IMG_PATH  "..//figures//12.jpg"

#define IMG_PATH  "..//figures//lotus.jpg"

#define CAT_PATH  "..//figures//cat.jpg"

void testroi(void){
    Mat img = imread(IMG_PATH);
    Mat cat = imread(CAT_PATH);
    if (img.empty()|| cat.empty())
        cerr << "can not read image."<<endl;

    // 指定感興趣區域,兩種方法
    Mat ROI =  img(Rect(40,40,cat.cols,cat.rows));
    Mat ROI2(img,Rect(40,40,cat.cols,cat.rows));

    // 展示 roi 區域
    imshow("roi",ROI);

    cout<<endl
        <<"將貓放到感興趣區域,兩種方法"<<endl;
    //cat.copyTo(ROI);
    cat.copyTo(ROI,cat);
    imshow("lotus with cat",img);


    // 在影象中畫出 矩形
    rectangle(img,Rect(240,240,cat.cols,cat.rows),Scalar(0,0,255));
    imshow("with rectangle box",img);

    //  另一種方法
    cout <<endl
        << "利用 Rect 儲存方框,然後使用"<<endl;
    Rect r1 = Rect(100,0,200,200);
    rectangle(img,r1,Scalar(255,0,0));
    imshow("with rectangle box 2",img);

}


void contour_roi(void){
    Mat img = imread(IMG_PATH);
    Mat dst;
    Mat roi = Mat::zeros(img.size(),CV_8U);

    // 利用 邊界設定roi區域
    vector<vector<Point>> contour;
    vector<Point> pts;
    pts.push_back(Point(30,45));
    pts.push_back(Point(100,15));
    pts.push_back(Point(300,145));
    pts.push_back(Point(330,240));
    pts.push_back(Point(50,250));
    contour.push_back(pts);

    // 畫出
    drawContours(roi,contour,0,Scalar::all(255),-1);
    img.copyTo(dst,roi);

    imshow("roi",roi);
    imshow("img",img);
    imshow("dst",dst);

}

void circle_roi(void){
    Mat image = imread(IMG_PATH);
    Mat dst = Mat::zeros(image.size(), image.type());
    Mat mask = Mat::zeros(image.size(),CV_8U);

    Point circleCenter(mask.cols / 2, mask.rows / 2);
    int radius = min(mask.cols, mask.rows)/2;

    // 畫圓
    //circle(mask, circleCenter, radius, Scalar(255),-1);
    // 畫橢圓
    ellipse(mask,circleCenter,Size(240,146),10,-180,180,Scalar(255),-1);

    image.copyTo(dst, mask);

    imshow("mask",mask);
    imshow("image",image);
    imshow("dst",dst);
}

int main()
{
    testroi();

    contour_roi();

    circle_roi();


    waitKey();
    system("pause");
    return 0;
}