我的代码与此tutorial相同。
当我在使用cv::watershed()
后看到结果图像时,有一个我想要找到的对象(右上角),但它缺失了。
使用cv::drawContours()
后,图像中确实有六个标记。
这是正常的,因为存在分水岭算法的不准确性吗?
以下是我的代码的一部分:
Mat src = imread("result01.png");
Mat gray;
cvtColor(src, gray, COLOR_BGR2GRAY);
Mat thresh;
threshold(gray, thresh, 0, 255, THRESH_BINARY | THRESH_OTSU);
// noise removal
Mat kernel = Mat::ones(3, 3, CV_8UC1);
Mat opening;
morphologyEx(thresh, opening, MORPH_OPEN, kernel, Point(-1, -1), 2);
// Perform the distance transform algorithm
Mat dist_transform;
distanceTransform(opening, dist_transform, CV_DIST_L2, 5);
// Normalize the distance image for range = {0.0, 1.0}
// so we can visualize and threshold it
normalize(dist_transform, dist_transform, 0, 1., NORM_MINMAX);
// Threshold to obtain the peaks
// This will be the markers for the foreground objects
Mat dist_thresh;
threshold(dist_transform, dist_thresh, 0.5, 1., CV_THRESH_BINARY);
Mat dist_8u;
dist_thresh.convertTo(dist_8u, CV_8U);
// Find total markers
vector<vector<Point> > contours;
findContours(dist_8u, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
// Create the marker image for the watershed algorithm
Mat markers = Mat::zeros(dist_thresh.size(), CV_32SC1);
// Draw the foreground markers
for (size_t i = 0; i < contours.size(); i++)
drawContours(markers, contours, static_cast<int>(i), Scalar::all(static_cast<int>(i)+1), -1);
// Perform the watershed algorithm
watershed(src, markers);
原始图片:
watershed
之后的结果:
您可以在此处找到原始图像,中间图像和结果图像:
答案 0 :(得分:1)
在您的示例中,您认为 background 的内容与&#34;缺少&#34;相同的标签(5)。对象
您也可以通过将标签(&gt; 0)设置为背景来轻松调整此项。
您可以找到确定背景扩张的内容并取消thresh
图像。
然后,在创建标记时,将标签定义为:
0
:未知1
:背景>1
:您的对象在输出图片中,markers
将包含:
-1
:对象之间的边缘0
:背景(按照watershed
的目的)1
:背景(如您所定义)>1
:您的对象。此代码应该有所帮助:
#include <opencv2\opencv.hpp>
#include <vector>
using namespace std;
using namespace cv;
int main()
{
Mat3b src = imread("path_to_image");
Mat1b gray;
cvtColor(src, gray, COLOR_BGR2GRAY);
Mat1b thresh;
threshold(gray, thresh, 0, 255, THRESH_BINARY | THRESH_OTSU);
// noise removal
Mat1b kernel = getStructuringElement(MORPH_RECT, Size(3,3));
Mat1b opening;
morphologyEx(thresh, opening, MORPH_OPEN, kernel, Point(-1, -1), 2);
Mat1b kernelb = getStructuringElement(MORPH_RECT, Size(21, 21));
Mat1b background;
morphologyEx(thresh, background, MORPH_DILATE, kernelb);
background = ~background;
// Perform the distance transform algorithm
Mat1f dist_transform;
distanceTransform(opening, dist_transform, CV_DIST_L2, 5);
// Normalize the distance image for range = {0.0, 1.0}
// so we can visualize and threshold it
normalize(dist_transform, dist_transform, 0, 1., NORM_MINMAX);
// Threshold to obtain the peaks
// This will be the markers for the foreground objects
Mat1f dist_thresh;
threshold(dist_transform, dist_thresh, 0.5, 1., CV_THRESH_BINARY);
Mat1b dist_8u;
dist_thresh.convertTo(dist_8u, CV_8U);
// Find total markers
vector<vector<Point> > contours;
findContours(dist_8u, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
// Create the marker image for the watershed algorithm
Mat1i markers(dist_thresh.rows, dist_thresh.cols, int(0));
// Background as 1
Mat1i one(markers.rows, markers.cols, int(1));
bitwise_or(one, markers, markers, background);
// Draw the foreground markers (from 2 up)
for (int i = 0; i < int(contours.size()); i++)
drawContours(markers, contours, i, Scalar(i+2), -1);
// Perform the watershed algorithm
Mat3b dbg;
cvtColor(opening, dbg, COLOR_GRAY2BGR);
watershed(dbg, markers);
Mat res;
markers.convertTo(res, CV_8U);
normalize(res, res, 0, 255, NORM_MINMAX);
return 0;
}
结果:
答案 1 :(得分:0)
流域的emgu cv数据非常少。 这是我使用c#翻译这个问题。我知道这不是正确的论坛,但这个答案会突然出现给所有的搜索者:
//Mat3b src = imread("path_to_image");
//cvtColor(src, gray, COLOR_BGR2GRAY);
Image<Gray, byte> gray = smallImage.Convert<Gray, byte>();
//threshold(gray, thresh, 0, 255, THRESH_BINARY | THRESH_OTSU);
Image<Gray, byte> thresh = gray.ThresholdBinaryInv(new Gray(55), new Gray(255));
// noise removal
Mat kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), new Point(-1, -1));
//Mat1b opening;
//morphologyEx(thresh, opening, MORPH_OPEN, kernel, Point(-1, -1), 2);
Image<Gray, byte> opening = thresh.MorphologyEx(MorphOp.Open, kernel, new Point(-1, -1), 2, BorderType.Default, new MCvScalar(255));
//Mat1b kernelb = getStructuringElement(MORPH_RECT, Size(21, 21));
Mat kernel1 = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), new Point(-1, -1));
//Mat1b background;
//morphologyEx(thresh, background, MORPH_DILATE, kernelb);
Image<Gray, byte> background = thresh.MorphologyEx(MorphOp.Dilate, kernel, new Point(-1, -1), 2, BorderType.Default, new MCvScalar(255));
background = ~background;
//// Perform the distance transform algorithm
//Mat1f dist_transform;
//distanceTransform(opening, dist_transform, CV_DIST_L2, 5);
Image<Gray, float> dist_transform = new Image<Gray, float>(opening.Width, opening.Height);
CvInvoke.DistanceTransform(opening, dist_transform, null, DistType.L2, 5);
//// Normalize the distance image for range = {0.0, 1.0}
//// so we can visualize and threshold it
//normalize(dist_transform, dist_transform, 0, 1., NORM_MINMAX);
CvInvoke.Normalize(dist_transform, dist_transform, 0, 1.0, NormType.MinMax, DepthType.Default);
//// Threshold to obtain the peaks
//// This will be the markers for the foreground objects
//Mat1f dist_thresh;
//threshold(dist_transform, dist_thresh, 0.5, 1., CV_THRESH_BINARY);
Image<Gray, float> dist_thresh = new Image<Gray, float>(opening.Width, opening.Height);
CvInvoke.Threshold(dist_transform, dist_thresh, 0.5, 1.0, ThresholdType.Binary);
//Mat1b dist_8u;
//dist_thresh.convertTo(dist_8u, CV_8U);
Image<Gray, Byte> dist_8u = dist_thresh.Convert<Gray, Byte>();
//// Find total markers
//vector<vector<Point>> contours;
//findContours(dist_8u, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
CvInvoke.FindContours(dist_8u, contours, null, RetrType.External, ChainApproxMethod.ChainApproxSimple);
//// Create the marker image for the watershed algorithm
//Mat1i markers(dist_thresh.rows, dist_thresh.cols, int(0));
Image<Gray, int> markers = new Image<Gray, int>(dist_thresh.Width, dist_thresh.Height, new Gray(0));
//// Background as 1
//Mat1i one(markers.rows, markers.cols, int(1));
//bitwise_or(one, markers, markers, background);
Image<Gray, int> one = new Image<Gray, int>(markers.Cols, markers.Rows, new Gray(1));
CvInvoke.BitwiseOr(one, markers, markers, background);
//// Draw the foreground markers (from 2 up)
for (int i = 0; i < contours.Size; i++)
// drawContours(markers, contours, i, Scalar(i + 2), -1);
CvInvoke.DrawContours(markers, contours, i, new MCvScalar(i + 2));
//// Perform the watershed algorithm
//Mat3b dbg;
//cvtColor(opening, dbg, COLOR_GRAY2BGR);
//watershed(dbg, markers);
Image<Bgr, byte> dbg = new Image<Bgr, byte>(markers.Cols, markers.Rows);
CvInvoke.CvtColor(opening, dbg, ColorConversion.Gray2Bgr);
CvInvoke.Watershed(dbg, markers);
//Mat res;
//markers.convertTo(res, CV_8U);
//normalize(res, res, 0, 255, NORM_MINMAX);
CvInvoke.Normalize(markers, markers, 0, 255, NormType.MinMax);
//return 0;
在深色背景上查找光对象,将ThresholdBinaryInv替换为ThresholdBinary