5

Is there a way to cut out non rectangular areas of an image with Python PIL?

e.g. in this picture I want to exclude all black areas as well as towers, rooftops and poles.
http://img153.imageshack.us/img153/5330/skybig.jpg

I guess the ImagePath Module can do that, but furthermore, how can I read data of e.g. a svg file and convert it into a path?

Any help will be appreciated.


(My sub question is presumably the easier task: how to cut at least a circle of an image?)

seb
  • 119
  • 1
  • 2
  • 4
  • 1
    In that example, there will be no way to programmatically remove the towers, rooftops, and poles without a complicated computer vision approach. Your best bet is to do that by hand. And what exactly do you mean to exclude the black areas? Digital images are rectangular- you want to make them transparent? As far as ImagePath, a Path is created simply from a list of coordinates, and I'm sure you could get that info from the SVG file with some python SVG library. – Rob Lourens Sep 20 '10 at 20:31
  • To do all that you are asking, PIL isn't enough as it lacks very fundamental tools for Image Processing. You could build them by yourself using Python given enough time, but, given how the question is worded, I suspect you will have trouble doing so. The only help I can give is to point out that you need to better understand your problem and ask only one question at once. – mmgp Jan 14 '13 at 01:55
  • @seb: I cannot open the file from your link. Can you post it here? – physicalattraction Sep 05 '19 at 19:43

1 Answers1

8

If I understood correctly, you want to make some areas transparent within the image. And these areas are random shaped. Easiest way (that I can think of) is to create a mask and put it to the alpha channel of the image. Below is a code that shows how to do this.

If your question was "How to create a polygon mask" I will redirect you to:

SciPy Create 2D Polygon Mask

and look the accepted answer.

br,

Juha

import numpy
import Image

# read image as RGB and add alpha (transparency)
im = Image.open("lena.png").convert("RGBA")

# convert to numpy (for convenience)
imArray = numpy.asarray(im)

# create mask (zeros + circle with ones)
center = (200,200)
radius = 100
mask = numpy.zeros((imArray.shape[0],imArray.shape[1]))
for i in range(imArray.shape[0]):
    for j in range(imArray.shape[1]):
        if (i-center[0])**2 + (j-center[0])**2 < radius**2:
            mask[i,j] = 1

# assemble new image (uint8: 0-255)
newImArray = numpy.empty(imArray.shape,dtype='uint8')

# colors (three first columns, RGB)
newImArray[:,:,:3] = imArray[:,:,:3]

# transparency (4th column)
newImArray[:,:,3] = mask*255          

# back to Image from numpy
newIm = Image.fromarray(newImArray, "RGBA")
newIm.save("lena3.png")

Edit

Actually, I could not resist... the polygon mask solution was so elegant (replace the above circle with this):

# create mask
polygon = [(100,100), (200,100), (150,150)]
maskIm = Image.new('L', (imArray.shape[0], imArray.shape[1]), 0)
ImageDraw.Draw(maskIm).polygon(polygon, outline=1, fill=1)
mask = numpy.array(maskIm)

Edit2

Now when I think of it. If you have a black and white svg, you can load your svg directly as mask (assuming white is your mask). I have no sample svg images, so I cannot test this. I am not sure if PIL can open svg images.

Community
  • 1
  • 1
Juha
  • 2,053
  • 23
  • 44