openCV任意几何形状感兴趣区域(ROI)提取

图像感兴趣区域(ROI)提取主要使用掩模来进行。掩模是二值图像,感兴趣区域的掩模值设置为255,非感兴趣区域的掩模值为0 
获取掩模的方法主要有两种

方法一 使用opencv中Mat函数方法,调用Mat(Rect).setTo方法设置掩模

 Mat Mat::operator()( const Rect& roi ) const
 //调用Mat(Rect).setTo方法
 mask(rect).setTo(255);
  • 1
  • 2
  • 3

方法二 在全为0的原始掩模中画一个封闭区域,使用漫水填充算法填充封闭区域,将封闭区域的值都设置为255,实现掩模的提取

下文对矩形、椭圆,有方向的矩形,轮廓进行提取

1.矩形感兴趣区域提取

(1)调用Mat(Rect).setTo方法设置掩模 
使用方法一对矩形感兴趣区域进行提取示例代码如下:

#include<cv.h>
#include<highgui.h>
using namespace cv;
//方法1,假如区域为长方形,使用MAT 构造函数设置区域内的值为255
int main()
{
    Mat image=imread("lena.jpg");
    //初始化掩模矩阵
    Mat mask = Mat::zeros(image.size(), CV_8UC1);

    Rect rect;
    rect.x = 100;
    rect.y = 100;
    rect.width = 100;
    rect.height = 100;  
    //设置矩形掩模
    mask(rect).setTo(255);

    Mat img2;
    image.copyTo(img2, mask);
    imshow("mask", mask);
    imshow("img2", img2);
    waitKey();
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

(2)使用漫水填充算法获取矩形ROI 
思路: 
1)新建一个值全为零的掩模图像(全是黑的,值为0) 
2)在掩模图像上用白色画出矩形的边界(边界值为255) 
3)选取矩形的中心作为种子点,使用漫水填充算法将矩形的内部填充为白色(255),最后得到掩模图像,使用掩模实现感兴趣区域提取。

#include<cv.h>
#include<highgui.h>
using namespace cv;
int main()
{
    Mat image = imread("lena.jpg");
    Mat mask = Mat::zeros(image.size(), CV_8UC1);
    Rect rect;
    rect.x = 100;
    rect.y = 100;
    rect.width = 100;
    rect.height = 100;
    //画矩形
    rectangle(mask, rect, Scalar(255));
    //设置种子点位置
    Point seed;
    seed.x = 150;
    seed.y = 150;
    //pi的值表示为 v(pi),if  v(seed)-loDiff<v(pi)<v(seed)+upDiff,将pi的值设置为newVal
    //使用漫水填充算法填充
    floodFill(mask, seed, 255, NULL, cvScalarAll(0), cvScalarAll(0), CV_FLOODFILL_FIXED_RANGE);
    //mask(rect).setTo(255);
    Mat img2;
    image.copyTo(img2, mask);
    imshow("mask", mask);
    imshow("img2", img2);
    waitKey();
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

2.任意几何形状ROI提取

任意几何形状感兴趣区域的提取主要使用方法二。提取的关键是画出几何形状的边界。 
(1)旋转的矩形(CvBox2D)、椭圆(RotatedRect)、圆的感兴趣区域的提取 
示例代码如下:

#include<cv.h>
#include<highgui.h>
using namespace cv;
#define WIDTH 256
#define HEIGHT 256
void DrawBox(CvBox2D box, IplImage* img)
{
    CvPoint2D32f point[4];
    int i;
    for (i = 0; i<4; i++)

    {
        point[i].x = 0;
        point[i].y = 0;

    }
    cvBoxPoints(box, point); //计算二维盒子顶点
    CvPoint pt[4];
    for (i = 0; i<4; i++)
    {
        pt[i].x = (int)point[i].x;
        pt[i].y = (int)point[i].y;

    }

    cvLine(img, pt[0], pt[1], cvScalar(255), 2, 8, 0);
    cvLine(img, pt[1], pt[2], cvScalar(255), 2, 8, 0);
    cvLine(img, pt[2], pt[3], cvScalar(255), 2, 8, 0);
    cvLine(img, pt[3], pt[0], cvScalar(255), 2, 8, 0);

}

//方法3.在掩模图像中画旋转的矩形(CvBox2D)、椭圆(RotatedRect)、圆,使用漫水填充算法将几何图形内部的值设置为255
int main()
{
    Mat image = imread("dot_link_11.jpg");

    Mat mask = Mat::zeros(image.size(), CV_8UC1);
    CvBox2D box;
    box.size.width = 100;
    box.size.height = 50;
    box.angle = 30;
    box.center.x = 200;
    box.center.y = 200;

    ////情况1.画旋转的矩形(CvBox2D)
    //IplImage* imask = &IplImage(mask);
    //DrawBox(box,imask);
    //Point seed;
    //seed.x = box.center.x;
    //seed.y = box.center.y;

    //情况2.画椭圆
    //RotatedRect roRect;
    //roRect.angle = 30;
    //roRect.center.x = 200;
    //roRect.center.y = 200;
    //roRect.size.width = 100;
    //roRect.size.height = 50;
    //ellipse(mask, roRect, cvScalar(255));
    //Point seed;
    //seed.x = roRect.center.x;
    //seed.y = roRect.center.y;

    ////情况3.画圆
    Point center;
    center.x = 100;
    center.y = 100;
    float radius = 50;
    circle(mask, center, radius, Scalar(255));

    Point seed;
    seed.x = center.x;
    seed.y = center.y;
    //漫水填充
    //pi的值表示为 v(pi),if  v(seed)-loDiff<v(pi)<v(seed)+upDiff,将pi的值设置为newVal
    floodFill(mask, seed, 255, NULL, cvScalarAll(0), cvScalarAll(0), CV_FLOODFILL_FIXED_RANGE);
    //mask(rect).setTo(255);
    Mat maskImage;
    image.copyTo(maskImage, mask);
    imshow("mask", mask);
    imshow("img2", maskImage);
    waitKey();
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85

(2)感兴趣区域为轮廓的提取 
思路:1)调用opencv的画图函数cvLine将轮廓中相邻的点连接为区域 
2)获取轮廓中心,使用漫水填充算法填充 
示例代码如下:

#include<cv.h>
#include<highgui.h>
using namespace cv;
#define WIDTH 256
#define HEIGHT 256
//draw in gray image
void draw_external_contour_gray(CvSeq *seq, IplImage* grayImage)
{

    if (seq->total < 2)
    {
        return;
    }
    CvPoint* prePoint = (CvPoint*)cvGetSeqElem(seq, 0);
    CvPoint* lastPoint = (CvPoint*)cvGetSeqElem(seq, seq->total - 1);
    cvLine(grayImage, *prePoint, *lastPoint,cvScalar(255), 1, 8, 0);
    for (int i = 1; i<seq->total; i++) {
        CvPoint *p;
        p = (CvPoint*)cvGetSeqElem(seq, i);

        cvLine(grayImage, *prePoint, *p, cvScalar(255), 1, 8, 0);
        //cvSet2D(img, p->y, p->x, color);
        *prePoint = *p;
    }

}
//方法4,假如区域边界为轮廓,使用掩模图像中画轮廓,使用漫水填充算法将几何图形内部的值设置为255
int main()
{
    Mat image=imread("dot_link_11.jpg");

    Mat mask = Mat::zeros(image.size(), CV_8UC1);
    CvMemStorage* storage = cvCreateMemStorage(0);
//  CvSeq* contour = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), storage);

    CvSeqWriter writer;
    cvStartWriteSeq(CV_32SC2, sizeof(CvSeq), sizeof(CvPoint),storage,&writer);

    CvPoint p1 = { 25, 60 };  CvPoint p2 = { 50, 110 };  CvPoint p4 = { 100, 60 }; CvPoint p3 = { 100, 110 }; CvPoint p5 = { 50, 10 };
    CV_WRITE_SEQ_ELEM(p1, writer);
    CV_WRITE_SEQ_ELEM(p2, writer);
    CV_WRITE_SEQ_ELEM(p3, writer);
    CV_WRITE_SEQ_ELEM(p4, writer);
    CV_WRITE_SEQ_ELEM(p5, writer);

    cvFlushSeqWriter(&writer);
    CvSeq* contour = cvEndWriteSeq(&writer);
    printf("contour.size=%d", contour->total);
    IplImage* imask = &IplImage(mask); 
    IplImage* iimage = &IplImage(image);

    draw_external_contour_gray(contour, imask);

    Point seed;
    seed.x = 35;
    seed.y = 60;
    //漫水填充
    //pi的值表示为 v(pi),if  v(seed)-loDiff<v(pi)<v(seed)+upDiff,将pi的值设置为newVal
    floodFill(mask, seed, 255, NULL, cvScalarAll(0), cvScalarAll(0), CV_FLOODFILL_FIXED_RANGE);

    Mat maskImage;
    image.copyTo(maskImage, mask);
    imshow("mask", maskImage);
    cvShowImage("imask",imask);
    waitKey();
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
版权声明:本文为博主原创文章,未经博主允许不得转载。

图像感兴趣区域(ROI)提取主要使用掩模来进行。掩模是二值图像,感兴趣区域的掩模值设置为255,非感兴趣区域的掩模值为0 
获取掩模的方法主要有两种

方法一 使用opencv中Mat函数方法,调用Mat(Rect).setTo方法设置掩模

 Mat Mat::operator()( const Rect& roi ) const
 //调用Mat(Rect).setTo方法
 mask(rect).setTo(255);
  • 1
  • 2
  • 3

方法二 在全为0的原始掩模中画一个封闭区域,使用漫水填充算法填充封闭区域,将封闭区域的值都设置为255,实现掩模的提取

下文对矩形、椭圆,有方向的矩形,轮廓进行提取

1.矩形感兴趣区域提取

(1)调用Mat(Rect).setTo方法设置掩模 
使用方法一对矩形感兴趣区域进行提取示例代码如下:

#include<cv.h>
#include<highgui.h>
using namespace cv;
//方法1,假如区域为长方形,使用MAT 构造函数设置区域内的值为255
int main()
{
    Mat image=imread("lena.jpg");
    //初始化掩模矩阵
    Mat mask = Mat::zeros(image.size(), CV_8UC1);

    Rect rect;
    rect.x = 100;
    rect.y = 100;
    rect.width = 100;
    rect.height = 100;  
    //设置矩形掩模
    mask(rect).setTo(255);

    Mat img2;
    image.copyTo(img2, mask);
    imshow("mask", mask);
    imshow("img2", img2);
    waitKey();
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

(2)使用漫水填充算法获取矩形ROI 
思路: 
1)新建一个值全为零的掩模图像(全是黑的,值为0) 
2)在掩模图像上用白色画出矩形的边界(边界值为255) 
3)选取矩形的中心作为种子点,使用漫水填充算法将矩形的内部填充为白色(255),最后得到掩模图像,使用掩模实现感兴趣区域提取。

#include<cv.h>
#include<highgui.h>
using namespace cv;
int main()
{
    Mat image = imread("lena.jpg");
    Mat mask = Mat::zeros(image.size(), CV_8UC1);
    Rect rect;
    rect.x = 100;
    rect.y = 100;
    rect.width = 100;
    rect.height = 100;
    //画矩形
    rectangle(mask, rect, Scalar(255));
    //设置种子点位置
    Point seed;
    seed.x = 150;
    seed.y = 150;
    //pi的值表示为 v(pi),if  v(seed)-loDiff<v(pi)<v(seed)+upDiff,将pi的值设置为newVal
    //使用漫水填充算法填充
    floodFill(mask, seed, 255, NULL, cvScalarAll(0), cvScalarAll(0), CV_FLOODFILL_FIXED_RANGE);
    //mask(rect).setTo(255);
    Mat img2;
    image.copyTo(img2, mask);
    imshow("mask", mask);
    imshow("img2", img2);
    waitKey();
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

2.任意几何形状ROI提取

任意几何形状感兴趣区域的提取主要使用方法二。提取的关键是画出几何形状的边界。 
(1)旋转的矩形(CvBox2D)、椭圆(RotatedRect)、圆的感兴趣区域的提取 
示例代码如下:

#include<cv.h>
#include<highgui.h>
using namespace cv;
#define WIDTH 256
#define HEIGHT 256
void DrawBox(CvBox2D box, IplImage* img)
{
    CvPoint2D32f point[4];
    int i;
    for (i = 0; i<4; i++)

    {
        point[i].x = 0;
        point[i].y = 0;

    }
    cvBoxPoints(box, point); //计算二维盒子顶点
    CvPoint pt[4];
    for (i = 0; i<4; i++)
    {
        pt[i].x = (int)point[i].x;
        pt[i].y = (int)point[i].y;

    }

    cvLine(img, pt[0], pt[1], cvScalar(255), 2, 8, 0);
    cvLine(img, pt[1], pt[2], cvScalar(255), 2, 8, 0);
    cvLine(img, pt[2], pt[3], cvScalar(255), 2, 8, 0);
    cvLine(img, pt[3], pt[0], cvScalar(255), 2, 8, 0);

}

//方法3.在掩模图像中画旋转的矩形(CvBox2D)、椭圆(RotatedRect)、圆,使用漫水填充算法将几何图形内部的值设置为255
int main()
{
    Mat image = imread("dot_link_11.jpg");

    Mat mask = Mat::zeros(image.size(), CV_8UC1);
    CvBox2D box;
    box.size.width = 100;
    box.size.height = 50;
    box.angle = 30;
    box.center.x = 200;
    box.center.y = 200;

    ////情况1.画旋转的矩形(CvBox2D)
    //IplImage* imask = &IplImage(mask);
    //DrawBox(box,imask);
    //Point seed;
    //seed.x = box.center.x;
    //seed.y = box.center.y;

    //情况2.画椭圆
    //RotatedRect roRect;
    //roRect.angle = 30;
    //roRect.center.x = 200;
    //roRect.center.y = 200;
    //roRect.size.width = 100;
    //roRect.size.height = 50;
    //ellipse(mask, roRect, cvScalar(255));
    //Point seed;
    //seed.x = roRect.center.x;
    //seed.y = roRect.center.y;

    ////情况3.画圆
    Point center;
    center.x = 100;
    center.y = 100;
    float radius = 50;
    circle(mask, center, radius, Scalar(255));

    Point seed;
    seed.x = center.x;
    seed.y = center.y;
    //漫水填充
    //pi的值表示为 v(pi),if  v(seed)-loDiff<v(pi)<v(seed)+upDiff,将pi的值设置为newVal
    floodFill(mask, seed, 255, NULL, cvScalarAll(0), cvScalarAll(0), CV_FLOODFILL_FIXED_RANGE);
    //mask(rect).setTo(255);
    Mat maskImage;
    image.copyTo(maskImage, mask);
    imshow("mask", mask);
    imshow("img2", maskImage);
    waitKey();
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85

(2)感兴趣区域为轮廓的提取 
思路:1)调用opencv的画图函数cvLine将轮廓中相邻的点连接为区域 
2)获取轮廓中心,使用漫水填充算法填充 
示例代码如下:

#include<cv.h>
#include<highgui.h>
using namespace cv;
#define WIDTH 256
#define HEIGHT 256
//draw in gray image
void draw_external_contour_gray(CvSeq *seq, IplImage* grayImage)
{

    if (seq->total < 2)
    {
        return;
    }
    CvPoint* prePoint = (CvPoint*)cvGetSeqElem(seq, 0);
    CvPoint* lastPoint = (CvPoint*)cvGetSeqElem(seq, seq->total - 1);
    cvLine(grayImage, *prePoint, *lastPoint,cvScalar(255), 1, 8, 0);
    for (int i = 1; i<seq->total; i++) {
        CvPoint *p;
        p = (CvPoint*)cvGetSeqElem(seq, i);

        cvLine(grayImage, *prePoint, *p, cvScalar(255), 1, 8, 0);
        //cvSet2D(img, p->y, p->x, color);
        *prePoint = *p;
    }

}
//方法4,假如区域边界为轮廓,使用掩模图像中画轮廓,使用漫水填充算法将几何图形内部的值设置为255
int main()
{
    Mat image=imread("dot_link_11.jpg");

    Mat mask = Mat::zeros(image.size(), CV_8UC1);
    CvMemStorage* storage = cvCreateMemStorage(0);
//  CvSeq* contour = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), storage);

    CvSeqWriter writer;
    cvStartWriteSeq(CV_32SC2, sizeof(CvSeq), sizeof(CvPoint),storage,&writer);

    CvPoint p1 = { 25, 60 };  CvPoint p2 = { 50, 110 };  CvPoint p4 = { 100, 60 }; CvPoint p3 = { 100, 110 }; CvPoint p5 = { 50, 10 };
    CV_WRITE_SEQ_ELEM(p1, writer);
    CV_WRITE_SEQ_ELEM(p2, writer);
    CV_WRITE_SEQ_ELEM(p3, writer);
    CV_WRITE_SEQ_ELEM(p4, writer);
    CV_WRITE_SEQ_ELEM(p5, writer);

    cvFlushSeqWriter(&writer);
    CvSeq* contour = cvEndWriteSeq(&writer);
    printf("contour.size=%d", contour->total);
    IplImage* imask = &IplImage(mask); 
    IplImage* iimage = &IplImage(image);

    draw_external_contour_gray(contour, imask);

    Point seed;
    seed.x = 35;
    seed.y = 60;
    //漫水填充
    //pi的值表示为 v(pi),if  v(seed)-loDiff<v(pi)<v(seed)+upDiff,将pi的值设置为newVal
    floodFill(mask, seed, 255, NULL, cvScalarAll(0), cvScalarAll(0), CV_FLOODFILL_FIXED_RANGE);

    Mat maskImage;
    image.copyTo(maskImage, mask);
    imshow("mask", maskImage);
    cvShowImage("imask",imask);
    waitKey();
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

猜你喜欢

转载自blog.csdn.net/zhouxianen1987/article/details/78722473
今日推荐