Skip to content

Commit

Permalink
Merge pull request #17 from localdevices/16-sample-dataset
Browse files Browse the repository at this point in the history
16 sample dataset
  • Loading branch information
hcwinsemius authored Nov 14, 2024
2 parents 510d0ee + 7dd6bcf commit 757c595
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 30 deletions.
54 changes: 54 additions & 0 deletions .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Upload FF-PIV to Test-PyPi

on:
workflow_dispatch:

jobs:
build-artifacts:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: |
pip install tomli flit twine
- name: Build artifacts
run: flit build
- uses: actions/upload-artifact@v3
with:
name: releases
path: dist
test-built-dist:
needs: build-artifacts
runs-on: ubuntu-latest
defaults:
run:
shell: bash -l {0}
steps:
- uses: actions/checkout@v4
with:
python-version: '3.11'
- name: Verify the built dist/wheel is valid
run: |
python -m pip install dist/ffpiv*.whl
python -c "import ffpiv;print(ffpiv.__version__)"
upload-to-test-pypi:
needs: test-built-dist
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v3
with:
name: releases
path: dist
- name: Publish package to TestPyPI
uses: pypa/gh-action-pypi-publish@v1.5.1
with:
user: __token__
password: ${{ secrets.PYPI_TOKEN }}
verbose: true
skip_existing: true
58 changes: 58 additions & 0 deletions .github/workflows/publish-test-pypi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: Upload FF-PIV to Test-PyPi

on:
release:
types: [published]
# allows running the workflow manually
workflow_dispatch:

jobs:
build-artifacts:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: |
pip install tomli flit twine
- name: Build artifacts
run: flit build
- uses: actions/upload-artifact@v3
with:
name: releases
path: dist
test-built-dist:
needs: build-artifacts
runs-on: ubuntu-latest
defaults:
run:
shell: bash -l {0}
steps:
- uses: actions/checkout@v4
with:
python-version: '3.11'
- name: Verify the built dist/wheel is valid
run: |
python -m pip install dist/ffpiv*.whl
python -c "import ffpiv;print(ffpiv.__version__)"
upload-to-test-pypi:
needs: test-built-dist
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v3
with:
name: releases
path: dist
- name: Publish package to TestPyPI
uses: pypa/gh-action-pypi-publish@v1.5.1
with:
user: __token__
password: ${{ secrets.PYPI_TEST_TOKEN }}
repository_url: https://test.pypi.org/legacy/
verbose: true
skip_existing: true
4 changes: 2 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
fail-fast: false
matrix:
os: ["ubuntu-latest" ] #, "macos-latest", "windows-latest"]
python-version: ["3.10"] # fix tests to support older versions
python-version: ["3.11"] # fix tests to support older versions

steps:
- uses: actions/checkout@v4
Expand All @@ -47,7 +47,7 @@ jobs:
# run all tests
- name: Test
run: python -m pytest --verbose --cov=pyorc --cov-report xml
run: python -m pytest --verbose --cov=ffpiv --cov-report xml

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
Expand Down
79 changes: 56 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,17 @@ image2 = np.array(Image.open(file_frame2))
u, v = piv(image1, image2)

# Plot the velocity field
plt.quiver(u, v)
plt.xlabel("x [window]")
plt.ylabel("y [window]")
plt.title("64x64 one image pair")
ax = plt.axes()
ax.quiver(u, v)
ax.invert_yaxis() # make sure that the coordinate order is according to real-world

ax.set_xlabel("x [window]")
ax.set_ylabel("y [window]")
ax.set_title("64x64 one image pair")
plt.show()
```
![piv_1_img](https://github.com/user-attachments/assets/2020e5c0-aca2-4f3d-8813-5bdcf5ec6841)

In this example:
- We first load two consecutive images from the sample dataset
- We call the `piv` function, passing the images.
Expand Down Expand Up @@ -128,13 +133,18 @@ overlap = (32, 32)
u, v = piv(image1, image2, window_size=window_size, overlap=overlap)

# Plot velocity field
plt.quiver(u, v)
plt.xlabel("x [window]")
plt.ylabel("y [window]")
plt.title("64x64, 32x32 overlap one image pair")
ax = plt.axes()
ax.quiver(u, v)
ax.invert_yaxis()

ax.set_xlabel("x [window]")
ax.set_ylabel("y [window]")
ax.set_title("64x64, 32x32 overlap one image pair")
plt.show()
```

![piv_1_img_overlap](https://github.com/user-attachments/assets/95a95102-f162-411a-b472-6142a21e84c3)

Here we specify the `window_size` and `overlap` parameters. Now, cross correlation
is computed on pixel patches of 64 by 64 pixels, and overlap of 32 pixels in both directions is used
to extract windows. This results in twice as many velocity vectors as shown in the resulting plot
Expand Down Expand Up @@ -171,13 +181,19 @@ plt.figure(figsize=(10, 5))
for i, (u, v) in enumerate(zip(u_stack[0:2], v_stack[0:2])):

# Display the first image of the pair
plt.subplot(1, 2, i + 1)
plt.quiver(u, v)
plt.title(f'Image pair {i+1}')
ax = plt.subplot(1, 2, i + 1)
ax.quiver(u, v)
ax.set_title(f'Image pair {i+1}')
ax.invert_yaxis()
ax.set_xlabel("x [window]")
ax.set_ylabel("y [window]")

plt.suptitle("2 image pairs")
plt.show()
```

![piv_2_img](https://github.com/user-attachments/assets/46cd091f-a974-41c4-98a1-382a45687e09)

In this example:
- We first load a stack of images into a full array. You may alter last_image to a max of 122 to check how fast this
is.
Expand Down Expand Up @@ -205,23 +221,29 @@ x, y = coords(dim_size, window_size=window_size, overlap=overlap) # window_size
ax = plt.axes()
pix_y = np.arange(im_sample.shape[0])
pix_x = np.arange(im_sample.shape[1])
ax.pcolor(pix_x, pix_y, im_sample, cmap="Greys_r")
ax.pcolor(pix_x, pix_y, im_sample, vmax=512, cmap="Greys_r") # plot a bit dark so that we see the quiver plot

# compute the time averaged velocities
u, v = u_stack.mean(axis=0), v_stack.mean(axis=0)
s = np.sqrt(u**2 + v**2)
# plot the vectors on top of this
p = ax.quiver(x, y, u, v, s, cmap="rainbow")
cb = plt.colorbar(p)

# make an inset axis for the colorbar
cax = ax.inset_axes([0.8, 0.1, 0.02, 0.4])
cb = plt.colorbar(p, cax=cax)
cb.set_label(label="velocity [pix/frame]")
plt.title("frame + average velocities")
ax.set_aspect('equal', adjustable='box') # ensure x and y coordinates have same visual length
ax.set_xlabel("x [pix]")
ax.set_ylabel("y [pix]")
ax.set_title("frame + average velocities")
plt.show()

```

![im_piv](https://github.com/user-attachments/assets/bd30791e-6a3c-41fe-8ba9-f4e92d2b554e)

In this example, you can ensure the coordinates are commensurate with the original data and plot the coordinates on
top of your original data.
top of your original data. The plot axis are now in pixel units instead of window units.

### Work with intermediate results

Expand Down Expand Up @@ -280,27 +302,38 @@ corr_max = corr_max.reshape(-1, n_rows, n_cols)
_, axs = plt.subplots(nrows=1, ncols=3, figsize=(16, 9))
p0 = axs[0].pcolor(x, y, corr_max.mean(axis=0))
axs[0].set_title("Image mean maximum correlation")
plt.colorbar(p0, ax=axs[0])
cax = axs[0].inset_axes([0.8, 0.1, 0.02, 0.4])
cb = plt.colorbar(p0, cax=cax)
cb.set_label(label="log s2n [-]")

p1 = axs[1].pcolor(x, y, np.log(s2n.mean(axis=0)))

p1 = axs[1].pcolor(x, y, np.log(s2n.mean(axis=0)), cmap="Blues")
axs[1].set_title("Image mean signal-to-noise ratio")
plt.colorbar(p1, ax=axs[1])
cax = axs[1].inset_axes([0.8, 0.1, 0.02, 0.4])
cb = plt.colorbar(p1, cax=cax)
cb.set_label(label="log s2n [-]")


axs[2].pcolor(pix_x, pix_y, im_sample, cmap="Greys_r")
axs[2].pcolor(pix_x, pix_y, im_sample, vmax=512, cmap="Greys_r")
s = np.sqrt(u**2 + v**2)

# plot the vectors on top of this
p = axs[2].quiver(x, y, u, v, s, cmap="rainbow", scale_units="xy", scale=0.3)
cb = plt.colorbar(p, ax=axs[2])
p2 = axs[2].quiver(x, y, u, v, s, cmap="rainbow", scale_units="xy", scale=0.3)
cax = axs[2].inset_axes([0.8, 0.1, 0.02, 0.4])
cb = plt.colorbar(p2, cax=cax)
cb.set_label(label="velocity [pix/frame]")
axs[2].set_title("frame + velocity")
# set all axes to equal sizing
for ax in axs:
ax.set_aspect('equal', adjustable='box')
ax.invert_yaxis()
ax.set_xlabel("x [pix]")
ax.set_ylabel("y [pix]")
plt.show()

```
![corr_piv](https://github.com/user-attachments/assets/bd2254d4-9a2d-4721-b532-1b1eed760c66)

![corr_piv](https://github.com/user-attachments/assets/9827a5f8-6909-4bd2-84ad-91d234edb5cc)

In this example, we first calculate the cross correlations and do not reduce them into vectors yet.
We use all images, to demonstrate that FF-PIV is truly fast! You need enough free memory for this.
Expand Down
7 changes: 2 additions & 5 deletions tests/test_fft.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@ def correlations(img_pair):
return corrs * np.random.rand(*corrs.shape) * 0.005


# def test_normalize_intensity(imgs_win):


def test_ncc(img_pair):
"""Test correlation analysis on a pair of image windows."""
image_a, image_b = img_pair
Expand All @@ -48,7 +45,7 @@ def test_ncc(img_pair):
t2 = time.time()
time_np = t2 - t1
print(f"Numpy took {time_np} secs.")
assert np.allclose(res_nb, res_np)
assert np.allclose(res_nb, res_np, atol=1e-6, rtol=1e-5)
# plt.imshow(res_nb[0])
# plt.colorbar()
# plt.show()
Expand All @@ -68,7 +65,7 @@ def test_multi_img_ncc(imgs_win_stack, mask):
t2 = time.time()
time_nb = t2 - t1
print(f"Numpy took {time_nb} secs.")
assert np.allclose(res_nb, res_np)
assert np.allclose(res_nb, res_np, atol=1e-6, rtol=1e-5)


def test_u_v_displacement(correlations, dims):
Expand Down

0 comments on commit 757c595

Please sign in to comment.