How to define radius for blur with Python Pillow? - python

I'm trying to blur an image with Pillow, using the ImageFilter as follows:
from PIL import ImageFilter
blurred_image = im.filter(ImageFilter.BLUR)
This works fine, except that it has a set radius which is way too small for me. I want to blur the image so much that it can be barely recognised anymore. In the docs I see that the radius is set to 2 by default, but I don't really understand how I can set it to a larger value?
Does anybody have any idea how I could increase the blur radius with Pillow? All tips are welcome!

Image.filter() takes an ImageFilter so you can create an ImageFilter.GaussianBlur instance with whatever radius you want, passed in as a named argument.
blurred_image = im.filter(ImageFilter.GaussianBlur(radius=50))
You can even make it more concise like so:
blurred_image = im.filter(ImageFilter.GaussianBlur(50))

Related

How to resize ImageDraw object?

I am following these instructions: https://www.geeksforgeeks.org/python-pil-imagedraw-draw-line/ .
from PIL import Image, ImageDraw
w, h = 220, 190
shape = [(40, 40), (w - 10, h - 10)]
# creating new Image object
img = Image.new("RGB", (w, h))
# create line image
img1 = ImageDraw.Draw(img)
img1.line(shape, fill ="red", width = 0)
img.show()
I then tried to add this line immediately before img.show():
img1 = img1.resize((1024, 1024), Image.BOX)
Which is what I usually do to resize Image objects (I know, if this worked it would distort the image since it's a square, but I don't care about that right now).
When I run the code I get the AttributeError: 'ImageDraw' object has no attribute 'resize'.
So, either there is a different method to resize ImageDraw objects or I need to convert the ImageDraw object back into an Image object. In both cases I couldn't find a solution, can you help me out?
Using
img1 = img1.resize((1024, 1024), Image.BOX)
you're trying to call a resize method on some ImageDraw object. And, the error message tells you, that ImageDraw objects don't have such a method.
Let's have a look at the different modules, classes, and objects involved:
Pillow has an Image module providing an Image class, that "represents an image object". Instances of that class, i.e. Image objects, have a resize method.
Also, there is an ImageDraw module, that "provides simple 2D graphics for Image objects". From the documentation on ImageDraw.Draw:
Creates an object that can be used to draw in the given image.
Note that the image will be modified in place.
The first sentence tells you, that the created ImageDraw object is linked to your actual Image object, and that any draw operation is performed in that image (Image object). The second sentence tells you, that any modification is instantly performed. There's no need to explicitly "update" the Image object, or to somehow "convert" the ImageDraw object (back) to some Image object. (It's also simply not possible.)
So, fixing your code is very easy now. Simply call resize on your actual Image object img, and not on your ImageDraw object img1:
img = img.resize((1024, 1024), Image.BOX)

wand: How to assemble transparent gif / clear background each frame

So I have a series of transparent pngs and append them to a new Image()
with Image() as new_gif:
for img_path in input_images:
with Image(filename=img_path) as inimg:
# create temp image with transparent background to composite
with Image(width=inimg.width, height=inimg.height, background=None) as new_img:
new_img.composite(inimg, 0, 0)
new_gif.sequence.append(new_img)
new_gif.save(filename=output_path)
unfortunately the background is not "cleared" when the new image is appended. They'll have the last image there as well:
But how do I clear the background? I though I do exactly that by compositing into a new image upfront.. `:| HALP!!
I see there is a similar thing with commandline ImageMagick but wand doesn't have anything like that. So far I have to workaround with a fitting background color.
Without seeing the source images, I can assume the -set dispose background is what's needed. For wand, you'll need to call wand.api.library.MagickSetOption method.
from wand.image import Image
from wand.api import library
with Image() as new_gif:
# Tell new gif how to manage background
library.MagickSetOption(new_gif.wand, 'dispose', 'background')
for img_path in input_images:
library.MagickReadImage(new_gif.wand, img_path)
new_gif.save(filename=output_path)
Or alternatively...
You can extent wand to manage Background Dispose behavior. This approach would give you the benefit of alter/generate each frame programmatically. But the down side would include a lot more work with ctypes. For example.
import ctypes
from wand.image import Image
from wand.api import library
# Tell python about library method
library.MagickSetImageDispose.argtypes = [ctypes.c_void_p, # Wand
ctypes.c_int] # DisposeType
# Define enum DisposeType
BackgroundDispose = ctypes.c_int(2)
with Image() as new_gif:
for img_path in input_images:
with Image(filename=img_path) as inimg:
# create temp image with transparent background to composite
with Image(width=inimg.width, height=inimg.height, background=None) as new_img:
new_img.composite(inimg, 0, 0)
library.MagickSetImageDispose(new_img.wand, BackgroundDispose)
new_gif.sequence.append(new_img)
# Also rebuild loop and delay as ``new_gif`` never had this defined.
new_gif.save(filename=output_path)
<- still needs delay correction

Manipulate color of QImage - QT

I have one generic icon image, which has an alpha. Lets say a black sphere placed on an square button, with transparancy.
Now I would like to change the color of the icon on the fly, without having several image of sphere_black.png, sphere_red.png etc etc.
Is there a way to colorize the pixmap, respecting the alpha and change HSV on that pixel, for all in the map?
I have something like this, but stuck:
img = QtGui.QImage(kwargs['icon_path']
pxmap = QtGui.QPixmap(img)
for x in range(img.width()):
for y in range(img.height()):
print img.pixel(1, 1), '###'
# ???? #
Any help is appreciated!
QGraphicsColorizeEffect might be what you are looking for. Sadly the QGraphicsEffect class is made to be used with the graphics view framework, it can't easily be applied to a QImage. However there are workarounds for that, as this discussion shows.
The implementation of the effect in QPixmapColorizeFilter::draw() shows how the colourization is done: A coloured rect (with the color having the alpha set to something else than fully opaque) is drawn over the image with QPainter::fillRect(), with an appropriate composition mode set.

How to scale down pixbuf image without losing quality?

I have a pixbuf image and I want to save it to pdf using cairo. Because the pixbuf is too large, I want to scale it down. I use scale_simple method. But, the scaled result became blur. Below is the screenshot I take. The real image is on the right and on the left is image from pdf
Do you know how to scale down pixbuf without losing its quality? Below is just my sample code.
from gi.repository import GdkPixbuf, Gdk
import cairo
class gui():
def __init__(self):
pix = GdkPixbuf.Pixbuf.new_from_file('tux2.png')
pix = pix.scale_simple(pix.get_width() / 3, pix.get_height() / 3, GdkPixbuf.InterpType.HYPER)
ps = cairo.PDFSurface('pix.pdf', 500, 500)
cr = cairo.Context(ps)
Gdk.cairo_set_source_pixbuf(cr, pix, 0, 0)
cr.paint()
if __name__ == '__main__':
gui()
You should not scale the pixbuf at all.
Instead you should scale the object (pixbuf as is).
It will look something like this:
cr.save()
cr.scale(scale_xy, scale_xy)
cr.xxx_place_image(...)
cr.restore()
What about recreating this particular image using PDF commands? It's vector format and you may design similar image in svg and import it.Image scaling is a fatal process of loosing actual color data, cause approximation takes place. Use advanced scaling algorithm, Lanczos filtering for example.

Python PIL Image.tostring()

I'm new to Python and PIL. I am trying to follow code samples on how to load an image into to Python through PIL and then draw its pixels using openGL. Here are some line of the code:
from Image import *
im = open("gloves200.bmp")
pBits = im.convert('RGBA').tostring()
.....
glDrawPixels(200, 200, GL_RGBA, GL_UNSIGNED_BYTE, pBits)
This will draw a 200 x 200 patch of pixels on the canvas. However, it is not the intended image-- it looks like it is drawing pixels from random memory. The random memory hypothesis is supported by the fact that I get the same pattern even when I attempt to draw entirely different images.Can someone help me? I'm using Python 2.7 and the 2.7 version of pyopenGL and PIL on Windows XP.
I think you were close. Try:
pBits = im.convert("RGBA").tostring("raw", "RGBA")
The image first has to be converted to RGBA mode in order for the RGBA rawmode packer to be available (see Pack.c in libimaging). You can check that len(pBits) == im.size[0]*im.size[1]*4, which is 200x200x4 = 160,000 bytes for your gloves200 image.
Have you tried using the conversion inside the tostring function directly?
im = open("test.bmp")
imdata = im.tostring("raw", "RGBA", 0, -1)
w, h = im.size[0], im.size[1]
glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, imdata)
Alternatively use compatibility version:
try:
data = im.tostring("raw", "BGRA")
except SystemError:
# workaround for earlier versions
r, g, b, a = im.split()
im = Image.merge("RGBA", (b, g, r, a))
Thank you for the help. Thanks to mikebabcock for updating the sample code on the Web. Thanks to eryksun for the code snippet-- I used it in my code.
I did find my error and it was Python newb mistake. Ouch. I declared some variables outside the scope of any function in the module and naively thought I was modifying their values inside a function. Of course, that doesn't work and so my glDrawPixels call was in fact drawing random memory.

Categories