简体   繁体   中英

Linear-Blurring an Image

I'm trying to blurr an image by mapping each pixel to the average of the N pixels to the right of it (in the same row). My iterative solution produces good output, but my linear-algebra solution is producing bad output.

From testing, I believe my kernel-matrix is correct; and, I know the last N rows don't get blurred, but that's fine for now. I'd appreciate any hints or solutions.

迭代解输出 在此处输入图片说明

iterative-solution output (good), linear-algebra output (bad)

在此处输入图片说明

original image; and here is the failing linear-algebra code:

def blur(orig_img):
    # turn image-mat into a vector
    flattened_img = orig_img.flatten()
    L = flattened_img.shape[0]
    N = 3

    # kernel
    kernel = np.zeros((L, L))
    for r, row in enumerate(kernel[0:-N]):
        row[r:r+N] = [round(1/N, 3)]*N
    print(kernel)

    # blurr the img
    print('starting blurring')
    blurred_img = np.matmul(kernel, flattened_img)
    blurred_img = blurred_img.reshape(orig_img.shape)
    return blurred_img

The equation I'm modelling is this:

在此处输入图片说明

One option might be to just use a kernel and a convolution?

For example if we load a gray scale image like so:

import numpy as np
import matplotlib.pyplot as plt

from PIL import Image
from scipy import ndimage

# load a hackinsh grayscale image
image = np.asarray(Image.open('cup.jpg')).mean(axis=2)
plt.imshow(image)
plt.title('Gray scale image')
plt.show()

示例图像

Now one can use a kernel and convolution. For example to create a filter that filters just one rows and compute the value of the center pixel as the difference between the pixels to the right and left one can do the following:

# Create a kernel that takes the difference between neighbors horizontal pixes
k = np.array([[-1,0,1]])
plt.subplot(121)
plt.title('Kernel')
plt.imshow(k)
plt.subplot(122)
plt.title('Output')
plt.imshow(ndimage.convolve(image, k, mode='constant', cval=0.0))
plt.show()

简单的边缘检测器

Therefore, one can blurr an image by mapping each pixel to the average of the N pixels to the right of it by creating the appropiate kernel.

# Create a kernel that takes the average of N pixels to the right
n=10
k = np.zeros(n*2);k[n:]=1/n
k = k[np.newaxis,...]
plt.subplot(121)
plt.title('Kernel')
plt.imshow(k)
plt.subplot(122)
plt.title('Output')

plt.imshow(ndimage.convolve(image, k, mode='constant', cval=0.0))
plt.show()

基于右的模糊

The issue was incorrect usage of cv2.imshow() in displaying the output image. It expects floating-point pixel values to be in [0, 1]; which, is done in the below code (near bottom):

def blur(orig_img):
    flattened_img = orig_img.flatten()
    L = flattened_img.shape[0]
    N = int(round(0.1 * orig_img.shape[0], 0))

    # mask (A)
    mask = np.zeros((L, L))
    for r, row in enumerate(mask[0:-N]):
        row[r:r+N] = [round(1/N, 2)]*N

    # blurred img = A * flattened_img
    print('starting blurring')
    blurred_img = np.matmul(mask, flattened_img)
    blurred_img = blurred_img.reshape(orig_img.shape)
    cv2.imwrite('blurred_img.png', blurred_img)

    # normalize img to [0,1]
    blurred_img = (
        blurred_img - blurred_img.min()) / (blurred_img.max()-blurred_img.min())
    return blurred_img

在此处输入图片说明

Ammended output

Thank you to @CrisLuengo for identifying the issue.

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