Skip to content

Commit

Permalink
differences for PR #328
Browse files Browse the repository at this point in the history
  • Loading branch information
actions-user committed Jun 21, 2024
1 parent 0c9362e commit ba145f8
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 0 deletions.
Binary file added data/A.tif
Binary file not shown.
Binary file modified fig/blur-demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions files/source-code/blur-animation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Simple blur animation of image
## Installation
Use the provided `env.yml` environment file to install dependencies:
```bash
$ conda env install -f env.yml
```

## Usage
1. Navigate to script directory:
```bash
$ cd ./image-processing/episodes/files/source-code/blur-animation
```

2. Run the script using the installed virtual environment:
```bash
$ conda activate anim-env
$ python create_blur_animation.py
```

3. Follow prompt (choose kernel size) and press Enter.


## Author
@marcodallavecchia
147 changes: 147 additions & 0 deletions files/source-code/blur-animation/create_blur_animation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
### METADATA
# author: Marco Dalla Vecchia
# description: Simple blurring animation of simple image
# data-source: A.tif was created using ImageJ (https://imagej.net/ij/)
###

### POTENTIAL IMPROVEMENTS
# - Change colors for rectangular patches in animation
# - Ask for image input instead of hard-coding it
# - Ask for FPS as input
# - Ask for animation format output


# Import packages
# Use associated requirements file to make sure you have all dependencies installed
from matplotlib import pyplot as plt
from matplotlib import patches as p
from matplotlib.animation import FuncAnimation
import numpy as np
from scipy.ndimage import convolve
from tqdm import tqdm

# Fix image path depending from where you run this script -> this should run as is, from the repo structure
img_path = "../../../data/A.tif"
# Change here colors to improve accessibility
kernel_color = "tab:red"
center_color = "tab:olive"

### ANIMATION FUNCTIONS
def init():
"""
Initialization function
- Set image array data
- Autoscale image display
- Set XY coordinates of rectangular patches
"""
im.set_array(img_convolved)
im.autoscale()
k_rect.set_xy((-0.5, -0.5))
c_rect1.set_xy((kernel_size / 2 - 1, kernel_size / 2 - 1))
return [im, k_rect, c_rect1]

def update(frame):
"""
Animation update function. For every frame do the following:
- Update X and Y coordinates of rectangular patch for kernel
- Update X and Y coordinates of rectangular patch for central pixel
- Update blurred image frame
"""
pbar.update(1)
row = (frame % total_frames) // (img_pad.shape[0] - kernel_size + 1)
col = (frame % total_frames) % (img_pad.shape[1] - kernel_size + 1)

k_rect.set_x(col - 0.5)
c_rect1.set_x(col + (kernel_size/2 - 1))
k_rect.set_y(row - 0.5)
c_rect1.set_y(row + (kernel_size/2 - 1))

im.set_array(all_frames[frame])
im.autoscale()

return [im, k_rect, c_rect1]

# MAIN PROGRAM
if __name__ == "__main__":
# simple input to ask for kernel size
print("Please provide kernel size for mean filter blur animation")
kernel_size = int(input("> "))

while kernel_size % 2 == 0:
print("Please use an odd kernel size")
kernel_size = int(input("> "))

print("Creating blurred animation with kernel size:", kernel_size)

# Load image
img = plt.imread(img_path)

### HERE WE USE THE CONVOLVE FUNCTION TO GET THE FINAL BLURRED IMAGE
# I chose a simple mean filter (equal kernel weights)
kernel = np.ones(shape=(kernel_size, kernel_size)) / kernel_size ** 2 # create kernel
# convolve the image i.e. apply mean filter
img_convolved = convolve(img, kernel, mode='constant', cval=0) # pad borders with zero like below for consistency


### HERE WE CONVOLVE MANUALLY STEP-BY-STEP TO CREATE ANIMATION
img_pad = np.pad(img, (int(np.ceil(kernel_size/2) - 1), int(np.ceil(kernel_size/2) - 1))) # Pad image to deal with borders
new_img = np.zeros(img.shape, dtype=np.uint16) # this will be the blurred final image

# add first frame with complete blurred image for print version of GIF
all_frames = [img_convolved]

# precompute animation frames and append to the list
total_frames = (img_pad.shape[0] - kernel_size + 1) * (img_pad.shape[1] - kernel_size + 1) # total frames if by change image is not squared
for frame in range(total_frames):
row = (frame % total_frames) // (img_pad.shape[0] - kernel_size + 1) # row index
col = (frame % total_frames) % (img_pad.shape[1] - kernel_size + 1) # col index
img_chunk = img_pad[row : row + kernel_size, col : col + kernel_size] # get current image chunk inside the kernel
new_img[row, col] = np.mean(img_chunk).astype(np.uint16) # calculate its mean -> mean filter
all_frames.append(new_img.copy()) # append to animation frames list

# We now have an extra frame
total_frames += 1

### FROM HERE WE START CREATING THE ANIMATION
# Initialize canvas
f, (ax1, ax2) = plt.subplots(1,2, figsize=(10,5))

# Display the padded image -> this one won't change during the animation
ax1.imshow(img_pad, cmap='gray')
# Initialize the blurred image -> this is the first frame with already the final result
im = ax2.imshow(img_convolved, animated=True, cmap='gray')

# Define rectangular patches to identify moving kernel
k_rect = p.Rectangle((-0.5,-0.5), kernel_size, kernel_size, linewidth=2, edgecolor=kernel_color, facecolor='none', alpha=0.8) # kernel rectangle
c_rect1 = p.Rectangle(((kernel_size/2 - 1), (kernel_size/2 - 1)), 1, 1, linewidth=2, edgecolor=center_color, facecolor='none') # central pixel rectangle
# Add them to the figure
ax1.add_patch(k_rect)
ax1.add_patch(c_rect1)

# Fix limits to the right image (without padding) is the same size as the left image (with padding)
ax2.set(
ylim=((img_pad.shape[0] - kernel_size / 2), -kernel_size / 2),
xlim=(-kernel_size / 2, (img_pad.shape[1] - kernel_size / 2))
)

# We don't need to see the ticks
ax1.axis("off")
ax2.axis("off")

# Create progress bar to visualize animation progress
pbar = tqdm(total=total_frames)

### HERE WE CREATE THE ANIMATION
# Use FuncAnimation to create the animation
ani = FuncAnimation(
f, update,
frames=range(total_frames),
interval=50, # we could change the animation speed
init_func=init,
blit=True
)

# Export animation
plt.tight_layout()
ani.save('../../../fig/blur-demo.gif')
print("Animation exported")
11 changes: 11 additions & 0 deletions files/source-code/blur-animation/env.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: anim-env
channels:
- defaults
dependencies:
- python=3.11
- pandas
- scikit-image
- seaborn
- pooch
- jupyterlab
- tqdm

0 comments on commit ba145f8

Please sign in to comment.