Search code examples
pythonnumpyopencvimage-processinginteger-overflow

Custom 2D Convolution not sharpening Image


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


Solution

  • 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