OpenCV中Selective Search算法的使用

本文所用的 OpenCV 版本为 opencv-3.2.0,编程语言为 C++。

前言

  OpenCV-3.2 中的 Selective Search 算法是在其扩展包中,所以要想使用该算法需自行编译 opencv_contrib-3.2.0。由于扩展包中的示例程序有点简陋,对初学者也不友好(Shaun 编程水平有限,粗浅评价,勿怪 (*^__^ *) 嘻嘻……),所以 Shaun 参考其官方文档及其官方示例程序写下此文。

说明篇

  该算法是选取 region proposal(一般翻译成候选区域 / 区域建议)领域中当时的 state-of-the-art。其算法具体思想出自 Jasper RR Uijlings, Koen EA van de Sande, Theo Gevers, and Arnold WM Smeulders. Selective search for object recognition. International journal of computer vision, 104(2):154–171, 2013.,若英文水平不够,还想了解其中文思想请参考文末参考资料。

  OpenCV中实现的相应函数:

void cv::ximgproc::segmentation::SelectiveSearchSegmentation::addGraphSegmentation(Ptr<GraphSegmentation> g);:添加相应的图割算法;

void cv::ximgproc::segmentation::SelectiveSearchSegmentation::addImage(InputArray img) ; :添加待处理的图片;

void cv::ximgproc::segmentation::SelectiveSearchSegmentation::addStrategy(Ptr<SelectiveSearchSegmentationStrategy> s); :添加相应的策略(颜色相似度、纹理相似度、尺寸相似度和填充相似度);

void cv::ximgproc::segmentation::SelectiveSearchSegmentation::process(std::vector<Rect> &rects);:结合图割算法和相应策略进行处理,返回候选框。

实例篇

  使用 Selective Search 算法需包含#include <opencv2/ximgproc.hpp>,完整示例程序如下:

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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <opencv2/opencv.hpp>
#include <opencv2/ximgproc.hpp>

void SSTest()
{
// [Image segmentation](http://docs.opencv.org/3.2.0/d5/df0/group__ximgproc__segmentation.html#ga5e3e721c5f16e34d3ad52b9eeb6d2860)

cv::Mat src_img = cv::imread("../data/true.png", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR); // 载入原始图像
cv::namedWindow("src_img", CV_WINDOW_KEEPRATIO);
cv::imshow("src_img", src_img);

//// 转换为灰度图
//cv::Mat gray_img;
//cvtColor(src_img, gray_img, cv::COLOR_BGR2GRAY);

// 图割算法
cv::Ptr<cv::ximgproc::segmentation::GraphSegmentation> gs = cv::ximgproc::segmentation::createGraphSegmentation();
cv::Mat graph_segmented;
gs->processImage(src_img, graph_segmented);
normalize(graph_segmented, graph_segmented, 0, 255, CV_MINMAX); // 归一化到[0,255]供显示
graph_segmented.convertTo(graph_segmented, CV_8U); // 数据类型转化成CV_8U型
// cvtColor(graph_segmented, graph_segmented, CV_GRAY2BGR);
cv::namedWindow("graph_segmented", CV_WINDOW_KEEPRATIO);
imshow("graph_segmented", graph_segmented);

// 为selective search算法添加图割算法处理结果
cv::Ptr<cv::ximgproc::segmentation::SelectiveSearchSegmentation> ss = cv::ximgproc::segmentation::createSelectiveSearchSegmentation();
ss->addGraphSegmentation(gs);

ss->addImage(src_img); // 添加待处理的图片

// 自定义策略
cv::Ptr<cv::ximgproc::segmentation::SelectiveSearchSegmentationStrategy> sss_color = cv::ximgproc::segmentation::createSelectiveSearchSegmentationStrategyColor(); // 颜色相似度策略
cv::Ptr<cv::ximgproc::segmentation::SelectiveSearchSegmentationStrategy> sss_texture = cv::ximgproc::segmentation::createSelectiveSearchSegmentationStrategyTexture(); // 纹理相似度策略
cv::Ptr<cv::ximgproc::segmentation::SelectiveSearchSegmentationStrategy> sss_size = cv::ximgproc::segmentation::createSelectiveSearchSegmentationStrategySize(); // 尺寸相似度策略
cv::Ptr<cv::ximgproc::segmentation::SelectiveSearchSegmentationStrategy> sss_fill = cv::ximgproc::segmentation::createSelectiveSearchSegmentationStrategyFill(); // 填充相似度策略
// 添加策略
cv::Ptr<cv::ximgproc::segmentation::SelectiveSearchSegmentationStrategy> sss = cv::ximgproc::segmentation::createSelectiveSearchSegmentationStrategyMultiple(sss_color, sss_texture, sss_size, sss_fill); // 合并以上4种策略
ss->addStrategy(sss);

std::vector<cv::Rect> regions;
ss->process(regions); // 处理结果

// 显示结果
cv::Mat show_img = src_img.clone();
for (std::vector<cv::Rect>::iterator it_r = regions.begin(); it_r != regions.end(); ++it_r)
{
cv::rectangle(show_img, *it_r, cv::Scalar(0, 0, 255), 3);
}
cv::namedWindow("show_img", CV_WINDOW_KEEPRATIO);
imshow("show_img", show_img);



// -------忽略上述步骤,直接采用方便算法提取候选区域------------------------
/***************************************************************************
cv::Ptr<cv::ximgproc::segmentation::SelectiveSearchSegmentation> ss = cv::ximgproc::segmentation::createSelectiveSearchSegmentation();
ss->setBaseImage(src_img); // 采用switch* functions提取候选区域
ss->switchToSelectiveSearchFast(); // 快速提取区域

std::vector<cv::Rect> rects;
ss->process(rects);

int nb_rects = 10;

char c = (char)cv::waitKey();

while (c != 'q')
{

cv::Mat wimg = src_img.clone();

int i = 0;

for (std::vector<cv::Rect>::iterator it = rects.begin(); it != rects.end(); ++it)
{
if (i++ < nb_rects)
{
cv::rectangle(wimg, *it, cv::Scalar(0, 0, 255), 3);
}
}

cv::namedWindow("Output", CV_WINDOW_KEEPRATIO);
imshow("Output", wimg);

c = (char)cv::waitKey();

if (c == 'd')
{
nb_rects += 10;
}

if (c == 'a' && nb_rects > 10)
{
nb_rects -= 10;
}
}
********************************************************/
}


int main(int argc, char *argv[])
{
SSTest();

while (cv::waitKey(0) != 27) {}
return 0;
}

以上代码在 Win10 VS2013 中编译运行成功。

后记

  使用该算法,要想达到理想效果,一般需要调整图割算法的参数或注释中方法 switchToSelectiveSearchFast() 的参数。Shaun 的这次实验为了达到理想的选取的效果,其调整参数花了不少时间,而且该算法运行时间在 Shaun 电脑上略显长。GitHub 上也有大神自己用 opencv 实现了该算法,参考 watanika/selective-search-cpp,该算法的参数感觉比 OpenCV 自带的 Selective Search 算法要好调一些,但优化效果没有 opencv 好,其运行时间在 Shaun 电脑上更长,毕竟 OpenCV 是 Intel 的亲儿子,Intel 肯定针对处理器对 OpenCV 底层做了一定的优化。

参考资料

[1] 论文笔记:Selective Search for Object Recognitionhttp://jermmy.xyz/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89/

[2] Selective Search for Object Recognition(阅读)http://blog.csdn.net/langb2014/article/category/5772811

[3] 论文笔记 《Selective Search for Object Recognition》http://blog.csdn.net/csyhhb/article/category/6048588