← .mpy 공유
사용자 공유시각화

image profile 측정

이미지를 y축 방향으로 전체 높이의 1/10 간격 구간으로 나누고, 구간마다 평균한 x방향 Contrast profile을 보여준다

image profile 측정 실행 결과 미리보기🔍 클릭하면 원본 크기로 보기

README

image profile 측정

설명

이미지를 y축 방향으로 전체 높이의 1/10 간격 구간으로 나누고, 구간마다 평균한 x방향 Contrast profile을 보여준다

필요 데이터

이미지 파일 1개(png/jpg/bmp/tif, 실행 중 선택) — df는 사용하지 않음

출력

구간 경계를 표시한 이미지 + 구간별 평균 profile 그래프

태그

visualization

작성자

메이커-4e07 | MDS 1.0

Source · 78줄 (실행 전에 꼭 확인하세요 — 펼치기)
# MDS_DESC: 이미지를 y축 방향으로 전체 높이의 1/10 간격 구간으로 나누고, 구간마다 평균한 x방향 Contrast profile을 보여준다
# MDS_TAGS: visualization
# MDS_INPUT: 이미지 파일 1개(png/jpg/bmp/tif, 실행 중 선택) — df는 사용하지 않음
# MDS_OUTPUT: 구간 경계를 표시한 이미지 + 구간별 평균 profile 그래프

from PIL import Image

N_BANDS = 10  # y축 간격 = 전체 높이의 1/10


def load_gray_image(path: str) -> np.ndarray:
    with Image.open(path) as img:
        arr = np.array(img)
    if arr.ndim == 3:
        arr = arr[..., :3].astype(np.float32) @ np.array([0.299, 0.587, 0.114], dtype=np.float32)
    return arr.astype(np.float32)


def band_profiles(gray: np.ndarray, n_bands: int) -> tuple[np.ndarray, np.ndarray]:
    height = gray.shape[0]
    n_bands = max(1, min(n_bands, height))
    edges = np.linspace(0, height, n_bands + 1).astype(int)
    profiles = np.stack([gray[edges[i]:edges[i + 1], :].mean(axis=0) for i in range(n_bands)])
    return profiles, edges


def michelson_contrast(profile: np.ndarray) -> float:
    p_max, p_min = float(profile.max()), float(profile.min())
    denom = p_max + p_min
    return (p_max - p_min) / denom if denom > 0 else 0.0


def plot_profiles(gray: np.ndarray, profiles: np.ndarray, edges: np.ndarray, title: str) -> None:
    plt.rcParams['font.family'] = 'Malgun Gothic'
    plt.rcParams['axes.unicode_minus'] = False

    fig, (ax_img, ax_prof) = plt.subplots(1, 2, figsize=(12, 5))
    colors = plt.cm.viridis(np.linspace(0, 1, len(profiles)))

    ax_img.imshow(gray, cmap="gray", aspect="auto")
    for i, y in enumerate(edges[1:-1]):
        ax_img.axhline(y, color=colors[i + 1], linewidth=0.8)
    ax_img.set_title(title)
    ax_img.set_xlabel("x (pixel)")
    ax_img.set_ylabel("y (pixel)")

    x = np.arange(profiles.shape[1])
    for i, prof in enumerate(profiles):
        label = f"y {edges[i]}–{edges[i + 1]} (C={michelson_contrast(prof):.3f})"
        ax_prof.plot(x, prof, color=colors[i], linewidth=1.0, label=label)
    ax_prof.set_title("y 구간별 평균 profile")
    ax_prof.set_xlabel("x (pixel)")
    ax_prof.set_ylabel("평균 강도")
    ax_prof.grid(True, alpha=0.3)
    ax_prof.legend(fontsize=7, loc="best")

    plt.tight_layout()
    plt.show()
    plt.close(fig)


def run(df: pd.DataFrame) -> str:
    path = mIO.open_file_single(
        dialog_title="이미지 파일 선택",
        file_filter="Images (*.png *.jpg *.jpeg *.bmp *.tif *.tiff)",
        initial_dir=None,
    )
    if not path:
        return "사용자가 취소했습니다."

    gray = load_gray_image(path)
    profiles, edges = band_profiles(gray, N_BANDS)
    plot_profiles(gray, profiles, edges, title=os.path.basename(path))
    return f"{gray.shape[1]}×{gray.shape[0]} 이미지, {len(profiles)}개 구간 profile 생성"


import os
result = run(df)

댓글