Communitygithub.com

openpiv

OpenPIV를 사용한 입자영상유속계(PIV) 분석. PIV 이미지 쌍에서 속도장을 추출하거나, 유체 역학 또는 흐름 가시화 실험을 분석하고, 관측 윈도우를 상호 상관시키며, 잘못된 PIV 벡터를 검증 및 대체하거나, 측정된 속도장으로부터 와도, 변형률 및 난류 통계량을 계산할 때 사용합니다.

openpiv란 무엇인가요?

OpenPIV(Open Particle Image Velocimetry) 스킬은 PIV 이미지 쌍으로부터 유체 흐름을 분석하는 오픈소스 Python 도구입니다. 이 스킬은 전처리, 상호 상관, 벡터 검증, 이상치 대체, 평활화 및 물리적 단위로의 스케일링을 포함한 전체 PIV 분석 파이프라인을 지원합니다. 개발자는 이 스킬을 사용하여 2D 속도장을 측정하고, 관측 윈도우 매개변수(윈도우 크기, 중첩, 검색 영역 크기)를 조정하며, 신호 대 잡음비 기반 벡터 검증을 수행하고, 와도, 변형률 및 난류 통계량을 계산할 수 있습니다. 이 스킬은 openpiv 0.25.4 버전에 대해 검증되었으며, CLI 기반 러너 스크립트를 제공하여 빠른 실험 재현성을 지원합니다. 다중 패스 처리(윈도우 변형)를 위한 `openpiv.windef` 모듈과 동적 마스킹을 위한 `openpiv.preprocess` 모듈도 포함되어 있어 복잡한 실험 설정을 유연하게 처리할 수 있습니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/K-Dense-AI/scientific-agent-skills/tree/main/skills/openpiv

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

openpiv은(는) 무엇을 하나요?

개요

OpenPIV(Open Particle Image Velocimetry)는 PIV 이미지 쌍으로부터 유체 흐름을 분석합니다. 전처리, 상호 상관, 벡터 검증, 이상값 대체, 평활화 및 물리적 단위로의 스케일링을 다룹니다.

아래의 모든 내용은 openpiv 0.25.4에서 검증되었습니다. API는 릴리스 간에 변경됩니다 — 다른 버전의 스니펫을 신뢰하기 전에 inspect.signature()를 확인하세요.

사용 시기

실험적인 PIV 또는 유동 가시화 이미지 쌍(2D 속도장 측정, 조사창 매개변수 조정, 벡터 검증, 또는 와도, 변형률, 난류 통계량 도출)을 다룰 때 이 스킬을 사용하세요. 흐름을 측정하는 대신 시뮬레이션하려면 CFD 스킬을 대신 사용하세요.

빠른 시작

OpenPIV 설치:

uv pip install openpiv

# 분석을 재현 가능하게 해야 할 때 고정 — 아래의 모든 스니펫이 검증된 버전입니다.
uv pip install "openpiv==0.25.4"

이미지 쌍에서 PIV 분석 실행:

import numpy as np
from openpiv import tools, pyprocess, validation, filters, scaling

frame_a = tools.imread("image_a.bmp")
frame_b = tools.imread("image_b.bmp")

# 상호 상관. sig2noise_method가 None이 아닐 때마다 (u, v, s2n)을 반환합니다.
u, v, s2n = pyprocess.extended_search_area_piv(
    frame_a.astype(np.int32),
    frame_b.astype(np.int32),
    window_size=32,
    overlap=12,
    dt=0.02,
    search_area_size=38,
    correlation_method="linear",   # search_area_size > window_size인 경우 필수
    sig2noise_method="peak2peak",
)

x, y = pyprocess.get_coordinates(
    image_size=frame_a.shape,
    search_area_size=38,
    overlap=12,
)

# flags는 부울 배열입니다. True는 잘못된 벡터를 표시합니다.
flags = validation.sig2noise_val(s2n, threshold=1.05)
u, v = filters.replace_outliers(u, v, flags, method="localmean", max_iter=3, kernel_size=2)

# 물리적 단위로 스케일링한 후 플롯을 위해 이미지 좌표로 뒤집습니다.
x, y, u, v = scaling.uniform(x, y, u, v, scaling_factor=96.52)
x, y, u, v = tools.transform_coordinates(x, y, u, v)

tools.save("vectors.txt", x, y, u, v, flags)

또는 정확히 그 파이프라인을 래핑하는 번들 CLI를 사용하세요:

python skills/openpiv/scripts/runner.py \
    --image frame_a.bmp --image frame_b.bmp --output_dir results --verbose

핵심 개념

PIV 기초

PIV(입자 이미지 유속계)는 조명된 추적 입자 사이의 두 이미지 사이에서 유체 속도를 측정하는 광학 방법입니다.

프로세스 흐름:

  1. 알려진 시간 간격 dt로 분리된 이미지 쌍(frame_a, frame_b)을 캡처합니다.
  2. 이미지를 조사창으로 나눕니다.
  3. 일치하는 창을 상호 상관시켜 최대 변위 피크를 찾습니다.
  4. 벡터를 검증합니다(신호 대 잡음비, 전역 범위, 국소 중앙값).
  5. 잘못된 벡터를 보간된 값으로 대체합니다.
  6. 픽셀 변위를 물리적 단위로 스케일링합니다.

조사창 매개변수

window_size — 픽셀 단위의 상관 창(일반적으로 16–128). 더 큰 창은 더 나은 상관 관계를 제공하지만 공간 해상도는 낮아집니다.

overlap — 인접한 창 사이에 공유되는 픽셀(일반적으로 window_size의 50–75%). 더 높은 중첩은 벡터 밀도와 비용을 높이지만 인접한 벡터는 독립적이지 않고 상관 관계가 됩니다.

search_area_size — 두 번째 프레임에서 검색되는 창 크기. window_size 이상이어야 하며, 더 큰 변위를 수용하기 위해 몇 픽셀 더 큰 것이 좋습니다. 확장된 검색 영역을 correlation_method="linear"와 함께 사용하세요. 기본값인 "circular"는 FFT 래핑에 의존하며 큰 변위를 작은 변위로 앨리어싱합니다. references/advanced_algorithms.md를 참조하세요.

경험 법칙: 가장 큰 변위를 window_size의 약 1/4 미만으로 유지하고 창당 5–10개의 입자를 목표로 하세요.

신호 대 잡음비

s2n은 상관 피크가 얼마나 뚜렷한지 측정합니다. sig2noise_method는 계산 방식을 제어합니다 — "peak2mean"(함수 기본값) 또는 "peak2peak". 두 방식은 서로 다른 스케일을 가지므로, 하나에 맞춰 조정된 임계값은 다른 방식에 대해 의미가 없습니다. 일반적인 peak2peak 임계값은 1.05–1.3입니다.

flags = validation.sig2noise_val(s2n, threshold=1.05)
# flags는 bool: True == 잘못된 값. `~flags`는 좋은 벡터를 선택합니다.

일반 작업

동적 마스킹

마스킹은 openpiv.preprocess에 있으며, openpiv.masking 모듈에 없습니다. (image, mask) 튜플을 반환하며 float 이미지를 입력으로 기대합니다.

from openpiv import preprocess

# method="edges"는 어둡고 날카로운 가장자리의 객체용; "intensity"는 고대비 객체용.
frame_a_masked, mask_a = preprocess.dynamic_masking(
    frame_a.astype(np.float64), method="intensity", filter_size=7, threshold=0.005
)
frame_b_masked, mask_b = preprocess.dynamic_masking(
    frame_b.astype(np.float64), method="intensity", filter_size=7, threshold=0.005
)

반환된 이미지를 상관 단계에 입력하세요. 이미 마스킹된 영역이 0으로 설정되어 있습니다. 원본 프레임에 mask를 곱하지 마세요. 마스킹은 이미 적용되었으며, method="edges"의 경우 마스크는 부울이 아닌 uint8 0/255로 반환되므로 곱하면 이미지가 255로 재조정됩니다.

다중 패스 처리

다중 패스(창 변형)는 PIVSettings 데이터클래스에 의해 구동되는 openpiv.windef에 있습니다. pyprocess에는 다중 패스 진입점이 없습니다.

import numpy as np
from openpiv import scaling, windef

settings = windef.PIVSettings()
settings.windowsizes = (64, 32, 16)   # 패스당 하나씩 감소(이것이 기본값이기도 함)
settings.overlap = (32, 16, 8)        # windowsizes와 동일한 길이
settings.num_iterations = 3           # 실제로 실행할 패스 수
settings.sig2noise_threshold = 1.05

x, y, u, v, flags = windef.simple_multipass(
    frame_a.astype(np.int32), frame_b.astype(np.int32), settings
)

# 출력은 프레임당 픽셀 단위입니다. 직접 변환하세요. scaling.uniform은
# scaling_factor로 나누기만 하므로 dt를 별도로 적용하세요.
dt = 0.02
x, y, u, v = scaling.uniform(x, y, u, v, scaling_factor=96.52)
u, v = u / dt, v / dt

simple_multipass는 이미 검증, 이상값 대체, 남은 NaN을 0으로 채우기, transform_coordinates 호출을 수행합니다. 이러한 단계를 반복하지 마세요.

단위 함정: PIVSettings에는 dt와 scaling_factor 필드가 있지만 windef는 둘 다 사용하지 않습니다. first_pass는 dt 없이 extended_search_area_piv를 호출하므로 전체 다중 패스 체인은 프레임당 픽셀 단위로 작동합니다. settings.dt = 0.02로 설정해도 반환된 값에는 아무런 변화가 없습니다. 위와 같이 사후에 변환하세요.

개별 패스를 제어하려면 windef.first_pass와 windef.multipass_img_deform이 더 낮은 수준의 구성 요소입니다.

검증 및 후처리

검증 방법

모든 검증 함수는 True가 잘못된 벡터를 표시하는 부울 배열을 반환합니다.

# 신호 대 잡음비
flags = validation.sig2noise_val(s2n, threshold=1.05)

# 전역 범위 — (min, max) 튜플을 위치 기반 또는 u_thresholds/v_thresholds로 받습니다.
flags = validation.global_val(u, v, (-300, 300), (-300, 300))

# 국소 중앙값 — u_threshold와 v_threshold는 필수; size는 이웃 반경입니다.
flags = validation.local_median_val(u, v, u_threshold=30.0, v_threshold=30.0, size=1)

# 부울 OR로 결합합니다(np.maximum이 아닙니다. 이들은 부울 배열입니다).
flags = (
    validation.sig2noise_val(s2n, threshold=1.05)
    | validation.global_val(u, v, (-300, 300), (-300, 300))
    | validation.local_median_val(u, v, u_threshold=30.0, v_threshold=30.0)
)

이러한 임계값을 u와 v의 단위(프레임당 픽셀 아님)로 설정하세요. extended_search_area_piv는 dt로 나누므로 dt=0.02인 경우 3px/프레임 변위는 150px/s가 됩니다. 위의 임계값은 해당 경우에 적합합니다. PIV 문헌과 PIVSettings.min_max_u_disp에서 사용하는 (-30, 30) 값은 px/프레임 제한이며, 이를 px/s 출력에 적용하면 전체 필드가 거부됩니다. 스케일링 전에 검증하거나 임계값도 1/dt로 스케일링하세요.

이상값 대체

u, v = filters.replace_outliers(
    u, v, flags, method="localmean", max_iter=3, tol=1e-3, kernel_size=2
)

method는 "localmean", "disk", "distance" — 이 세 가지만 허용합니다. 인식되지 않는 이름은 거부되지 않습니다. 모든 커널이 0인 상태로 대체되어 조용히 쓸모없는 필드를 반환합니다. 대체는 플래그가 지정된 위치를 보간된 값으로 채운다는 점에 유의하세요. 이후에 NaN으로 덮어쓰면 대체가 낭비됩니다. 둘 중 하나를 선택하세요:

# 보간하는 대신 플래그가 지정된 벡터를 분석에서 완전히 제외합니다.
u = np.where(flags, np.nan, u)
v = np.where(flags, np.nan, v)

평활화

평활화는 openpiv.smoothn.smoothn이며, openpiv.smooth 모듈은 없습니다. 첫 번째 요소가 평활화된 필드인 튜플을 반환하며 NaN 입력을 허용하지 않습니다.

from openpiv.smoothn import smoothn

u_smooth, *_ = smoothn(np.nan_to_num(u), s=0.5)  # s: 클수록 더 부드러움
v_smooth, *_ = smoothn(np.nan_to_num(v), s=0.5)
u_smooth = np.asarray(u_smooth)

시각화

벡터장 플로팅

display_vector_field는 저장된 벡터 파일을 읽고 내부적으로 plt.show()를 호출하므로 배치 실행을 위해 비대화형 백엔드를 선택하세요.

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from openpiv import tools

fig, ax = plt.subplots(figsize=(8, 8))
tools.display_vector_field(
    "vectors.txt",
    ax=ax,
    scaling_factor=96.52,   # 이미지에 다시 매핑하기 위해 scaling.uniform에 사용된 것과 동일한 계수
    scale=50,
    width=0.0035,
    on_img=True,
    image_name="frame_a.bmp",
)
fig.savefig("vector_field.png", dpi=150, bbox_inches="tight")
plt.close(fig)

맞춤 시각화

import numpy as np
import matplotlib.pyplot as plt

fig, axes = plt.subplots(1, 3, figsize=(15, 5))

mag = np.sqrt(u**2 + v**2)
for ax, field, title, cmap in [
    (axes[0], mag, "Velocity Magnitude", "viridis"),
    (axes[1], u, "U Velocity", "RdBu_r"),
    (axes[2], v, "V Velocity", "RdBu_r"),
]:
    im = ax.imshow(field, cmap=cmap)
    ax.set_title(title)
    plt.colorbar(im, ax=ax)

fig.tight_layout()
fig.savefig("velocity_components.png")
plt.close(fig)

분석 함수

scripts/analyze.py는 runner.py가 작성한 params.npz에 대해 이러한 기능을 번들로 제공합니다. 저장된 좌표에서 물리적 그리드 간격을 추론하므로 도함수는 단위 길이당 계산됩니다:

import sys
sys.path.insert(0, "skills/openpiv/scripts")
from analyze import PIVAnalyzer

piv = PIVAnalyzer("results/params.npz")
vorticity = piv.compute_vorticity()          # dv/dx - du/dy
exx, eyy, exy = piv.compute_strain()
stats = piv.compute_statistics()             # u_mean, v_mean, rms_u, rms_v, tke
piv.plot_vector_field(save_path="quiver.png")

인라인으로 계산하려는 경우의 독립형 형식:

와도

def compute_vorticity(u, v, dx=1.0, dy=None):
    """면외 와도 dv/dx - du/dy. 1.0이 아닌 물리적 그리드 간격을 전달하세요."""
    dy = dx if dy is None else dy
    return np.gradient(v, dx, axis=1) - np.gradient(u, dy, axis=0)

그리드 간격은 물리적 단위로 (window_size - overlap) / scaling_factor이므로 dx=1.0으로 두면 단위 길이가 아닌 그리드 셀당 와도가 생성됩니다.

부호 규칙: runner.py는 transform_coordinates로 끝나며, 그리드를 오른손 법칙 y-상향 프레임으로 다시 레이블링하지만 행을 이미지 순서로 남겨 두므로 저장된 y는 행 인덱스가 증가함에 따라 감소합니다. 위의 독립형 형식은 반대를 가정하므로 params.npz 필드에서 -du/dy를 반환하고 와도와 전단 변형률의 부호를 뒤집습니다. axis=0 도함수를 부정하거나 저장된 좌표에서 방향을 읽는 PIVAnalyzer를 사용하세요.

변형률

def compute_strain(u, v, dx=1.0, dy=None):
    """2D 변형률 텐서의 (exx, eyy, exy)를 반환합니다."""
    dy = dx if dy is None else dy
    du_dx = np.gradient(u, dx, axis=1)
    du_dy = np.gradient(u, dy, axis=0)
    dv_dx = np.gradient(v, dx, axis=1)
    dv_dy = np.gradient(v, dy, axis=0)
    return du_dx, dv_dy, 0.5 * (du_dy + dv_dx)

난류 통계

def compute_statistics(u, v):
    """단일 프레임 공간 통계. 레이놀즈 분해가 아닙니다."""
    u_prime = u - np.nanmean(u)
    v_prime = v - np.nanmean(v)
    rms_u, rms_v = np.nanstd(u_prime), np.nanstd(v_prime)
    return {
        "u_mean": np.nanmean(u),
        "v_mean": np.nanmean(v),
        "rms_u": rms_u,
        "rms_v": rms_v,
        "tke": 0.5 * (rms_u**2 + rms_v**2),
    }

주의 사항: 한 프레임의 공간적 평균을 빼면 공간적 분산이 측정되며, 이는 균질한 필드에 대해서만 난류 강도와 같습니다. 진정한 레이놀즈 분해는 이미지 쌍의 앙상블이 필요합니다. 시간 축에 대해 평균을 낸 다음 각 실현에서 해당 평균 필드를 뺍니다.

CLI 사용법

# 기본 실행
python skills/openpiv/scripts/runner.py \
    --image img1.bmp --image img2.bmp --output_dir results --verbose

# 동적 마스킹을 사용한 튜닝된 매개변수
python skills/openpiv/scripts/runner.py \
    --image frame_a.bmp \
    --image frame_b.bmp \
    --output_dir results \
    --window_size 32 \
    --overlap 12 \
    --search_area 38 \
    --dt 0.02 \
    --scaling 96.52 \
    --threshold 1.05 \
    --mask dynamic \
    --mask_method intensity \
    --verbose

CLI 옵션

옵션기본값설명
--image필수이미지 파일; 쌍을 위해 정확히 두 번 지정
--output_dirresults출력 디렉터리(없으면 생성)
--window_size32조사창 크기(픽셀)
--overlap12창 중첩(픽셀)
--search_area38검색 영역 크기(픽셀), --window_size 이상이어야 함
--dt0.02프레임 간 시간(초)
--scaling96.52스케일링 계수, 물리적 단위당 픽셀 수(예: px/mm)
--threshold1.05peak2peak 신호 대 잡음비 임계값
--masknonenone 또는 dynamic (openpiv.preprocess.dynamic_masking)
--mask_methodintensityedges 또는 intensity, 사용 시

... (이하 생략)

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

adaptyv

How to use the Adaptyv Bio Foundry API and Python SDK for protein experiment design, submission, and results retrieval. Use this skill whenever the user mentions Adaptyv, Foundry API, protein binding assays, protein screening experiments, BLI/SPR assays, thermostability assays, or wants to submit protein sequences for experimental characterization. Also trigger when code imports `adaptyv`, `adaptyv_sdk`, or `FoundryClient`, or references `foundry-api-public.adaptyvbio.com`.

aeon

This skill should be used for time series machine learning tasks including classification, regression, clustering, forecasting, anomaly detection, segmentation, and similarity search. Use when working with temporal data, sequential patterns, or time-indexed observations requiring specialized algorithms beyond standard ML approaches. Particularly suited for univariate and multivariate time series analysis with scikit-learn compatible APIs.

alphagenome

Look up precomputed AlphaGenome Atlas effects for any GRCh38 single-nucleotide variant (AVI score with Phred and 18 SHAP feature attributions, plus raw and quantile scores for RNA-seq, DNase, ATAC, ChIP-TF, ChIP-histone, CAGE, PRO-cap, splicing, polyadenylation and contact-map tracks), score variants or scan windows on demand with the AlphaGenome model for human and mouse (variant scoring, in silico mutagenesis, REF-versus-ALT track prediction), and build Atlas website deep links. Use when the user mentions AlphaGenome, AlphaGenome Atlas, AVI or AlphaGenome Variant Impact, DeepMind variant effect prediction, or wants to prioritise or mechanistically interpret non-coding, regulatory, splicing, enhancer, promoter, or chromatin-accessibility effects of SNVs from a VCF, credible set, or region. Research use only; not a clinical tool.

analytical-method-validation

Plan, execute, and document validation, verification, and transfer of analytical procedures under the governing framework - ICH Q2(R2) and Q14, USP <1220>/<1225>/<1226>, ICH M10 bioanalytical, CLSI EP, or ISO/IEC 17025. Use for HPLC, LC-MS/MS, GC, CE, ICP-MS, dissolution, qNMR, qPCR, NIR, and ligand binding or cell-based assays whenever the question is whether a procedure is fit for its intended purpose. Triggers include

anndata

Data structure for annotated matrices in single-cell analysis. Use when working with .h5ad files or integrating with the scverse ecosystem. This is the data format skill—for analysis workflows use scanpy; for probabilistic models use scvi-tools; for population-scale queries use cellxgene-census.

arbor

Autonomously improve a real artifact (code, training recipe, agent harness, data pipeline, prompt) against an objective and an evaluator, using Hypothesis Tree Refinement (HTR) from the Arbor paper. Use this whenever someone wants to iteratively optimize something over many experiments without overfitting — e.g.

arboreto

Infer gene regulatory networks (GRNs) from gene expression data using scalable algorithms (GRNBoost2, GENIE3). Use when analyzing transcriptomics data (bulk RNA-seq, single-cell RNA-seq) to identify transcription factor-target gene relationships and regulatory interactions. Supports distributed computation for large-scale datasets.

astropy

Core Python library for astronomy and astrophysics workflows that need Astropy APIs, including units/quantities, coordinates, FITS I/O, tables, time systems, WCS, and cosmology. Use when implementing or debugging astronomical data analysis code with Astropy.

autoskill

Observe the user

benchling-integration

Benchling Python SDK and REST API integration for registry entities, inventory, ELN entries, workflows, Benchling Apps, and Data Warehouse queries. Use when automating lab data with benchling-sdk or the v2 API.

bgpt-paper-search

Search scientific papers and retrieve structured experimental data extracted from full-text studies via the BGPT MCP server. Returns 25+ fields per paper including methods, results, sample sizes, quality scores, and conclusions. Use for literature reviews, evidence synthesis, and finding experimental details not available in abstracts alone.

bids

>

biopython

Comprehensive molecular biology toolkit. Use for sequence manipulation, file parsing (FASTA/GenBank/PDB), phylogenetics, and programmatic NCBI/PubMed access (Bio.Entrez). Best for batch processing, custom bioinformatics pipelines, BLAST automation. For quick lookups use gget; for multi-service integration use bioservices.

bioservices

Unified Python interface to 40+ bioinformatics services. Use when querying multiple databases (UniProt, KEGG, ChEMBL, Reactome) in a single workflow with consistent API. Best for cross-database analysis, ID mapping across services. For quick single-database lookups use gget; for sequence/file manipulation use biopython.

bulk-rnaseq

End-to-end bulk RNA-seq orchestrator — takes raw FASTQ reads through QC and trimming (FastQC, fastp/Trim Galore), alignment and quantification (STAR, Salmon, featureCounts), assembles a gene-level counts matrix, then hands off to differential expression (pydeseq2), pathway/GSEA enrichment (pathway-enrichment), and publication figures (scientific-visualization). Use whenever the user has bulk RNA-seq reads or quant output and wants a complete, reproducible differential-expression workflow — e.g.

cellxgene-census

Query the CZ CELLxGENE Census programmatically for versioned public single-cell and spatial transcriptomics data. Use when you need population-scale cell metadata, gene expression slices, Census summary counts, source H5AD URIs/downloads, embeddings, spatial Census data, or reference atlas comparisons across organisms, tissues, diseases, assays, and cell types. For analyzing your own local single-cell data use scanpy, anndata, or scvi-tools.

cirq

Google quantum computing framework. Use when targeting Google Quantum AI hardware, designing noise-aware circuits, or running quantum characterization experiments. Best for Google hardware, noise modeling, and low-level circuit design. For IBM hardware use qiskit; for quantum ML with autodiff use pennylane; for physics simulations use qutip.

citation-management

Comprehensive citation management for academic research. Search OpenAlex, PubMed, and Google Scholar for papers, extract accurate metadata, validate citations, and generate properly formatted BibTeX entries. This skill should be used when you need to find papers, verify citation information, convert DOIs to BibTeX, or ensure reference accuracy in scientific writing.

clinical-decision-support

Prepare and validate research-only clinical decision-support evaluation, evidence-profile, cohort, survival, biomarker/model, privacy, and governance artifacts. Use for aggregate or synthetic research documentation and traceability—not patient care or live clinical operation.

clinical-reports

Create safety-bounded draft structures and run local deterministic checks for clinical case, diagnostic, trial, safety, and aggregate research reports. Use only with synthetic, de-identified, or aggregate inputs and verified source-fact manifests; every output requires qualified review.

관련 스킬