# Combining various image channels after gaussian filtering produces white image

## Issue

I am trying to implement a gaussian filter for an image with dimensions (256, 320, 4).

I first generated a gaussian Kernel for the same and then individually perform the convolution on each of the 4 channel, i.e on all the 256*320 greyscale images. After performing this I wish to combine the image into a coloured image.

However, when I do this it does not seem to work as expected. The expectation is to see a blurred version of the original image with the blurring depending on the value of sigma. However, when I run the code, I simply get a white image, no blurring nothing.

``````from PIL import Image
print(image.shape)

def gaussian_filter(image, s):

probs = [np.exp(-z*z/(2*s*s))/np.sqrt(2*np.pi*s*s) for z in range(-3*s,3*s+1)]
kernel = np.outer(probs, probs)
channels = image.shape[2]
final_output = np.ndarray((image.shape[0],image.shape[1], image.shape[2]))

for i in range(4):

channels = image.shape[2]
im = np.ndarray((image.shape[0],image.shape[1]))
print(channels)
im[:,:] = image[:,:,i]
#  generate a (2k+1)x(2k+1) gaussian kernel with mean=0 and sigma = s
probs = [np.exp(-z*z/(2*s*s))/np.sqrt(2*np.pi*s*s) for z in range(-3*s,3*s+1)]
kernel = np.outer(probs, probs)
# Cross Correlation
# Gather Shapes of Kernel + Image + Padding
xKernShape = kernel.shape[0]
yKernShape = kernel.shape[1]
xImgShape = im.shape[0]
yImgShape = im.shape[1]

strides= 1

# Shape of Output Convolution
xOutput = int(((xImgShape - xKernShape + 2 * padding) / strides) + 1)
yOutput = int(((yImgShape - yKernShape + 2 * padding) / strides) + 1)
output = np.zeros((xOutput, yOutput))

# Apply Equal Padding to All Sides
else:

# Iterate through image
for y in range(image.shape[1]):
# Exit Convolution
if y > image.shape[1] - yKernShape:
break
# Only Convolve if y has gone down by the specified Strides
if y % strides == 0:
for x in range(image.shape[0]):
# Go to next row once kernel is out of bounds
if x > image.shape[0] - xKernShape:
break
try:
# Only Convolve if x has moved by the specified Strides
if x % strides == 0:
output[x, y] = (kernel * imagePadded[x: x + xKernShape, y: y + yKernShape]).sum()
except:
break
final_output[:,:,i] = output[:,:]

final_output =np.dstack((final_output[:,:,0],final_output[:,:,1],final_output[:,:,2],final_output[:,:,3]))
#print(merged.shape)
return final_output
``````

To test the function out, a helper function is called >

``````
def plot_multiple(images, titles, colormap='gray', max_columns=np.inf, share_axes=True):
"""Plot multiple images as subplots on a grid."""
assert len(images) == len(titles)
n_images = len(images)
n_cols = min(max_columns, n_images)
n_rows = int(np.ceil(n_images / n_cols))
fig, axes = plt.subplots(
n_rows, n_cols, figsize=(n_cols * 4, n_rows * 4),
squeeze=False, sharex=share_axes, sharey=share_axes)

axes = axes.flat
# Hide subplots without content
for ax in axes[n_images:]:
ax.axis('off')

if not isinstance(colormap, (list,tuple)):
colormaps = [colormap]*n_images
else:
colormaps = colormap

for ax, image, title, cmap in zip(axes, images, titles, colormaps):
ax.imshow(image, cmap=cmap)
ax.set_title(title)

fig.tight_layout()

``````
``````image = imageio.imread('graf_small.png')
sigmas = [2]
blurred_images = [gaussian_filter(image, s) for s in sigmas]
titles = [f'sigma={s}' for s in sigmas]

plot_multiple(blurred_images, titles)
``````

## Solution

It seems all problem is that you get images in `float64` but `matplot` needs `uint8` to display it.

`imageio` saves it in file as correct images but with warning `"Lossy conversion from float64 to uint8"`

Both problem can resolve converting to `uint8`

``````    return final_output.astype(np.uint8)
``````

Full working code with few small changes

• I removed dstack
• I needed `size = output.shape[:2]` and `final_output[:size[0],:size[1],i] = output[:,:]`
``````import imageio
import numpy as np
import matplotlib.pyplot as plt

def gaussian_filter(image, s):

probs = [np.exp(-z*z/(2*s*s))/np.sqrt(2*np.pi*s*s) for z in range(-3*s,3*s+1)]
kernel = np.outer(probs, probs)

channels = image.shape[2]
print('channels:', channels)

final_output = np.ndarray((image.shape[0],image.shape[1], image.shape[2]))

for i in range(channels):

im = image[:,:,i]

#  generate a (2k+1)x(2k+1) gaussian kernel with mean=0 and sigma = s
probs = [np.exp(-z*z/(2*s*s))/np.sqrt(2*np.pi*s*s) for z in range(-3*s,3*s+1)]
kernel = np.outer(probs, probs)
# Cross Correlation
# Gather Shapes of Kernel + Image + Padding
xKernShape = kernel.shape[0]
yKernShape = kernel.shape[1]
xImgShape = im.shape[0]
yImgShape = im.shape[1]

strides= 1

# Shape of Output Convolution
xOutput = int(((xImgShape - xKernShape + 2 * padding) / strides) + 1)
yOutput = int(((yImgShape - yKernShape + 2 * padding) / strides) + 1)
output = np.zeros((xOutput, yOutput))

# Apply Equal Padding to All Sides
else:

# Iterate through image
for y in range(image.shape[1]):
# Exit Convolution
if y > image.shape[1] - yKernShape:
break
# Only Convolve if y has gone down by the specified Strides
if y % strides == 0:
for x in range(image.shape[0]):
# Go to next row once kernel is out of bounds
if x > image.shape[0] - xKernShape:
break
try:
# Only Convolve if x has moved by the specified Strides
if x % strides == 0:
output[x, y] = (kernel * imagePadded[x: x + xKernShape, y: y + yKernShape]).sum()
except:
break

size = output.shape[:2]

final_output[:size[0],:size[1],i] = output[:,:]

return final_output.astype(np.uint8)

def plot_multiple(images, titles, colormap='gray', max_columns=np.inf, share_axes=True):
"""Plot multiple images as subplots on a grid."""
assert len(images) == len(titles)
n_images = len(images)
n_cols = min(max_columns, n_images)
n_rows = int(np.ceil(n_images / n_cols))
fig, axes = plt.subplots(
n_rows, n_cols, figsize=(n_cols * 4, n_rows * 4),
squeeze=False, sharex=share_axes, sharey=share_axes)

axes = axes.flat
# Hide subplots without content
for ax in axes[n_images:]:
ax.axis('off')

if not isinstance(colormap, (list,tuple)):
colormaps = [colormap]*n_images
else:
colormaps = colormap

for ax, image, title, cmap in zip(axes, images, titles, colormaps):
ax.imshow(image, cmap=cmap)
ax.set_title(title)

fig.tight_layout()
plt.show()

# --- main --

print('shape:', image.shape)

sigmas = [2, 3, 5]
blurred_images = [gaussian_filter(image, s) for s in sigmas]
titles = [f'sigma={s}' for s in sigmas]

plot_multiple(blurred_images, titles)

for number, image in enumerate(blurred_images, 1):
imageio.imsave(f'output-{number}.png', image)
``````

Original image Lenna from Wikipedia

Result: