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."<;

    // 指定感兴趣区域,两种方法
    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<"将猫放到感兴趣区域,两种方法"<;
    //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 <"利用 Rect 保存方框,然后使用"<;
    Rect r1 = Rect(100,0,200,200);
    rectangle(img,r1,Scalar(255,0,0));
    imshow("with rectangle box 2",img);

下面是程序最终的结果:
OpenCV2.4.13 中 选取roi区域,任意形状(矩形,不规则多边形,圆形,椭圆,手动指定形状)_第1张图片

  • 问题:如果感兴趣区域不是方形的怎么办?
    答:参考这里的代码,也就是说,使用 contour (轮廓)来指定roi。
    其代码如下:
    Mat img = imread(IMG_PATH);
    Mat dst;
    Mat roi = Mat::zeros(img.size(),CV_8U);

    vector<vector> contour;
    vector 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);

效果图:OpenCV2.4.13 中 选取roi区域,任意形状(矩形,不规则多边形,圆形,椭圆,手动指定形状)_第2张图片

  • 问题:我不想要这么复杂的区域,只是想要一个圆形区域呢?
    答:经过参考这里的回答,给出其中回答中的代码,可以画出圆形区域的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);

效果如下:OpenCV2.4.13 中 选取roi区域,任意形状(矩形,不规则多边形,圆形,椭圆,手动指定形状)_第3张图片
- 问题:我想要个椭圆区域呢?
答:将上面代码中画圆的那一句替换为:

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

效果如下:
OpenCV2.4.13 中 选取roi区域,任意形状(矩形,不规则多边形,圆形,椭圆,手动指定形状)_第4张图片
- 问题:说了这么多,有什么规律么?
答:有啊。
其实主要用到了一个函数:copyTo,先看手册中 它的定义:
OpenCV2.4.13 中 选取roi区域,任意形状(矩形,不规则多边形,圆形,椭圆,手动指定形状)_第5张图片
给出一个例子:

src.copyTo(dst, mask);

这里解释一下:将 src 的位于 mask 中的部分,拷贝到 dst 中。
这里,mask是一个“掩膜”, 其中非零的位置既是指定了 src 中的那些需要拷贝的部分。

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

  • 问题:我想手动,用鼠标选取感兴趣区域,怎么办么?
    答:额,这个我还没用到,不过帮你搜到了一个相关的博客,在这里。具体效果如何,我没有实验,实在需要的话,可以自己折腾一下。
    不过,这里貌似只能手动选择方形区域。

放大招:整体代码如下:

// csdn_code.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include 
#include 

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."<// 指定感兴趣区域,两种方法
    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<"将猫放到感兴趣区域,两种方法"<//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 <"利用 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> contour;
    vector 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;
}

你可能感兴趣的:(opencv)