OpenCV分水岭分割错过了一些对象 [英] OpenCV Watershed segmentation miss some objects

查看:198
本文介绍了OpenCV分水岭分割错过了一些对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的代码与此教程. 当我使用cv::watershed()后看到结果图像时,有一个我想找出的对象(右上),但它丢失了. 使用cv::drawContours()后,图像中确实有六个标记. 这是正常现象,因为分水岭算法存在误差吗?

My code is the same as this tutorial. When I see the result image after using cv::watershed(), there is a object(upper-right) that I want to find out, but it's missing. There are indeed six marks in image after using cv::drawContours(). Is this normal because the inaccuracy of the watershed algorithm exist?

这是我的代码的一部分:

Here is part of my code:

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之后的结果:

您可以在此处找到原始图像,中间图像和结果图像:

You can find original, intermediate and result image here:

经过特定处理后的结果图像

推荐答案

在您的示例中,您认为 background 与缺少"对象具有相同的标签(5).

In your example, what you consider background is given the same label (5) as the "missing" object.

您也可以通过将标签(> 0)设置为背景来轻松地进行调整. 您可以确定背景放大和否定thresh图像的目的. 然后,在创建标记时,将标签定义为:

You can easily adjust this by setting a label (>0) to background, too. You can find what is for sure background dilating and negating the thresh image. Then, when creating a marker, you define the labels as:

  • 0:未知
  • 1:背景
  • >1:您的对象
  • 0: unknown
  • 1: background
  • >1 : your objects

在您的输出图像中,markers将具有:

In your output image, markers will have:

  • -1:对象之间的边缘
  • 0:背景(由决定)
  • 1:背景(根据您的定义)
  • >1:您的对象.
  • -1 : the edges between objects
  • 0: the background (as intended by watershed)
  • 1: the background (as you defined)
  • >1 : your objects.

此代码应提供帮助:

#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;
}

结果:

这篇关于OpenCV分水岭分割错过了一些对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆