Я использую findContours
для обнаружения blob. Теперь я бы объединил близкие и похожие капли вместе.
Вот несколько примеров изображений:
Возможно ли это с обычным Opencv?
Я использую findContours
для обнаружения blob. Теперь я бы объединил близкие и похожие капли вместе.
Вот несколько примеров изображений:
Возможно ли это с обычным Opencv?
Входные изображения, которые вы нам дали, довольно просты в работе:
Первый шаг изолировать желтые капли от всего остального, и простая задача сегментации цвета может выполнить эту задачу. Вы можете посмотреть Сегментация и обнаружение объектов по цвету или Отслеживание цветные объекты в OpenCV, чтобы иметь представление о том, как это сделать.
Затем, время для слияния капли. Одним из методов, который может быть полезен, является ограничивающий прямоугольник, чтобы поместить все капли внутри прямоугольника. Обратите внимание на изображения ниже, что есть зеленый прямоугольник, окружающий капли:
После этого все, что вам нужно сделать, это заполнить прямоугольник цветом по вашему выбору, тем самым соединяя все капли. Я оставляю это в качестве домашней работы для вас.
Это самый быстрый и простой подход, о котором я мог думать. Следующий код демонстрирует, как добиться того, что я только что описал:
#include <cv.h>
#include <highgui.h>
#include <iostream>
#include <vector>
int main(int argc, char* argv[])
{
cv::Mat img = cv::imread(argv[1]);
if (!img.data)
{
std::cout "!!! Failed to open file: " << argv[1] << std::endl;
return 0;
}
// Convert RGB Mat into HSV color space
cv::Mat hsv;
cv::cvtColor(img, hsv, CV_BGR2HSV);
// Split HSV Mat into HSV components
std::vector<cv::Mat> v;
cv::split(hsv,v);
// Erase pixels with low saturation
int min_sat = 70;
cv::threshold(v[1], v[1], min_sat, 255, cv::THRESH_BINARY);
/* Work with the saturated image from now on */
// Erode could provide some enhancement, but I'm not sure.
// cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
// cv::erode(v[1], v[1], element);
// Store the set of points in the image before assembling the bounding box
std::vector<cv::Point> points;
cv::Mat_<uchar>::iterator it = v[1].begin<uchar>();
cv::Mat_<uchar>::iterator end = v[1].end<uchar>();
for (; it != end; ++it)
{
if (*it) points.push_back(it.pos());
}
// Compute minimal bounding box
cv::RotatedRect box = cv::minAreaRect(cv::Mat(points));
// Display bounding box on the original image
cv::Point2f vertices[4];
box.points(vertices);
for (int i = 0; i < 4; ++i)
{
cv::line(img, vertices[i], vertices[(i + 1) % 4], cv::Scalar(0, 255, 0), 1, CV_AA);
}
cv::imshow("box", img);
//cv::imwrite(argv[2], img);
cvWaitKey(0);
return 0;
}
Я думаю, что сделал это, благодаря вашим данным программы я нашел это решение: (комментарии приветствуются)
vector<vector<Point> > contours;
vector<vector<Point> > tmp_contours;
findContours(detectedImg, tmp_contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
vector<vector<Point> >::iterator it1;
it1 = tmp_contours.begin();
Mat test;
test = Mat(FImage.size(), CV_32FC3);
while (it1 != tmp_contours.end()) {
vector<Point> approx1;
approxPolyDP(Mat(*it1), approx1, 3, true);
Rect box1 = boundingRect(approx1);
float area1 = contourArea(approx1);
if ((area1 > 50) && (area1 < 13000) && (box1.width < 100) && (box1.height < 120)) {
vector<vector<Point> >::iterator it2;
it2 = tmp_contours.begin();
while (it2 != tmp_contours.end()) {
vector<Point> approx2;
approxPolyDP(Mat(*it2), approx2, 3, true);
Moments m1 = moments(Mat(approx1), false);
Moments m2 = moments(Mat(approx2), false);
float x1 = m1.m10 / m1.m00;
float y1 = m1.m01 / m1.m00;
float x2 = m2.m10 / m2.m00;
float y2 = m2.m01 / m2.m00;
vector<Point> dist;
dist.push_back(Point(x1, y1));
dist.push_back(Point(x2, y2));
float d = arcLength(dist, false);
Rect box2 = boundingRect(approx2);
if (box1 != box2) {
if (d < 25) {
//Method to merge the vectors
approx1 = mergePoints(approx1, approx2);
}
}
++it2;
}
Rect b = boundingRect(approx1);
rectangle(test, b, CV_RGB(125, 255, 0), 2);
contours.push_back(approx1);
}
++it1;
}