Reputation: 11
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?
Upvotes: 1
Views: 7361
Reputation: 23099
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()
Upvotes: 0
Reputation: 3077
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:
sharp[3*m+k]
where you wrote sharp[i]
.l
has 3 dimensions and can't be directly compared to a single number (0 or 255).l
value and the putpixel
call should be inside the innerest loop.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.
Upvotes: 5