是选基于图的图像分割后,就可以使用选择性搜索算法找到目标的候选区域。本主题介绍了选择性搜索算法的原理,主要是基于OpenCV实现框架来说明,起核心是四个常规的相似度计算:颜色相似度、尺度相似度、交叠相似度、纹理相似度。可以根据特色的规则建立其他相似度:比如人脸可以选在高宽差别不大的区域等。
有了候选区域,就可以使用卷积神经网络做特征抽取,抽取的特征没有使用神经网络的分类器,标准算法中都是使用号称史上最好的分类器SVM来训练分类(请参考我们对OpenCV与Sklearn中SVM的解释)。
在老版本的OpenCV(3.4以前)采用的是级联分类,新版本提供了基于SS算法的分类目标检测训练。可以参考OpenCV的app提供的工具。
选择性搜索(Selective Search)
OpenCV的Selective Search模块使用
搜索的使用
- 基于质量的搜索
import cv2
# 准备一张图像
img = cv2.imread("gpu.jpeg")
# 创建SelectiveSearch对象
ss = cv2.ximgproc.segmentation.createSelectiveSearchSegmentation()
# 添加图像到处理列表
ss.setBaseImage(img)
# 初始化算法参数
ss.switchToSelectiveSearchQuality()
# int base_k = 150,
# int inc_k = 150,
# float sigma = 0.8f
# ss.switchToSelectiveSearchFast()
# ss.switchToSingleStrategy()
# 所选择性搜索
rects = ss.process()
print(type(rects), rects.shape)
(51469, 4)
- 基于速度的搜索
import cv2
# 准备一张图像
img = cv2.imread("gpu.jpeg")
# 创建SelectiveSearch对象
ss = cv2.ximgproc.segmentation.createSelectiveSearchSegmentation()
# 添加图像到处理列表
ss.setBaseImage(img)
# 初始化算法参数
# ss.switchToSelectiveSearchQuality()
# int base_k = 150,
# int inc_k = 150,
# float sigma = 0.8f
ss.switchToSelectiveSearchFast()
# ss.switchToSingleStrategy()
# 所选择性搜索
rects = ss.process()
print(type(rects), rects.shape)
(12569, 4)
- 单策略搜索
import cv2
# 准备一张图像
img = cv2.imread("gpu.jpeg")
# 创建SelectiveSearch对象
ss = cv2.ximgproc.segmentation.createSelectiveSearchSegmentation()
# 添加图像到处理列表
ss.setBaseImage(img)
# 初始化算法参数
# ss.switchToSelectiveSearchQuality()
# int base_k = 150,
# int inc_k = 150,
# float sigma = 0.8f
# ss.switchToSelectiveSearchFast()
ss.switchToSingleStrategy()
# 所选择性搜索
rects = ss.process()
print(type(rects), rects.shape)
(2750, 4)
基于颜色、交叠、尺度、纹理的搜索策略
import cv2
# 基于颜色策略的搜索
ssc = cv2.ximgproc.segmentation.createSelectiveSearchSegmentationStrategyColor()
# 基于填充的策略
ssf = cv2.ximgproc.segmentation.createSelectiveSearchSegmentationStrategyFill()
img = cv2.imread("gpu.jpeg")
ss = cv2.ximgproc.segmentation.createSelectiveSearchSegmentation()
ss.clearStrategies()
ss.addStrategy(ssc) ## 不用设置,下面几个方法意境是比较成熟的策略方案了,看源代码了解
ss.addStrategy(ssf)
ss.addImage(img)
ss.setBaseImage(img)
# ss.switchToSingleStrategy()
ss.switchToSelectiveSearchFast()
rects = ss.process()
print(type(rects), rects.shape)
(12569, 4)
OpenCV实现说明
- 上述只是一个演示,实际OpenCV的策略都是内部使用。下面是源代码实现的说明
策略类
- 一共四个策略类:颜色相似度,填充(Fill:就是交叠的意思)相似,纹理相似度,尺度相似合并策略。这类列出类的声明。
class SelectiveSearchSegmentationStrategyColorImpl CV_FINAL : public SelectiveSearchSegmentationStrategyColor {
public:
SelectiveSearchSegmentationStrategyColorImpl() {
name_ = "SelectiveSearchSegmentationStrategyColor";
last_image_id = -1;
}
virtual void setImage(InputArray img, InputArray regions, InputArray sizes, int image_id = -1) CV_OVERRIDE;
virtual float get(int r1, int r2) CV_OVERRIDE;
virtual void merge(int r1, int r2) CV_OVERRIDE;
private:
String name_;
Mat histograms; // [Region X Histogram]
Mat sizes;
int histogram_size;
int last_image_id; // If the image_id is not equal to -1 and the same as the previous call for setImage, computations are used again
Mat last_histograms;
};
switchToSingleStrategy函数实现
- 其他几个函数类似,只是策略使用不同。
- 不同策略产生不同输出,可以阅读参考代码,直接判定出计算的快慢。
- switchToSelectiveSearchFast(中等)
- switchToSingleStrategy(最快)
- switchToSelectiveSearchQuality(最慢)
- 不同策略产生不同输出,可以阅读参考代码,直接判定出计算的快慢。
void SelectiveSearchSegmentationImpl::switchToSingleStrategy(int k, float sigma) {
clearImages();
clearGraphSegmentations();
clearStrategies();
Mat hsv;
cvtColor(base_image, hsv, COLOR_BGR2HSV);
addImage(hsv);
Ptr gs = createGraphSegmentation();
gs->setK((float)k);
gs->setSigma(sigma);
addGraphSegmentation(gs);
Ptr color = createSelectiveSearchSegmentationStrategyColor();
Ptr fill = createSelectiveSearchSegmentationStrategyFill();
Ptr texture = createSelectiveSearchSegmentationStrategyTexture();
Ptr size = createSelectiveSearchSegmentationStrategySize();
Ptr m = createSelectiveSearchSegmentationStrategyMultiple(color, fill, texture, size);
addStrategy(m);
}
process的实现
void SelectiveSearchSegmentationImpl::process(std::vector& rects) {
std::vector all_regions;
int image_id = 0;
for(std::vector::iterator image = images.begin(); image != images.end(); ++image) {
for(std::vector >::iterator gs = segmentations.begin(); gs != segmentations.end(); ++gs) {
Mat img_regions;
Mat_ is_neighbour;
Mat_ sizes;
// Compute initial segmentation
(*gs)->processImage(*image, img_regions);
// Get number of regions
double min, max;
minMaxLoc(img_regions, &min, &max);
int nb_segs = (int)max + 1;
// Compute bouding rects and neighbours
std::vector bounding_rects;
bounding_rects.resize(nb_segs);
std::vector > points;
points.resize(nb_segs);
is_neighbour = Mat::zeros(nb_segs, nb_segs, CV_8UC1);
sizes = Mat::zeros(nb_segs, 1, CV_32SC1);
const int* previous_p = NULL;
for (int i = 0; i < (int)img_regions.rows; i++) {
const int* p = img_regions.ptr(i);
for (int j = 0; j < (int)img_regions.cols; j++) {
points[p[j]].push_back(cv::Point(j, i));
sizes.at(p[j], 0) = sizes.at(p[j], 0) + 1;
if (i > 0 && j > 0) {
is_neighbour.at(p[j], p[j - 1]) = 1;
is_neighbour.at(p[j], previous_p[j]) = 1;
is_neighbour.at(p[j], previous_p[j - 1]) = 1;
is_neighbour.at(p[j - 1], p[j]) = 1;
is_neighbour.at(previous_p[j], p[j]) = 1;
is_neighbour.at(previous_p[j - 1], p[j]) = 1;
}
}
previous_p = p;
}
for(int seg = 0; seg < nb_segs; seg++) {
bounding_rects[seg] = cv::boundingRect(points[seg]);
}
for(std::vector >::iterator strategy = strategies.begin(); strategy != strategies.end(); ++strategy) {
std::vector regions;
hierarchicalGrouping(*image, *strategy, img_regions, is_neighbour, sizes, nb_segs, bounding_rects, regions, image_id);
for(std::vector::iterator region = regions.begin(); region != regions.end(); ++region) {
all_regions.push_back(*region);
}
}
image_id++;
}
}
std::sort(all_regions.begin(), all_regions.end());
std::map processed_rect;
rects.clear();
// Remove duplicate in rect list
for(std::vector::iterator region = all_regions.begin(); region != all_regions.end(); ++region) {
if (processed_rect.find((*region).bounding_box) == processed_rect.end()) {
processed_rect[(*region).bounding_box] = true;
rects.push_back((*region).bounding_box);
}
}
}
- 通过参考上面代码大致可以可以自己手撸代码!
SelectiveSearch算法的相似度计算公式
颜色相似度
-
将色彩空间转为HSV,每个通道下以bins=25计算直方图,这样每个区域的颜色直方图有个区间。 对直方图除以区域尺寸做归一化后使用下式计算相似度:
-
上面 , 理解这个公式的意义:
- 假设每一个颜色通道的直方图累加和为1.0(归一化后的值),三个通道的累加和就为3.0,如果区域和区域直方图完全一样,则此时颜色相似度最大为3.0,如果不一样,由于累加取两个区域bin的最小值进行累加,当直方图差距越大,累加的和就会越小,即颜色相似度越小。
纹理相似度
-
论文采用方差为1的高斯分布在8个方向做梯度统计,然后将统计结果(尺寸与区域大小一致)以bins=10计算直方图。直方图区间数为8310=240(使用RGB色彩空间),纹理相似度计算方式和颜色相似度计算方式类似:
8个方向的梯度就是SIFT-Like特征。
尺寸相似度
-
保证合并操作的尺度较为均匀,避免一个大区域陆续“吃掉”其他小区域。计算公式使用区域大小:
im是两个区域合并的区域,如果是包含区域,则相似度为0.这时候是不合并的。
交叠相似度
-
两个区域的重叠度
-
BBij是合并后的区域的Bounding Box(能够框住区域的最小矩形BBij)越小
- 合并区域的外接矩阵。
最终相似度
按照相似度合并区域即可。
附录
- 其他候选区域生成算法:
- Objectness(需要权限)
- 地址:
http://groups.inf.ed.ac.uk/calvin/objectness/
- 地址:
- Constrained Parametric Min-Cuts for Automatic Object Segmentation
- 地址:
http://www.maths.lth.se/sminchisescu/
- 地址:
- Category Independent Object Proposals
- 地址:
http://vision.cs.uiuc.edu/proposals/
- 地址:
- Selective Search
- 地址:
https://www.koen.me/research/selectivesearch/
- 地址:
- Objectness(需要权限)