Skip to content

Commit 77a3c47

Browse files
authored
Merge pull request #4 from NatLee/feat/add-support-for-lens-radius
Feat/add support for lens radius
2 parents c2e6989 + 08b83b4 commit 77a3c47

File tree

7 files changed

+54
-71
lines changed

7 files changed

+54
-71
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
runs-on: ubuntu-latest
1616
strategy:
1717
matrix:
18-
python: [3.7, 3.8, 3.9, '3.10', '3.11']
18+
python: [3.7, 3.8, 3.9, '3.10', '3.11', '3.12']
1919
os:
2020
- name: Linux
2121
runs-on: ubuntu-latest
@@ -37,38 +37,3 @@ jobs:
3737
- name: Run Tox
3838
# Run tox using the version of Python in `PATH`
3939
run: tox -e py
40-
41-
build36:
42-
runs-on: ${{ matrix.os.runs-on }}
43-
strategy:
44-
matrix:
45-
python-version: [ 3.6 ]
46-
os:
47-
- name: Linux
48-
runs-on: ubuntu-20.04
49-
python_platform: linux
50-
- name: Windows
51-
runs-on: windows-latest
52-
python_platform: win32
53-
- name: macOS
54-
runs-on: macos-latest
55-
python_platform: darwin
56-
steps:
57-
- uses: actions/checkout@v3
58-
- name: Set up Python 3.6
59-
uses: actions/setup-python@v4
60-
with:
61-
python-version: 3.6
62-
- name: install-dependencies
63-
run: |
64-
python -m pip install --upgrade pip
65-
pip install opencv-python==4.6.0.66
66-
- name: Test with unittest
67-
run: |
68-
python setup.py test
69-
70-
#- name: Install Tox and other packages
71-
#run: pip install tox
72-
#- name: Run Tox
73-
# Run tox using the version of Python in `PATH`
74-
#run: python -m tox -e py

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ usage: blurgenerator [-h] [--input INPUT] [--input_depth_map INPUT_DEPTH_MAP] [-
4141
--motion_blur_angle MOTION_BLUR_ANGLE
4242
Angle for motion blur. Default is 30.
4343
--lens_radius LENS_RADIUS
44-
Radius for lens blur. Default is 5.
44+
Radius for lens blur. Default is 5.0.
4545
--lens_components LENS_COMPONENTS
4646
Components for lens blur. Default is 4.
4747
--lens_exposure_gamma LENS_EXPOSURE_GAMMA

reinstall.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
#!/bin/bash
2+
pip uninstall -y blurgenerator
23
python setup.py clean --all install clean --all

setup.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
'Topic :: Software Development :: Build Tools',
3030

3131
'Programming Language :: Python :: 3',
32-
'Programming Language :: Python :: 3.6',
3332
'Programming Language :: Python :: 3.7',
3433
'Programming Language :: Python :: 3.8',
3534
'Programming Language :: Python :: 3.9',
@@ -39,7 +38,7 @@
3938
'License :: OSI Approved :: MIT License',
4039
'Operating System :: OS Independent',
4140
],
42-
python_requires='>=3.6',
41+
python_requires='>=3.7',
4342
install_requires=['opencv-python'],
4443
extras_require={
4544
'dev': ['check-manifest'],

src/blurgenerator/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def main():
2323
parser.add_argument('--motion_blur_size', type=int, default=100, help='Size for motion blur. Default is 100.')
2424
parser.add_argument('--motion_blur_angle', type=int, default=30, help='Angle for motion blur. Default is 30.')
2525

26-
parser.add_argument('--lens_radius', type=int, default=5, help='Radius for lens blur. Default is 5.')
26+
parser.add_argument('--lens_radius', type=float, default=5.0, help='Radius for lens blur. Default is 5.0.')
2727
parser.add_argument('--lens_components', type=int, default=4, help='Components for lens blur. Default is 4.')
2828
parser.add_argument('--lens_exposure_gamma', type=int, default=2, help='Exposure gamma for lens blur. Default is 2.')
2929

src/blurgenerator/lens_blur.py

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Lens blur generator
33
"""
4+
from typing import Tuple, Dict, List
45
import os
56
import math
67
from functools import reduce
@@ -50,76 +51,93 @@
5051
[2.201904, 19.032909, -0.152784, -0.107988]]]
5152

5253
# Obtain specific parameters and scale for a given component count
53-
def get_parameters(component_count = 2):
54+
def get_parameters(component_count: int = 2) -> Tuple[List[Dict[str, float]], float]:
55+
"""
56+
Obtain specific parameters and scale for a given component count.
57+
"""
5458
parameter_index = max(0, min(component_count - 1, len(kernel_params)))
55-
parameter_dictionaries = [dict(zip(['a','b','A','B'], b)) for b in kernel_params[parameter_index]]
56-
return (parameter_dictionaries, kernel_scales[parameter_index])
59+
parameter_dictionaries = [dict(zip(['a', 'b', 'A', 'B'], b)) for b in kernel_params[parameter_index]]
60+
return parameter_dictionaries, kernel_scales[parameter_index]
5761

5862
# Produces a complex kernel of a given radius and scale (adjusts radius to be more accurate)
5963
# a and b are parameters of this complex kernel
60-
def complex_kernel_1d(radius, scale, a, b):
61-
kernel_radius = radius
64+
def complex_kernel_1d(radius: float, scale: float, a: float, b: float) -> np.ndarray:
65+
"""
66+
Produces a complex kernel of a given radius and scale (adjusts radius to be more accurate).
67+
"""
68+
kernel_radius = int(math.ceil(radius))
6269
kernel_size = kernel_radius * 2 + 1
63-
ax = np.arange(-kernel_radius, kernel_radius + 1., dtype=np.float32)
64-
ax = ax * scale * (1 / kernel_radius)
65-
kernel_complex = np.zeros((kernel_size), dtype=np.complex64)
70+
ax = np.linspace(-radius, radius, kernel_size, dtype=np.float32)
71+
ax = ax * scale * (1 / radius)
72+
kernel_complex = np.zeros((kernel_size,), dtype=np.complex64)
6673
kernel_complex.real = np.exp(-a * (ax**2)) * np.cos(b * (ax**2))
6774
kernel_complex.imag = np.exp(-a * (ax**2)) * np.sin(b * (ax**2))
6875
return kernel_complex.reshape((1, kernel_size))
6976

70-
def normalise_kernels(kernels, params):
71-
# Normalises with respect to A*real+B*imag
77+
78+
def normalise_kernels(kernels: List[np.ndarray], params: List[Dict[str, float]]) -> np.ndarray:
79+
"""
80+
Normalises the kernels with respect to A*real + B*imag.
81+
"""
7282
total = 0
7383

74-
for k,p in zip(kernels, params):
75-
# 1D kernel - applied in 2D
84+
for k, p in zip(kernels, params):
7685
for i in range(k.shape[1]):
7786
for j in range(k.shape[1]):
78-
# Complex multiply and weighted sum
79-
total += p['A'] * (k[0,i].real*k[0,j].real - k[0,i].imag*k[0,j].imag) + p['B'] * (k[0,i].real*k[0,j].imag + k[0,i].imag*k[0,j].real)
87+
total += p['A'] * (k[0, i].real * k[0, j].real - k[0, i].imag * k[0, j].imag) + \
88+
p['B'] * (k[0, i].real * k[0, j].imag + k[0, i].imag * k[0, j].real)
8089

8190
scalar = 1 / math.sqrt(total)
8291
kernels = np.asarray(kernels) * scalar
8392

8493
return kernels
8594

86-
# Combine the real and imaginary parts of an image, weighted by A and B
87-
def weighted_sum(kernel, params):
95+
def weighted_sum(kernel: np.ndarray, params: Dict[str, float]) -> np.ndarray:
96+
"""
97+
Combine the real and imaginary parts of an image, weighted by A and B.
98+
"""
8899
return np.add(kernel.real * params['A'], kernel.imag * params['B'])
89100

90101
# Produce a 2D kernel by self-multiplying a 1d kernel. This would be slower to use
91102
# than the separable approach, mostly for visualisation below
92-
def multiply_kernel(kernel):
103+
def multiply_kernel(kernel: np.ndarray) -> np.ndarray:
104+
"""
105+
Produce a 2D kernel by self-multiplying a 1D kernel.
106+
"""
93107
kernel_size = kernel.shape[1]
94108
a = np.repeat(kernel, kernel_size, 0)
95109
b = np.repeat(kernel.transpose(), kernel_size, 1)
96-
return np.multiply(a,b)
110+
return np.multiply(a, b)
97111

98112
# ----------------------------------------------------------------
99113

100-
def filter_task(idx, channel, img_channel, component, component_params):
114+
def filter_task(idx: int, channel: int, img_channel: np.ndarray, component: np.ndarray, component_params: Dict[str, float]) -> Tuple[int, int, np.ndarray]:
101115
"""
102-
https://github.com/Davide-sd/GIMP-lens-blur/blob/master/GIMP-lens-blur.py#L188
116+
Perform convolution with the complex kernel components on the image channel.
103117
"""
104118
component_real = np.real(component)
105119
component_imag = np.imag(component)
106120

107121
component_real_t = component_real.transpose()
108122
component_imag_t = component_imag.transpose()
109-
# first convolution
110-
inter_real = cv2.filter2D(img_channel, -1, component_real)
111-
inter_imag = cv2.filter2D(img_channel, -1, component_imag)
112-
# second convolution (see NOTE above, here inter_ is f, component_ is g)
113-
final_1 = cv2.filter2D(inter_real, -1, component_real_t)
114-
final_2 = cv2.filter2D(inter_real, -1, component_imag_t)
115-
final_3 = cv2.filter2D(inter_imag, -1, component_real_t)
116-
final_4 = cv2.filter2D(inter_imag, -1, component_imag_t)
123+
124+
inter_real = cv2.filter2D(img_channel, -1, component_real, borderType=cv2.BORDER_REPLICATE)
125+
inter_imag = cv2.filter2D(img_channel, -1, component_imag, borderType=cv2.BORDER_REPLICATE)
126+
127+
final_1 = cv2.filter2D(inter_real, -1, component_real_t, borderType=cv2.BORDER_REPLICATE)
128+
final_2 = cv2.filter2D(inter_real, -1, component_imag_t, borderType=cv2.BORDER_REPLICATE)
129+
final_3 = cv2.filter2D(inter_imag, -1, component_real_t, borderType=cv2.BORDER_REPLICATE)
130+
final_4 = cv2.filter2D(inter_imag, -1, component_imag_t, borderType=cv2.BORDER_REPLICATE)
131+
117132
final = final_1 - final_4 + 1j * (final_2 + final_3)
118133
weight_sum = weighted_sum(final, component_params)
119-
# return index, channel No. and sum of weights
134+
120135
return idx, channel, weight_sum
121136

122-
def lens_blur(img, radius=3, components=5, exposure_gamma=5):
137+
def lens_blur(img: np.ndarray, radius: float = 3.0, components: int = 5, exposure_gamma: float = 5.0) -> np.ndarray:
138+
"""
139+
Apply lens blur to the input image.
140+
"""
123141

124142
img = img/255.
125143

tox.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[tox]
2-
envlist = py{36, 37, 38, 39, 310, 311}
2+
envlist = py{37, 38, 39, 310, 311, 312}
33
minversion = 3.28.0
44
isolated_build = true
55

0 commit comments

Comments
 (0)