8
\$\begingroup\$

The code I wrote performs a mean blur on an image (I hardcoded it as zebra.jpg for testing purposes). My problem is that for an image of 39KB image it take minutes to perform, is there any way of making this code more efficient? Preferably using built in python modules. Also is there any way of improving my code in other ways?

from PIL import Image
img = Image.open('zebra.jpg')
img_w = img.size[0]
img_h = img.size[1]
# The bigger the kernel size, the more intense the blur
kernel = [[1]*10]*10
outputIm = Image.new("RGB", (img_w, img_h))
d = []
for y in range(0, int(img_h)):
 for x in range(0, int(img_w)):
 r, g, b, count = 0, 0, 0, 0
 index_y = int((len(kernel[0]) - 1) / 2.0) * -1
 for kernel_offset_y in kernel:
 index_x = int((len(kernel_offset_y) - 1) / 2.0) * -1
 for kernel_val in kernel_offset_y:
 if img_w > x + index_x+1 > 0 and img_h > y + index_y+1 > 0:
 temp_r, temp_g, temp_b = img.getpixel((int(x + index_x), int(y + index_y)))
 r += temp_r * kernel_val
 g += temp_g * kernel_val
 b += temp_b * kernel_val
 count += 1
 index_x += 1
 index_y += 1
 if (r > 0):
 r = r / count
 if (g > 0):
 g = g / count
 if (b > 0):
 b = b / count
 d.append((r,g,b))
outputIm.putdata([tuple(pixel) for pixel in d])
outputIm.save('blurred.jpg')
janos
113k15 gold badges154 silver badges396 bronze badges
asked May 28, 2017 at 18:36
\$\endgroup\$
5
  • 2
    \$\begingroup\$ Try using pypy as well, as it is very good at speeding up this sort of code. \$\endgroup\$ Commented May 28, 2017 at 21:44
  • 2
    \$\begingroup\$ Usually FFT is an answer (definitely better than a brute-forsish approach you took). I am not sure it is an ultimate answer for your particular filter. \$\endgroup\$ Commented May 29, 2017 at 4:47
  • \$\begingroup\$ How would I go about implementing FFT here? @vnp \$\endgroup\$ Commented May 29, 2017 at 12:24
  • 1
    \$\begingroup\$ As usual, FFT the signal, FFT the kernel, (matrix-)multiply the results, and FFT back. \$\endgroup\$ Commented May 30, 2017 at 6:55
  • \$\begingroup\$ Do you have a link to where I can read more on FFT on images? Because I don't really understand what you mean @vnp \$\endgroup\$ Commented May 30, 2017 at 7:03

1 Answer 1

4
\$\begingroup\$

Unnecessary type conversions

There are a couple of unnecessary type conversions, for example:

index_y = int((len(kernel[0]) - 1) / 2.0) * -1

Casting to int truncates, but so does integer division. So you can simplify the above with:

index_y = -(len(kernel_offset_y) - 1) // 2

In Python 2 integer division truncates by default, so ... / 2 would work too. But not in Python 3, where the behavior was changed. Using // works in Python 2.7 and Python 3 consistently.

I also replaced the * -1 with a simpler - prefix.


On this line, x, index_x, y and index_y are all integers, so no need to convert them to int:

temp_r, temp_g, temp_b = img.getpixel((int(x + index_x), int(y + index_y)))

This is also unnecessary:

outputIm.putdata([tuple(pixel) for pixel in d])

Since d is already a list of tuples, you could write simply:

outputIm.putdata(d)

Simplify

The default start value of range is 0, so instead of range(0, k) you could write range(k).

Instead of x = x / y you could write x /= y.

The parentheses are unnecessary in if (expr):.

Formatting

Instead of this:

kernel = [[1]*10]*10

PEP8 recommends this writing style:

kernel = [[1] * 10] * 10
answered May 28, 2017 at 18:56
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Awesome input, but is there any way to make the 4 nested for loops any more efficient? \$\endgroup\$ Commented May 28, 2017 at 19:04
  • 1
    \$\begingroup\$ @mark There is. Use linear algebra libraries like numpy. Unless you're doing this for learning purposes - use opencv or numpy opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/… \$\endgroup\$ Commented May 28, 2017 at 22:23
  • 1
    \$\begingroup\$ I did this for learning purpose so using opencv isn't really my goal, but do you have any input on how I would implement a version with numpy?@user1685095 \$\endgroup\$ Commented May 29, 2017 at 10:21

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.