早期的RCNN目标检测算法中使用selective search算法来产生region proposals.
该算法的大致流程如下:
1、利用图分割算法将图像分成不同的区域,并为这些区域产生相应的包围框
2、计算包围框之间的相似度,相似度可以分为四个部分(颜色相似度、纹理相似度和大小,相交约束),合并相近的包围框
3、排除过大、过小、长宽比过大、过小的包围框即可
参考代码:https://github.com/tttanikawa/selective-search-cpp
#pragma once
#include <algorithm>
#include <array>
#include <cassert>
#include <chrono>
#include <cmath>
#include <iostream>
#include <iterator>
#include <map>
#include <memory>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/ml.hpp>
#include <opencv2/objdetect.hpp>
#include <random>
#include <unordered_map>
#include <vector>
namespace std
{
template <>
class hash<std::pair<int, int>>
{
public:
std::size_t operator()(const std::pair<int, int> &x) const
{
return hash<int>()(x.first) ^ hash<int>()(x.second);
}
};
} // namespace std
namespace ss
{
inline double square(double a)
{
return a * a;
}
inline double diff(const cv::Mat &img, int x1, int y1, int x2, int y2)
{
return sqrt(square(img.at<cv::Vec3f>(y1, x1)[0] - img.at<cv::Vec3f>(y2, x2)[0]) +
square(img.at<cv::Vec3f>(y1, x1)[1] - img.at<cv::Vec3f>(y2, x2)[1]) +
square(img.at<cv::Vec3f>(y1, x1)[2] - img.at<cv::Vec3f>(y2, x2)[2]));
}
struct UniverseElement
{
int rank;
int p;
int size;
UniverseElement() : rank(0), size(1), p(0) {
}
UniverseElement(int rank, int size, int p) : rank(rank), size(size), p(p) {
}
bool operator==(const UniverseElement &other) const
{
return rank == other.rank && p == other.p && size == other.size;
}
};
class Universe
{
private:
std::vector<UniverseElement> elements;
int num;
public:
Universe(int num) : num(num)
{
elements.reserve(num);
for (int i = 0; i < num; i++)
{
elements.emplace_back(0, 1, i);
}
}
~Universe() {
}
int findFast(int x)
{
return elements[x].p;
}
int find(int x)
{
int y = x;
while (y != elements[y].p)
{
y = elements[y].p;
}
elements[x].p = y;
return y;
}
void join(int x, int y)
{
if (elements[x].rank > elements[y].rank)
{
elements[y].p = x;
elements[x].size += elements[y].size;
}
else
{
elements[x].p = y;
elements[y].size += elements[x].size;
if (elements[x].rank == elements[y].rank)
{
elements[y].rank++;
}
}
num--;
}
int size(int x) const {
return elements[x].size; }
int numSets() const {
return num; }
};
struct edge
{
int a;
int b;
double w;
};
bool operator<(const edge &a, const edge &b)
{
return a.w < b.w;
}
inline double calThreshold(int size, double scale)
{
return scale / size;
}
std::shared_ptr<Universe> segmentGraph(int numVertices, int numEdges, std::vector<edge> &edges, double scale)
{
std::sort(edges.begin(), edges.end());
auto universe = std::make_shared<Universe>(numVertices);
std::vector<double> threshold(numVertices, scale);
for (auto &pedge : edges)
{
int a = universe->find(pedge.a);
int b = universe->find(pedge.b);
if (a != b)
{
if ((pedge.w <= threshold[a]) && (pedge.w <= threshold[b]))
{
universe->join(a, b);
a = universe->find(a);
threshold[a] = pedge.w + calThreshold(universe->size(a), scale);
}
}
}
return universe;
}
// image segmentation using "Efficient Graph-Based Image Segmentation" // 类似并查集
std::sha