1

I have an image where in I need to remove the "white" artifacts that do not represent a detected curve. I want to preserve the white pixels which represent the curve but, remove pixel outliers which are far away from the curve. After removing the artifacts, I would like to fit a smooth curve to the points in the image.

This is my image:

white detected curve

The image is a 8-bit grayscale image image with only black and white points. The white pixels in the "curve" are the area of interest and most of them are only a single pixel thick. Some white pixels are connected to each other but, not all of them. Some white pixels are strewn across. I would like to remove these white pixels since they are not contributing to the overall shape because I want to fit a smooth curve to them.

So far, I have tried to do dilation followed by erosion, closing and black hat operations. None of them seem to give me the result that I expect. I also tried to iterate through all points in the image, find the bright points, look in a 3x3 neighborhood around that pixel and set the value to 0 if it did not have more than two neighbors which are equal to itself.

What can I apply in order to achieve my desired result? Also, once I have my final "clean" output, how do I fit a smooth curve to the points in the image?

Community
  • 1
  • 1
Eagle
  • 1,187
  • 5
  • 22
  • 40
  • I think that a dilation followed by a bigger erosion should remove most of the artifacts while keeping the components of the curve. To fit the curve, you may try some Hough voting approach. – ChronoTrigger Apr 04 '14 at 20:25
  • @ChronoTrigger No, that's worse. The detected surface either completely disappears of has more pixels than necessary which is considered noise. I am looking for a way to preserve the detected edges. Maybe similar to a connected-component approach? – Eagle Apr 05 '14 at 00:20
  • @ChronoTrigger What is the Hough Voting scheme? Do you have a few links to the documentation/implementation from where I can learn stuff? – Eagle Apr 05 '14 at 00:26
  • I found this: http://homepages.inf.ed.ac.uk/rbf/BOOKS/BANDB/LIB/bandb4_3.pdf – ChronoTrigger Apr 05 '14 at 01:27

1 Answers1

0

I don't know how to fit the curve, it would be nice of you to ask this in another question.


About the noise: This function should do the trick, I've used it to remove noise in a black and wait image. It is a code sample from the book:

Mastering OpenCV with Practical Computer Vision Projects - Daniel Lelis Baggio

I have these includes added on the header where this function was instantiated:

#include  "opencv2/opencv.hpp"
#include <stdio.h>
#include <iostream>
#include <vector>

using namespace cv;
using namespace std;

mask is the image you want to filter, and it removes dots that don't have dots in any 5 pixels around the analysed one... Hope it helps

void removePepperNoise(Mat &mask)
{
// For simplicity, ignore the top & bottom row border.
for (int y=2; y<mask.rows-2; y++) {
    // Get access to each of the 5 rows near this pixel.
    uchar *pThis = mask.ptr(y);
    uchar *pUp1 = mask.ptr(y-1);
    uchar *pUp2 = mask.ptr(y-2);
    uchar *pDown1 = mask.ptr(y+1);
    uchar *pDown2 = mask.ptr(y+2);

    // For simplicity, ignore the left & right row border.
    pThis += 2;
    pUp1 += 2;
    pUp2 += 2;
    pDown1 += 2;
    pDown2 += 2;
    for (int x=2; x<mask.cols-2; x++) {
        uchar v = *pThis;   // Get the current pixel value (either 0 or 255).
        // If the current pixel is black, but all the pixels on the 2-pixel-radius-border are white
        // (ie: it is a small island of black pixels, surrounded by white), then delete that island.
        if (v == 0) {
            bool allAbove = *(pUp2 - 2) && *(pUp2 - 1) && *(pUp2) && *(pUp2 + 1) && *(pUp2 + 2);
            bool allLeft = *(pUp1 - 2) && *(pThis - 2) && *(pDown1 - 2);
            bool allBelow = *(pDown2 - 2) && *(pDown2 - 1) && *(pDown2) && *(pDown2 + 1) && *(pDown2 + 2);
            bool allRight = *(pUp1 + 2) && *(pThis + 2) && *(pDown1 + 2);
            bool surroundings = allAbove && allLeft && allBelow && allRight;
            if (surroundings == true) {
                // Fill the whole 5x5 block as white. Since we know the 5x5 borders
                // are already white, just need to fill the 3x3 inner region.
                *(pUp1 - 1) = 255;
                *(pUp1 + 0) = 255;
                *(pUp1 + 1) = 255;
                *(pThis - 1) = 255;
                *(pThis + 0) = 255;
                *(pThis + 1) = 255;
                *(pDown1 - 1) = 255;
                *(pDown1 + 0) = 255;
                *(pDown1 + 1) = 255;
            }
            // Since we just covered the whole 5x5 block with white, we know the next 2 pixels
            // won't be black, so skip the next 2 pixels on the right.
            pThis += 2;
            pUp1 += 2;
            pUp2 += 2;
            pDown1 += 2;
            pDown2 += 2;
        }
        // Move to the next pixel.
        pThis++;
        pUp1++;
        pUp2++;
        pDown1++;
        pDown2++;
    }
}
nico
  • 1,136
  • 1
  • 15
  • 33
  • I don't want to remove the white pixels. I want to preserve the structure of the white pixels in the curve but, I want to get rid of those outlier white pixels which are far away from the curve. I'm not sure what your code is trying to do but, I will try and see if it works. – Eagle Apr 04 '14 at 19:12
  • The code removes single 'black pixels' in a 5x5 block from the image (the time I used it my noise was black). I didn't notice you have island of pixels together the same proportion as in your line. Sorry for the bad approach, it will not solve your problem. – nico Apr 07 '14 at 05:53
  • Your code pointed me in the right direction. I had an idea after that to look for pixels across diagonals as shown here: http://stackoverflow.com/questions/22898881/opencv-fit-a-curve-to-a-set-of-points . The output looks good when line segments are used to approximate a curve. However, I would ideally like a smooth curve since I cannot get rid of all of the outliers without risking the loss of a bunch of points on the detected curve. I have to tradeoff now somehow I guess unless I can actually fit a curve properly. – Eagle Apr 07 '14 at 06:08
  • If you are able to find adjacent points centroids you could try a *polynomial regression* (actually I think it would work with the image you already have just knowing the white pixel positions). The *GNU Scientific Library* can do it. (http://rosettacode.org/wiki/Polynomial_regression#C) – nico Apr 07 '14 at 07:48
  • I don't understand what you mean by "adjacent point centroids"? Do you mean points which have white pixels to its left and right? – Eagle Apr 08 '14 at 19:02
  • No, centroid would be an assigned point that would represent points nearby. You have a few points islands, a polynomial regression using this "islands" coordinates could give you a good approach of your function. – nico Apr 11 '14 at 23:55