Apply depth of field effect to an image. Args: img (numpy.ndarray): (H, W, 3) input image. depth (numpy.ndarray): (H, W) depth map of the scene. focus_depth (float): Focus depth of the lens. strength (float): Strength of the depth of field effect. ma
(
img: np.ndarray,
disp: np.ndarray,
focus_disp : float,
max_blur_radius : int = 10,
)
| 354 | |
| 355 | |
| 356 | def depth_of_field( |
| 357 | img: np.ndarray, |
| 358 | disp: np.ndarray, |
| 359 | focus_disp : float, |
| 360 | max_blur_radius : int = 10, |
| 361 | ) -> np.ndarray: |
| 362 | """ |
| 363 | Apply depth of field effect to an image. |
| 364 | |
| 365 | Args: |
| 366 | img (numpy.ndarray): (H, W, 3) input image. |
| 367 | depth (numpy.ndarray): (H, W) depth map of the scene. |
| 368 | focus_depth (float): Focus depth of the lens. |
| 369 | strength (float): Strength of the depth of field effect. |
| 370 | max_blur_radius (int): Maximum blur radius (in pixels). |
| 371 | |
| 372 | Returns: |
| 373 | numpy.ndarray: (H, W, 3) output image with depth of field effect applied. |
| 374 | """ |
| 375 | # Precalculate dialated depth map for each blur radius |
| 376 | max_disp = np.max(disp) |
| 377 | disp = disp / max_disp |
| 378 | focus_disp = focus_disp / max_disp |
| 379 | dilated_disp = [] |
| 380 | for radius in range(max_blur_radius + 1): |
| 381 | dilated_disp.append(cv2.dilate(disp, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2*radius+1, 2*radius+1)), iterations=1)) |
| 382 | |
| 383 | # Determine the blur radius for each pixel based on the depth map |
| 384 | blur_radii = np.clip(abs(disp - focus_disp) * max_blur_radius, 0, max_blur_radius).astype(np.int32) |
| 385 | for radius in range(max_blur_radius + 1): |
| 386 | dialted_blur_radii = np.clip(abs(dilated_disp[radius] - focus_disp) * max_blur_radius, 0, max_blur_radius).astype(np.int32) |
| 387 | mask = (dialted_blur_radii >= radius) & (dialted_blur_radii >= blur_radii) & (dilated_disp[radius] > disp) |
| 388 | blur_radii[mask] = dialted_blur_radii[mask] |
| 389 | blur_radii = np.clip(blur_radii, 0, max_blur_radius) |
| 390 | blur_radii = cv2.blur(blur_radii, (5, 5)) |
| 391 | |
| 392 | # Precalculate the blured image for each blur radius |
| 393 | unique_radii = np.unique(blur_radii) |
| 394 | precomputed = {} |
| 395 | for radius in range(max_blur_radius + 1): |
| 396 | if radius not in unique_radii: |
| 397 | continue |
| 398 | precomputed[radius] = disk_blur(img, radius) |
| 399 | |
| 400 | # Composit the blured image for each pixel |
| 401 | output = np.zeros_like(img) |
| 402 | for r in unique_radii: |
| 403 | mask = blur_radii == r |
| 404 | output[mask] = precomputed[r][mask] |
| 405 | |
| 406 | return output |
nothing calls this directly
no test coverage detected