Custom 2D Convolution not sharpening Image

86 Views Asked by At

I have written my own 2D Convolution function as follows

def TwoD_convolution(img, kernel):

    # Flipping the kernel by 180 degrees

    kernel = kernel[::-1]
    for i in range(len(kernel)):
        kernel[i] = kernel[i][::-1]

    # Filling the new image with zeroes

    convolve = np.zeros((img.shape[0]+len(kernel)-1, img.shape[1]+len(kernel[0])-1, 3), np.uint8)

    midx = len(kernel)//2
    midy = len(kernel[0])//2

    # Trying to fill each cell one by one, and RGB values

    for i in range(convolve.shape[0]):
        for j in range(convolve.shape[1]):
            for k in range(3):

                cur = 0 #current sum

                for x in range(-midx,midx+1):
                    for y in range(-midy,midy+1):
                        if i+x >= 0 and i+x < img.shape[0] and j+y >= 0 and j+y < img.shape[1]:

                            # going through every neighbour of the middle cell
                            cur += ((img[i+x][j+y][k])*(kernel[midx+x][midy+y]))

                convolve[i][j][k] = cur

    return convolve

To get a sharpened image, I am calling the function as follows:

display_image(TwoD_convolution(img,[[-0.5,-1,-0.5],[-1,7,-1],[-0.5,-1,-0.5]]))

Where display_image is defined as follows:

 plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
 plt.show()

It is displaying this image:

enter image description here

I am sure it is getting sharpened on some pixels.. but why are the colors at the edges so random ? Where am I going wrong ?

Thanks

1

There are 1 best solutions below

2
Gabriel Voss On BEST ANSWER

In the code for the TwoD_convolution I have made the following modifications:

  1. I have tried normalizing the kernel, ensuring that the overall intensity of the image remains relatively stable across different regions.

  2. I have clipped the values ensuring that no overflow occurs, thus minimizing artifacts like green dots.

I have run this on google colab and it works (I have used a different kernel but yours works fine too, it's just a bit more sharp)

import numpy as np
from PIL import Image
import matplotlib.pyplot as plt

import requests

def TwoD_convolution(img, kernel):
    kernel = kernel[::-1]
    for i in range(len(kernel)):
        kernel[i] = kernel[i][::-1]

    convolve = np.zeros((img.shape[0]+len(kernel)-1, img.shape[1]+len(kernel[0])-1, 3), np.uint8)

    midx = len(kernel) // 2
    midy = len(kernel[0]) // 2

    # HERE I NORMALIZE THE KERNEL
    kernel_sum = np.sum(kernel)
    if kernel_sum == 0:
        kernel_sum = 1  
    normalized_kernel = kernel / kernel_sum

    for i in range(convolve.shape[0]):
        for j in range(convolve.shape[1]):
            for k in range(3):
                cur = 0 
                for x in range(-midx, midx+1):
                    for y in range(-midy, midy+1):
                        if i+x >= 0 and i+x < img.shape[0] and j+y >= 0 and j+y < img.shape[1]:
                            cur += ((img[i+x][j+y][k]) * (normalized_kernel[midx+x][midy+y]))
                convolve[i][j][k] = np.clip(cur, 0, 255)  # RANGE CHECKING

    return convolve


url = 'https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png'
image = Image.open(requests.get(url, stream=True).raw) 
img_array = np.array(image)

# you can try yours too [-0.5,-1,-0.5],[-1,7,-1],[-0.5,-1,-0.5]
kernel = np.array([[0, -1, 0],
                            [-1, 5, -1],
                            [0, -1, 0]])


convolved_img = TwoD_convolution(img_array, kernel)


plt.figure(figsize=(10, 5))

plt.subplot(1, 2, 1)
plt.imshow(img_array)
plt.title('Original Image')
plt.axis('off')

plt.subplot(1, 2, 2)
plt.imshow(convolved_img)
plt.title('Convolved Image')
plt.axis('off')

plt.show()


with my kernel enter image description here

with your kernel enter image description here

I'm sorry If I have putted all of this code here but it's to get the example clear