2

I am trying to remove isolated pixels from an image.

I thought of using:

cvErode(img, img, 0, 1);

The problem is that I want a kernel of:

0 0 0
0 1 0
0 0 0

I'm unsure how to do that. Can anyone help?

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
Lilz
  • 4,013
  • 13
  • 61
  • 95
  • Do you mean a non-flat kernel or the one you described have some other meaning ? Having a value greater than 0 at origin will cause level shifting. Isn't that a problem for you ? – mmgp Dec 07 '12 at 02:16
  • Your kernel is just a dot! Use [cv::getStructuringElement](http://docs.opencv.org/modules/imgproc/doc/filtering.html?highlight=erode#getstructuringelement) with any shape (rect, ellipse) and cv::Size(1,1) – remi Dec 07 '12 at 07:30
  • I see it as a non-flat element, @remi. It is either a line with a peak at mid, or maybe a 3x3 square (flattened in the description) with a peak at mid. – mmgp Dec 07 '12 at 11:51
  • Yes but morphology is different than convolution/filtering. So the relevant parts of the kernel is the one where the non-zero values are. In this case, there is only a single non-zero value. If you wanted a line, you should fill the values with one, in a 1rowx9cols matrix – remi Dec 07 '12 at 15:12
  • That makes no sense to what I'm saying, @remi. There is flat morphology and non-flat morphology. In flat morphology you just deal with the neighborhood of a given point, in non-flat morphology you deal with a weighted neighborhood. In flat morphology, every structuring element is equivalent to a set of displacements, i.e., they all effectively have the value `0`, and the "neighborhood kernel" of `1`s defines the shape of this set of displacements. In the non-flat case, there is no need to stick to the value `0`. – mmgp Dec 07 '12 at 17:12

5 Answers5

0

You can filter the image with custom kernels in opencv using filter2D function.

Look at the documentation

Documents are always a good source to start from :)

satishffy
  • 153
  • 8
  • 2
    I'm not a CV Enthusiast :), so pardon me for the question. How do you perform a morphological erosion using filter2D ? – mmgp Dec 07 '12 at 02:14
  • Let me check whether I understood the question right. You have an image and you want to do morphological erosion on the same using a custom kernel. The custom kernel is a 3x3 matrix with elements {0,0,0,0,1,0,0,0,0}. By the way the kernel you mentioned is useless, as it will return the same image. – satishffy Dec 07 '12 at 11:59
  • If your question is about finding which kernel to use for obtaining a particular effect (morphological operation), you might have to re-phrase the question. Also, you will have to give more details for people in the forum to help you. Of course, it would be good if you can specify what options did you try. – satishffy Dec 07 '12 at 12:04
  • While the question is not mine, that would be a kernel possible from the description of the question. My problem with filter2D is that it is made to do linear filtering, while morphology is a non-linear approach. Now, we need to get in agreement between differences of a structuring function and structuring element, where the later is clearly supported by OpenCV. Or we can skip this and pose the question: can OpenCV perform a weighted-rank-order filter ? In that case, I would apply the weights {0, ..., 0, 1, 0, ... 0} to the horizontal neighbors of a given point and pick the n-ranked result. – mmgp Dec 07 '12 at 12:05
  • @mmgp : Yes. Non-linear morphology in OpenCV is something I'm not aware. I will search through the forum (during my leisure time) for any posts on that. If you find any, please provide links. – satishffy Dec 07 '12 at 12:35
  • Morphology is always non-linear. I'm talking about flat and non-flat morphology. – mmgp Dec 07 '12 at 17:13
0

Now you are setting default kernel by passing NULL as 3rd argument.

You should use http://docs.opencv.org/modules/imgproc/doc/filtering.html?highlight=erode#getstructuringelement and pass output as argument for erode function.

If you can not generate your kernel with this function. Simply create IplConvKernel element by hand.

krzych
  • 2,126
  • 7
  • 31
  • 50
  • OpenCV's documentation in this case looks poor to me. You can at best specify a custom shaped structuring element, but not a non-flat one. I understand that people mostly will only use flat morphology, and there are older publications about the decomposability of such elements for speedup. Now, there is a thing in Mathematical Morphology called non-flat element, generally a structuring function (not a structuring element) which seems to be lacking at OpenCV. It is certainly possible to perform non-flat operations using OpenCV, but it looks like one would need to drop the use of cvErode and co. – mmgp Dec 07 '12 at 11:57
0

After re-reading the question's title, now I see what you want. You are after the hit-or-miss morphological operator, the kernel you described is actually a 3x3 square perfectly fine for a function that performs a hit-or-miss. It doesn't seem OpenCV support it, but you can perform the equivalent of you what you want by doing a simple analysis of each point neighborhood: if a point isn't connected to any other point, remove it.

mmgp
  • 18,901
  • 3
  • 53
  • 80
0

Here is my 5 cent event though i dont know openCV at all.

But you should consider looking for a function called "Opening". This in an erosion followed by a dilation. This will remove small isolated pixel. The size of the removed elements will ofcourse depend on the kernel you use.

Another option is finding a function for doing a lowpass filtering of the image.

nomather what you do, it comes down to two steps. call a function to create a kernel. apply the kernel to the image using another function.

Whatever you do! Dont just use an "erode" function. It will also change the elements on the remaining image. In that case you should definitly use the "opening" function.

0

If you're using the new OpenCV 2.x API, you can do it like this:

cv::Mat kernel = (cv::Mat_<uchar>(3,3) << 0, 0, 0, 
                                          0, 1, 0, 
                                          0, 0, 0);
cv::erode(img, img, kernel);
flowfree
  • 16,356
  • 12
  • 52
  • 76
  • Except that does nothing. Morphology in OpenCV is exclusively done with flat elements, and it also ignores displacements marked with zeros. Effectively your SE is a single point (1), which doesn't change the image. – mmgp Jan 24 '13 at 05:05