Copy disabled (too large)
Download .txt
Showing preview only (10,592K chars total). Download the full file to get everything.
Repository: OpenPIV/openpiv-python
Branch: master
Commit: 80a798f08cdf
Files: 174
Total size: 10.1 MB
Directory structure:
gitextract_ysndazwy/
├── .coveragerc
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ ├── copilot-instructions.md
│ ├── dependabot.yml
│ └── workflows/
│ ├── build.yml
│ └── testing.yml
├── .gitignore
├── .readthedocs.yaml
├── .travis.yml
├── INSTALL
├── MANIFEST.in
├── MILESTONES
├── OPTIMIZATION_SUMMARY.md
├── PERFORMANCE_IMPROVEMENTS.md
├── README.md
├── openpiv/
│ ├── PIV_3D_plotting.py
│ ├── __init__.py
│ ├── data/
│ │ ├── test1/
│ │ │ └── test_data.vec
│ │ ├── test2/
│ │ │ ├── 2image_00.tif
│ │ │ ├── 2image_01.tif
│ │ │ ├── 2image_10.tif
│ │ │ ├── 2image_11.tif
│ │ │ ├── 2image_20.tif
│ │ │ ├── 2image_21.tif
│ │ │ ├── 2image_30.tif
│ │ │ ├── 2image_31.tif
│ │ │ ├── 2image_40.tif
│ │ │ ├── 2image_41.tif
│ │ │ ├── 2image_50.tif
│ │ │ └── 2image_51.tif
│ │ ├── test4/
│ │ │ ├── Camera1-0101.tif
│ │ │ └── Camera1-0102.tif
│ │ ├── test5/
│ │ │ ├── Pattern_10_A.tif
│ │ │ ├── Pattern_10_B.tif
│ │ │ ├── Pattern_1_A.tif
│ │ │ ├── Pattern_1_B.tif
│ │ │ ├── Pattern_2_A.tif
│ │ │ ├── Pattern_2_B.tif
│ │ │ ├── Pattern_3_A.tif
│ │ │ ├── Pattern_3_B.tif
│ │ │ ├── Pattern_4_A.tif
│ │ │ ├── Pattern_4_B.tif
│ │ │ ├── Pattern_5_A.tif
│ │ │ ├── Pattern_5_B.tif
│ │ │ ├── Pattern_6_A.tif
│ │ │ ├── Pattern_6_B.tif
│ │ │ ├── Pattern_7_A.tif
│ │ │ ├── Pattern_7_B.tif
│ │ │ ├── Pattern_8_A.tif
│ │ │ ├── Pattern_8_B.tif
│ │ │ ├── Pattern_9_A.tif
│ │ │ └── Pattern_9_B.tif
│ │ └── test6/
│ │ ├── Pattern_0001_A.tif
│ │ ├── Pattern_0002_A.tif
│ │ ├── Pattern_0003_A.tif
│ │ ├── Pattern_0004_A.tif
│ │ ├── Pattern_0005_A.tif
│ │ ├── Pattern_1001_B.tif
│ │ ├── Pattern_1002_B.tif
│ │ ├── Pattern_1003_B.tif
│ │ ├── Pattern_1004_B.tif
│ │ └── Pattern_1005_B.tif
│ ├── docs/
│ │ ├── Makefile
│ │ ├── conf.py
│ │ ├── images/
│ │ │ ├── B005_1.tif
│ │ │ └── B005_2.tif
│ │ ├── index.rst
│ │ ├── make.bat
│ │ └── src/
│ │ ├── api_reference.rst
│ │ ├── developers.rst
│ │ ├── faq.rst
│ │ ├── generated/
│ │ │ ├── openpiv.filters._gaussian_kernel.rst
│ │ │ ├── openpiv.filters.gaussian.rst
│ │ │ ├── openpiv.filters.replace_outliers.rst
│ │ │ ├── openpiv.lib.replace_nans.rst
│ │ │ ├── openpiv.lib.sincinterp.rst
│ │ │ ├── openpiv.preprocess.dynamic_masking.rst
│ │ │ ├── openpiv.process.CorrelationFunction.rst
│ │ │ ├── openpiv.process.correlate_windows.rst
│ │ │ ├── openpiv.process.extended_search_area_piv.rst
│ │ │ ├── openpiv.process.get_coordinates.rst
│ │ │ ├── openpiv.process.get_field_shape.rst
│ │ │ ├── openpiv.process.normalize_intensity.rst
│ │ │ ├── openpiv.pyprocess.correlate_windows.rst
│ │ │ ├── openpiv.pyprocess.find_first_peak.rst
│ │ │ ├── openpiv.pyprocess.find_second_peak.rst
│ │ │ ├── openpiv.pyprocess.find_subpixel_peak_position.rst
│ │ │ ├── openpiv.pyprocess.get_coordinates.rst
│ │ │ ├── openpiv.pyprocess.get_field_shape.rst
│ │ │ ├── openpiv.pyprocess.moving_window_array.rst
│ │ │ ├── openpiv.pyprocess.normalize_intensity.rst
│ │ │ ├── openpiv.pyprocess.piv.rst
│ │ │ ├── openpiv.scaling.uniform.rst
│ │ │ ├── openpiv.tools.Multiprocesser.rst
│ │ │ ├── openpiv.tools.display.rst
│ │ │ ├── openpiv.tools.display_vector_field.rst
│ │ │ ├── openpiv.tools.imread.rst
│ │ │ ├── openpiv.tools.save.rst
│ │ │ ├── openpiv.validation.global_std.rst
│ │ │ ├── openpiv.validation.global_val.rst
│ │ │ ├── openpiv.validation.local_median_val.rst
│ │ │ └── openpiv.validation.sig2noise_val.rst
│ │ ├── gui_doc.rst
│ │ ├── installation_instruction.rst
│ │ ├── introduction.rst
│ │ ├── masking.ipynb
│ │ ├── modules.rst
│ │ ├── openpiv.rst
│ │ ├── openpiv_pivuq.ipynb
│ │ ├── piv_basics.ipynb
│ │ ├── tutorial1.ipynb
│ │ └── windef.ipynb
│ ├── filters.py
│ ├── lib.py
│ ├── phase_separation.py
│ ├── piv.py
│ ├── preprocess.py
│ ├── preprocess.py,cover
│ ├── pyprocess.py
│ ├── pyprocess3D.py
│ ├── scaling.py
│ ├── settings.py
│ ├── smoothn.py
│ ├── test/
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── extended_search_area_vectorized.ipynb
│ │ ├── test_PIV_3D_plotting.py
│ │ ├── test_filters.ipynb
│ │ ├── test_filters.py
│ │ ├── test_find_peaks.ipynb
│ │ ├── test_lib.py
│ │ ├── test_package_metadata.py
│ │ ├── test_performance.py
│ │ ├── test_piv.py
│ │ ├── test_preprocess.py
│ │ ├── test_process.ipynb
│ │ ├── test_process.py
│ │ ├── test_pyprocess.py
│ │ ├── test_pyprocess3D.py
│ │ ├── test_scaling.py
│ │ ├── test_smoothn.py
│ │ ├── test_tools.ipynb
│ │ ├── test_tools.py
│ │ ├── test_tools_background.py
│ │ ├── test_tools_basic_utils.py
│ │ ├── test_tools_image_processing.py
│ │ ├── test_tools_multiprocessing.py
│ │ ├── test_tools_vector_field.py
│ │ ├── test_validation.ipynb
│ │ ├── test_validation.py
│ │ ├── test_vectorized_extended_search.py
│ │ ├── test_windef.ipynb
│ │ ├── test_windef.py
│ │ ├── test_windef_coverage.py
│ │ ├── test_windef_detailed.py
│ │ └── test_windef_final.py
│ ├── tools.py
│ ├── tutorials/
│ │ ├── Example for overlap setting change.ipynb
│ │ ├── masking_tutorial.py
│ │ ├── tutorial1.py
│ │ ├── tutorial2.py
│ │ └── windef_tutorial.py
│ ├── validation.py
│ └── windef.py
├── poetry.toml
├── pyproject.toml
├── recipe/
│ └── meta.yaml
├── setup.py
└── synimage/
├── PIV_experiment_data.npz
├── Synthetic_Image_Generator_examples.ipynb
├── simple_synthetic_image_demo.ipynb
├── synimagegen.py
└── test_synimagegen.py.bck
================================================
FILE CONTENTS
================================================
================================================
FILE: .coveragerc
================================================
[run]
source = openpiv
omit =
*/test/*
*/__init__.py
*/setup.py
[report]
exclude_lines =
pragma: no cover
def __repr__
raise NotImplementedError
if __name__ == .__main__.:
pass
raise ImportError
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/copilot-instructions.md
================================================
# OpenPIV Python
OpenPIV is a Python and Cython library for Particle Image Velocimetry (PIV) analysis of fluid flow images. It provides tools for scripting and executing PIV analysis on image pairs to extract velocity fields from particle-seeded flow visualizations. The library includes both computational algorithms and optional Qt/Tk graphical user interfaces.
**Always reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.**
## Working Effectively
### Bootstrap and Install Dependencies
- **Primary method (recommended)**: Use Poetry for development:
- Install Poetry: `pip install poetry`
- Install dependencies: `poetry install` -- takes ~10 seconds. NEVER CANCEL.
- All development commands should use `poetry run <command>`
### Alternative Installation Methods
- **From PyPI**: `pip install openpiv` -- takes ~33 seconds. NEVER CANCEL.
- **From conda-forge**: `conda install -c conda-forge openpiv` -- takes ~46 seconds. NEVER CANCEL.
- **Build from source**: `python setup.py build_ext --inplace` -- takes <1 second (no Cython extensions in current setup)
### Build and Test the Repository
- **Run tests**: `poetry run pytest openpiv -v` -- takes ~12 seconds, 198 tests pass, 12 skipped. NEVER CANCEL. Set timeout to 30+ minutes for safety.
- **Test import**: `poetry run python -c "import openpiv; print('OpenPIV imported successfully')"`
- **Test core functionality**: `poetry run python -c "import openpiv.piv as piv; import numpy as np; frame_a = np.random.rand(64, 64); frame_b = np.random.rand(64, 64); result = piv.simple_piv(frame_a, frame_b); print('PIV analysis completed, returned:', len(result), 'outputs')"`
### Run Example Workflows
- **Tutorial 1**: `poetry run python openpiv/tutorials/tutorial1.py` -- demonstrates complete PIV analysis workflow
- **Test data location**: `openpiv/data/test1/` contains sample image pairs (`exp1_001_a.bmp`, `exp1_001_b.bmp`)
## Validation
### ALWAYS run these validation steps after making changes:
1. **Import test**: Verify basic import works: `poetry run python -c "import openpiv"`
2. **Core functionality test**: Run simple PIV analysis to ensure algorithms work
3. **Full test suite**: `poetry run pytest openpiv -v` -- NEVER CANCEL, takes ~12 seconds but allow 30+ minutes timeout
4. **Tutorial execution**: Run `poetry run python openpiv/tutorials/tutorial1.py` to test complete workflow
### Critical User Scenarios to Test
After making changes, ALWAYS test these scenarios:
- **Basic PIV Analysis**: Load two images, run PIV analysis, get velocity fields
- **Data Loading**: Import test images from `openpiv/data/test1/`
- **Validation and Filtering**: Apply signal-to-noise filtering and outlier detection
- **File I/O**: Save and load PIV results in vector field format
### CI/CD Validation
- The repository has GitHub Actions workflows in `.github/workflows/`:
- `testing.yml`: Runs tests on Python 3.10, 3.11, 3.12 with Poetry
- `build.yml`: Builds and publishes to PyPI on releases
- No linting tools are configured (no black, flake8, etc.)
## Common Tasks
### Repository Structure
```
openpiv/
├── __init__.py # Main package initialization
├── piv.py # High-level PIV analysis functions
├── pyprocess.py # Core PIV processing algorithms
├── pyprocess3D.py # 3D PIV algorithms
├── tools.py # Utility functions for I/O and visualization
├── validation.py # Signal validation and filtering
├── filters.py # Outlier detection and replacement
├── windef.py # Window deformation PIV
├── scaling.py # Coordinate scaling and transformation
├── preprocess.py # Image preprocessing
├── smoothn.py # Smoothing algorithms
├── data/ # Sample test data
├── test/ # Comprehensive test suite (210 tests)
├── tutorials/ # Example scripts
└── docs/ # Documentation source
```
### Key APIs and Usage Patterns
- **Simple PIV**: `piv.simple_piv(frame_a, frame_b)` returns `(x, y, u, v, s2n)`
- **Extended search area**: `pyprocess.extended_search_area_piv()` for higher accuracy
- **Window deformation**: `windef` module for advanced PIV with iterative refinement
- **File I/O**: `tools.imread()`, `tools.save()`, `tools.display_vector_field()`
- **Validation**: `validation.sig2noise_val()`, `validation.global_val()`
- **Filtering**: `filters.replace_outliers()` for cleaning velocity fields
### Project Management
- **Dependencies**: Managed via Poetry (`pyproject.toml`) and fallback setuptools (`setup.py`)
- **Package name**: "OpenPIV" (capital letters)
- **Version**: 0.25.3 (defined in both `pyproject.toml` and `setup.py`)
- **Python support**: 3.10, 3.11, 3.12
- **Key dependencies**: numpy, scipy, scikit-image, matplotlib, imageio
### Development Notes
- Uses `importlib_resources` for accessing package data files
- Test configurations in `openpiv/test/conftest.py` disable plotting for CI
- Sample data includes real PIV image pairs for testing workflows
- Documentation built with Sphinx (source in `openpiv/docs/`)
- External examples repository: [OpenPIV-Python-Examples](https://github.com/OpenPIV/openpiv-python-examples)
### Common Command Reference
```bash
# Development setup
poetry install # ~10 seconds
poetry run pytest openpiv -v # ~12 seconds, 198 tests pass
# Testing functionality
poetry run python openpiv/tutorials/tutorial1.py # Complete PIV workflow
poetry run python -c "import openpiv.piv as piv; ..." # API test
# Alternative installs
pip install openpiv # ~33 seconds
conda install -c conda-forge openpiv # ~46 seconds
# Build from source (minimal - no Cython compilation needed)
python setup.py build_ext --inplace # <1 second
```
### Timing Expectations and Timeouts
- **Poetry install**: ~10 seconds (set 5+ minute timeout)
- **Test suite**: ~12 seconds (set 30+ minute timeout for safety)
- **Tutorial execution**: ~1-2 seconds
- **Pip install**: ~33 seconds (set 10+ minute timeout)
- **Conda install**: ~46 seconds (set 15+ minute timeout)
- **Build from source**: <1 second (no Cython compilation currently)
**CRITICAL: NEVER CANCEL long-running commands. PIV analysis can be computationally intensive and build systems may take longer than expected.**
================================================
FILE: .github/dependabot.yml
================================================
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "github-actions" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "daily"
================================================
FILE: .github/workflows/build.yml
================================================
name: Build and upload to PyPI
on:
push:
tags:
- "v[0-9]*.[0-9]*.[0-9]*"
- "[0-9]*.[0-9]*.[0-9]*"
jobs:
build-and-publish:
name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI
strategy:
fail-fast: false
matrix:
python-version: [3.12]
poetry-version: [1.5.0]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6.2.0
with:
python-version: ${{ matrix.python-version }}
- name: Run image
uses: abatilo/actions-poetry@v4.0.0
with:
poetry-version: ${{ matrix.poetry-version }}
- name: Publish
env:
PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
run: |
poetry config pypi-token.pypi $PYPI_TOKEN
poetry publish --build
================================================
FILE: .github/workflows/testing.yml
================================================
name: Python package
on: [push]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
poetry-version: [1.5.0]
steps:
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6.2.0
with:
python-version: ${{ matrix.python-version }}
- name: Install poetry
uses: abatilo/actions-poetry@v4.0.0
with:
poetry-version: ${{ matrix.poetry-version }}
- name: Install the project dependencies
run: poetry install
- name: Run the automated tests (for example)
run: poetry run pytest openpiv -v
================================================
FILE: .gitignore
================================================
*.m
*.jvc
*.pyc
build/
*.txt
/setup.cfg
dist/*
masking_tutorial/.ipynb_checkpoints
openpiv/masking_tutorial/.ipynb_checkpoints
.eggs
*.pyd
OpenPIV.egg-info
*.ipynb_checkpoints*
.vscode/settings.json
*.so
tmp.png
openpiv/examples/notebooks/*.html
openpiv/examples/notebooks/test_3d/
Open_PIV_results_*
openpiv/docs/.vscode/
openpiv/docs/_build/
openpiv/examples/.vscode/settings.json
openpiv/docs/_build/doctrees/environment.pickle
openpiv/docs/src/test1.vec
openpiv/test/OpenPIV_results_16_/field_A0000.png
.coverage
================================================
FILE: .readthedocs.yaml
================================================
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Set the version of Python and other tools you might need
build:
os: ubuntu-22.04
tools:
python: "3.9"
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: openpiv/docs/conf.py
# We recommend specifying your dependencies to enable reproducible builds:
# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: openpiv/docs/requirements.txt
================================================
FILE: .travis.yml
================================================
language: python
python:
- "3.8"
notifications:
email: false
install:
- pip install poetry
- poetry install --with=tests
script:
- poetry run pytest openpiv
================================================
FILE: INSTALL
================================================
=========================
Installation instructions
=========================
Dependencies
============
OpenPIV would not have been possible if other great open source projects did not
exist. We make extensive use of code and tools that other people have created, so
you should install them before you can use OpenPIV.
The main dependencies are:
* `python <http://python.org/>`_
* `scipy <http://numpy.scipy.org/>`_
* `numpy <http://www.scipy.org/>`_
* `scikit-image <http://scikit-image.org/>`_
On all the platforms, the binary Anaconda installation is recommended.
Visit https://www.continuum.io/downloads
Get OpenPIV source code!
========================
At this moment the only way to get OpenPIV's source code is using git.
`Git <http://en.wikipedia.org/wiki/Git_%28software%29>`_ Git is a distributed revision control system and
our code is hosted at `GitHub <www.github.com>`_.
Use PyPI and pip
================
pip install -U openpiv
Downloads the code from PyPI and runs the setup for you with installation and Cython (if preinstalled)
Use Poetry
================
poetry add openpiv
Bleeding edge development version
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you are interested in the source code you are welcome to browse out git repository
stored at https://github.com/gasagna/OpenPIV. If you want to download the source code
on your machine, for testing, you need to set up git on your computer. Please look at
http://help.github.com/ which provide extensive help for how to set up git.
To follow the development of OpenPIV, clone our repository with the command::
git clone http://github.com/alexlib/openpiv-python.git
and update from time to time. You can also download a tarball containing everything.
Then add the path where the OpenPIV source are to the PYTHONPATH environment variable, so
that OpenPIV module can be imported and used in your programs. Remeber to build the extension
with ::
python setup.py build
================================================
FILE: MANIFEST.in
================================================
include *.md
include *.txt
include INSTALL
include LICENSE.txt
include MILESTONES
include TODO
recursive-include openpiv/tutorials *
recursive-include openpiv/test *
recursive-exclude openpiv/data *
recursive-exclude openpiv/docs *
recursive-exclude openpiv/test/__pycache__ *
recursive-exclude openpiv/examples/notebooks/.ipynb_checkpoints *
recursive-include openpiv *.bmp
recursive-include openpiv *.c
recursive-include openpiv *.ipynb
recursive-include openpiv *.pdf
recursive-include openpiv *.png
recursive-include openpiv *.py
recursive-include openpiv *.pyx
recursive-include openpiv *.rst
recursive-include openpiv *.tif
================================================
FILE: MILESTONES
================================================
Milestones and targets for future OpenPiv versions.
v 0.1
+ all functions should be unit tested
+ all functions should be correctly documented
+ the basic api structure should be clear and defined
v 0.2
+ Lavision file format reader
+ Hdf5 output
+ at least one advanced processing algorithm, ( 1st order, 2nd order )
v 0.3
+ data display submodule using matplotlib
+ post-processing facilities
v 0.4
+ basic gui for image processing. The gui will allow to select image directory
processing parameters, algorithm, etc, but not display result at the moment.
v 0.5
+ Gui post-processing and data visualization
================================================
FILE: OPTIMIZATION_SUMMARY.md
================================================
# Performance Optimization Summary
## Quick Summary
This PR implements performance optimizations across the OpenPIV codebase to reduce execution time and memory usage.
## Files Changed
- `openpiv/pyprocess.py` - Vectorized array operations, reduced copies
- `openpiv/validation.py` - Eliminated unnecessary masked array copies
- `openpiv/filters.py` - Conditional masked array creation
- `openpiv/test/test_performance.py` - New performance validation tests (NEW)
- `PERFORMANCE_IMPROVEMENTS.md` - Detailed documentation (NEW)
## Key Optimizations
1. **Vectorized Operations**: Replaced Python loops and list comprehensions with NumPy operations
2. **Reduced Array Copies**: Eliminated unnecessary copy operations, especially with masked arrays
3. **Conditional Conversions**: Only convert dtypes when necessary
4. **Optimized Border Checking**: Use np.maximum/np.minimum instead of array indexing
## Performance Gains
- `find_all_first_peaks`: Fully vectorized, < 10ms for 100 windows
- `normalize_intensity`: Conditional conversion, < 50ms for 50 windows
- `global_std`: No copies for non-masked input, < 10ms for 100x100 arrays
- `replace_outliers`: Conditional masking, < 100ms for 50x50 arrays
## Testing
✅ All 198 existing tests pass
✅ 5 new performance tests added
✅ Total: 203 tests pass in ~8 seconds
✅ Tutorial scripts verified working
## Backward Compatibility
✅ 100% backward compatible
- Function signatures unchanged
- Return types unchanged
- Numerical results unchanged
## Documentation
See `PERFORMANCE_IMPROVEMENTS.md` for:
- Detailed before/after code comparisons
- Performance metrics
- Future optimization opportunities
- General optimization principles
## Impact
These optimizations particularly benefit:
- Large PIV analysis with many interrogation windows
- Iterative refinement algorithms
- High-resolution image processing
- Batch processing workflows
================================================
FILE: PERFORMANCE_IMPROVEMENTS.md
================================================
# Performance Improvements Documentation
## Overview
This document summarizes the performance optimizations made to the OpenPIV Python library to improve execution speed and reduce memory usage.
## Summary of Changes
### 1. pyprocess.py Optimizations
#### find_all_first_peaks() - Line 335-340
**Before:**
```python
index_list = [(i, v[0], v[1]) for i, v in enumerate(peaks)]
return np.array(index_list), np.array(peaks_max)
```
**After:**
```python
n = peaks.shape[0]
index_list = np.column_stack((np.arange(n), peaks))
return index_list, peaks_max
```
**Impact:** Eliminates Python list comprehension and array conversion overhead. Fully vectorized using NumPy operations.
---
#### normalize_intensity() - Lines 752-776
**Before:**
```python
window = window.astype(np.float32) # Always converts
```
**After:**
```python
if window.dtype != np.float32:
window = window.astype(np.float32)
else:
window = window.copy() # Still need a copy to avoid modifying input
```
**Impact:** Avoids unnecessary dtype conversion when input is already float32, reducing memory allocation and copy operations.
---
#### find_all_second_peaks() - Lines 368-375
**Before:**
```python
iini = x - width
ifin = x + width + 1
jini = y - width
jfin = y + width + 1
iini[iini < 0] = 0 # border checking
ifin[ifin > corr.shape[1]] = corr.shape[1]
jini[jini < 0] = 0
jfin[jfin > corr.shape[2]] = corr.shape[2]
```
**After:**
```python
iini = np.maximum(x - width, 0)
ifin = np.minimum(x + width + 1, corr.shape[1])
jini = np.maximum(y - width, 0)
jfin = np.minimum(y + width + 1, corr.shape[2])
```
**Impact:** Uses vectorized NumPy maximum/minimum operations instead of array indexing, reducing operations and improving clarity.
---
### 2. validation.py Optimizations
#### global_std() - Lines 115-116
**Before:**
```python
tmpu = np.ma.copy(u).filled(np.nan)
tmpv = np.ma.copy(v).filled(np.nan)
```
**After:**
```python
if np.ma.is_masked(u):
tmpu = np.where(u.mask, np.nan, u.data)
tmpv = np.where(v.mask, np.nan, v.data)
else:
tmpu = u
tmpv = v
```
**Impact:** Eliminates unnecessary array copies and uses direct np.where operation. For non-masked arrays, avoids any copying.
---
#### local_median_val() - Lines 229-234
**Before:**
```python
if np.ma.is_masked(u):
masked_u = np.where(~u.mask, u.data, np.nan)
masked_v = np.where(~v.mask, v.data, np.nan)
```
**After:**
```python
if np.ma.is_masked(u):
masked_u = np.where(u.mask, np.nan, u.data)
masked_v = np.where(v.mask, np.nan, v.data)
```
**Impact:** Simplified logic by inverting condition, slightly more readable and efficient (avoids NOT operation).
---
#### local_norm_median_val() - Lines 303-308
**Same optimization as local_median_val()** - Consistent pattern across validation functions.
---
### 3. filters.py Optimizations
#### replace_outliers() - Lines 177-181
**Before:**
```python
if not isinstance(u, np.ma.MaskedArray):
u = np.ma.masked_array(u, mask=np.ma.nomask)
# store grid_mask for reinforcement
grid_mask = u.mask.copy()
```
**After:**
```python
# Only create masked array if needed
if isinstance(u, np.ma.MaskedArray):
grid_mask = u.mask.copy()
else:
u = np.ma.masked_array(u, mask=np.ma.nomask)
grid_mask = np.ma.nomask
```
**Impact:** Avoids creating masked arrays when input is already a regular array, reducing memory allocation and copy operations.
---
## Performance Metrics
The following performance tests have been added to verify the improvements:
### Test Results
1. **find_all_first_peaks_performance**: < 10ms for 100 windows
2. **normalize_intensity_performance**: < 50ms for 50 64x64 windows
3. **global_std_performance**: < 10ms for 100x100 arrays
4. **replace_outliers_performance**: < 100ms for 50x50 arrays with 3 iterations
5. **vectorized_sig2noise_ratio_performance**: < 50ms for 200 windows
All performance tests consistently pass, ensuring the optimizations maintain correctness while improving speed.
---
## General Optimization Principles Applied
1. **Avoid Unnecessary Copies**: Check if data is already in the required format before copying
2. **Use Vectorized Operations**: Replace Python loops and list comprehensions with NumPy operations
3. **Minimize Type Conversions**: Only convert dtypes when necessary
4. **Direct Array Access**: Use np.where and direct indexing instead of masked array copy operations
5. **Conditional Array Creation**: Only create complex data structures when needed
---
## Testing
All existing tests continue to pass:
- 198 tests passed
- 12 tests skipped
- Total test suite runtime: ~8.5 seconds
New performance tests added:
- 5 performance validation tests
- Runtime: ~0.4 seconds
---
## Impact on Real-World Usage
These optimizations particularly benefit:
- Large PIV analysis jobs with many interrogation windows
- Iterative refinement algorithms that call these functions repeatedly
- Processing of high-resolution image pairs
- Batch processing workflows
The improvements are most significant when:
- Processing hundreds or thousands of interrogation windows
- Using masked arrays for complex geometries
- Running validation and filtering on large velocity fields
- Using extended search area PIV with normalized correlation
---
## Backward Compatibility
All changes maintain full backward compatibility:
- Function signatures unchanged
- Return types unchanged
- Numerical results unchanged (verified by test suite)
- Only internal implementation optimized
---
## Future Optimization Opportunities
Additional areas that could be optimized in future work:
1. **correlation_to_displacement()** (pyprocess.py, lines 1110-1122): Nested loops for processing correlations could be vectorized
2. **sig2noise_ratio()** (pyprocess.py, lines 517-589): Already has vectorized version but could be made default
3. **lib.replace_nans()**: Complex nested loop algorithm, difficult to vectorize but potential for Numba/Cython optimization
4. Consider using Numba JIT compilation for hot paths
5. Investigate GPU acceleration for FFT operations
---
## References
- NumPy best practices: https://numpy.org/doc/stable/user/basics.performance.html
- Masked array documentation: https://numpy.org/doc/stable/reference/maskedarray.html
================================================
FILE: README.md
================================================
# OpenPIV
[](https://github.com/OpenPIV/openpiv-python/actions/workflows/testing.yml)
[](https://doi.org/10.5281/zenodo.18304582)

OpenPIV consists in a Python and Cython modules for scripting and executing the analysis of
a set of PIV image pairs. In addition, a Qt and Tk graphical user interfaces are in
development, to ease the use for those users who don't have python skills.
## Warning
The OpenPIV python version is still in its *beta* state. This means that
it still might have some bugs and the API may change. However, testing and contributing
is very welcome, especially if you can contribute with new algorithms and features.
## Test it without installation
Click the link - thanks to BinderHub, Jupyter and Conda you can now get it in your browser with zero installation:
[](https://mybinder.org/v2/gh/openpiv/openpiv-python/master?filepath=openpiv%2Fexamples%2Fnotebooks%2Ftutorial1.ipynb)
## Installing
### Recommended: Using uv (fastest)
[uv](https://github.com/astral-sh/uv) is a fast Python package installer and resolver written in Rust:
pip install uv
uv pip install openpiv
### Using pip (standard)
Use PyPI: <https://pypi.python.org/pypi/OpenPIV>:
pip install openpiv
### Or [Poetry](https://python-poetry.org/)
poetry add openpiv
### Note on Conda/Anaconda
⚠️ **Conda packages are no longer actively maintained.** The conda-forge package may be outdated.
If you previously installed OpenPIV via conda, you can migrate to pip or uv:
# Remove the conda package
conda remove openpiv
# Install with pip or uv
pip install openpiv
# or
uv pip install openpiv
### To build from source
<!-- TODO: Change this build method to use poetry -->
Download the package from the Github: https://github.com/OpenPIV/openpiv-python/archive/master.zip
or clone using git
git clone https://github.com/OpenPIV/openpiv-python.git
Using distutils create a local (in the same directory) compilation of the Cython files:
python setup.py build_ext --inplace
Or for the global installation, use:
python setup.py install
## Documentation
The OpenPIV documentation is available on the project web page at <http://openpiv.readthedocs.org>
## Demo notebooks
1. [Tutorial Notebook 1](https://nbviewer.jupyter.org/github/OpenPIV/openpiv-python-examples/blob/main/notebooks/tutorial1.ipynb)
2. [Tutorial notebook 2](https://nbviewer.jupyter.org/github/OpenPIV/openpiv-python-examples/blob/main/notebooks/tutorial2.ipynb)
3. [Dynamic masking tutorial](https://nbviewer.jupyter.org/github/OpenPIV/openpiv-python-examples/blob/main/notebooks/masking_tutorial.ipynb)
4. [Multipass with Windows Deformation](https://nbviewer.jupyter.org/github/OpenPIV/openpiv-python-examples/blob/main/notebooks/window_deformation_comparison.ipynb)
5. [Multiple sets in one notebook](https://nbviewer.jupyter.org/github/OpenPIV/openpiv-python-examples/blob/main/notebooks/all_test_cases_sample.ipynb)
6. [3D PIV](https://nbviewer.org/github/OpenPIV/openpiv-python-examples/blob/main/notebooks/PIV_3D_example.ipynb)
These and many additional examples are in another repository: [OpenPIV-Python-Examples](https://github.com/OpenPIV/openpiv-python-examples)
## Contributors
1. [Alex Liberzon](http://github.com/alexlib)
2. [Roi Gurka](http://github.com/roigurka)
3. [Zachary J. Taylor](http://github.com/zjtaylor)
4. [David Lasagna](http://github.com/gasagna)
5. [Mathias Aubert](http://github.com/MathiasAubert)
6. [Pete Bachant](http://github.com/petebachant)
7. [Cameron Dallas](http://github.com/CameronDallas5000)
8. [Cecyl Curry](http://github.com/leycec)
9. [Theo Käufer](http://github.com/TKaeufer)
10. [Andreas Bauer](https://github.com/AndreasBauerGit)
11. [David Bohringer](https://github.com/davidbhr)
12. [Erich Zimmer](https://github.com/ErichZimmer)
13. [Peter Vennemann](https://github.com/eguvep)
14. [Lento Manickathan](https://github.com/lento234)
15. [Yuri Ishizawa](https://github.com/yuriishizawa)
Copyright statement: `smoothn.py` is a Python version of `smoothn.m` originally created by D. Garcia [https://de.mathworks.com/matlabcentral/fileexchange/25634-smoothn], written by Prof. Lewis and available on Github [https://github.com/profLewis/geogg122/blob/master/Chapter5_Interpolation/python/smoothn.py]. We include a version of it in the `openpiv` folder for convenience and preservation. We are thankful to the original authors for releasing their work as an open source. OpenPIV license does not relate to this code. Please communicate with the authors regarding their license.
## How to cite this work
[](https://doi.org/10.5281/zenodo.4409178)
================================================
FILE: openpiv/PIV_3D_plotting.py
================================================
"""
functions to plot 3D-deformation fields and simple 3D-structures
"""
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from itertools import chain
from mpl_toolkits.mplot3d import Axes3D
def set_axes_equal(ax):
"""
Following https://stackoverflow.com/questions/13685386/matplotlib-equal-unit-length-with-equal-aspect-ratio-z-axis-is-not-equal-to
Make axes of 3D plot have equal scale so that spheres appear as spheres,
cubes as cubes, etc.. This is one possible solution to Matplotlib's
ax.set_aspect('equal') and ax.axis('equal') not working for 3D.
Parameters
----------
ax: matplotlib.axes object
"""
x_limits = ax.get_xlim3d()
y_limits = ax.get_ylim3d()
z_limits = ax.get_zlim3d()
x_range = abs(x_limits[1] - x_limits[0])
x_middle = np.mean(x_limits)
y_range = abs(y_limits[1] - y_limits[0])
y_middle = np.mean(y_limits)
z_range = abs(z_limits[1] - z_limits[0])
z_middle = np.mean(z_limits)
# The plot bounding box is a sphere in the sense of the infinity
# norm, hence I call half the max range the plot radius.
plot_radius = 0.5 * max([x_range, y_range, z_range])
ax.set_xlim3d([x_middle - plot_radius, x_middle + plot_radius])
ax.set_ylim3d([y_middle - plot_radius, y_middle + plot_radius])
ax.set_zlim3d([z_middle - plot_radius, z_middle + plot_radius])
def scatter_3D(a, cmap="jet", sca_args=None, control="color", size=60):
# default arguments for the quiver plot. can be overwritten by quiv_args
if not isinstance(sca_args, dict):
sca_args = {}
scatter_args = {"alpha": 1}
scatter_args.update(sca_args)
x, y, z = np.indices(a.shape)
x = x.flatten()
y = y.flatten()
z = z.flatten()
fig = plt.figure()
ax = fig.add_subplot(projection='3d', rasterized=True)
if control == "color":
# make cmap
cbound = [np.nanmin(a), np.nanmax(a)]
# create normalized color map for arrows
norm = matplotlib.colors.Normalize(
vmin=cbound[0], vmax=cbound[1]
) # 10 ) #cbound[1] ) #)
sm = matplotlib.cm.ScalarMappable(cmap=cmap, norm=norm)
sm.set_array([])
# different option
cm = matplotlib.colormaps.get_cmap(cmap)
colors = cm(norm(a)).reshape(a.shape[0] * a.shape[1] * a.shape[2], 4) #
# plotting
nan_filter = ~np.isnan(a.flatten())
ax.scatter(
x[nan_filter],
y[nan_filter],
z[nan_filter],
c=colors[nan_filter],
s=size,
**scatter_args
)
fig.colorbar(sm, ax=ax)
if control == "alpha":
# untested #
colors = [(0, 0, 1, x / np.max(z)) for x in np.ravel(z)]
ax.scatter(x, y, z, c=colors, s=size, **scatter_args)
plt.show()
if control == "size":
value_range = np.ptp(a)
if value_range == 0:
sizes = np.full(a.shape, size, dtype=float)
else:
sizes = (a - a.min()) * size / value_range
ax.scatter(x, y, z, c=a.flatten(), s=sizes.flatten(), **scatter_args)
ax_scale = plt.axes([0.88, 0.1, 0.05, 0.7])
# ax_scale.set_ylim((0.1,1.2))
nm = 5
ax_scale.scatter(
[0] * nm,
np.linspace(a.min(), a.max(), nm),
s=sizes.max() * np.linspace(0, 1, nm),
)
ax_scale.spines["left"].set_visible(False)
ax_scale.spines["right"].set_visible(True)
ax_scale.spines["bottom"].set_visible(False)
ax_scale.spines["top"].set_visible(False)
ax_scale.tick_params(
axis="both",
which="both",
labelbottom=False,
labelleft=False,
labelright=True,
bottom=False,
left=False,
right=True,
)
ax.set_xlim(0, a.shape[0])
ax.set_ylim(0, a.shape[1])
ax.set_zlim(0, a.shape[2])
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
return fig
def explode(data):
# following "https://matplotlib.org/3.1.1/gallery/mplot3d/voxels_numpy_logo.html"
if len(data.shape) == 3:
size = np.array(data.shape) * 2
data_e = np.zeros(size - 1, dtype=data.dtype)
data_e[::2, ::2, ::2] = data
if len(data.shape) == 4: ## color data
size = np.array(data.shape)[:3] * 2
data_e = np.zeros(np.concatenate([size - 1, np.array([4])]), dtype=data.dtype)
data_e[::2, ::2, ::2, :] = data
return data_e
def plot_3D_alpha(data):
# plotting each voxel as a slightly smaller block with transparency depending
# on the data value
# following "https://matplotlib.org/3.1.1/gallery/mplot3d/voxels_numpy_logo.html"
col = np.zeros((data.shape[0], data.shape[1], data.shape[2], 4))
data_fil = data.copy()
data_fil[(data == np.inf)] = np.nanmax(data[~(data == np.inf)])
data_fil = (data_fil - np.nanmin(data_fil)) / (
np.nanmax(data_fil) - np.nanmin(data_fil)
)
data_fil[np.isnan(data_fil)] = 0
col[:, :, :, 2] = 1
col[:, :, :, 3] = data_fil
col_exp = explode(col)
fill = explode(np.ones(data.shape))
x, y, z = np.indices(np.array(fill.shape) + 1).astype(float) // 2
x[0::2, :, :] += 0.05
y[:, 0::2, :] += 0.05
z[:, :, 0::2] += 0.05
x[1::2, :, :] += 0.95
y[:, 1::2, :] += 0.95
z[:, :, 1::2] += 0.95
fig = plt.figure()
ax = fig.add_subplot(projection="3d")
ax.voxels(x, y, z, fill, facecolors=col_exp, edgecolors=col_exp)
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
plt.show()
return fig
def quiver_3D(
u,
v,
w,
x=None,
y=None,
z=None,
mask_filtered=None,
filter_def=0,
filter_reg=(1, 1, 1),
cmap="jet",
quiv_args=None,
vmin=None,
vmax=None,
arrow_scale=0.15,
equal_ax=True,
):
"""
Displaying 3D deformation fields vector arrows
Parameters
----------
u,v,w: 3d ndarray or lists
arrays or list with deformation in x,y and z direction
x,y,z: 3d ndarray or lists
Arrays or list with deformation the coordinates of the deformations.
Must match the dimensions of the u,v qnd w. If not provided x,y and z are created
with np.indices(u.shape)
mask_filtered, boolean 3d ndarray or 1d ndarray
Array, or list with same dimensions as the deformations. Defines the area where deformations are drawn
filter_def: float
Filter that prevents the display of deformations arrows with length < filter_def
filter_reg: tuple,list or int
Filter that prevents the display of every i-th deformations arrows separatly alon each axis.
filter_reg=(2,2,2) means that only every second arrow along x,y z axis is displayed leading to
a total reduction of displayed arrows by a factor of 8. filter_reg=3 is interpreted
as (3,3,3).
cmap: string
matplotlib colorbar that defines the coloring of the arrow
quiv_args: dict
Dictionary with kwargs passed on to the matplotlib quiver function.
vmin,vmax: float
Upper and lower bounds for the colormap. Works like vmin and vmax in plt.imshow().
arrow_scale: float
Automatic scaling of the quiver arrows so that the longest arrow has the
length axis length * arrow_scale. Arrow length can alternatively be set by
passing a "lenght" argument in quiv_args.
equal_axes: bool
resize the figure axis so that they are have equal scaling.
Returns
-------
fig: matploltib figure object
ax: mattplotlib axes object
the holding the main 3D quiver plot
"""
# default arguments for the quiver plot. can be overwritten by quiv_args
quiver_args = {
"normalize": False,
"alpha": 0.8,
"pivot": "tail",
"linewidth": 1,
"length": 1,
}
if isinstance(quiv_args, dict):
quiver_args.update(quiv_args)
# overwriting length if an arrow scale and a "length" argument in quiv_args
# is provided at the same
if arrow_scale is not None:
quiver_args["length"] = 1
# convert filter ot list if proveided as int
if not isinstance(filter_reg, (tuple, list)):
filter_reg = [filter_reg] * 3
# generating coordinates if not provided
if x is None:
# if you provide deformations as a list
if len(u.shape) == 1:
x, y, z = [np.indices(u.shape)[0] for i in range(3)]
# if you provide deformations as an array
elif len(u.shape) == 3:
x, y, z = np.indices(u.shape)
else:
raise ValueError(
"displacement data has wrong number of dimensions (%s). Use 1d array, list, or 3d array."
% str(len(u.shape))
)
# conversion to array
x, y, z = np.array([x, y, z])
deformation = np.sqrt(u ** 2 + v ** 2 + w ** 2)
if not isinstance(mask_filtered, np.ndarray):
mask_filtered = deformation > filter_def
if isinstance(filter_reg, list):
show_only = np.zeros(u.shape).astype(bool)
# filtering out every x-th
show_only[:: filter_reg[0], :: filter_reg[1], :: filter_reg[2]] = True
mask_filtered = np.logical_and(mask_filtered, show_only)
xf = x[mask_filtered]
yf = y[mask_filtered]
zf = z[mask_filtered]
uf = u[mask_filtered]
vf = v[mask_filtered]
wf = w[mask_filtered]
df = deformation[mask_filtered]
# make cmap
# create normalized color map for arrows
norm = matplotlib.colors.Normalize(vmin=vmin, vmax=vmax) # 10 ) #cbound[1] ) #)
sm = matplotlib.cm.ScalarMappable(cmap=cmap, norm=norm)
sm.set_array([])
# different option
colors = matplotlib.cm.jet(norm(df)) #
colors = [c for c, d in zip(colors, df) if d > 0] + list(
chain(*[[c, c] for c, d in zip(colors, df) if d > 0])
)
# colors in ax.quiver 3d will probably change with updates:
# requires list with: first len(u) entries define the colors of the shaft, then the next len(u)*2 entries define
# the color ofleft and right arrow head side in alternating order. Try for example:
# colors = ["red" for i in range(len(cf))] + list(chain(*[["blue", "yellow"] for i in range(len(cf))]))
# to see this effect.
# BUT WAIT THERS MORE: zeor length arrows are apparently filtered out in the matplolib with out filtering
# the color list appropriately so we have to do this our selfs as well
# scale arrows to axis dimensions:
ax_dims = [(x.min(), x.max()), (y.min(), y.max()), (z.min(), z.max())]
if arrow_scale is not None:
max_length = df.max()
max_dim_length = np.max([(d[1] - d[0] + 1) for d in ax_dims])
scale = max_dim_length * arrow_scale / max_length
else:
scale = 1
# plotting
fig = plt.figure()
ax = fig.add_subplot(projection="3d", rasterized=True)
ax.quiver(
xf, yf, zf, vf * scale, uf * scale, wf * scale, colors=colors, **quiver_args
)
fig.colorbar(sm, ax=ax)
ax.set_xlim(ax_dims[0])
ax.set_ylim(ax_dims[1])
ax.set_zlim(ax_dims[2])
if equal_ax:
set_axes_equal(ax)
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
for axis in (ax.xaxis, ax.yaxis, ax.zaxis):
pane = getattr(axis, "pane", None)
if pane is not None:
pane.set_facecolor((0.2, 0.2, 0.2, 1.0))
return fig
================================================
FILE: openpiv/__init__.py
================================================
from importlib.metadata import version
__version__ = version("OpenPIV")
def test():
import pytest
pytest.main()
================================================
FILE: openpiv/data/test1/test_data.vec
================================================
# x y u v flags mask
4.0406e-01 3.3983e+00 -5.2592e-03 -5.9910e-02 0.0000e+00 0.0000e+00
9.0137e-01 3.3983e+00 -9.6075e-04 -6.4036e-02 0.0000e+00 0.0000e+00
1.3987e+00 3.3983e+00 -3.4784e-06 -5.9356e-02 1.0000e+00 0.0000e+00
1.8960e+00 3.3983e+00 4.9192e-03 -6.1691e-02 0.0000e+00 0.0000e+00
2.3933e+00 3.3983e+00 -9.2873e-04 -5.6505e-02 1.0000e+00 0.0000e+00
2.8906e+00 3.3983e+00 -5.9565e-03 -5.0575e-02 0.0000e+00 0.0000e+00
3.3879e+00 3.3983e+00 2.1094e-04 -5.7925e-02 0.0000e+00 0.0000e+00
3.8852e+00 3.3983e+00 -2.7240e-03 -6.0472e-02 0.0000e+00 0.0000e+00
4.3825e+00 3.3983e+00 -3.7283e-03 -5.8267e-02 1.0000e+00 0.0000e+00
4.8798e+00 3.3983e+00 2.4173e-03 -6.4150e-02 0.0000e+00 0.0000e+00
4.0406e-01 2.9010e+00 -1.8216e-03 -5.4789e-02 0.0000e+00 0.0000e+00
9.0137e-01 2.9010e+00 -1.8865e-04 -5.9088e-02 1.0000e+00 0.0000e+00
1.3987e+00 2.9010e+00 5.2738e-03 -5.5928e-02 0.0000e+00 0.0000e+00
1.8960e+00 2.9010e+00 8.0944e-03 -5.4726e-02 0.0000e+00 0.0000e+00
2.3933e+00 2.9010e+00 -2.6124e-03 -5.5983e-02 0.0000e+00 0.0000e+00
2.8906e+00 2.9010e+00 -4.3661e-03 -5.1347e-02 0.0000e+00 0.0000e+00
3.3879e+00 2.9010e+00 -3.3565e-03 -5.6682e-02 0.0000e+00 0.0000e+00
3.8852e+00 2.9010e+00 -3.5475e-03 -6.1713e-02 0.0000e+00 0.0000e+00
4.3825e+00 2.9010e+00 -3.8556e-03 -5.6242e-02 1.0000e+00 0.0000e+00
4.8798e+00 2.9010e+00 -6.4612e-03 -6.4347e-02 0.0000e+00 0.0000e+00
4.0406e-01 2.4036e+00 8.3705e-04 -5.9559e-02 0.0000e+00 0.0000e+00
9.0137e-01 2.4036e+00 1.4459e-03 -6.0987e-02 0.0000e+00 0.0000e+00
1.3987e+00 2.4036e+00 -3.0819e-04 -5.8402e-02 1.0000e+00 0.0000e+00
1.8960e+00 2.4036e+00 -7.8548e-03 -6.5643e-02 0.0000e+00 0.0000e+00
2.3933e+00 2.4036e+00 -6.7928e-04 -6.3742e-02 0.0000e+00 0.0000e+00
2.8906e+00 2.4036e+00 1.2726e-04 -4.9550e-02 0.0000e+00 0.0000e+00
3.3879e+00 2.4036e+00 -6.4997e-03 -4.9535e-02 0.0000e+00 0.0000e+00
3.8852e+00 2.4036e+00 -5.7793e-03 -5.4359e-02 0.0000e+00 0.0000e+00
4.3825e+00 2.4036e+00 -7.7358e-03 -5.8984e-02 0.0000e+00 0.0000e+00
4.8798e+00 2.4036e+00 -3.6829e-03 -5.6436e-02 1.0000e+00 0.0000e+00
4.0406e-01 1.9063e+00 -8.4074e-03 -5.9327e-02 0.0000e+00 0.0000e+00
9.0137e-01 1.9063e+00 2.5401e-03 -5.4095e-02 0.0000e+00 0.0000e+00
1.3987e+00 1.9063e+00 -3.3883e-03 -5.7585e-02 0.0000e+00 0.0000e+00
1.8960e+00 1.9063e+00 1.9393e-03 -5.9907e-02 0.0000e+00 0.0000e+00
2.3933e+00 1.9063e+00 1.4774e-03 -6.0280e-02 0.0000e+00 0.0000e+00
2.8906e+00 1.9063e+00 -1.7161e-03 -5.2136e-02 0.0000e+00 0.0000e+00
3.3879e+00 1.9063e+00 -9.2400e-03 -4.8946e-02 0.0000e+00 0.0000e+00
3.8852e+00 1.9063e+00 -7.1067e-03 -4.8031e-02 0.0000e+00 0.0000e+00
4.3825e+00 1.9063e+00 -1.2505e-03 -5.2882e-02 0.0000e+00 0.0000e+00
4.8798e+00 1.9063e+00 6.4614e-04 -5.0812e-02 0.0000e+00 0.0000e+00
4.0406e-01 1.4090e+00 2.2486e-03 -5.0550e-02 0.0000e+00 0.0000e+00
9.0137e-01 1.4090e+00 -6.7877e-03 -5.4202e-02 0.0000e+00 0.0000e+00
1.3987e+00 1.4090e+00 -2.5288e-03 -6.3126e-02 0.0000e+00 0.0000e+00
1.8960e+00 1.4090e+00 -5.9178e-04 -5.8457e-02 0.0000e+00 0.0000e+00
2.3933e+00 1.4090e+00 5.8459e-03 -5.2184e-02 0.0000e+00 0.0000e+00
2.8906e+00 1.4090e+00 5.4790e-03 -4.3826e-02 0.0000e+00 0.0000e+00
3.3879e+00 1.4090e+00 -7.8645e-04 -5.1268e-02 0.0000e+00 0.0000e+00
3.8852e+00 1.4090e+00 -5.9201e-03 -5.2166e-02 0.0000e+00 0.0000e+00
4.3825e+00 1.4090e+00 -4.3095e-03 -5.2602e-02 0.0000e+00 0.0000e+00
4.8798e+00 1.4090e+00 -2.2094e-03 -5.4975e-02 0.0000e+00 0.0000e+00
4.0406e-01 9.1173e-01 9.7924e-03 -5.5734e-02 0.0000e+00 0.0000e+00
9.0137e-01 9.1173e-01 7.5636e-03 -5.2847e-02 0.0000e+00 0.0000e+00
1.3987e+00 9.1173e-01 9.0445e-03 -4.9824e-02 0.0000e+00 0.0000e+00
1.8960e+00 9.1173e-01 1.4482e-03 -5.3496e-02 0.0000e+00 0.0000e+00
2.3933e+00 9.1173e-01 -3.3418e-03 -5.3215e-02 0.0000e+00 0.0000e+00
2.8906e+00 9.1173e-01 -5.2835e-03 -4.9696e-02 0.0000e+00 0.0000e+00
3.3879e+00 9.1173e-01 -5.0878e-03 -5.0559e-02 0.0000e+00 0.0000e+00
3.8852e+00 9.1173e-01 -5.8373e-03 -5.1331e-02 0.0000e+00 0.0000e+00
4.3825e+00 9.1173e-01 -9.5435e-04 -5.1071e-02 0.0000e+00 0.0000e+00
4.8798e+00 9.1173e-01 -1.7836e-03 -5.0735e-02 0.0000e+00 0.0000e+00
4.0406e-01 4.1442e-01 7.7151e-03 -5.9321e-02 0.0000e+00 0.0000e+00
9.0137e-01 4.1442e-01 1.0424e-02 -5.2889e-02 0.0000e+00 0.0000e+00
1.3987e+00 4.1442e-01 -1.2132e-03 -5.1367e-02 0.0000e+00 0.0000e+00
1.8960e+00 4.1442e-01 1.8418e-03 -5.2428e-02 1.0000e+00 0.0000e+00
2.3933e+00 4.1442e-01 3.0095e-03 -4.7837e-02 0.0000e+00 0.0000e+00
2.8906e+00 4.1442e-01 2.7171e-03 -5.1027e-02 0.0000e+00 0.0000e+00
3.3879e+00 4.1442e-01 -5.2003e-03 -5.0522e-02 0.0000e+00 0.0000e+00
3.8852e+00 4.1442e-01 -4.6899e-03 -5.3185e-02 0.0000e+00 0.0000e+00
4.3825e+00 4.1442e-01 -2.9401e-03 -5.4006e-02 0.0000e+00 0.0000e+00
4.8798e+00 4.1442e-01 2.9101e-03 -5.1380e-02 0.0000e+00 0.0000e+00
================================================
FILE: openpiv/docs/Makefile
================================================
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/OpenPIV.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/OpenPIV.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/OpenPIV"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/OpenPIV"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
================================================
FILE: openpiv/docs/conf.py
================================================
# -*- coding: utf-8 -*-
#
# OpenPIV documentation build configuration file, created by
# sphinx-quickstart on Tue Feb 4 13:18:21 2014.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
import os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('../openpiv'))
sys.path.append(os.path.abspath("sphinxext"))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.coverage',
'sphinx.ext.mathjax',
'sphinx.ext.viewcode',
'sphinx.ext.napoleon',
'recommonmark',
'nbsphinx'
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = {
".rst": "restructuredtext",
".txt": "restructuredtext",
".md": "markdown",
}
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = 'OpenPIV'
copyright = '2014, OpenPIV team'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.25.4'
# The full version, including alpha/beta/rc tags.
# release = '0.0.1a'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
# html_theme = 'default'
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'OpenPIVdoc'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'OpenPIV.tex', u'OpenPIV Documentation',
u'OpenPIV group', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'openpiv', 'OpenPIV Documentation',
['OpenPIV group'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'OpenPIV', u'OpenPIV Documentation',
u'OpenPIV group', 'OpenPIV', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
================================================
FILE: openpiv/docs/index.rst
================================================
.. OpenPIV documentation master file, created by
sphinx-quickstart on Mon Apr 18 23:22:32 2011.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
OpenPIV: a python package for PIV image analysis.
=================================================
OpenPIV is a effort of scientists to deliver a tool for the analysis of PIV images
using state-of-the-art algorithms. OpenPIV is released under the
`GPL Licence <http://en.wikipedia.org/wiki/GNU_General_Public_License>`_,
which means that the source code is freely available for users to study, copy, modify
and improve. Because of its permissive licence, you are welcome to download and try
OpenPIV for whatever need you may have. Furthermore, you are encouraged to contribute
to OpenPIV, with code, suggestions and critics.
OpenPIV exists in three forms: Matlab, C++ and Python. This is the home page of the **Python** implementation.
=========
Contents:
=========
.. toctree::
:maxdepth: 2
:titlesonly:
src/piv_basics
src/installation_instruction
src/tutorial1
src/windef
src/masking
src/developers
src/api_reference
src/faq
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
================================================
FILE: openpiv/docs/make.bat
================================================
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\OpenPIV.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\OpenPIV.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end
================================================
FILE: openpiv/docs/src/api_reference.rst
================================================
.. _api_reference:
API reference
=============
This is a complete api reference to the openpiv python module.
The ``openpiv.preprocess`` module
----------------------------------
.. automodule:: openpiv.preprocess
:members:
The ``openpiv.tools`` module
----------------------------
.. automodule:: openpiv.tools
:members:
The ``openpiv.pyprocess`` module
--------------------------------
.. automodule:: openpiv.pyprocess
:members:
The ``openpiv.process`` module
--------------------------------
.. automodule:: openpiv.process
:members:
The ``openpiv.lib`` module
--------------------------------
.. automodule:: openpiv.lib
:members:
The ``openpiv.filters`` module
------------------------------
.. automodule:: openpiv.filters
:members:
The ``openpiv.validation`` module
---------------------------------
.. automodule:: openpiv.validation
:members:
The ``openpiv.scaling`` module
------------------------------
.. automodule:: openpiv.scaling
:members:
================================================
FILE: openpiv/docs/src/developers.rst
================================================
Information for developers and contributors
===========================================
OpenPiv need developers to improve further. Your support, code and contribution is very welcome and
we are grateful you can provide some. Please send us an email to openpiv-develop@googlegroups.com
to get started, or for any kind of information.
We use `git <http://git-scm.com/>`_ for development version control, and we have a main repository on `github <https://github.com/>`_.
Development workflow
--------------------
This is absolutely not a comprehensive guide of git development, and it is only an indication of our workflow.
1) Download and install git. Instruction can be found `here <http://help.github.com/>`_.
2) Set up a github account.
3) Clone OpenPiv repository using::
git clone http://github.com/openpiv/openpiv-python.git
4) create a branch `new_feature` where you implement your new feature.
5) Fix, change, implement, document code, ...
6) From time to time fetch and merge your master branch with that of the main repository.
7) Be sure that everything is ok and works in your branch.
8) Merge your master branch with your `new_feature` branch.
9) Be sure that everything is now ok and works in you master branch.
10) Send a `pull request <http://help.github.com/pull-requests/>`_.
11) Create another branch for a new feature.
Which language can I use?
-------------------------
As a general rule, we use Python where it does not make any difference with code speed. In those situations where Python speed is
the bottleneck, we have some possibilities, depending on your skills and background. If something has to be written from scratch
use the first language from the following which you are confortable with: Cython, C, C++, FORTRAN. If you have existing, debugged, tested code that
you would like to share, then no problem. We accept it, whichever language may be written in!
Things OpenPIV currently needs, (in order of importance)
--------------------------------------------------------
* Good documentation (in progress)
* The implementation of advanced processing algorithms (in progress)
* Flow field filtering and validation functions
* Cython wrappers for C/C++ codes.
* A good graphical user interface (in progress)
How to test all the notebooks::
-----------------------------
conda create -n openpiv
conda activate openpiv
conda install -c conda-forge openpiv
conda install ipykernel
python -m ipykernel install --user --name openpiv --display-name="openpiv"
jupyter nbconvert --to html --ExecutePreprocessor.kernel_name=openpiv --execute *.ipynb
Then open the `openpiv/examples/notebooks` and check the HTML files. If one of those will fail, the error message will be in the command shell
If you need to install cv2::
--------------------------
conda install -c conda-forge opencv
================================================
FILE: openpiv/docs/src/faq.rst
================================================
Frequently Asked Questions about PIV parameters
===============================================
1. Can you please elaborate on the ``sclt`` parameter which is passed to the openpiv function.
E.g. if the time between the two consecutive image is 0.5 seconds and 1 pixel in the image corresponds to 50 cms, what would be the value of sclt.
``sclt`` is a shortcut for _scaling factor from displacement to velocity units_. It's also called the _scale_, or _scaling_.
PIV provides the local displacement in pixel units. In order to know the displacement in the real physical units you multiply it by the scaling of **cm/pixel**, i.e. by 50 cm/pixel. To know the speed, the displacement is divided by the time separation, i.e. by 0.5 seconds, then we get:
`scaling = sclt = 50 cm/pixels / 0.5 = 100 [cm/seconds/pixels]`
For example, if the vector is 10 pixels, then the result will be `100 * 10 = 1000 cm/s`
2. Whats the purpose of the local and global filtering?
**global filtering** supposingly removes the obvious **outliers**, i.e. the vectors which length is larger than the mean of the flow field plus 3 times its standard deviation. These are global outliers in the statistical sense.
**local filtering** is performed on small neighborhoods of vectors, e.g. 3 x 3 or 5 x 5, in order to find **local outliers** - the vectors that are dissimilar from the close neighbors. Typically there are about 5 per-cent of erroneous vectors and these are removed and later the missing values are interpolated from the neighbor vector values. This is also a reason for the Matlab version to generate three lists of files:
**raw** - **_noflt.txt**
**filtered** (after global and local filters) - **_flt.txt**
final (after filtering and interpolation) - **.txt**
3. Why, while taking the FFT, we use the Nfft parameter?
`ffta=fft2(a2,Nfft,Nfft);
fftb=fft2(b2,Nfft,Nfft);`
and why the size has been specified as Nfft which is twice the interrogation window size.
In the FFT-based correlation analysis, we have to pad the window with zeros and get correlation map of the right size and avoid aliasing problem (see Raffel et al. 2007)
4. Also in the same function why sub image **b2** is rotated before taking the correlation.
`b2 = b2(end:-1:1,end:-1:1);`
Without rotation the result will be convolution, not correlation. The definition is **ifft(fft(a)*fft(conj(b)))**. conj() is replaced by rotation in the case of real values. It is more computationally efficient.
5. In the find_displacement(c,s2nm) function for finding peak2, why neighbourhood pixels around peak1 are removed? %line no:352
These peaks might appear as 'false second peak', but they are the part
of the same peak. Think about a top of a mountain. You want to remove
not only the single point, but cut out the top part in order to search
for the second peak.
6. In the read_pair _of_images( ) function why
`A = double(A(:,:,1))/255; %line no:259
B = double(B(:,:,1))/255;`
In order to convert RGB to gray scale. Not always true.
7. After the program is executed, the variable vel contains all the parameters for all the velocity vectors. Here what are the units of u & v. Is it in metres/second?
It is not, the result depends on the **SCLT** variable. if it SCLT is 1, then it is in **pixels/dt** (dt is the interval between two images).
8. What is the "Outlier Filter Value" in OpenPIV?
The outlier filter value is the threshold of the global outlier filter and is says how many times the standard deviation of the whole vector field is exceeded before the vector is considered as outlier. See above discussion on the filters.
9. What is the fifth column in the Output data *.txt,*flt.txt or *noflt.txt?
The fifth column is the value of the Signal-To-Noise (s2n) ration. Note that the value is different (numerically) if the user choses Peak-to-Second-Peak ratio as the s2n parameter or Peak-to-Mean ratio as s2n parameter. The value of Peak-to-Second-Peak or Peak-to-Mean ratio is stored for the further processing.
================================================
FILE: openpiv/docs/src/generated/openpiv.filters._gaussian_kernel.rst
================================================
openpiv.filters._gaussian_kernel
================================
.. currentmodule:: openpiv.filters
.. autofunction:: _gaussian_kernel
================================================
FILE: openpiv/docs/src/generated/openpiv.filters.gaussian.rst
================================================
openpiv.filters.gaussian
========================
.. currentmodule:: openpiv.filters
.. autofunction:: gaussian
================================================
FILE: openpiv/docs/src/generated/openpiv.filters.replace_outliers.rst
================================================
openpiv.filters.replace_outliers
================================
.. currentmodule:: openpiv.filters
.. autofunction:: replace_outliers
================================================
FILE: openpiv/docs/src/generated/openpiv.lib.replace_nans.rst
================================================
openpiv.lib.replace_nans
========================
.. currentmodule:: openpiv.lib
.. autofunction:: replace_nans
================================================
FILE: openpiv/docs/src/generated/openpiv.lib.sincinterp.rst
================================================
openpiv.lib.sincinterp
======================
.. currentmodule:: openpiv.lib
.. autofunction:: sincinterp
================================================
FILE: openpiv/docs/src/generated/openpiv.preprocess.dynamic_masking.rst
================================================
openpiv.preprocess.dynamic_masking
==================================
.. currentmodule:: openpiv.preprocess
.. autofunction:: dynamic_masking
================================================
FILE: openpiv/docs/src/generated/openpiv.process.CorrelationFunction.rst
================================================
openpiv.process.CorrelationFunction
===================================
.. currentmodule:: openpiv.process
.. autoclass:: CorrelationFunction
.. automethod:: __init__
.. rubric:: Methods
.. autosummary::
~CorrelationFunction.__init__
~CorrelationFunction.sig2noise_ratio
~CorrelationFunction.subpixel_peak_position
================================================
FILE: openpiv/docs/src/generated/openpiv.process.correlate_windows.rst
================================================
openpiv.process.correlate_windows
=================================
.. currentmodule:: openpiv.process
.. autofunction:: correlate_windows
================================================
FILE: openpiv/docs/src/generated/openpiv.process.extended_search_area_piv.rst
================================================
openpiv.process.extended_search_area_piv
========================================
.. currentmodule:: openpiv.process
.. autofunction:: extended_search_area_piv
================================================
FILE: openpiv/docs/src/generated/openpiv.process.get_coordinates.rst
================================================
openpiv.process.get_coordinates
===============================
.. currentmodule:: openpiv.process
.. autofunction:: get_coordinates
================================================
FILE: openpiv/docs/src/generated/openpiv.process.get_field_shape.rst
================================================
openpiv.process.get_field_shape
===============================
.. currentmodule:: openpiv.process
.. autofunction:: get_field_shape
================================================
FILE: openpiv/docs/src/generated/openpiv.process.normalize_intensity.rst
================================================
openpiv.process.normalize_intensity
===================================
.. currentmodule:: openpiv.process
.. autofunction:: normalize_intensity
================================================
FILE: openpiv/docs/src/generated/openpiv.pyprocess.correlate_windows.rst
================================================
openpiv.pyprocess.correlate_windows
===================================
.. currentmodule:: openpiv.pyprocess
.. autofunction:: correlate_windows
================================================
FILE: openpiv/docs/src/generated/openpiv.pyprocess.find_first_peak.rst
================================================
openpiv.pyprocess.find_first_peak
=================================
.. currentmodule:: openpiv.pyprocess
.. autofunction:: find_first_peak
================================================
FILE: openpiv/docs/src/generated/openpiv.pyprocess.find_second_peak.rst
================================================
openpiv.pyprocess.find_second_peak
==================================
.. currentmodule:: openpiv.pyprocess
.. autofunction:: find_second_peak
================================================
FILE: openpiv/docs/src/generated/openpiv.pyprocess.find_subpixel_peak_position.rst
================================================
openpiv.pyprocess.find_subpixel_peak_position
=============================================
.. currentmodule:: openpiv.pyprocess
.. autofunction:: find_subpixel_peak_position
================================================
FILE: openpiv/docs/src/generated/openpiv.pyprocess.get_coordinates.rst
================================================
openpiv.pyprocess.get_coordinates
=================================
.. currentmodule:: openpiv.pyprocess
.. autofunction:: get_coordinates
================================================
FILE: openpiv/docs/src/generated/openpiv.pyprocess.get_field_shape.rst
================================================
openpiv.pyprocess.get_field_shape
=================================
.. currentmodule:: openpiv.pyprocess
.. autofunction:: get_field_shape
================================================
FILE: openpiv/docs/src/generated/openpiv.pyprocess.moving_window_array.rst
================================================
openpiv.pyprocess.moving_window_array
=====================================
.. currentmodule:: openpiv.pyprocess
.. autofunction:: moving_window_array
================================================
FILE: openpiv/docs/src/generated/openpiv.pyprocess.normalize_intensity.rst
================================================
openpiv.pyprocess.normalize_intensity
=====================================
.. currentmodule:: openpiv.pyprocess
.. autofunction:: normalize_intensity
================================================
FILE: openpiv/docs/src/generated/openpiv.pyprocess.piv.rst
================================================
openpiv.pyprocess.piv
=====================
.. currentmodule:: openpiv.pyprocess
.. autofunction:: piv
================================================
FILE: openpiv/docs/src/generated/openpiv.scaling.uniform.rst
================================================
openpiv.scaling.uniform
=======================
.. currentmodule:: openpiv.scaling
.. autofunction:: uniform
================================================
FILE: openpiv/docs/src/generated/openpiv.tools.Multiprocesser.rst
================================================
openpiv.tools.Multiprocesser
============================
.. currentmodule:: openpiv.tools
.. autoclass:: Multiprocesser
.. automethod:: __init__
.. rubric:: Methods
.. autosummary::
~Multiprocesser.__init__
~Multiprocesser.run
================================================
FILE: openpiv/docs/src/generated/openpiv.tools.display.rst
================================================
openpiv.tools.display
=====================
.. currentmodule:: openpiv.tools
.. autofunction:: display
================================================
FILE: openpiv/docs/src/generated/openpiv.tools.display_vector_field.rst
================================================
openpiv.tools.display_vector_field
==================================
.. currentmodule:: openpiv.tools
.. autofunction:: display_vector_field
================================================
FILE: openpiv/docs/src/generated/openpiv.tools.imread.rst
================================================
openpiv.tools.imread
====================
.. currentmodule:: openpiv.tools
.. autofunction:: imread
================================================
FILE: openpiv/docs/src/generated/openpiv.tools.save.rst
================================================
openpiv.tools.save
==================
.. currentmodule:: openpiv.tools
.. autofunction:: save
================================================
FILE: openpiv/docs/src/generated/openpiv.validation.global_std.rst
================================================
openpiv.validation.global_std
=============================
.. currentmodule:: openpiv.validation
.. autofunction:: global_std
================================================
FILE: openpiv/docs/src/generated/openpiv.validation.global_val.rst
================================================
openpiv.validation.global_val
=============================
.. currentmodule:: openpiv.validation
.. autofunction:: global_val
================================================
FILE: openpiv/docs/src/generated/openpiv.validation.local_median_val.rst
================================================
openpiv.validation.local_median_val
===================================
.. currentmodule:: openpiv.validation
.. autofunction:: local_median_val
================================================
FILE: openpiv/docs/src/generated/openpiv.validation.sig2noise_val.rst
================================================
openpiv.validation.sig2noise_val
================================
.. currentmodule:: openpiv.validation
.. autofunction:: sig2noise_val
================================================
FILE: openpiv/docs/src/gui_doc.rst
================================================
.. _gui:
====================================
The OpenPIV graphical user interface
====================================
https://github.com/OpenPIV/openpiv_tk_gui
================================================
FILE: openpiv/docs/src/installation_instruction.rst
================================================
.. _installation_instruction:
========================
Installation instruction
========================
.. _dependencies:
Dependencies
============
OpenPIV would not have been possible if other great open source projects did not
exist. We make extensive use of code and tools that other people have created, so
you should install them before you can use OpenPIV.
The dependencies are:
* `Python <http://python.org/>`_
* `Scipy <http://numpy.scipy.org/>`_
* `Numpy <http://www.scipy.org/>`_
* `scikit-image <http://scikit-image.org/>`_
Installation
============
Recommended: Use `uv` (fastest)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`uv <https://github.com/astral-sh/uv>`_ is a fast Python package installer and resolver written in Rust.
It provides faster and more reliable package installation compared to traditional tools.
To install OpenPIV with uv::
pip install uv
uv pip install openpiv
Or use `pip` (standard)
^^^^^^^^^^^^^^^^^^^^^^^^
::
pip install openpiv
.. warning::
**Conda packages are no longer actively maintained.** The conda-forge package may be outdated.
If you previously installed OpenPIV via conda, you can migrate to pip or uv::
# Remove the conda package
conda remove openpiv
# Install with pip or uv
pip install openpiv
# or
uv pip install openpiv
Get OpenPIV source code!
========================
At this moment the only way to get OpenPIV's source code is using git.
`Git <http://en.wikipedia.org/wiki/Git_%28software%29>`_ Git is a distributed revision control system and
our code is hosted at `GitHub <www.github.com>`_.
Bleeding edge development version
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you are interested in the source code you are welcome to browse out git repository
stored at https://github.com/alexlib/openpiv-python. If you want to download the source code
on your machine, for testing, you need to set up git on your computer. Please look at
http://help.github.com/ which provide extensive help for how to set up git.
To follow the development of OpenPIV, clone our repository with the command::
git clone http://github.com/openpiv/openpiv-python.git
and update from time to time. You can also download a tarball containing everything.
Then add the path where the OpenPIV source are to the PYTHONPATH environment variable, so
that OpenPIV module can be imported and used in your programs. Remeber to build the extension
with ::
python setup.py build_ext --inplace
Experience problems?
====================
If you encountered some issues, found difficult to install OpenPIV following these instructions
please register and write on our Google groups forum https://groups.google.com/g/openpiv-users , so that we can help you and
improve this page!
================================================
FILE: openpiv/docs/src/introduction.rst
================================================
Introduction
============
================================================
FILE: openpiv/docs/src/masking.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# OpenPIV masking tutorial\n",
"\n",
"\n",
"In this tutorial we focus on the two ways you can use image masking in OpenPIV. \n",
"\n",
"**Definitions**:\n",
"\n",
"1. _static mask_ - an image with regions that should not be processed are marked as 1 (white color in black and white image or True) and regions that are processed are unmasked (zeros, False)\n",
"\n",
"2. _dynamic mask_ - every pair of images (frame A, B) are processed to find out the region that has to be masked, e.g. a fish body around which we want to analyze PIV vectors. An average mask is then applied to both frames and PIV analysis \n",
"\n",
"\n",
"OpenPIV uses these masks in two ways: \n",
"\n",
"1. masked image regions are set to zero or completely black. `frame_a[image_mask] = 0`\n",
"2. PIV analysis in a completely black interrogation windows result in a zero peak and marked as invalid. \n",
"3. in addition, the image mask is converted in a set of `x,y` coordinates on a PIV grid that mark the masked region in the vector field. These `mask_coords` are propagating through the window deformation and stored with the `x,y,u,v,mask` in the ASCII result files. The vector fields `u,v` are `numpy.MaskedArray` so the masked regions are invalid and should not appear in the plot. They could be also replaced by zeros or `NaN` if needed. "
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"lines_to_next_cell": 2
},
"outputs": [],
"source": [
"from openpiv import tools, pyprocess, validation, filters, scaling, preprocess\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"%matplotlib inline\n",
"\n",
"import imageio\n",
"import importlib_resources\n",
"import pathlib"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"path = importlib_resources.files('openpiv') # pathlib.Path type"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"frame_a = tools.imread( path / 'data' / 'test3' / 'pair_4_frame_0.jpg' )\n",
"frame_b = tools.imread( path / 'data' / 'test3' / 'pair_4_frame_1.jpg' )"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": [
"<Figure size 864x720 with 2 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"fig,ax = plt.subplots(1,2,figsize=(12,10))\n",
"ax[0].imshow(frame_a,cmap='gray');\n",
"ax[1].imshow(frame_b,cmap='gray');"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Rescale intensity or stretch histogram to get better contrast"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.image.AxesImage at 0x7fec92ebf970>"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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
gitextract_ysndazwy/
├── .coveragerc
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ ├── copilot-instructions.md
│ ├── dependabot.yml
│ └── workflows/
│ ├── build.yml
│ └── testing.yml
├── .gitignore
├── .readthedocs.yaml
├── .travis.yml
├── INSTALL
├── MANIFEST.in
├── MILESTONES
├── OPTIMIZATION_SUMMARY.md
├── PERFORMANCE_IMPROVEMENTS.md
├── README.md
├── openpiv/
│ ├── PIV_3D_plotting.py
│ ├── __init__.py
│ ├── data/
│ │ ├── test1/
│ │ │ └── test_data.vec
│ │ ├── test2/
│ │ │ ├── 2image_00.tif
│ │ │ ├── 2image_01.tif
│ │ │ ├── 2image_10.tif
│ │ │ ├── 2image_11.tif
│ │ │ ├── 2image_20.tif
│ │ │ ├── 2image_21.tif
│ │ │ ├── 2image_30.tif
│ │ │ ├── 2image_31.tif
│ │ │ ├── 2image_40.tif
│ │ │ ├── 2image_41.tif
│ │ │ ├── 2image_50.tif
│ │ │ └── 2image_51.tif
│ │ ├── test4/
│ │ │ ├── Camera1-0101.tif
│ │ │ └── Camera1-0102.tif
│ │ ├── test5/
│ │ │ ├── Pattern_10_A.tif
│ │ │ ├── Pattern_10_B.tif
│ │ │ ├── Pattern_1_A.tif
│ │ │ ├── Pattern_1_B.tif
│ │ │ ├── Pattern_2_A.tif
│ │ │ ├── Pattern_2_B.tif
│ │ │ ├── Pattern_3_A.tif
│ │ │ ├── Pattern_3_B.tif
│ │ │ ├── Pattern_4_A.tif
│ │ │ ├── Pattern_4_B.tif
│ │ │ ├── Pattern_5_A.tif
│ │ │ ├── Pattern_5_B.tif
│ │ │ ├── Pattern_6_A.tif
│ │ │ ├── Pattern_6_B.tif
│ │ │ ├── Pattern_7_A.tif
│ │ │ ├── Pattern_7_B.tif
│ │ │ ├── Pattern_8_A.tif
│ │ │ ├── Pattern_8_B.tif
│ │ │ ├── Pattern_9_A.tif
│ │ │ └── Pattern_9_B.tif
│ │ └── test6/
│ │ ├── Pattern_0001_A.tif
│ │ ├── Pattern_0002_A.tif
│ │ ├── Pattern_0003_A.tif
│ │ ├── Pattern_0004_A.tif
│ │ ├── Pattern_0005_A.tif
│ │ ├── Pattern_1001_B.tif
│ │ ├── Pattern_1002_B.tif
│ │ ├── Pattern_1003_B.tif
│ │ ├── Pattern_1004_B.tif
│ │ └── Pattern_1005_B.tif
│ ├── docs/
│ │ ├── Makefile
│ │ ├── conf.py
│ │ ├── images/
│ │ │ ├── B005_1.tif
│ │ │ └── B005_2.tif
│ │ ├── index.rst
│ │ ├── make.bat
│ │ └── src/
│ │ ├── api_reference.rst
│ │ ├── developers.rst
│ │ ├── faq.rst
│ │ ├── generated/
│ │ │ ├── openpiv.filters._gaussian_kernel.rst
│ │ │ ├── openpiv.filters.gaussian.rst
│ │ │ ├── openpiv.filters.replace_outliers.rst
│ │ │ ├── openpiv.lib.replace_nans.rst
│ │ │ ├── openpiv.lib.sincinterp.rst
│ │ │ ├── openpiv.preprocess.dynamic_masking.rst
│ │ │ ├── openpiv.process.CorrelationFunction.rst
│ │ │ ├── openpiv.process.correlate_windows.rst
│ │ │ ├── openpiv.process.extended_search_area_piv.rst
│ │ │ ├── openpiv.process.get_coordinates.rst
│ │ │ ├── openpiv.process.get_field_shape.rst
│ │ │ ├── openpiv.process.normalize_intensity.rst
│ │ │ ├── openpiv.pyprocess.correlate_windows.rst
│ │ │ ├── openpiv.pyprocess.find_first_peak.rst
│ │ │ ├── openpiv.pyprocess.find_second_peak.rst
│ │ │ ├── openpiv.pyprocess.find_subpixel_peak_position.rst
│ │ │ ├── openpiv.pyprocess.get_coordinates.rst
│ │ │ ├── openpiv.pyprocess.get_field_shape.rst
│ │ │ ├── openpiv.pyprocess.moving_window_array.rst
│ │ │ ├── openpiv.pyprocess.normalize_intensity.rst
│ │ │ ├── openpiv.pyprocess.piv.rst
│ │ │ ├── openpiv.scaling.uniform.rst
│ │ │ ├── openpiv.tools.Multiprocesser.rst
│ │ │ ├── openpiv.tools.display.rst
│ │ │ ├── openpiv.tools.display_vector_field.rst
│ │ │ ├── openpiv.tools.imread.rst
│ │ │ ├── openpiv.tools.save.rst
│ │ │ ├── openpiv.validation.global_std.rst
│ │ │ ├── openpiv.validation.global_val.rst
│ │ │ ├── openpiv.validation.local_median_val.rst
│ │ │ └── openpiv.validation.sig2noise_val.rst
│ │ ├── gui_doc.rst
│ │ ├── installation_instruction.rst
│ │ ├── introduction.rst
│ │ ├── masking.ipynb
│ │ ├── modules.rst
│ │ ├── openpiv.rst
│ │ ├── openpiv_pivuq.ipynb
│ │ ├── piv_basics.ipynb
│ │ ├── tutorial1.ipynb
│ │ └── windef.ipynb
│ ├── filters.py
│ ├── lib.py
│ ├── phase_separation.py
│ ├── piv.py
│ ├── preprocess.py
│ ├── preprocess.py,cover
│ ├── pyprocess.py
│ ├── pyprocess3D.py
│ ├── scaling.py
│ ├── settings.py
│ ├── smoothn.py
│ ├── test/
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── extended_search_area_vectorized.ipynb
│ │ ├── test_PIV_3D_plotting.py
│ │ ├── test_filters.ipynb
│ │ ├── test_filters.py
│ │ ├── test_find_peaks.ipynb
│ │ ├── test_lib.py
│ │ ├── test_package_metadata.py
│ │ ├── test_performance.py
│ │ ├── test_piv.py
│ │ ├── test_preprocess.py
│ │ ├── test_process.ipynb
│ │ ├── test_process.py
│ │ ├── test_pyprocess.py
│ │ ├── test_pyprocess3D.py
│ │ ├── test_scaling.py
│ │ ├── test_smoothn.py
│ │ ├── test_tools.ipynb
│ │ ├── test_tools.py
│ │ ├── test_tools_background.py
│ │ ├── test_tools_basic_utils.py
│ │ ├── test_tools_image_processing.py
│ │ ├── test_tools_multiprocessing.py
│ │ ├── test_tools_vector_field.py
│ │ ├── test_validation.ipynb
│ │ ├── test_validation.py
│ │ ├── test_vectorized_extended_search.py
│ │ ├── test_windef.ipynb
│ │ ├── test_windef.py
│ │ ├── test_windef_coverage.py
│ │ ├── test_windef_detailed.py
│ │ └── test_windef_final.py
│ ├── tools.py
│ ├── tutorials/
│ │ ├── Example for overlap setting change.ipynb
│ │ ├── masking_tutorial.py
│ │ ├── tutorial1.py
│ │ ├── tutorial2.py
│ │ └── windef_tutorial.py
│ ├── validation.py
│ └── windef.py
├── poetry.toml
├── pyproject.toml
├── recipe/
│ └── meta.yaml
├── setup.py
└── synimage/
├── PIV_experiment_data.npz
├── Synthetic_Image_Generator_examples.ipynb
├── simple_synthetic_image_demo.ipynb
├── synimagegen.py
└── test_synimagegen.py.bck
SYMBOL INDEX (345 symbols across 41 files)
FILE: openpiv/PIV_3D_plotting.py
function set_axes_equal (line 13) | def set_axes_equal(ax):
function scatter_3D (line 48) | def scatter_3D(a, cmap="jet", sca_args=None, control="color", size=60):
function explode (line 134) | def explode(data):
function plot_3D_alpha (line 149) | def plot_3D_alpha(data):
function quiver_3D (line 188) | def quiver_3D(
FILE: openpiv/__init__.py
function test (line 7) | def test():
FILE: openpiv/filters.py
function _gaussian_kernel (line 26) | def _gaussian_kernel(half_width: int=1)-> np.ndarray:
function gaussian_kernel (line 57) | def gaussian_kernel(sigma:float, truncate:float=4.0)->np.ndarray:
function gaussian (line 73) | def gaussian(
function replace_outliers (line 107) | def replace_outliers(
FILE: openpiv/lib.py
function replace_nans (line 4) | def replace_nans(array, max_iter, tol, kernel_size=2, method="disk"):
function get_dist (line 158) | def get_dist(kernel, kernel_size):
FILE: openpiv/phase_separation.py
function opening_method (line 26) | def opening_method(original_image, kernel_size, iterations=1, thresh_fac...
function median_filter_method (line 104) | def median_filter_method(original_image, kernel_size):
function khalitov_longmire (line 141) | def khalitov_longmire(
function get_particles_size_array (line 273) | def get_particles_size_array(
function get_size_brightness_map (line 318) | def get_size_brightness_map(
function khalitov_longmire_analyse_particle_segments (line 390) | def khalitov_longmire_analyse_particle_segments(original_image, object_p...
function khalitov_longmire_get_object_pixels (line 411) | def khalitov_longmire_get_object_pixels(
FILE: openpiv/piv.py
function simple_piv (line 27) | def simple_piv(im1, im2, window_size=32, overlap=16, search_area_size=32,
function piv_example (line 114) | def piv_example(plot_animation=True, plot_quiver=True):
function process_pair (line 198) | def process_pair(frame_a, frame_b, window_size=32, overlap=16,
FILE: openpiv/preprocess.py
function dynamic_masking (line 34) | def dynamic_masking(image, method="edges", filter_size=7, threshold=0.005):
function mask_coordinates (line 100) | def mask_coordinates(image_mask, tolerance=1.5, min_length=10, plot=False):
function prepare_mask_from_polygon (line 134) | def prepare_mask_from_polygon(x, y, mask_coords):
function prepare_mask_on_grid (line 149) | def prepare_mask_on_grid(
function normalize_array (line 167) | def normalize_array(array, axis = None):
function standardize_array (line 208) | def standardize_array(array, axis = None):
function instensity_cap (line 234) | def instensity_cap(img, std_mult = 2):
function intensity_clip (line 259) | def intensity_clip(img, min_val = 0, max_val = None, flag = 'clip'):
function high_pass (line 296) | def high_pass(img, sigma = 5, clip = False):
function local_variance_normalization (line 322) | def local_variance_normalization(img, sigma_1 = 2, sigma_2 = 1, clip = T...
function contrast_stretch (line 363) | def contrast_stretch(img, lower_limit = 2, upper_limit = 98):
function threshold_binarize (line 395) | def threshold_binarize(img, threshold, max_val = 255):
function gen_min_background (line 423) | def gen_min_background(img_list, resize = 255):
function gen_lowpass_background (line 458) | def gen_lowpass_background(img_list, sigma = 3, resize = None):
function stretch_image (line 548) | def stretch_image(img,
FILE: openpiv/pyprocess.py
function get_field_shape (line 31) | def get_field_shape(
function get_coordinates (line 70) | def get_coordinates(
function get_rect_coordinates (line 159) | def get_rect_coordinates(
function sliding_window_array (line 183) | def sliding_window_array(
function moving_window_array (line 214) | def moving_window_array(array, window_size, overlap):
function find_first_peak (line 248) | def find_first_peak(corr):
function find_second_peak (line 267) | def find_second_peak(corr, i=None, j=None, width=2):
function find_all_first_peaks (line 320) | def find_all_first_peaks(corr):
function find_all_second_peaks (line 345) | def find_all_second_peaks(corr, width = 2):
function find_subpixel_peak_position (line 385) | def find_subpixel_peak_position(corr, subpixel_method="gaussian"):
function sig2noise_ratio (line 483) | def sig2noise_ratio(
function vectorized_sig2noise_ratio (line 595) | def vectorized_sig2noise_ratio(correlation,
function fft_correlate_images (line 676) | def fft_correlate_images(
function normalize_intensity (line 755) | def normalize_intensity(window):
function correlate_windows (line 787) | def correlate_windows(window_a, window_b, correlation_method="fft",
function fft_correlate_windows (line 854) | def fft_correlate_windows(window_a, window_b,
function extended_search_area_piv (line 908) | def extended_search_area_piv(
function correlation_to_displacement (line 1098) | def correlation_to_displacement(corr, n_rows, n_cols,
function vectorized_correlation_to_displacements (line 1134) | def vectorized_correlation_to_displacements(corr: np.ndarray,
function nextpower2 (line 1248) | def nextpower2(i):
FILE: openpiv/pyprocess3D.py
function get_coordinates (line 29) | def get_coordinates(image_size, search_area_size, window_size, overlap):
function find_second_peak_3D (line 111) | def find_second_peak_3D(corr, i=None, j=None, z=None, width=2):
function find_subpixel_peak_position (line 170) | def find_subpixel_peak_position(corr, subpixel_method="gaussian"):
function sig2noise_ratio (line 267) | def sig2noise_ratio(corr, sig2noise_method="peak2peak", width=2):
function correlate_windows (line 334) | def correlate_windows(
function normalize_intensity (line 405) | def normalize_intensity(window):
function nextpower2 (line 422) | def nextpower2(i):
function check_input (line 430) | def check_input(window_size, overlap, search_area_size, frame_a, frame_b):
function extended_search_area_piv3D (line 456) | def extended_search_area_piv3D(
FILE: openpiv/scaling.py
function uniform (line 23) | def uniform(x, y, u, v, scaling_factor):
FILE: openpiv/settings.py
class PIVSettings (line 9) | class PIVSettings:
FILE: openpiv/smoothn.py
function smoothn (line 7) | def smoothn(
function warning (line 394) | def warning(s1, s2):
function gcv (line 402) | def gcv(p, Lambda, aow, DCTy, IsFinite, Wtot, y, nof, noe, smoothOrder):
function RobustWeights (line 423) | def RobustWeights(r, I, h, wstr):
function InitialGuess (line 448) | def InitialGuess(y, z0):
function dctND (line 494) | def dctND(data, f=dct):
function peaks (line 509) | def peaks(n):
function test1 (line 553) | def test1():
function test2 (line 574) | def test2(axis=None):
function test3 (line 591) | def test3(axis=None):
function test4 (line 627) | def test4(i=10, step=0.2, axis=None):
function test5 (line 653) | def test5():
function test6 (line 666) | def test6(noise=0.05, nout=30):
function sparseSVD (line 698) | def sparseSVD(D):
function sparseTest (line 711) | def sparseTest(n=1000):
function smooth (line 768) | def smooth(u, mask):
function smooth_masked_array (line 776) | def smooth_masked_array(u):
FILE: openpiv/test/conftest.py
function pytest_configure (line 10) | def pytest_configure(config):
function debug_show (line 17) | def debug_show(*args, **kwargs):
function debug_draw (line 24) | def debug_draw(*args, **kwargs):
function configure_plots (line 37) | def configure_plots(request):
FILE: openpiv/test/test_PIV_3D_plotting.py
function temp_dir (line 26) | def temp_dir(tmpdir):
function test_set_axes_equal (line 29) | def test_set_axes_equal():
function test_explode (line 70) | def test_explode():
function test_scatter_3D (line 96) | def test_scatter_3D():
function test_scatter_3D_size_control (line 123) | def test_scatter_3D_size_control():
function test_quiver_3D (line 147) | def test_quiver_3D():
function test_quiver_3D_with_coordinates (line 176) | def test_quiver_3D_with_coordinates():
function test_quiver_3D_with_filter (line 208) | def test_quiver_3D_with_filter():
function test_plot_3D_alpha (line 222) | def test_plot_3D_alpha():
FILE: openpiv/test/test_filters.py
function test_gaussian_kernel (line 7) | def test_gaussian_kernel():
function test_gaussian_kernel_function (line 25) | def test_gaussian_kernel_function():
function test_gaussian (line 38) | def test_gaussian():
function test_replace_nans (line 65) | def test_replace_nans():
function test_replace_outliers (line 84) | def test_replace_outliers():
function test_replace_outliers_with_w (line 100) | def test_replace_outliers_with_w():
function test_replace_outliers_different_methods (line 137) | def test_replace_outliers_different_methods():
function test_replace_outliers_non_masked_input (line 170) | def test_replace_outliers_non_masked_input():
FILE: openpiv/test/test_lib.py
function test_replace_nans_2d (line 6) | def test_replace_nans_2d():
function test_replace_nans_3d (line 28) | def test_replace_nans_3d():
function test_replace_nans_masked_array (line 54) | def test_replace_nans_masked_array():
function test_replace_nans_convergence (line 68) | def test_replace_nans_convergence():
function test_replace_nans_max_iter (line 88) | def test_replace_nans_max_iter():
function test_replace_nans_kernel_size (line 106) | def test_replace_nans_kernel_size():
function test_replace_nans_invalid_method (line 125) | def test_replace_nans_invalid_method():
function test_replace_nans_all_nan_neighbors (line 135) | def test_replace_nans_all_nan_neighbors():
function test_replace_nans_no_nans (line 149) | def test_replace_nans_no_nans():
function test_get_dist_2d (line 159) | def test_get_dist_2d():
function test_get_dist_3d (line 179) | def test_get_dist_3d():
FILE: openpiv/test/test_package_metadata.py
function test_package_version_matches_metadata (line 6) | def test_package_version_matches_metadata():
FILE: openpiv/test/test_performance.py
function test_find_all_first_peaks_performance (line 8) | def test_find_all_first_peaks_performance():
function test_normalize_intensity_performance (line 34) | def test_normalize_intensity_performance():
function test_global_std_performance (line 59) | def test_global_std_performance():
function test_replace_outliers_performance (line 87) | def test_replace_outliers_performance():
function test_vectorized_sig2noise_ratio_performance (line 109) | def test_vectorized_sig2noise_ratio_performance():
FILE: openpiv/test/test_piv.py
function create_test_pair (line 13) | def create_test_pair(image_size=32, shift=(2, 2)):
function test_simple_piv_with_arrays (line 41) | def test_simple_piv_with_arrays():
function test_simple_piv_with_file_paths (line 71) | def test_simple_piv_with_file_paths():
function test_simple_piv_validation_methods (line 92) | def test_simple_piv_validation_methods(validation_method):
function test_simple_piv_parameters (line 117) | def test_simple_piv_parameters(window_size, overlap, search_area_size):
function test_piv_example_no_plots (line 142) | def test_piv_example_no_plots():
function test_process_pair (line 157) | def test_process_pair():
function test_process_pair_validation_methods (line 194) | def test_process_pair_validation_methods(validation_method):
function test_process_pair_filter_methods (line 215) | def test_process_pair_filter_methods(filter_method):
function test_process_pair_with_real_images (line 241) | def test_process_pair_with_real_images():
function test_piv_example_with_quiver_only (line 271) | def test_piv_example_with_quiver_only():
function test_simple_piv_with_plotting (line 298) | def test_simple_piv_with_plotting():
function test_process_pair_with_plotting (line 329) | def test_process_pair_with_plotting():
function test_simple_piv_with_different_dt (line 367) | def test_simple_piv_with_different_dt(dt):
function test_simple_piv_with_invalid_inputs (line 395) | def test_simple_piv_with_invalid_inputs():
function test_process_pair_with_different_parameters (line 409) | def test_process_pair_with_different_parameters():
FILE: openpiv/test/test_preprocess.py
function test_dynamic_masking (line 22) | def test_dynamic_masking(display_images=False):
function test_mask_coordinates (line 51) | def test_mask_coordinates():
function test_normalize_array (line 74) | def test_normalize_array():
function test_standardize_array (line 185) | def test_standardize_array():
function test_instensity_cap (line 216) | def test_instensity_cap():
function test_intensity_clip (line 240) | def test_intensity_clip():
function test_high_pass (line 262) | def test_high_pass():
function test_local_variance_normalization (line 281) | def test_local_variance_normalization():
function test_contrast_stretch (line 300) | def test_contrast_stretch():
function test_threshold_binarize (line 322) | def test_threshold_binarize():
function test_gen_min_background (line 340) | def test_gen_min_background():
function test_gen_lowpass_background (line 392) | def test_gen_lowpass_background():
function test_stretch_image (line 432) | def test_stretch_image():
function test_prepare_mask_on_grid (line 457) | def test_prepare_mask_on_grid():
function test_prepare_mask_from_polygon (line 476) | def test_prepare_mask_from_polygon():
FILE: openpiv/test/test_process.py
function create_pair (line 36) | def create_pair(image_size=32, u=SHIFT_U, v=SHIFT_V):
function test_piv (line 58) | def test_piv():
function test_piv_smaller_window (line 70) | def test_piv_smaller_window():
function test_extended_search_area (line 78) | def test_extended_search_area():
function test_extended_search_area_overlap (line 92) | def test_extended_search_area_overlap():
function test_extended_search_area_sig2noise (line 120) | def test_extended_search_area_sig2noise():
function test_process_extended_search_area (line 141) | def test_process_extended_search_area():
function test_sig2noise_ratio (line 151) | def test_sig2noise_ratio():
function test_fft_correlate (line 173) | def test_fft_correlate():
function test_new_overlap_setting (line 182) | def test_new_overlap_setting():
function test_extended_search_area_piv_parameters (line 210) | def test_extended_search_area_piv_parameters(window_size, overlap):
FILE: openpiv/test/test_pyprocess.py
function test_get_field_shape (line 7) | def test_get_field_shape():
function test_get_coordinates (line 37) | def test_get_coordinates():
function test_get_rect_coordinates (line 68) | def test_get_rect_coordinates():
function test_sliding_window_array (line 97) | def test_sliding_window_array():
function test_find_first_peak (line 133) | def test_find_first_peak():
function test_find_subpixel_peak_position (line 163) | def test_find_subpixel_peak_position():
function test_vectorized_sig2noise_ratio (line 215) | def test_vectorized_sig2noise_ratio():
function test_fft_correlate_images (line 252) | def test_fft_correlate_images():
function test_correlate_windows (line 309) | def test_correlate_windows():
function test_find_second_peak (line 342) | def test_find_second_peak():
function test_correlation_to_displacement (line 364) | def test_correlation_to_displacement():
FILE: openpiv/test/test_pyprocess3D.py
function dist (line 14) | def dist(u, shift):
function create_pair (line 18) | def create_pair(image_size=32, u=3, v=2, w=1):
function test_piv (line 32) | def test_piv():
function test_piv_extended_search_area (line 45) | def test_piv_extended_search_area():
FILE: openpiv/test/test_smoothn.py
function test_smoothn_basic (line 18) | def test_smoothn_basic():
function test_smoothn_2d (line 41) | def test_smoothn_2d():
function test_smoothn_with_s (line 55) | def test_smoothn_with_s():
function test_smoothn_with_weights (line 70) | def test_smoothn_with_weights():
function test_smoothn_with_missing_data (line 95) | def test_smoothn_with_missing_data():
function test_smoothn_with_masked_array (line 117) | def test_smoothn_with_masked_array():
function test_smoothn_with_standard_deviation (line 139) | def test_smoothn_with_standard_deviation():
function test_smoothn_robust (line 164) | def test_smoothn_robust():
function test_smoothn_with_initial_guess (line 192) | def test_smoothn_with_initial_guess():
function test_smoothn_with_axis (line 212) | def test_smoothn_with_axis():
function test_smoothn_with_different_smoothing_orders (line 254) | def test_smoothn_with_different_smoothing_orders():
function test_smoothn_with_different_weight_strings (line 284) | def test_smoothn_with_different_weight_strings():
function test_smoothn_edge_cases (line 317) | def test_smoothn_edge_cases():
function test_gcv_function (line 334) | def test_gcv_function():
function test_robust_weights (line 364) | def test_robust_weights():
function test_dctND (line 397) | def test_dctND():
function test_warning_function (line 426) | def test_warning_function():
function test_smoothn_with_negative_weights (line 448) | def test_smoothn_with_negative_weights():
function test_initial_guess_function (line 479) | def test_initial_guess_function():
function test_peaks_function (line 506) | def test_peaks_function():
function test_smoothn_3d (line 523) | def test_smoothn_3d():
function test_smoothn_with_verbose (line 547) | def test_smoothn_with_verbose():
function test_smoothn_with_max_iter (line 574) | def test_smoothn_with_max_iter():
function test_smoothn_with_tolerance (line 591) | def test_smoothn_with_tolerance():
FILE: openpiv/test/test_tools.py
function test_imread (line 20) | def test_imread(image_file=_file_a):
function test_imread_edge_cases (line 32) | def test_imread_edge_cases():
function test_display_vector_field_with_warnings_suppressed (line 42) | def test_display_vector_field_with_warnings_suppressed():
function test_file_patterns (line 67) | def test_file_patterns():
function test_transform_coordinates (line 83) | def test_transform_coordinates():
function test_save_and_load (line 105) | def test_save_and_load():
function test_negative (line 130) | def test_negative():
function test_display_vector_field_from_arrays_with_warnings_suppressed (line 147) | def test_display_vector_field_from_arrays_with_warnings_suppressed():
function test_multiprocesser (line 175) | def test_multiprocesser():
function test_imread (line 208) | def test_imread():
FILE: openpiv/test/test_tools_background.py
function create_test_images (line 12) | def create_test_images(num_images=3, size=(20, 20)):
function test_mark_background (line 41) | def test_mark_background():
function test_mark_background2 (line 79) | def test_mark_background2():
function test_find_reflexions (line 114) | def test_find_reflexions():
function test_find_boundaries (line 150) | def test_find_boundaries():
FILE: openpiv/test/test_tools_basic_utils.py
function test_natural_sort (line 8) | def test_natural_sort():
function test_sorted_unique (line 42) | def test_sorted_unique():
function test_display (line 79) | def test_display(capsys):
function test_negative (line 103) | def test_negative():
FILE: openpiv/test/test_tools_image_processing.py
function test_imread_grayscale (line 10) | def test_imread_grayscale():
function test_imread_rgb (line 34) | def test_imread_rgb():
function test_rgb2gray (line 63) | def test_rgb2gray():
function test_imsave (line 97) | def test_imsave():
function test_imsave_with_negative_values (line 120) | def test_imsave_with_negative_values():
function test_imsave_with_large_values (line 153) | def test_imsave_with_large_values():
function test_imsave_tiff_format (line 185) | def test_imsave_tiff_format():
function test_convert_16bits_tif (line 208) | def test_convert_16bits_tif():
FILE: openpiv/test/test_tools_multiprocessing.py
function test_multiprocesser_basic (line 10) | def test_multiprocesser_basic():
function test_multiprocesser_pattern_1_plus_2 (line 39) | def test_multiprocesser_pattern_1_plus_2():
function test_multiprocesser_pattern_1_plus_3 (line 71) | def test_multiprocesser_pattern_1_plus_3():
function test_multiprocesser_pattern_1_plus_2_3_plus_4 (line 106) | def test_multiprocesser_pattern_1_plus_2_3_plus_4():
function test_multiprocesser_run (line 135) | def test_multiprocesser_run():
function test_multiprocesser_error_handling (line 176) | def test_multiprocesser_error_handling():
FILE: openpiv/test/test_tools_vector_field.py
function test_save_basic (line 13) | def test_save_basic():
function test_save_with_flags_and_mask (line 44) | def test_save_with_flags_and_mask():
function test_save_with_masked_array (line 77) | def test_save_with_masked_array():
function test_save_with_custom_format (line 109) | def test_save_with_custom_format():
function test_transform_coordinates_2d (line 138) | def test_transform_coordinates_2d():
function test_transform_coordinates_1d (line 159) | def test_transform_coordinates_1d():
function test_display_vector_field_from_arrays (line 181) | def test_display_vector_field_from_arrays(show_invalid):
function test_display_windows_sampling (line 208) | def test_display_windows_sampling(method):
FILE: openpiv/test/test_validation.py
function test_validation_peak2mean (line 23) | def test_validation_peak2mean():
function test_validation_peak2peak (line 34) | def test_validation_peak2peak():
function test_sig2noise_val (line 44) | def test_sig2noise_val():
function test_sig2noise_val_3d (line 56) | def test_sig2noise_val_3d():
function test_sig2noise_val_edge_cases (line 74) | def test_sig2noise_val_edge_cases():
function test_local_median_validation (line 103) | def test_local_median_validation(u_threshold=3, N=3):
function test_local_norm_median_validation (line 126) | def test_local_norm_median_validation():
function test_global_val (line 182) | def test_global_val():
function test_global_std (line 209) | def test_global_std():
function test_uniform_shift_std (line 240) | def test_uniform_shift_std(N: int = 2):
function test_typical_validation_basic (line 261) | def test_typical_validation_basic():
function test_typical_validation_normalized_median (line 298) | def test_typical_validation_normalized_median():
function test_typical_validation_no_s2n (line 329) | def test_typical_validation_no_s2n():
function test_typical_validation_with_plots (line 360) | def test_typical_validation_with_plots():
FILE: openpiv/test/test_vectorized_extended_search.py
function fft_correlate_strided_images (line 16) | def fft_correlate_strided_images(image_a, image_b):
FILE: openpiv/test/test_windef.py
function test_first_pass_circ (line 36) | def test_first_pass_circ():
function test_multi_pass_circ (line 64) | def test_multi_pass_circ():
function test_first_pass_lin (line 113) | def test_first_pass_lin():
function test_save_plot (line 135) | def test_save_plot():
function test_invert_and_piv (line 152) | def test_invert_and_piv():
function test_multi_pass_lin (line 174) | def test_multi_pass_lin():
function test_simple_multipass (line 226) | def test_simple_multipass():
function test_simple_rectangular_window (line 279) | def test_simple_rectangular_window():
FILE: openpiv/test/test_windef_coverage.py
function test_prepare_images_with_invert_and_show_plots_direct (line 23) | def test_prepare_images_with_invert_and_show_plots_direct():
function test_multipass_img_deform_with_non_masked_array_after_smoothn (line 74) | def test_multipass_img_deform_with_non_masked_array_after_smoothn():
function test_direct_code_coverage (line 122) | def test_direct_code_coverage():
function test_monkey_patch_for_coverage (line 167) | def test_monkey_patch_for_coverage():
FILE: openpiv/test/test_windef_detailed.py
function test_prepare_images_basic (line 24) | def test_prepare_images_basic():
function test_prepare_images_with_roi (line 42) | def test_prepare_images_with_roi():
function test_prepare_images_with_invert (line 60) | def test_prepare_images_with_invert():
function test_prepare_images_with_invert_and_show_plots (line 89) | def test_prepare_images_with_invert_and_show_plots():
function test_prepare_images_with_static_mask (line 128) | def test_prepare_images_with_static_mask():
function test_prepare_images_with_dynamic_mask (line 152) | def test_prepare_images_with_dynamic_mask():
function test_create_deformation_field (line 172) | def test_create_deformation_field():
function test_deform_windows (line 206) | def test_deform_windows():
function test_first_pass_edge_cases (line 233) | def test_first_pass_edge_cases():
function test_multipass_img_deform_error_handling (line 265) | def test_multipass_img_deform_error_handling():
function test_multipass_img_deform_with_mask (line 282) | def test_multipass_img_deform_with_mask():
function test_simple_multipass_basic (line 315) | def test_simple_multipass_basic():
function test_simple_multipass_single_pass (line 342) | def test_simple_multipass_single_pass():
function test_deformation_methods (line 359) | def test_deformation_methods():
function test_prepare_images_with_show_plots (line 397) | def test_prepare_images_with_show_plots():
function test_prepare_images_with_dynamic_mask_and_show_plots (line 423) | def test_prepare_images_with_dynamic_mask_and_show_plots():
function test_deform_windows_with_debugging (line 452) | def test_deform_windows_with_debugging():
function test_multipass_img_deform_with_static_mask (line 480) | def test_multipass_img_deform_with_static_mask():
function test_multipass_img_deform_with_dynamic_mask (line 514) | def test_multipass_img_deform_with_dynamic_mask():
function test_multipass_img_deform_with_show_plots (line 547) | def test_multipass_img_deform_with_show_plots():
function test_piv_with_validation_and_smoothn (line 581) | def test_piv_with_validation_and_smoothn():
function test_piv_with_validation_all_passes (line 622) | def test_piv_with_validation_all_passes():
function test_piv_with_show_plots (line 663) | def test_piv_with_show_plots():
function test_piv_with_static_mask (line 708) | def test_piv_with_static_mask():
function test_piv_with_multiple_iterations (line 747) | def test_piv_with_multiple_iterations():
function test_multipass_img_deform_with_non_masked_array (line 784) | def test_multipass_img_deform_with_non_masked_array():
FILE: openpiv/test/test_windef_final.py
function test_final_coverage (line 15) | def test_final_coverage():
FILE: openpiv/tools.py
function _read_image_stack (line 37) | def _read_image_stack(list_img: list) -> np.ndarray:
function _set_figure_window_title (line 46) | def _set_figure_window_title(fig: Any, title: str) -> None:
function _prepare_image_for_save (line 53) | def _prepare_image_for_save(arr: np.ndarray, preserve_tiff_depth: bool =...
function natural_sort (line 80) | def natural_sort(file_list: List[pathlib.Path]) -> List[pathlib.Path]:
function sorted_unique (line 88) | def sorted_unique(array: np.ndarray) -> np.ndarray:
function display_vector_field_from_arrays (line 105) | def display_vector_field_from_arrays(
function display_vector_field (line 240) | def display_vector_field(
function imread (line 366) | def imread(filename, flatten=0):
function rgb2gray (line 399) | def rgb2gray(rgb: np.ndarray) -> np.ndarray:
function imsave (line 411) | def imsave(filename, arr):
function convert_16bits_tif (line 440) | def convert_16bits_tif(filename, save_name):
function mark_background (line 461) | def mark_background(
function mark_background2 (line 484) | def mark_background2(list_img, filename):
function edges (line 492) | def edges(list_img, filename):
function find_reflexions (line 498) | def find_reflexions(list_img, filename):
function find_boundaries (line 506) | def find_boundaries(threshold, list_img1, list_img2, filename, picname):
function save (line 534) | def save(
function display (line 624) | def display(message):
class Multiprocesser (line 638) | class Multiprocesser:
method __init__ (line 639) | def __init__(self,
method run (line 731) | def run(self, func, n_cpus=1):
function negative (line 764) | def negative(image):
function display_windows_sampling (line 779) | def display_windows_sampling(x, y, window_size, skip=0, method="standard"):
function transform_coordinates (line 876) | def transform_coordinates(x, y, u, v):
FILE: openpiv/tutorials/tutorial2.py
function func (line 6) | def func( args ):
FILE: openpiv/validation.py
function global_val (line 30) | def global_val(
function global_std (line 76) | def global_std(
function sig2noise_val (line 131) | def sig2noise_val(
function local_median_val (line 184) | def local_median_val(
function local_norm_median_val (line 247) | def local_norm_median_val(
function typical_validation (line 367) | def typical_validation(
FILE: openpiv/windef.py
function prepare_images (line 25) | def prepare_images(
function piv (line 110) | def piv(settings):
function create_deformation_field (line 365) | def create_deformation_field(frame, x, y, u, v, interpolation_order = 3):
function deform_windows (line 425) | def deform_windows(frame, x, y, u, v, interpolation_order=1, interpolati...
function first_pass (line 489) | def first_pass(frame_a, frame_b, settings):
function multipass_img_deform (line 579) | def multipass_img_deform(
function simple_multipass (line 831) | def simple_multipass(
FILE: synimage/synimagegen.py
class continuous_flow_field (line 28) | class continuous_flow_field:
method __init__ (line 29) | def __init__(self, data, inter=False):
method f_U (line 43) | def f_U(self, x, y):
method f_V (line 48) | def f_V(self, x, y):
method get_U_V (line 53) | def get_U_V(self, x, y):
method create_syn_quiver (line 60) | def create_syn_quiver(self, number_of_grid_points, path=None):
function create_synimage_parameters (line 100) | def create_synimage_parameters(
function generate_particle_image (line 310) | def generate_particle_image(
Copy disabled (too large)
Download .json
Condensed preview — 174 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (10,614K chars).
[
{
"path": ".coveragerc",
"chars": 232,
"preview": "[run]\nsource = openpiv\nomit = \n */test/*\n */__init__.py\n */setup.py\n\n[report]\nexclude_lines =\n pragma: no co"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 834,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the b"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 595,
"preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your fea"
},
{
"path": ".github/copilot-instructions.md",
"chars": 6476,
"preview": "# OpenPIV Python\n\nOpenPIV is a Python and Cython library for Particle Image Velocimetry (PIV) analysis of fluid flow ima"
},
{
"path": ".github/dependabot.yml",
"chars": 512,
"preview": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where "
},
{
"path": ".github/workflows/build.yml",
"chars": 870,
"preview": "name: Build and upload to PyPI\non:\n push:\n tags:\n - \"v[0-9]*.[0-9]*.[0-9]*\"\n - \"[0-9]*.[0-9]*.[0-9]*\"\n\njob"
},
{
"path": ".github/workflows/testing.yml",
"chars": 702,
"preview": "name: Python package\n\non: [push]\n\njobs:\n build:\n runs-on: ubuntu-latest\n strategy:\n matrix:\n python-v"
},
{
"path": ".gitignore",
"chars": 519,
"preview": "*.m\n*.jvc\n*.pyc\nbuild/\n*.txt\n/setup.cfg\n\ndist/*\nmasking_tutorial/.ipynb_checkpoints\nopenpiv/masking_tutorial/.ipynb_chec"
},
{
"path": ".readthedocs.yaml",
"chars": 586,
"preview": "# .readthedocs.yaml\n# Read the Docs configuration file\n# See https://docs.readthedocs.io/en/stable/config-file/v2.html f"
},
{
"path": ".travis.yml",
"chars": 174,
"preview": "language: python\npython:\n - \"3.8\"\n\nnotifications:\n email: false\n\ninstall:\n - pip install poetry\n - poetry instal"
},
{
"path": "INSTALL",
"chars": 1978,
"preview": "=========================\nInstallation instructions\n=========================\n\nDependencies\n============\n\nOpenPIV would "
},
{
"path": "MANIFEST.in",
"chars": 634,
"preview": "include *.md\ninclude *.txt\ninclude INSTALL\ninclude LICENSE.txt\ninclude MILESTONES\ninclude TODO\n\nrecursive-include openpi"
},
{
"path": "MILESTONES",
"chars": 613,
"preview": "Milestones and targets for future OpenPiv versions.\n\nv 0.1\n+ all functions should be unit tested\n+ all functions should "
},
{
"path": "OPTIMIZATION_SUMMARY.md",
"chars": 1898,
"preview": "# Performance Optimization Summary\n\n## Quick Summary\n\nThis PR implements performance optimizations across the OpenPIV co"
},
{
"path": "PERFORMANCE_IMPROVEMENTS.md",
"chars": 6254,
"preview": "# Performance Improvements Documentation\n\n## Overview\n\nThis document summarizes the performance optimizations made to th"
},
{
"path": "README.md",
"chars": 4975,
"preview": "# OpenPIV\n[](https:/"
},
{
"path": "openpiv/PIV_3D_plotting.py",
"chars": 11629,
"preview": "\"\"\"\nfunctions to plot 3D-deformation fields and simple 3D-structures\n\"\"\"\n\n\nimport matplotlib\nimport matplotlib.pyplot as"
},
{
"path": "openpiv/__init__.py",
"chars": 125,
"preview": "from importlib.metadata import version\n\n\n__version__ = version(\"OpenPIV\")\n\n\ndef test():\n import pytest\n\n pytest.ma"
},
{
"path": "openpiv/data/test1/test_data.vec",
"chars": 4756,
"preview": "# x\ty\tu\tv\tflags\tmask\n4.0406e-01\t3.3983e+00\t-5.2592e-03\t-5.9910e-02\t0.0000e+00\t0.0000e+00\n9.0137e-01\t3.3983e+00\t-9.6075e-"
},
{
"path": "openpiv/docs/Makefile",
"chars": 5567,
"preview": "# Makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS =\nSPHINXBUILD "
},
{
"path": "openpiv/docs/conf.py",
"chars": 8106,
"preview": "# -*- coding: utf-8 -*-\n#\n# OpenPIV documentation build configuration file, created by\n# sphinx-quickstart on Tue Feb 4"
},
{
"path": "openpiv/docs/index.rst",
"chars": 1285,
"preview": ".. OpenPIV documentation master file, created by\n sphinx-quickstart on Mon Apr 18 23:22:32 2011.\n You can adapt this"
},
{
"path": "openpiv/docs/make.bat",
"chars": 5098,
"preview": "@ECHO OFF\n\nREM Command file for Sphinx documentation\n\nif \"%SPHINXBUILD%\" == \"\" (\n\tset SPHINXBUILD=sphinx-build\n)\nset BUI"
},
{
"path": "openpiv/docs/src/api_reference.rst",
"chars": 1010,
"preview": ".. _api_reference:\n\nAPI reference\n=============\n\nThis is a complete api reference to the openpiv python module.\n\nThe ``o"
},
{
"path": "openpiv/docs/src/developers.rst",
"chars": 2874,
"preview": "Information for developers and contributors\n===========================================\n\nOpenPiv need developers to impr"
},
{
"path": "openpiv/docs/src/faq.rst",
"chars": 4030,
"preview": "Frequently Asked Questions about PIV parameters\n===============================================\n\n1. Can you please elabo"
},
{
"path": "openpiv/docs/src/generated/openpiv.filters._gaussian_kernel.rst",
"chars": 137,
"preview": "openpiv.filters._gaussian_kernel\n================================\n\n.. currentmodule:: openpiv.filters\n\n.. autofunction::"
},
{
"path": "openpiv/docs/src/generated/openpiv.filters.gaussian.rst",
"chars": 113,
"preview": "openpiv.filters.gaussian\n========================\n\n.. currentmodule:: openpiv.filters\n\n.. autofunction:: gaussian"
},
{
"path": "openpiv/docs/src/generated/openpiv.filters.replace_outliers.rst",
"chars": 137,
"preview": "openpiv.filters.replace_outliers\n================================\n\n.. currentmodule:: openpiv.filters\n\n.. autofunction::"
},
{
"path": "openpiv/docs/src/generated/openpiv.lib.replace_nans.rst",
"chars": 113,
"preview": "openpiv.lib.replace_nans\n========================\n\n.. currentmodule:: openpiv.lib\n\n.. autofunction:: replace_nans"
},
{
"path": "openpiv/docs/src/generated/openpiv.lib.sincinterp.rst",
"chars": 107,
"preview": "openpiv.lib.sincinterp\n======================\n\n.. currentmodule:: openpiv.lib\n\n.. autofunction:: sincinterp"
},
{
"path": "openpiv/docs/src/generated/openpiv.preprocess.dynamic_masking.rst",
"chars": 143,
"preview": "openpiv.preprocess.dynamic_masking\n==================================\n\n.. currentmodule:: openpiv.preprocess\n\n.. autofun"
},
{
"path": "openpiv/docs/src/generated/openpiv.process.CorrelationFunction.rst",
"chars": 379,
"preview": "openpiv.process.CorrelationFunction\n===================================\n\n.. currentmodule:: openpiv.process\n\n.. autoclas"
},
{
"path": "openpiv/docs/src/generated/openpiv.process.correlate_windows.rst",
"chars": 140,
"preview": "openpiv.process.correlate_windows\n=================================\n\n.. currentmodule:: openpiv.process\n\n.. autofunction"
},
{
"path": "openpiv/docs/src/generated/openpiv.process.extended_search_area_piv.rst",
"chars": 161,
"preview": "openpiv.process.extended_search_area_piv\n========================================\n\n.. currentmodule:: openpiv.process\n\n."
},
{
"path": "openpiv/docs/src/generated/openpiv.process.get_coordinates.rst",
"chars": 134,
"preview": "openpiv.process.get_coordinates\n===============================\n\n.. currentmodule:: openpiv.process\n\n.. autofunction:: g"
},
{
"path": "openpiv/docs/src/generated/openpiv.process.get_field_shape.rst",
"chars": 134,
"preview": "openpiv.process.get_field_shape\n===============================\n\n.. currentmodule:: openpiv.process\n\n.. autofunction:: g"
},
{
"path": "openpiv/docs/src/generated/openpiv.process.normalize_intensity.rst",
"chars": 146,
"preview": "openpiv.process.normalize_intensity\n===================================\n\n.. currentmodule:: openpiv.process\n\n.. autofunc"
},
{
"path": "openpiv/docs/src/generated/openpiv.pyprocess.correlate_windows.rst",
"chars": 146,
"preview": "openpiv.pyprocess.correlate_windows\n===================================\n\n.. currentmodule:: openpiv.pyprocess\n\n.. autofu"
},
{
"path": "openpiv/docs/src/generated/openpiv.pyprocess.find_first_peak.rst",
"chars": 140,
"preview": "openpiv.pyprocess.find_first_peak\n=================================\n\n.. currentmodule:: openpiv.pyprocess\n\n.. autofuncti"
},
{
"path": "openpiv/docs/src/generated/openpiv.pyprocess.find_second_peak.rst",
"chars": 143,
"preview": "openpiv.pyprocess.find_second_peak\n==================================\n\n.. currentmodule:: openpiv.pyprocess\n\n.. autofunc"
},
{
"path": "openpiv/docs/src/generated/openpiv.pyprocess.find_subpixel_peak_position.rst",
"chars": 176,
"preview": "openpiv.pyprocess.find_subpixel_peak_position\n=============================================\n\n.. currentmodule:: openpiv."
},
{
"path": "openpiv/docs/src/generated/openpiv.pyprocess.get_coordinates.rst",
"chars": 140,
"preview": "openpiv.pyprocess.get_coordinates\n=================================\n\n.. currentmodule:: openpiv.pyprocess\n\n.. autofuncti"
},
{
"path": "openpiv/docs/src/generated/openpiv.pyprocess.get_field_shape.rst",
"chars": 140,
"preview": "openpiv.pyprocess.get_field_shape\n=================================\n\n.. currentmodule:: openpiv.pyprocess\n\n.. autofuncti"
},
{
"path": "openpiv/docs/src/generated/openpiv.pyprocess.moving_window_array.rst",
"chars": 152,
"preview": "openpiv.pyprocess.moving_window_array\n=====================================\n\n.. currentmodule:: openpiv.pyprocess\n\n.. au"
},
{
"path": "openpiv/docs/src/generated/openpiv.pyprocess.normalize_intensity.rst",
"chars": 152,
"preview": "openpiv.pyprocess.normalize_intensity\n=====================================\n\n.. currentmodule:: openpiv.pyprocess\n\n.. au"
},
{
"path": "openpiv/docs/src/generated/openpiv.pyprocess.piv.rst",
"chars": 104,
"preview": "openpiv.pyprocess.piv\n=====================\n\n.. currentmodule:: openpiv.pyprocess\n\n.. autofunction:: piv"
},
{
"path": "openpiv/docs/src/generated/openpiv.scaling.uniform.rst",
"chars": 110,
"preview": "openpiv.scaling.uniform\n=======================\n\n.. currentmodule:: openpiv.scaling\n\n.. autofunction:: uniform"
},
{
"path": "openpiv/docs/src/generated/openpiv.tools.Multiprocesser.rst",
"chars": 286,
"preview": "openpiv.tools.Multiprocesser\n============================\n\n.. currentmodule:: openpiv.tools\n\n.. autoclass:: Multiprocess"
},
{
"path": "openpiv/docs/src/generated/openpiv.tools.display.rst",
"chars": 104,
"preview": "openpiv.tools.display\n=====================\n\n.. currentmodule:: openpiv.tools\n\n.. autofunction:: display"
},
{
"path": "openpiv/docs/src/generated/openpiv.tools.display_vector_field.rst",
"chars": 143,
"preview": "openpiv.tools.display_vector_field\n==================================\n\n.. currentmodule:: openpiv.tools\n\n.. autofunction"
},
{
"path": "openpiv/docs/src/generated/openpiv.tools.imread.rst",
"chars": 101,
"preview": "openpiv.tools.imread\n====================\n\n.. currentmodule:: openpiv.tools\n\n.. autofunction:: imread"
},
{
"path": "openpiv/docs/src/generated/openpiv.tools.save.rst",
"chars": 95,
"preview": "openpiv.tools.save\n==================\n\n.. currentmodule:: openpiv.tools\n\n.. autofunction:: save"
},
{
"path": "openpiv/docs/src/generated/openpiv.validation.global_std.rst",
"chars": 128,
"preview": "openpiv.validation.global_std\n=============================\n\n.. currentmodule:: openpiv.validation\n\n.. autofunction:: gl"
},
{
"path": "openpiv/docs/src/generated/openpiv.validation.global_val.rst",
"chars": 128,
"preview": "openpiv.validation.global_val\n=============================\n\n.. currentmodule:: openpiv.validation\n\n.. autofunction:: gl"
},
{
"path": "openpiv/docs/src/generated/openpiv.validation.local_median_val.rst",
"chars": 146,
"preview": "openpiv.validation.local_median_val\n===================================\n\n.. currentmodule:: openpiv.validation\n\n.. autof"
},
{
"path": "openpiv/docs/src/generated/openpiv.validation.sig2noise_val.rst",
"chars": 137,
"preview": "openpiv.validation.sig2noise_val\n================================\n\n.. currentmodule:: openpiv.validation\n\n.. autofunctio"
},
{
"path": "openpiv/docs/src/gui_doc.rst",
"chars": 167,
"preview": ".. _gui:\n\n====================================\nThe OpenPIV graphical user interface\n===================================="
},
{
"path": "openpiv/docs/src/installation_instruction.rst",
"chars": 2829,
"preview": ".. _installation_instruction:\n\n========================\nInstallation instruction\n========================\n\n.. _dependenc"
},
{
"path": "openpiv/docs/src/introduction.rst",
"chars": 26,
"preview": "Introduction\n============\n"
},
{
"path": "openpiv/docs/src/masking.ipynb",
"chars": 1480948,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# OpenPIV masking tutorial\\n\",\n "
},
{
"path": "openpiv/docs/src/modules.rst",
"chars": 58,
"preview": "openpiv\n=======\n\n.. toctree::\n :maxdepth: 4\n\n openpiv\n"
},
{
"path": "openpiv/docs/src/openpiv.rst",
"chars": 2231,
"preview": "openpiv package\n===============\n\nSubmodules\n----------\n\nopenpiv.PIV\\_3D\\_plotting module\n-------------------------------"
},
{
"path": "openpiv/docs/src/openpiv_pivuq.ipynb",
"chars": 1063209,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Tutorial on using OpenPIV with PI"
},
{
"path": "openpiv/docs/src/piv_basics.ipynb",
"chars": 363205,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Basics of the PIV algorithms\\n\",\n"
},
{
"path": "openpiv/docs/src/tutorial1.ipynb",
"chars": 671848,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# OpenPIV tutorial\\n\",\n \"\\n\",\n "
},
{
"path": "openpiv/docs/src/windef.ipynb",
"chars": 78120,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {\n \"scrolled\": true\n },\n \"source\": [\n \"# Multi-gr"
},
{
"path": "openpiv/filters.py",
"chars": 5903,
"preview": "\"\"\"The openpiv.filters module contains some filtering/smoothing routines.\"\"\"\nfrom typing import Tuple, Optional\nimport n"
},
{
"path": "openpiv/lib.py",
"chars": 6313,
"preview": "import numpy as np\n\n\ndef replace_nans(array, max_iter, tol, kernel_size=2, method=\"disk\"):\n \"\"\"Replace NaN elements i"
},
{
"path": "openpiv/phase_separation.py",
"chars": 15398,
"preview": "\"\"\"A module for separating solid phase from liquid tracers using image processing techniques.\"\"\"\n\n__licence__ = \"\"\"\nCopy"
},
{
"path": "openpiv/piv.py",
"chars": 9528,
"preview": "import numpy as np\nimport matplotlib.pyplot as plt\n\nfrom openpiv import pyprocess, tools, validation, filters\nfrom impor"
},
{
"path": "openpiv/preprocess.py",
"chars": 15915,
"preview": "\"\"\"This module contains image processing routines that improve\nimages prior to PIV processing.\"\"\"\n\nimport numpy as np\nfr"
},
{
"path": "openpiv/preprocess.py,cover",
"chars": 17073,
"preview": "> \"\"\"This module contains image processing routines that improve\n> images prior to PIV processing.\"\"\"\n \n> import numpy "
},
{
"path": "openpiv/pyprocess.py",
"chars": 44767,
"preview": "\"\"\"This module contains a pure python implementation of the basic\ncross-correlation algorithm for PIV image processing.\""
},
{
"path": "openpiv/pyprocess3D.py",
"chars": 23276,
"preview": "import numpy.lib.stride_tricks\nimport numpy as np\nfrom scipy.fft import rfftn, irfftn\nfrom numpy import ma\nfrom tqdm imp"
},
{
"path": "openpiv/scaling.py",
"chars": 1252,
"preview": "#!/usr/bin/env python\n\"\"\"Scaling utilities\n\"\"\"\n\n__licence__ = \"\"\"\nCopyright (C) 2011 www.openpiv.net\n\nThis program is f"
},
{
"path": "openpiv/settings.py",
"chars": 6173,
"preview": "\nimport pathlib\nfrom dataclasses import dataclass\nfrom importlib.resources import files\nfrom typing import Optional, Tup"
},
{
"path": "openpiv/smoothn.py",
"chars": 24636,
"preview": "import numpy as np\nimport numpy.ma as ma\nfrom scipy.fftpack import dct, idct\nfrom scipy.optimize import fmin_l_bfgs_b\n\n\n"
},
{
"path": "openpiv/test/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "openpiv/test/conftest.py",
"chars": 1827,
"preview": "import pytest\nimport matplotlib\nimport matplotlib.pyplot as plt\nfrom unittest.mock import patch\nimport traceback\n\n# Set "
},
{
"path": "openpiv/test/extended_search_area_vectorized.ipynb",
"chars": 456007,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n "
},
{
"path": "openpiv/test/test_PIV_3D_plotting.py",
"chars": 5934,
"preview": "\"\"\"Test module for PIV_3D_plotting.py\"\"\"\n\nimport os\nimport numpy as np\nimport pytest\nimport matplotlib\n\nmatplotlib.use(\""
},
{
"path": "openpiv/test/test_filters.ipynb",
"chars": 10738,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Test filters on masked arrays\"\n "
},
{
"path": "openpiv/test/test_filters.py",
"chars": 5396,
"preview": "from openpiv import filters\nfrom openpiv.lib import replace_nans\nimport numpy as np\nimport pytest\n\n\ndef test_gaussian_ke"
},
{
"path": "openpiv/test/test_find_peaks.ipynb",
"chars": 17929,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n "
},
{
"path": "openpiv/test/test_lib.py",
"chars": 7775,
"preview": "import numpy as np\nimport pytest\nfrom openpiv.lib import replace_nans, get_dist\n\n\ndef test_replace_nans_2d():\n \"\"\"Tes"
},
{
"path": "openpiv/test/test_package_metadata.py",
"chars": 155,
"preview": "from importlib.metadata import version\n\nimport openpiv\n\n\ndef test_package_version_matches_metadata():\n assert openpiv"
},
{
"path": "openpiv/test/test_performance.py",
"chars": 5544,
"preview": "\"\"\"Performance tests to verify optimizations.\"\"\"\nimport numpy as np\nimport pytest\nimport time\nfrom openpiv import pyproc"
},
{
"path": "openpiv/test/test_piv.py",
"chars": 13960,
"preview": "\"\"\"Tests for the piv module\"\"\"\nimport numpy as np\nimport pytest\nfrom importlib.resources import files\nfrom openpiv impor"
},
{
"path": "openpiv/test/test_preprocess.py",
"chars": 17143,
"preview": "\"\"\" Test preprocess \"\"\"\nimport os\nimport numpy as np\nimport pytest\nfrom skimage import img_as_float\nfrom skimage.color i"
},
{
"path": "openpiv/test/test_process.ipynb",
"chars": 4237,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n "
},
{
"path": "openpiv/test/test_process.py",
"chars": 7540,
"preview": "\"\"\" Testing basic PIV processes \"\"\"\nimport numpy as np\nimport pytest\nfrom skimage.util import random_noise\nfrom skimage "
},
{
"path": "openpiv/test/test_pyprocess.py",
"chars": 16036,
"preview": "import numpy as np\nimport pytest\nfrom openpiv.pyprocess import get_field_shape, get_coordinates, get_rect_coordinates\nfr"
},
{
"path": "openpiv/test/test_pyprocess3D.py",
"chars": 1590,
"preview": "from openpiv.pyprocess3D import extended_search_area_piv3D\nimport numpy as np\n\nfrom skimage.util import random_noise\nfro"
},
{
"path": "openpiv/test/test_scaling.py",
"chars": 0,
"preview": ""
},
{
"path": "openpiv/test/test_smoothn.py",
"chars": 20549,
"preview": "\"\"\"Test module for smoothn.py\"\"\"\n\nimport numpy as np\nimport numpy.ma as ma\nimport pytest\nfrom scipy.fftpack import dct, "
},
{
"path": "openpiv/test/test_tools.ipynb",
"chars": 9287,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {\n \"tags\": []\n },\n \"outputs\": ["
},
{
"path": "openpiv/test/test_tools.py",
"chars": 7390,
"preview": "\"\"\" tests windef functionality \"\"\"\nimport pathlib\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pytest\nfrom "
},
{
"path": "openpiv/test/test_tools_background.py",
"chars": 6777,
"preview": "\"\"\"Tests for background processing functions in tools.py\"\"\"\nimport os\nimport tempfile\nimport numpy as np\nimport pytest\nf"
},
{
"path": "openpiv/test/test_tools_basic_utils.py",
"chars": 3671,
"preview": "\"\"\"Tests for basic utility functions in tools.py\"\"\"\nimport pathlib\nimport numpy as np\nimport pytest\nfrom openpiv.tools i"
},
{
"path": "openpiv/test/test_tools_image_processing.py",
"chars": 7160,
"preview": "\"\"\"Tests for image processing functions in tools.py\"\"\"\nimport os\nimport tempfile\nimport numpy as np\nimport pytest\nfrom P"
},
{
"path": "openpiv/test/test_tools_multiprocessing.py",
"chars": 7093,
"preview": "\"\"\"Tests for multiprocessing functions in tools.py\"\"\"\nimport os\nimport tempfile\nimport pathlib\nimport numpy as np\nimport"
},
{
"path": "openpiv/test/test_tools_vector_field.py",
"chars": 7662,
"preview": "\"\"\"Tests for vector field operations in tools.py\"\"\"\nimport os\nimport tempfile\nimport numpy as np\nimport matplotlib.pyplo"
},
{
"path": "openpiv/test/test_validation.ipynb",
"chars": 33008,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n "
},
{
"path": "openpiv/test/test_validation.py",
"chars": 11413,
"preview": "\"\"\" Testing validation functions \"\"\"\nfrom typing import Tuple\nimport numpy as np\nfrom importlib.resources import files\ni"
},
{
"path": "openpiv/test/test_vectorized_extended_search.py",
"chars": 2555,
"preview": "import numpy as np\nimport matplotlib.pyplot as plt\n\nfrom scipy.fft import rfft2, irfft2\nfrom scipy.ndimage import shift "
},
{
"path": "openpiv/test/test_windef.ipynb",
"chars": 968752,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 16,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n"
},
{
"path": "openpiv/test/test_windef.py",
"chars": 9728,
"preview": "\"\"\"\nCreated on Fri Oct 4 14:33:21 2019\n\n@author: Theo\n\"\"\"\n\nimport pytest\nimport pathlib\nimport numpy as np\nimport warni"
},
{
"path": "openpiv/test/test_windef_coverage.py",
"chars": 7358,
"preview": "\"\"\"\nTests specifically designed to achieve 100% coverage of windef.py\n\"\"\"\n\nimport pytest\nimport numpy as np\nimport matpl"
},
{
"path": "openpiv/test/test_windef_detailed.py",
"chars": 29110,
"preview": "\"\"\"\nDetailed tests for the windef.py module with focus on edge cases and small units.\n\"\"\"\n\nimport pytest\nimport numpy as"
},
{
"path": "openpiv/test/test_windef_final.py",
"chars": 2267,
"preview": "\"\"\"\nFinal tests to achieve 100% coverage of windef.py\n\"\"\"\n\nimport pytest\nimport numpy as np\nimport matplotlib.pyplot as "
},
{
"path": "openpiv/tools.py",
"chars": 26192,
"preview": "\"\"\"The openpiv.tools module is a collection of utilities and tools.\n\"\"\"\n\n__licence__ = \"\"\"\nCopyright (C) 2011 www.openp"
},
{
"path": "openpiv/tutorials/Example for overlap setting change.ipynb",
"chars": 3986936,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"fd7cda0f-13b2-4ac0-8780-11d4e0ae71b8\",\n "
},
{
"path": "openpiv/tutorials/masking_tutorial.py",
"chars": 4121,
"preview": "import pathlib\nfrom importlib.resources import files\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom openpiv imp"
},
{
"path": "openpiv/tutorials/tutorial1.py",
"chars": 1350,
"preview": "from importlib.resources import files\nimport numpy as np\nfrom openpiv import tools, pyprocess, scaling, validation, filt"
},
{
"path": "openpiv/tutorials/tutorial2.py",
"chars": 1409,
"preview": "\"\"\" Tutorial of using window deformation multi-pass \"\"\"\nfrom importlib.resources import files\nfrom openpiv import tools,"
},
{
"path": "openpiv/tutorials/windef_tutorial.py",
"chars": 4934,
"preview": "from importlib.resources import files\nfrom openpiv import windef\n\n\n\nsettings = windef.PIVSettings()\nprint(settings)\n\n# '"
},
{
"path": "openpiv/validation.py",
"chars": 17962,
"preview": "\"\"\"A module for spurious vector detection.\"\"\"\n\n__licence__ = \"\"\"\nCopyright (C) 2011 www.openpiv.net\n\nThis program is fr"
},
{
"path": "openpiv/windef.py",
"chars": 29427,
"preview": "\"\"\"\nCreated on Fri Oct 4 14:04:04 2019\n\n@author: Theo\n@modified: Alex, Erich\n\"\"\"\n\nimport pathlib\nfrom typing import Opt"
},
{
"path": "poetry.toml",
"chars": 56,
"preview": "[virtualenvs]\nin-project = true\npath = \".\"\ncreate = true"
},
{
"path": "pyproject.toml",
"chars": 1782,
"preview": "[tool.poetry]\nname = \"OpenPIV\"\nversion = \"0.25.4\"\ndescription = \"OpenPIV consists in a Python and Cython modules for scr"
},
{
"path": "recipe/meta.yaml",
"chars": 684,
"preview": "{% set data = load_setup_py_data(setup_file=\"../setup.py\",\n from_recipe_dir=True) %}\n\npackage:\n name: openpiv\n versio"
},
{
"path": "setup.py",
"chars": 1991,
"preview": "from os import path\nfrom setuptools import setup, find_packages\n\n\n# read the contents of your README file\nthis_directory"
},
{
"path": "synimage/Synthetic_Image_Generator_examples.ipynb",
"chars": 669330,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Synthetic Image Generation examp"
},
{
"path": "synimage/simple_synthetic_image_demo.ipynb",
"chars": 188164,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 131,\n \"metadata\": {},\n \"outputs\": [\n {\n \"data"
},
{
"path": "synimage/synimagegen.py",
"chars": 12167,
"preview": "\"\"\"This module contains a pure python implementation of the basic\ncross-correlation algorithm for PIV image processing.\""
},
{
"path": "synimage/test_synimagegen.py.bck",
"chars": 3265,
"preview": "import unittest\nimport numpy as np\nfrom synimagegen import generate_particle_image\n\nclass TestGenerateParticleImage(unit"
}
]
// ... and 47 more files (download for full content)
About this extraction
This page contains the full source code of the OpenPIV/openpiv-python GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 174 files (10.1 MB), approximately 2.6M tokens, and a symbol index with 345 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.