blob_detector.cpp
Go to the documentation of this file.
2 #include <opencv2/opencv.hpp>
3 #include <iostream>
4 
5 BlobDetector::BlobDetector(const SimpleBlobDetector::Params& parameters) : params_(parameters) {}
6 
7 cv::Ptr<BlobDetector> BlobDetector::create(const cv::SimpleBlobDetector::Params& params)
8 {
9  return cv::Ptr<BlobDetector> (new BlobDetector(params)); // compatibility with older versions
10  //return cv::makePtr<BlobDetector>(params);
11 }
12 
13 void BlobDetector::detect(const cv::Mat& image, std::vector<cv::KeyPoint>& keypoints, const cv::Mat&)
14 {
15  // TODO: support mask
16  contours_.clear();
17 
18  keypoints.clear();
19  cv::Mat grayscale_image;
20  if (image.channels() == 3)
21  cv::cvtColor(image, grayscale_image, cv::COLOR_BGR2GRAY);
22  else
23  grayscale_image = image;
24 
25  if (grayscale_image.type() != CV_8UC1)
26  {
27  //CV_Error(cv::Error::StsUnsupportedFormat, "Blob detector only supports 8-bit images!");
28  std::cerr << "Blob detector only supports 8-bit images!\n";
29  }
30 
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)
34  {
35  cv::Mat binarized_image;
36  cv::threshold(grayscale_image, binarized_image, thresh, 255, cv::THRESH_BINARY);
37 
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)
43  {
44  bool isNew = true;
45  for (std::size_t j = 0; j < centers.size(); ++j)
46  {
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;
50  if (!isNew)
51  {
52  centers[j].push_back(cur_centers[i]);
53 
54  size_t k = centers[j].size() - 1;
55  while (k > 0 && centers[j][k].radius < centers[j][k - 1].radius)
56  {
57  centers[j][k] = centers[j][k - 1];
58  k--;
59  }
60  centers[j][k] = cur_centers[i];
61 
62  break;
63  }
64  }
65  if (isNew)
66  {
67  new_centers.push_back(std::vector<Center>(1, cur_centers[i]));
68  new_contours.push_back(cur_contours[i]);
69  }
70  }
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));
73  }
74 
75  for (size_t i = 0; i < centers.size(); ++i)
76  {
77  if (centers[i].size() < params_.minRepeatability)
78  continue;
79  cv::Point2d sum_point(0, 0);
80  double normalizer = 0;
81  for (std::size_t j = 0; j < centers[i].size(); ++j)
82  {
83  sum_point += centers[i][j].confidence * centers[i][j].location;
84  normalizer += centers[i][j].confidence;
85  }
86  sum_point *= (1. / normalizer);
87  cv::KeyPoint kpt(sum_point, (float)(centers[i][centers[i].size() / 2].radius));
88  keypoints.push_back(kpt);
89  contours_.push_back(contours[i]);
90  }
91 }
92 
93 void BlobDetector::findBlobs(const cv::Mat& image, const cv::Mat& binary_image, std::vector<Center>& centers,
94  std::vector<std::vector<cv::Point>>& cur_contours) const
95 {
96  (void)image;
97  centers.clear();
98  cur_contours.clear();
99 
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);
103 
104  for (std::size_t contour_idx = 0; contour_idx < contours.size(); ++contour_idx)
105  {
106  Center center;
107  center.confidence = 1;
108  cv::Moments moms = cv::moments(cv::Mat(contours[contour_idx]));
109  if (params_.filterByArea)
110  {
111  double area = moms.m00;
112  if (area < params_.minArea || area >= params_.maxArea)
113  continue;
114  }
115 
116  if (params_.filterByCircularity)
117  {
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)
122  continue;
123  }
124 
125  if (params_.filterByInertia)
126  {
127  double denominator = std::sqrt(std::pow(2 * moms.mu11, 2) + std::pow(moms.mu20 - moms.mu02, 2));
128  const double eps = 1e-2;
129  double ratio;
130  if (denominator > eps)
131  {
132  double cosmin = (moms.mu20 - moms.mu02) / denominator;
133  double sinmin = 2 * moms.mu11 / denominator;
134  double cosmax = -cosmin;
135  double sinmax = -sinmin;
136 
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;
139  ratio = imin / imax;
140  }
141  else
142  {
143  ratio = 1;
144  }
145 
146  if (ratio < params_.minInertiaRatio || ratio >= params_.maxInertiaRatio)
147  continue;
148 
149  center.confidence = ratio * ratio;
150  }
151 
152  if (params_.filterByConvexity)
153  {
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)
160  continue;
161  }
162 
163  if (moms.m00 == 0.0)
164  continue;
165  center.location = cv::Point2d(moms.m10 / moms.m00, moms.m01 / moms.m00);
166 
167  if (params_.filterByColor)
168  {
169  if (binary_image.at<uchar>(cvRound(center.location.y), cvRound(center.location.x)) != params_.blobColor)
170  continue;
171  }
172 
173  // compute blob radius
174  {
175  std::vector<double> dists;
176  for (std::size_t point_idx = 0; point_idx < contours[contour_idx].size(); ++point_idx)
177  {
178  cv::Point2d pt = contours[contour_idx][point_idx];
179  dists.push_back(cv::norm(center.location - pt));
180  }
181  std::sort(dists.begin(), dists.end());
182  center.radius = (dists[(dists.size() - 1) / 2] + dists[dists.size() / 2]) / 2.;
183  }
184 
185  centers.push_back(center);
186  cur_contours.push_back(contours[contour_idx]);
187  }
188 }
189 
190 void BlobDetector::updateParameters(const Params& parameters)
191 {
192  params_ = parameters;
193 }
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 &parameters)
Update internal parameters.
virtual void findBlobs(const cv::Mat &image, const cv::Mat &binary_image, std::vector< Center > &centers, std::vector< std::vector< cv::Point >> &cur_contours) const
BlobDetector(const cv::SimpleBlobDetector::Params &parameters=cv::SimpleBlobDetector::Params())
Default constructor which optionally accepts custom parameters.
cv::Point2d location
Definition: blob_detector.h:98
static cv::Ptr< BlobDetector > create(const BlobDetector::Params &params)
Create shared instance of the blob detector with given parameters.
std::vector< std::vector< cv::Point > > contours_


costmap_converter
Author(s): Christoph Rösmann , Franz Albers , Otniel Rinaldo
autogenerated on Sat May 16 2020 03:19:18