Extracting Shapes that meet a certain criteria from an Image

梦想的初衷 提交于 2019-12-12 18:38:37

问题


Let's say I have an image that I want to extract certain shapes from. This image has a plethora of shapes, but I'm only concerned about the shapes that are filled with diagonal lines. Such an image could look like this:

Since I only care about shapes that have diagonal lines in them, I'm trying to use this image to generate one that looks like this:

Currently, I'm attempting to do this with convolution. I start by convolving the image with this matrix: ]

Which produces an image that looks like this: This does a fairly good job of extracting the information i'm looking for, but now I want to make it look like my ideal final image.

The next step in my current process is to blur the image, and after blurring the image I use a threshold to obtain a result that looks like this.

This is very close to what I want, but I'm a little stuck. Do you guys know a better solution to this problem? The end goal is to write a piece of software that will take any image that has features like this, and extract them in this way.

Thanks for your time!


回答1:


Great question. I'll have a try with ImageMagick straight from the command line - it's installed on most Linux distros and available for OSX and Windows. It has bindings for C++, C#, .Net, Python, Perl, PHP etc.

I would go for a Hit and Miss style morphology with a diagonal kernel like this:

convert tetris.png -negate     \
   -morphology hit-and-miss "3x3: 1,0,0 0,1,0 0,0,1" result.png

Once you have that, you may need a method to locate the diagonally hatched area. One method is to "squidge" all the pixels into a single pixel wide column - imagine pressing in on both sides at once till the picture is just a thin column. You can also do the same thing vertically - imagine putting a heavy weight on the top of the image till it squashes flat to just one pixel tall. Like this:

convert tetris.png -negate -morphology hit-and-miss "3x3: 1,0,0 0,1,0 0,0,1" -resize 1x2200! -scale 25x2200! -normalize tall.png

convert tetris.png -negate -morphology hit-and-miss "3x3: 1,0,0 0,1,0 0,0,1" -resize 3400x1! -scale 3400x25! -normalize wide.png

The last -scale above is just to make it wide enough to see - you don't need that really.

You can then ask for the output in text format, and look for where the colour changes from black to a shade of grey, or white, and that is the coordinate of the edge of your shape. Like this:

convert tetris.png -negate -morphology hit-and-miss "3x3: 1,0,0 0,1,0 0,0,1" -resize 1x2199! -normalize -alpha off -depth 8 txt:

# ImageMagick pixel enumeration: 1,2199,255,gray
0,0: (0,0,0)  #000000  gray(0)
0,1: (0,0,0)  #000000  gray(0)
0,2: (0,0,0)  #000000  gray(0)
0,3: (0,0,0)  #000000  gray(0)
0,4: (0,0,0)  #000000  gray(0)
...
...
0,184: (0,0,0)  #000000  gray(0)
0,185: (0,0,0)  #000000  gray(0)
0,186: (0,0,0)  #000000  gray(0)
0,187: (257,257,257)  #010101  gray(1)
0,188: (3855,3855,3855)  #0F0F0F  gray(15)   <= Transition from black = start of shape
0,189: (3855,3855,3855)  #0F0F0F  gray(15)
0,190: (3855,3855,3855)  #0F0F0F  gray(15)
0,191: (3855,3855,3855)  #0F0F0F  gray(15)
0,192: (3855,3855,3855)  #0F0F0F  gray(15)
0,193: (3855,3855,3855)  #0F0F0F  gray(15)
0,194: (3855,3855,3855)  #0F0F0F  gray(15)
0,195: (3855,3855,3855)  #0F0F0F  gray(15)
0,196: (3855,3855,3855)  #0F0F0F  gray(15)
0,197: (3855,3855,3855)  #0F0F0F  gray(15)
0,198: (3855,3855,3855)  #0F0F0F  gray(15)
0,199: (3855,3855,3855)  #0F0F0F  gray(15)
0,200: (3855,3855,3855)  #0F0F0F  gray(15)
0,201: (3855,3855,3855)  #0F0F0F  gray(15)
0,202: (3855,3855,3855)  #0F0F0F  gray(15)
...
....
0,324: (3855,3855,3855)  #0F0F0F  gray(15)
0,325: (3855,3855,3855)  #0F0F0F  gray(15)
0,326: (3855,3855,3855)  #0F0F0F  gray(15)
0,327: (4883,4883,4883)  #131313  gray(19)
0,328: (19789,19789,19789)  #4D4D4D  gray(77)   <= Fatter part of shape
0,329: (20817,20817,20817)  #515151  gray(81)
0,330: (20817,20817,20817)  #515151  gray(81)
0,331: (20817,20817,20817)  #515151  gray(81)

So you can see that your shape starts at pixel 188, and gets to the fat part at pixel 328.

Also, a Connected Component Analysis (also called Blob Analysis), on your original image like this:

convert tetris.png                                    \
  -define connected-components:verbose=true           \
  -define connected-components:area-threshold=100000  \
  -connected-components 8 -auto-level output.png

Output

Objects (id: bounding-box centroid area mean-color):
  0: 3399x2199+0+0 1774.2,1149.3 5390079 srgba(255,255,255,1)
  7: 2045x1180+405+187 1475.1,930.4 1681486 srgba(255,255,255,1)
  40: 546x334+1753+1661 2025.5,1827.5 182364 srgba(255,255,255,1)
  6: 2057x1192+399+181 1580.7,839.8 117980 srgba(0,0,0,1)
  5: 702x146+621+149 971.5,221.5 102492 srgba(255,255,255,1)

If I draw in the box on the second line of output, you can see it:

convert tetris.png -stroke red -fill none -draw "rectangle 405,187 2450,1367" x.png

You might look at the area of the red bounding box (1681486 pixels), and/or its shape (2045x1180) to think about its proportions and whether they match the shape and size of your sought patterned box, i.e. how square it is or isn't.




回答2:


Could you not just postprocess your results to average neighborhoods of pixels and set a threshold at which all pixels from the neighborhood will be assigned to be either black or white? By using square neighborhoods whose size is the period of the edge "sawtooth" artifacts, you will smooth the edges by filling in the "valleys" and eliminating the "peaks".



来源:https://stackoverflow.com/questions/35367932/extracting-shapes-that-meet-a-certain-criteria-from-an-image

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!