图像感兴趣区域(ROI)提取主要使用掩模来进行。掩模是二值图像,感兴趣区域的掩模值设置为255,非感兴趣区域的掩模值为0
获取掩模的方法主要有两种
方法一 使用opencv中Mat函数方法,调用Mat(Rect).setTo方法设置掩模
Mat Mat::operator()( const Rect& roi ) const mask(rect).setTo(255);
方法二 在全为0的原始掩模中画一个封闭区域,使用漫水填充算法填充封闭区域,将封闭区域的值都设置为255,实现掩模的提取
下文对矩形、椭圆,有方向的矩形,轮廓进行提取
1.矩形感兴趣区域提取
(1)调用Mat(Rect).setTo方法设置掩模
使用方法一对矩形感兴趣区域进行提取示例代码如下:
#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; 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; floodFill(mask, seed, 255, NULL, cvScalarAll(0), cvScalarAll(0), CV_FLOODFILL_FIXED_RANGE); 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 256void DrawBox(CvBox2D box, IplImage* img){ CvPoint2D32f point[4] int i for (i = 0 { point[i].x = 0 point[i].y = 0 } cvBoxPoints(box, point) CvPoint pt[4] for (i = 0 { 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)、圆,使用漫水填充算法将几何图形内部的值设置为255int 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)获取轮廓中心,使用漫水填充算法填充
示例代码如下:
using namespace cv;//draw in gray imagevoid 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,假如区域边界为轮廓,使用掩模图像中画轮廓,使用漫水填充算法将几何图形内部的值设置为255int 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