Skip to content

Commit

Permalink
Merge pull request #2 from NatLee/dev
Browse files Browse the repository at this point in the history
Add method of generating blur with a depth map
  • Loading branch information
NatLee authored Feb 1, 2023
2 parents 83b3740 + b77e761 commit 542a8ad
Show file tree
Hide file tree
Showing 14 changed files with 320 additions and 45 deletions.
5 changes: 4 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
include pyproject.toml
include *.md
include *.sh
include *.bat
include LICENSE
recursive-include tests test*.py
recursive-include doc *.png
recursive-include doc *.png
recursive-include doc *.jpg
120 changes: 105 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,12 @@ Check it on [Pypi](https://pypi.org/project/BlurGenerator/).
## Usage

```bash
usage: blurgenerator [-h] [--input INPUT] [--output OUTPUT] [--type TYPE] [--motion_blur_size MOTION_BLUR_SIZE] [--motion_blur_angle MOTION_BLUR_ANGLE]
[--lens_radius LENS_RADIUS] [--lens_components LENS_COMPONENTS] [--lens_exposure_gamma LENS_EXPOSURE_GAMMA]
[--gaussian_kernel GAUSSIAN_KERNEL]

optional arguments:
-h, --help show this help message and exit
--input INPUT Specific path of image as `input`.
--output OUTPUT Specific path for `output`. Default is `./result.png`.
--type TYPE Blur type of `motion`, `lens`, or `gaussian`. Default is `motion`.
--motion_blur_size MOTION_BLUR_SIZE
blurgenerator --help
```

```bash
usage: blurgenerator [-h] [--input INPUT] [--input_depth_map INPUT_DEPTH_MAP] [--output OUTPUT] [--type TYPE] [--motion_blur_size MOTION_BLUR_SIZE] [--motion_blur_angle MOTION_BLUR_ANGLE] [--lens_radius LENS_RADIUS] [--lens_components LENS_COMPONENTS]
[--lens_exposure_gamma LENS_EXPOSURE_GAMMA] [--gaussian_kernel GAUSSIAN_KERNEL] [--depth_num_layers DEPTH_NUM_LAYERS] [--depth_min_blur DEPTH_MIN_BLUR] [--depth_max_blur DEPTH_MAX_BLUR]
Size for motion blur. Default is 100.
--motion_blur_angle MOTION_BLUR_ANGLE
Angle for motion blur. Default is 30.
Expand All @@ -40,13 +36,23 @@ optional arguments:
Exposure gamma for lens blur. Default is 2.
--gaussian_kernel GAUSSIAN_KERNEL
Kernel for gaussian. Default is 100.
--depth_num_layers DEPTH_NUM_LAYERS
Layer for depth blur. Default is 3.
--depth_min_blur DEPTH_MIN_BLUR
Min. blur for depth blur. Default is 1.
--depth_max_blur DEPTH_MAX_BLUR
Max. blur for depth blur. Default is 100.
```

## Example and Result

### Common use

- Original image

![original image](https://github.com/NatLee/Blur-Generator/blob/main/doc/test.png?raw=true)
![original image](./doc/test.png)

#### Usage

- Motion blur

Expand All @@ -57,22 +63,24 @@ import cv2
from blurgenerator import motion_blur
img = cv2.imread('test.png')
result = motion_blur(img, size=100, angle=30)
cv2.imwrite('./output.png', result)
```

![motion blur image](https://github.com/NatLee/Blur-Generator/blob/main/doc/motion.png?raw=true)
![motion blur image](./doc/motion.png)

- Lens blur

`blurgenerator--type lens --input ./doc/test.png --output ./doc/lens.png`
`blurgenerator --type lens --input ./doc/test.png --output ./doc/lens.png`

```python
import cv2
from blurgenerator import lens_blur
img = cv2.imread('test.png')
result = lens_blur(img, radius=5, components=4, exposure_gamma=2)
cv2.imwrite('./output.png', result)
```

![lens blur image](https://github.com/NatLee/Blur-Generator/blob/main/doc/lens.png?raw=true)
![lens blur image](./doc/lens.png)

- Gaussian blur

Expand All @@ -83,6 +91,88 @@ import cv2
from blurgenerator import gaussian_blur
img = cv2.imread('test.png')
result = gaussian_blur(img, 100)
cv2.imwrite('./output.png', result)
```

![gaussian blur image](./doc/gaussian.png)

### With depth map

Feature from this [issue](https://github.com/NatLee/Blur-Generator/issues/1).

- Original image

![photo](./doc/depth-test.jpg)

- Depth map

![depth map](./doc/depth-map-test.png)

#### Usage

- Motion blur with depth map

`blurgenerator --input .\doc\depth-test.jpg --type motion --input_depth_map .\doc\depth-map-test.png --depth_num_layers 5 --depth_min_blur 1 --depth_max_blur 50 --output .\doc\depth-motion-output.png`

```python
import cv2
from blurgenerator import motion_blur_with_depth_map
img = cv2.imread('test.jpg')
depth_img = cv2.imread('test-depth.png')
result = motion_blur_with_depth_map(
img,
depth_map=depth_img,
angle=30,
num_layers=10,
min_blur=1,
max_blur=50
)
cv2.imwrite('./output.png', result)
```

![depth motion blur image](./doc/depth-motion-output.png)

- Lens blur with depth map

`blurgenerator --input .\doc\depth-test.jpg --type lens --input_depth_map .\doc\depth-map-test.png --depth_num_layers 3 --depth_min_blur 1 --depth_max_blur 50 --output .\doc\depth-lens-output.png`

```python
import cv2
from blurgenerator import lens_blur_with_depth_map
img = cv2.imread('test.jpg')
depth_img = cv2.imread('test-depth.png')
result = lens_blur_with_depth_map(
img,
depth_map=depth_img,
components=5,
exposure_gamma=5,
num_layers=10,
min_blur=1,
max_blur=50
)
cv2.imwrite('./output.png', result)
```

![depth lens blur image](./doc/depth-lens-output.png)

- Gaussian blur with depth map

`blurgenerator --input .\doc\depth-test.jpg --type gaussian --input_depth_map .\doc\depth-map-test.png --depth_num_layers 3 --depth_min_blur 1 --depth_max_blur 50 --output .\doc\depth-gaussian-output.png`

```python
import cv2
from blurgenerator import gaussian_blur_with_depth_map
img = cv2.imread('test.jpg')
depth_img = cv2.imread('test-depth.png')
result = gaussian_blur_with_depth_map(
img,
depth_map=depth_img,
sigma=5,
num_layers=10,
min_blur=1,
max_blur=50
)
cv2.imwrite('./output.png', result)
```

![gaussian blur image](https://github.com/NatLee/Blur-Generator/blob/main/doc/gaussian.png?raw=true)
![depth gaussian blur image](./doc/depth-gaussian-output.png)
Binary file added doc/depth-gaussian-output.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/depth-lens-output.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/depth-map-test.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/depth-motion-output.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/depth-test.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions reinstall.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python setup.py clean --all install clean --all
2 changes: 2 additions & 0 deletions reinstall.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
python setup.py clean --all install clean --all
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
'Operating System :: OS Independent',
],
python_requires='>=3.7',
install_requires=['opencv-python', 'scipy'],
install_requires=['opencv-python'],
extras_require={
'dev': ['check-manifest'],
# 'test': ['coverage'],
Expand Down
6 changes: 5 additions & 1 deletion src/blurgenerator/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
"""
Blur maker init
"""
__version__ = "1.0.1"
__version__ = "1.0.2"

from .motion_blur import motion_blur
from .lens_blur import lens_blur
from .gaussian_blur import gaussian_blur

from .depth import motion_blur_with_depth_map
from .depth import lens_blur_with_depth_map
from .depth import gaussian_blur_with_depth_map

from .cli import main
127 changes: 100 additions & 27 deletions src/blurgenerator/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from pathlib import Path

import cv2
import numpy as np

from blurgenerator import motion_blur, lens_blur, gaussian_blur

Expand All @@ -13,6 +14,8 @@ def main():
parser = argparse.ArgumentParser()

parser.add_argument('--input', type=str, default=None, help='Specific path of image as `input`.')
parser.add_argument('--input_depth_map', type=str, default=None, help='Specific path of depth image as `input_depth_map`.')

parser.add_argument('--output', type=str, default='./result.png', help='Specific path for `output`. Default is `./result.png`.')

parser.add_argument('--type', type=str, default='motion', help='Blur type of `motion`, `lens`, or `gaussian`. Default is `motion`.')
Expand All @@ -26,34 +29,104 @@ def main():

parser.add_argument('--gaussian_kernel', type=int, default=100, help='Kernel for gaussian. Default is 100.')

args = parser.parse_args()

if args.input:
img_path = Path(args.input)
if img_path.is_file():
if img_path.suffix in ['.jpg', '.jpeg', '.png']:

img = cv2.imread(img_path.absolute().as_posix())
img = img / 255.

if args.type not in ['motion', 'lens', 'gaussian']:
print('----- No type has been selected. Please specific `motion`, `lens`, or `gaussian`.')
else:
if args.type == 'motion':
result = motion_blur(img, size=args.motion_blur_size, angle=args.motion_blur_angle)
# depth blur settings
parser.add_argument('--depth_num_layers', type=int, default=10, help='Layer for depth blur. Default is 3.')
parser.add_argument('--depth_min_blur', type=int, default=1, help='Min. blur for depth blur. Default is 1.')
parser.add_argument('--depth_max_blur', type=int, default=100, help='Max. blur for depth blur. Default is 100.')

elif args.type == 'lens':
result = lens_blur(img, radius=args.lens_radius, components=args.lens_components, exposure_gamma=args.lens_exposure_gamma)
# ---------------------------------------------------------------

elif args.type == 'gaussian':
result = gaussian_blur(img, args.gaussian_kernel)

cv2.imwrite(args.output, result*255)

else:
print('----- Only support common types of image `.jpg` and `.png`.')
args = parser.parse_args()

else:
print('----- File not exists!')
else:
if not args.input:
print('----- Please specific image for input.')
return

img_path = Path(args.input)

if not img_path.is_file():
print('----- `img_path` is not a file!')
return

if img_path.suffix not in ['.jpg', '.jpeg', '.png']:
print('----- Only support common types of image `.jpg` and `.png`.')
return

if args.type not in ['motion', 'lens', 'gaussian']:
print('----- No type has been selected. Please specific `motion`, `lens`, or `gaussian`.')
return

if args.type == 'motion':
def blur_job(img, size=args.motion_blur_size):
return motion_blur(img, size=size, angle=args.motion_blur_angle)

if args.type == 'lens':
def blur_job(img, radius=args.lens_radius):
return lens_blur(img, radius=radius, components=args.lens_components, exposure_gamma=args.lens_exposure_gamma)

if args.type == 'gaussian':
def blur_job(img, kernel=args.gaussian_kernel):
return gaussian_blur(img, kernel)

# ---------------------------------------------------------------

img = cv2.imread(img_path.absolute().as_posix())

depth_map_path = args.input_depth_map

if depth_map_path is None:
print(f'----- Generating `{args.type}` blur.')
result = blur_job(img)
cv2.imwrite(args.output, result)
return

depth_map_path = Path(depth_map_path)
if not depth_map_path.is_file():
print('----- `input_depth_map` is not a file!')
return
if depth_map_path.suffix not in ['.jpg', '.jpeg', '.png']:
print('----- Only support common types of image `.jpg` and `.png`.')
return

print(f'----- Generating `{args.type}` blur with depth map.')
print('----- `motion_blur_size` will be ignored.')
print('----- `lens_radius` will be ignored.')
print('----- `gaussian_kernel` will be ignored.')

depth_map = cv2.imread(depth_map_path.absolute().as_posix())

def map_range(value, inMin, inMax, outMin, outMax):
return outMin + (((value - inMin) / (inMax - inMin)) * (outMax - outMin))

def blur_with_depth(img, depth, num_layers=10, min_blur=1, max_blur=100):
min_depth = np.min(np.unique(depth))
max_depth = np.max(np.unique(depth))
step = (max_depth - min_depth) // num_layers
layers = np.array(range(min_depth, max_depth, step))
out = np.zeros(img.shape)

for value in layers:
dm = cv2.cvtColor(depth, cv2.COLOR_BGR2GRAY)
m = np.zeros(dm.shape)
m[dm > value] = 255
m[dm > (value + step)] = 0
l_mask = depth.copy()
l_mask[:,:,0] = m[:,:]
l_mask[:,:,1] = m[:,:]
l_mask[:,:,2] = m[:,:]
blur_amount = int(map_range(value, 0, 255, min_blur, max_blur))
slice = blur_job(img, blur_amount)
_, mask = cv2.threshold(l_mask, 100, 255, cv2.THRESH_BINARY)
layer = cv2.bitwise_and(slice, slice, mask = mask[:,:,0])
out = cv2.add(out, layer, dtype=0)
return out

num_layers = args.depth_num_layers
min_blur = args.depth_min_blur
max_blur = args.depth_max_blur

result = blur_with_depth(img, depth_map, num_layers=num_layers, min_blur=min_blur, max_blur=max_blur)
cv2.imwrite(args.output, result)

return

Loading

0 comments on commit 542a8ad

Please sign in to comment.