2 #include <opencv2/opencv.hpp> 19 cv::Mat grayscale_image;
20 if (image.channels() == 3)
21 cv::cvtColor(image, grayscale_image, cv::COLOR_BGR2GRAY);
23 grayscale_image = image;
25 if (grayscale_image.type() != CV_8UC1)
28 std::cerr <<
"Blob detector only supports 8-bit images!\n";
31 std::vector<std::vector<Center>> centers;
32 std::vector<std::vector<cv::Point>> contours;
33 for (
double thresh =
params_.minThreshold; thresh <
params_.maxThreshold; thresh +=
params_.thresholdStep)
35 cv::Mat binarized_image;
36 cv::threshold(grayscale_image, binarized_image, thresh, 255, cv::THRESH_BINARY);
38 std::vector<Center> cur_centers;
39 std::vector<std::vector<cv::Point>> cur_contours, new_contours;
40 findBlobs(grayscale_image, binarized_image, cur_centers, cur_contours);
41 std::vector<std::vector<Center>> new_centers;
42 for (std::size_t i = 0; i < cur_centers.size(); ++i)
45 for (std::size_t j = 0; j < centers.size(); ++j)
47 double dist = cv::norm(centers[j][centers[j].size() / 2].location - cur_centers[i].location);
48 isNew = dist >=
params_.minDistBetweenBlobs && dist >= centers[j][centers[j].size() / 2].radius &&
49 dist >= cur_centers[i].radius;
52 centers[j].push_back(cur_centers[i]);
54 size_t k = centers[j].size() - 1;
55 while (k > 0 && centers[j][k].radius < centers[j][k - 1].radius)
57 centers[j][k] = centers[j][k - 1];
60 centers[j][k] = cur_centers[i];
67 new_centers.push_back(std::vector<Center>(1, cur_centers[i]));
68 new_contours.push_back(cur_contours[i]);
71 std::copy(new_centers.begin(), new_centers.end(), std::back_inserter(centers));
72 std::copy(new_contours.begin(), new_contours.end(), std::back_inserter(contours));
75 for (
size_t i = 0; i < centers.size(); ++i)
77 if (centers[i].size() <
params_.minRepeatability)
79 cv::Point2d sum_point(0, 0);
80 double normalizer = 0;
81 for (std::size_t j = 0; j < centers[i].size(); ++j)
83 sum_point += centers[i][j].confidence * centers[i][j].location;
84 normalizer += centers[i][j].confidence;
86 sum_point *= (1. / normalizer);
87 cv::KeyPoint kpt(sum_point, (
float)(centers[i][centers[i].size() / 2].radius));
88 keypoints.push_back(kpt);
94 std::vector<std::vector<cv::Point>>& cur_contours)
const 100 std::vector<std::vector<cv::Point>> contours;
101 cv::Mat tmp_binary_image = binary_image.clone();
102 cv::findContours(tmp_binary_image, contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE);
104 for (std::size_t contour_idx = 0; contour_idx < contours.size(); ++contour_idx)
108 cv::Moments moms = cv::moments(cv::Mat(contours[contour_idx]));
111 double area = moms.m00;
112 if (area < params_.minArea || area >=
params_.maxArea)
116 if (
params_.filterByCircularity)
118 double area = moms.m00;
119 double perimeter = cv::arcLength(cv::Mat(contours[contour_idx]),
true);
120 double ratio = 4 * CV_PI * area / (perimeter * perimeter);
121 if (ratio < params_.minCircularity || ratio >=
params_.maxCircularity)
127 double denominator = std::sqrt(std::pow(2 * moms.mu11, 2) + std::pow(moms.mu20 - moms.mu02, 2));
128 const double eps = 1e-2;
130 if (denominator > eps)
132 double cosmin = (moms.mu20 - moms.mu02) / denominator;
133 double sinmin = 2 * moms.mu11 / denominator;
134 double cosmax = -cosmin;
135 double sinmax = -sinmin;
137 double imin = 0.5 * (moms.mu20 + moms.mu02) - 0.5 * (moms.mu20 - moms.mu02) * cosmin - moms.mu11 * sinmin;
138 double imax = 0.5 * (moms.mu20 + moms.mu02) - 0.5 * (moms.mu20 - moms.mu02) * cosmax - moms.mu11 * sinmax;
146 if (ratio < params_.minInertiaRatio || ratio >=
params_.maxInertiaRatio)
154 std::vector<cv::Point> hull;
155 cv::convexHull(cv::Mat(contours[contour_idx]), hull);
156 double area = cv::contourArea(cv::Mat(contours[contour_idx]));
157 double hullArea = cv::contourArea(cv::Mat(hull));
158 double ratio = area / hullArea;
159 if (ratio < params_.minConvexity || ratio >=
params_.maxConvexity)
165 center.
location = cv::Point2d(moms.m10 / moms.m00, moms.m01 / moms.m00);
175 std::vector<double> dists;
176 for (std::size_t point_idx = 0; point_idx < contours[contour_idx].size(); ++point_idx)
178 cv::Point2d pt = contours[contour_idx][point_idx];
179 dists.push_back(cv::norm(center.
location - pt));
181 std::sort(dists.begin(), dists.end());
182 center.
radius = (dists[(dists.size() - 1) / 2] + dists[dists.size() / 2]) / 2.;
185 centers.push_back(center);
186 cur_contours.push_back(contours[contour_idx]);
virtual void detect(const cv::Mat &image, std::vector< cv::KeyPoint > &keypoints, const cv::Mat &mask=cv::Mat())
Detects keypoints in an image and extracts contours.
void updateParameters(const cv::SimpleBlobDetector::Params ¶meters)
Update internal parameters.
virtual void findBlobs(const cv::Mat &image, const cv::Mat &binary_image, std::vector< Center > ¢ers, std::vector< std::vector< cv::Point >> &cur_contours) const
BlobDetector(const cv::SimpleBlobDetector::Params ¶meters=cv::SimpleBlobDetector::Params())
Default constructor which optionally accepts custom parameters.
static cv::Ptr< BlobDetector > create(const BlobDetector::Params ¶ms)
Create shared instance of the blob detector with given parameters.
std::vector< std::vector< cv::Point > > contours_