Я использую сегментацию водораздела, чтобы обнаружить соприкасающиеся объекты, и это работает хорошо, делая это. Теперь я хотел бы нарисовать контуры каждого объекта, чтобы я мог получить их длину, площадь, моменты и т. Д. Но объекты в результате сегментации все еще соприкасаются. Поэтому я не могу нарисовать контуры каждого из них. Как я могу нарисовать контуры каждого объекта?
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("source.png");
// Create binary image from source image
Mat srcGray;
cvtColor(src, srcGray, CV_BGR2GRAY);
Mat srcThresh;
threshold(srcGray, srcThresh, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
// Perform the distance transform algorithm
Mat dist;
distanceTransform(srcThresh, dist, CV_DIST_L2, 3);
// Normalize the distance image for range = {0.0, 1.0}
normalize(dist, dist, 0, 1., NORM_MINMAX);
// Threshold to obtain the peaks
threshold(dist, dist, 0.1, 3.5, CV_THRESH_BINARY);
// Create the CV_8U version of the distance image
Mat dist_8u;
dist.convertTo(dist_8u, CV_8U);
// Find total markers
std::vector<std::vector<Point> > contours;
findContours(dist_8u, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
int ncomp = contours.size();
// Create the marker image for the watershed algorithm
Mat markers = Mat::zeros(dist.size(), CV_32SC1);
// Draw the foreground markers
for (int i = 0; i < ncomp; i++)
drawContours(markers, contours, i, Scalar::all(i + 1), -1);
// Draw the background marker
circle(markers, Point(5, 5), 3, CV_RGB(255, 255, 255), -1);
// Perform the watershed algorithm
watershed(src, markers);
Mat wgResult = (markers.clone()) * 10000;
imshow("Watershed", wgResult);
waitKey(0);
return 0;
}
markers
матрица возвращается watershed
содержит индексы сегментированных областей, согласно семени. Так что каждый составная часть будет иметь такое же начальное значение. Затем вы можете создать двоичную матрицу для каждого семени, например:
Mat1b mask = (markers == seed);
Если у вас есть двоичная маска для каждого компонента, вы можете легко вычислить его площадь, моменты и т. Д.
Код:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("D:\\SO\\img\\postit.png");
// Create binary image from source image
Mat srcGray;
cvtColor(src, srcGray, CV_BGR2GRAY);
Mat srcThresh;
threshold(srcGray, srcThresh, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
// Perform the distance transform algorithm
Mat dist;
distanceTransform(srcThresh, dist, CV_DIST_L2, 3);
// Normalize the distance image for range = {0.0, 1.0}
normalize(dist, dist, 0, 1., NORM_MINMAX);
// Threshold to obtain the peaks
threshold(dist, dist, 0.1, 3.5, CV_THRESH_BINARY);
// Create the CV_8U version of the distance image
Mat dist_8u;
dist.convertTo(dist_8u, CV_8U);
// Find total markers
std::vector<std::vector<Point> > contours;
findContours(dist_8u, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
int ncomp = contours.size();
// Create the marker image for the watershed algorithm
Mat markers = Mat::zeros(dist.size(), CV_32SC1);
// Draw the foreground markers
for (int i = 0; i < ncomp; i++)
drawContours(markers, contours, i, Scalar::all(i + 1), -1);
// Draw the background marker
circle(markers, Point(5, 5), 3, CV_RGB(255, 255, 255), -1);
// Perform the watershed algorithm
watershed(src, markers);
for (int seed = 1; seed <= ncomp; ++seed)
{
Mat1b mask = (markers == seed);
// Now you have the mask, you can compute your statistics
imshow("Mask", mask);
waitKey();
}
return 0;
}
Есть много способов сделать это. В зависимости от текущего изображения, которое было показано, вы можете просто выполнить операцию эрозии и расширения, чтобы разделить их. Однако это не сработает, если площадь прохождения больше.
Вам нужна операция закрытия:
http://docs.opencv.org/2.4/doc/tutorials/imgproc/opening_closing_hats/opening_closing_hats.html