ndimage/morphology - binary dilation and erosion?
![](https://secure.gravatar.com/avatar/b8db648ce5b0b58a7dda6eab71e5a98f.jpg?s=120&d=mm&r=g)
While preparing some images for OCR, I usually discard those with low DPI, but as this happens often I thought to try some image processing and on suggestion (morphological operations) I tried ndimage.morph with idea to play around binary_dilation Images were G4 TIFFs which PIL/MPL can't decode, so I convert to 1bit PNG which I normalized after to 0 and 1. On sample img I applied: ndi.morphology.binary_dilation(img).astype(img.dtype) and ndi.morphology.binary_erosion(img).astype(img.dtype) I attached result images, and wanted to ask two question: 1. Is this result correct? From what I read today seems like what dilation does is erosion and vice versa, but I probably overlooked something 2. Does someone maybe know of better approach for enhancing original sample for OCR (except thresholding, for which I'm aware)? TIA [image: Inline image 1]
![](https://secure.gravatar.com/avatar/b80364cc6fbb2eac7dcfdb7738bae083.jpg?s=120&d=mm&r=g)
On Sat, Mar 31, 2012 at 12:24 PM, klo uo <klonuo@gmail.com> wrote:
While preparing some images for OCR, I usually discard those with low DPI, but as this happens often I thought to try some image processing and on suggestion (morphological operations) I tried ndimage.morph with idea to play around binary_dilation
Images were G4 TIFFs which PIL/MPL can't decode, so I convert to 1bit PNG which I normalized after to 0 and 1.
On sample img I applied:
ndi.morphology.binary_dilation(img).astype(img.dtype)
and
ndi.morphology.binary_erosion(img).astype(img.dtype)
I attached result images, and wanted to ask two question:
1. Is this result correct? From what I read today seems like what dilation does is erosion and vice versa, but I probably overlooked something
This result looks correct to me. I think it depends on what you consider "object" and "background": Typically (I think), image-processing operators consider light regions to be objects and dark objects to be background. So dilation grows right regions and erosion shrinks bright regions. Obviously, in your images, definitions of object and background are reversed (black is object; white is background).
2. Does someone maybe know of better approach for enhancing original sample for OCR (except thresholding, for which I'm aware)?
Have you tried the `open` and `close` operators? A morphological opening is just an erosion followed by a dilation and the closing is just the reverse (see e.g., the scikits-image docstrings<http://scikits-image.org/docs/dev/api/skimage.morphology.html#greyscale-open>). For an opening, the erosion would remove some of "salt" (white pixels) in the letters, and the dilation would (more-or-less) restore the letters to their original thickness. The closing would do the same for black pixels on the background. There are other approaches of course, but since you're already thinking about erosion and dilation, these came to mind -Tony
TIA
[image: Inline image 1]
_______________________________________________ SciPy-User mailing list SciPy-User@scipy.org http://mail.scipy.org/mailman/listinfo/scipy-user
![](https://secure.gravatar.com/avatar/b8db648ce5b0b58a7dda6eab71e5a98f.jpg?s=120&d=mm&r=g)
On Sat, Mar 31, 2012 at 6:48 PM, Tony Yu <tsyu80@gmail.com> wrote:
1. Is this result correct? From what I read today seems like what dilation does is erosion and vice versa, but I probably overlooked something
This result looks correct to me. I think it depends on what you consider "object" and "background": Typically (I think), image-processing operators consider light regions to be objects and dark objects to be background. So dilation grows right regions and erosion shrinks bright regions. Obviously, in your images, definitions of object and background are reversed (black is object; white is background).
You are right. I thought on first it couldn't be flip logic, but thinking more about it and then backing with result from abs(img-1) shows it's just like that.
2. Does someone maybe know of better approach for enhancing original
sample for OCR (except thresholding, for which I'm aware)?
Have you tried the `open` and `close` operators? A morphological opening is just an erosion followed by a dilation and the closing is just the reverse (see e.g., the scikits-image docstrings<http://scikits-image.org/docs/dev/api/skimage.morphology.html#greyscale-open>). For an opening, the erosion would remove some of "salt" (white pixels) in the letters, and the dilation would (more-or-less) restore the letters to their original thickness. The closing would do the same for black pixels on the background.
Thanks for suggestion. Is morphology module in skimage reflection of ndimage, or it's separate implementation?
![](https://secure.gravatar.com/avatar/b8db648ce5b0b58a7dda6eab71e5a98f.jpg?s=120&d=mm&r=g)
On Sat, Mar 31, 2012 at 6:48 PM, Tony Yu <tsyu80@gmail.com> wrote:
Have you tried the `open` and `close` operators? A morphological opening is just an erosion followed by a dilation and the closing is just the reverse (see e.g., the scikits-image docstrings<http://scikits-image.org/docs/dev/api/skimage.morphology.html#greyscale-open>). For an opening, the erosion would remove some of "salt" (white pixels) in the letters, and the dilation would (more-or-less) restore the letters to their original thickness. The closing would do the same for black pixels on the background.
I tried grey opening on sample image with both modules. Approach seems good and result is bit identical with both modules (footprint=square(3)), and I thought to comment on differences on both modules: - skimage requires converting data type to 'uint8' and won't accept anything less - ndimage grey opening is 3 times faster on my PC
![](https://secure.gravatar.com/avatar/3aa58c446bbefaff35dbd90e27a3a107.jpg?s=120&d=mm&r=g)
On Saturday, March 31, 2012 08:08:41 PM klo uo wrote:
I tried grey opening on sample image with both modules. Approach seems good and result is bit identical with both modules (footprint=square(3)), and I thought to comment on differences on both modules:
- skimage requires converting data type to 'uint8' and won't accept anything less - ndimage grey opening is 3 times faster on my PC
Mahotas (which I wrote): http://luispedro.org/software/mahotas is closer in implementation to ndimage and should be as fast (as well as supporting multiple types). It doesn't have the open() operation, but you can dilate() & erode() yourself: def open(f, Bc, output=None): output = mahotas.dilate(f, Bc, output=output) return mahotas.erode(f, Bc, output=output) (Also, I think that the skimage erode() & dilate() are for flat structuring elements only, but that doesn't seem to be an issue for you). HTH, -- Luis Pedro Coelho | Institute for Molecular Medicine | http://luispedro.org
![](https://secure.gravatar.com/avatar/b8db648ce5b0b58a7dda6eab71e5a98f.jpg?s=120&d=mm&r=g)
Hi Luis, a bit prolonged reply, but as I remembered this messages thought to maybe get to you :) I wanted to try next on, with "skeleton-ing" some images, but "ndimage" doesn't have this function AFAIK. Then I googled and pointed to "pymorph" which I assume you are the author. So I'm curious, why did you recommended "mohotas", when "pymorph" seems like made for morphological analysis? Regards, klo On Mon, Apr 2, 2012 at 6:25 PM, Luis Pedro Coelho <lpc@cmu.edu> wrote:
On Saturday, March 31, 2012 08:08:41 PM klo uo wrote:
I tried grey opening on sample image with both modules. Approach seems good and result is bit identical with both modules (footprint=square(3)), and I thought to comment on differences on both modules:
- skimage requires converting data type to 'uint8' and won't accept anything less - ndimage grey opening is 3 times faster on my PC
Mahotas (which I wrote): http://luispedro.org/software/mahotas is closer in implementation to ndimage and should be as fast (as well as supporting multiple types).
It doesn't have the open() operation, but you can dilate() & erode() yourself:
def open(f, Bc, output=None): output = mahotas.dilate(f, Bc, output=output) return mahotas.erode(f, Bc, output=output)
(Also, I think that the skimage erode() & dilate() are for flat structuring elements only, but that doesn't seem to be an issue for you).
HTH, -- Luis Pedro Coelho | Institute for Molecular Medicine | http://luispedro.org
![](https://secure.gravatar.com/avatar/b8db648ce5b0b58a7dda6eab71e5a98f.jpg?s=120&d=mm&r=g)
So I'm curious, why did you recommended "mohotas", when "pymorph" seems like made for morphological analysis?
Just couple of minutes later, I read this (http://luispedro.org/software/pymorph#see-also): "mahotas is another Python image processing package, but most of its functions are in C++. It is, therefore, much faster for the operations it supports." So I assume that will be the answer ;)
![](https://secure.gravatar.com/avatar/b8db648ce5b0b58a7dda6eab71e5a98f.jpg?s=120&d=mm&r=g)
(http://luispedro.org/software/pymorph#see-also):
"mahotas is another Python image processing package, but most of its functions are in C++. It is, therefore, much faster for the operations it supports."
Skeletonization with "pymorph" is indeed very very slow I found very nice example how to do this just with "ndimage" and in a blink of a second time: ======================================== def sk(i, r): x = ndimage.distance_transform_edt(i) y = ndimage.morphological_laplace(x, (r, r)) return y < y.min()/2 ======================================== For example in pylab mode: In [1]: from scipy import ndimage In [2]: im = imread('clip.png')[:,:,0] In [3]: imshow(sk(im, 5), cmap='binary', interpolation='nearest')
![](https://secure.gravatar.com/avatar/b80364cc6fbb2eac7dcfdb7738bae083.jpg?s=120&d=mm&r=g)
On Sun, May 6, 2012 at 4:49 AM, klo uo <klonuo@gmail.com> wrote:
(http://luispedro.org/software/pymorph#see-also):
"mahotas is another Python image processing package, but most of its functions are in C++. It is, therefore, much faster for the operations it supports."
Skeletonization with "pymorph" is indeed very very slow
I found very nice example how to do this just with "ndimage" and in a blink of a second time:
======================================== def sk(i, r): x = ndimage.distance_transform_edt(i) y = ndimage.morphological_laplace(x, (r, r)) return y < y.min()/2 ========================================
For example in pylab mode:
In [1]: from scipy import ndimage In [2]: im = imread('clip.png')[:,:,0] In [3]: imshow(sk(im, 5), cmap='binary', interpolation='nearest') _______________________________________________
There's also a couple of skeletonize functions in scikits-image: skeletonize<http://scikits-image.org/docs/dev/auto_examples/plot_skeleton.html> and medial_axis<http://scikits-image.org/docs/dev/auto_examples/plot_medial_transform.html>. But I'm not sure how the performance compares to the other solutions you've found. Cheers, -Tony
![](https://secure.gravatar.com/avatar/b8db648ce5b0b58a7dda6eab71e5a98f.jpg?s=120&d=mm&r=g)
There's also a couple of skeletonize functions in scikits-image: skeletonize and medial_axis. But I'm not sure how the performance compares to the other solutions you've found.
Well, it can't be compared :) "skimage" skeletonize() executes almost instantly. There must be something wrong "pymorph" skelm() other then requirement to convert numpy array in boolean dtype ;) It just showed first in Google, I should have tried harder and check skimage Thanks Tony
![](https://secure.gravatar.com/avatar/3aa58c446bbefaff35dbd90e27a3a107.jpg?s=120&d=mm&r=g)
On Sunday, May 06, 2012 05:31:29 PM klo uo wrote:
There's also a couple of skeletonize functions in scikits-image: skeletonize and medial_axis. But I'm not sure how the performance compares to the other solutions you've found.
Well, it can't be compared :) "skimage" skeletonize() executes almost instantly. There must be something wrong "pymorph" skelm() other then requirement to convert numpy array in boolean dtype ;)
There is nothing wrong, it's just Python instead of compiled code. I maintain both mahotas and pymorph and, increasingly, there is little point to using pymorph. Mahotas is starting to do it all and it does it much, much, faster. Mahotas has thin() which is a really well-tuned implementation.
It just showed first in Google, I should have tried harder and check skimage
If you're interested, check out the pythonvision google group for more computer vision related questions. https://groups.google.com/forum/#!forum/pythonvision -- Luis Pedro Coelho | Institute for Molecular Medicine | http://luispedro.org
participants (3)
-
klo uo
-
Luis Pedro Coelho
-
Tony Yu