Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Non connecting morphological filter

After some simple preprocessing I am receiving boolean mask of segmented images.

Threshhold preprocessing

I want to "enhance" borders of the mask and make them more smooth. For that I am using OPEN morphology filter with a rather big circle kernel , it works very well until the distance between segmented objects is enough. But In alot of samples objects stick together. Is there exists some more or less simple method to smooth such kind of images without changing its morphology ?

enter image description here

like image 954
Oleg Avatar asked Mar 01 '26 02:03

Oleg


1 Answers

Without applying a morphological filter first, you can try to detect the external contours of the image. Now you can draw these external contours as filled contours and then apply your morphological filter. This works because now you don't have any holes to fill. This is fairly simple.

Another approach:

  • find external contours
  • take the x, y of coordinates of the contour points. you can consider these as 1-D signals and apply a smoothing filter to these signals

In the code below, I've applied the second approach to a sample image.

Input image

input

External contours without any smoothing

no smoothing

After applying a Gaussian filter to x and y 1-D signals

smooth

C++ code

Mat im = imread("4.png", 0);

Mat cont = im.clone();
Mat original = Mat::zeros(im.rows, im.cols, CV_8UC3);
Mat smoothed = Mat::zeros(im.rows, im.cols, CV_8UC3);

// contour smoothing parameters for gaussian filter
int filterRadius = 5;
int filterSize = 2 * filterRadius + 1;
double sigma = 10;      

vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
// find external contours and store all contour points
findContours(cont, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, Point(0, 0));
for(size_t j = 0; j < contours.size(); j++)
{
    // draw the initial contour shape
    drawContours(original, contours, j, Scalar(0, 255, 0), 1);
    // extract x and y coordinates of points. we'll consider these as 1-D signals
    // add circular padding to 1-D signals
    size_t len = contours[j].size() + 2 * filterRadius;
    size_t idx = (contours[j].size() - filterRadius);
    vector<float> x, y;
    for (size_t i = 0; i < len; i++)
    {
        x.push_back(contours[j][(idx + i) % contours[j].size()].x);
        y.push_back(contours[j][(idx + i) % contours[j].size()].y);
    }
    // filter 1-D signals
    vector<float> xFilt, yFilt;
    GaussianBlur(x, xFilt, Size(filterSize, filterSize), sigma, sigma);
    GaussianBlur(y, yFilt, Size(filterSize, filterSize), sigma, sigma);
    // build smoothed contour
    vector<vector<Point> > smoothContours;
    vector<Point> smooth;
    for (size_t i = filterRadius; i < contours[j].size() + filterRadius; i++)
    {
        smooth.push_back(Point(xFilt[i], yFilt[i]));
    }
    smoothContours.push_back(smooth);

    drawContours(smoothed, smoothContours, 0, Scalar(255, 0, 0), 1);

    cout << "debug contour " << j << " : " << contours[j].size() << ", " << smooth.size() << endl;
}
like image 126
dhanushka Avatar answered Mar 04 '26 03:03

dhanushka



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!