2022-06-26

How to improve a variable lens blur in Python OpenCV?

I want to emulate the blur of a cheap camera lens (like Holga). It's not the same as standard Gaussian blur with constant kernel size.

So I'm not sure that I have to use GaussianBlur or 2D filter.

I wrote the code and it works in general.

Input:

Input

Result:

Result

But I feel that it can be done better and faster.
I've found a similar question but it still has no answer.

How to implement different variable kernel shapes and avoid a black border?

import cv2
import numpy as np
import requests

url = r'https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png'
resp = requests.get(url, stream=True).raw
img = np.asarray(bytearray(resp.read()), dtype="uint8")
img = cv2.imdecode(img, cv2.IMREAD_COLOR)

img_lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
l, a, b = cv2.split(img_lab)

# make blur map 
height, width = l.shape[:2]
center = np.array([height/2, width/2])
diag = ((height / 2) ** 2 + (width / 2) ** 2) ** 0.5
blur_map = np.linalg.norm(
    np.indices(img.shape[:2]) - center[:,None,None] + 0.5,
     axis = 0
)
blur_map = blur_map / diag 
blur_map = blur_map * blur_rad
cv2.imwrite('blur_map.png', cv2.normalize(blur_map, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_32F))  

blur_rad = 15

# bluring
l_blur = np.copy(l)
for x in range(width):
    for y in range(height):
        kernel_size = int(blur_map[y, x])
        cut = l[y - kernel_size:y + kernel_size, x - kernel_size:x + kernel_size].mean()
        if kernel_size == 0:
            #print(kernel_size)
            l_blur[y, x] = l[y, x]
            continue
        l_blur[y, x] = cut

cv2.imwrite('result_blur.png', l_blur)  


No comments:

Post a Comment