简体   繁体   中英

Error with image sharpening in Python

from PIL import Image
fp="C:\\lena.jpg"
img=Image.open(fp)
w,h=img.size
pixels=img.load()

imgsharp=Image.new(img.mode,img.size,color=0)
sharp=[0,-1,0,-1,8,-1,0,-1,0]

for i in range(w):
    for j in range(h):

        for k in range(3):
                for m in range(3):
                    l=pixels[i-k+1,j-m+1]*sharp[i]

        if l>255:
            l=255
        elif l<0:
            l=0
        imgsharp.putpixel((i,j),l)

imgsharp.show()

I want to apply a high pass (sharpening) filter with 3x3 mask size to a grayscale image. But I am getting an error:

Traceback (most recent call last):
File "C:\sharp.py", line 16, in <module>
l=pixels[i-k+1,j-m+1]*sharp[i]
IndexError: image index out of range

How can I fix my mistake and how can I get the image sharpening to work in this code?

The specific error you mentioned is because you are not dealing with the borders of the image. A solution is to pad the image or deal with the width and height limits. For example: replace i-k+1 and j-m+1 by max(0, min(w, i-k+1)) and max(0, min(h, j-m+1))) respectively.

There are other issues with your code:

  • The element of the filter you are accessing is not right... you probably meant sharp[3*m+k] where you wrote sharp[i] .
  • Are you using colored or greyscale image? For colored images, l has 3 dimensions and can't be directly compared to a single number (0 or 255).
  • Also, the clipping of l value and the putpixel call should be inside the innerest loop.
  • Your kernel looks a bit odd. Is that 8 supposed to be a 5? Or maybe a 9 and 0 become -1? Take a look at kernels and at this example .
  • This implementation with several nested loops is not very efficient.

I recommend the following solutions to your problem.

If you want to sharpen the image and that's all, you can use PIL.Image.filter :

from PIL import Image, ImageFilter


img = Image.open('lena.png')
img_sharp = img.filter(ImageFilter.SHARPEN)
img_sharp.show()

If you do want to specify the kernel, try the following with scipy . Be sure to take a look at convolve documentation .

from PIL import Image

from scipy import ndimage, misc
import numpy as np


img = misc.imread('lena.png').astype(np.float)  # read as float
kernel = np.array([0, -1, 0, -1, 5, -1, 0, -1, 0]).reshape((3, 3, 1))

# here we do the convolution with the kernel
imgsharp = ndimage.convolve(img, kernel, mode='nearest')
# then we clip (0 to 255) and convert to unsigned int
imgsharp = np.clip(imgsharp, 0, 255).astype(np.uint8)

Image.fromarray(imgsharp).show()  # display

Another approach is to use OpenCV. Take a look at this article . It will clearify things about many implementation details.

We can sharpen an RGB image with scipy.convolve2d as well. We have to apply the convolution separately for each image channel. The below code shows the same for the lena image

from scipy import misc, signal
import numpy as np

im = misc.imread('../images/lena.jpg')/255. # scale pixel values in [0,1] for each channel

print(np.max(im))
# 1.0
print(im.shape)
# (220, 220, 3)

sharpen_kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]])
im_sharpened = np.ones(im.shape)
for i in range(3):
    im_sharpened[...,i] = np.clip(signal.convolve2d(im[...,i], sharpen_kernel, mode='same', boundary="symm"),0,1)

fig, ax = plt.subplots(nrows=2, figsize=(10, 20))
ax[0].imshow(im)
ax[0].set_title('Original Image', size=20)
ax[1].imshow(im_sharpened)
ax[1].set_title('Sharpened Image', size=20)
plt.show()

在此处输入图片说明

We can use the gaussian kernel to first blur the image and subtract from the original image to get a sharpened image as well, as shown in the following code:

from scipy import misc, ndimage

im = misc.imread('../images/lena.jpg') / 255 # scale pixel values in [0,1] for each channel    

# First a 1-D  Gaussian
t = np.linspace(-10, 10, 30)
bump = np.exp(-0.1*t**2)
bump /= np.trapz(bump) # normalize the integral to 1

# make a 2-D kernel out of it
kernel = bump[:, np.newaxis] * bump[np.newaxis, :]

im_blur = ndimage.convolve(im, kernel.reshape(30,30,1))

im_sharp = np.clip(2*im - im_blur, 0, 1)

fig, ax = plt.subplots(nrows=2, figsize=(10, 20))

ax[0].imshow(im)
ax[0].set_title('Original Image', size=20)

ax[1].imshow(im_sharp)
ax[1].set_title('Sharpened Image', size=20)

plt.show()

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM