DN 히스토그램 누적 분석
설명
영상 센서의 DN(Digital Number)별 픽셀 수를 로그 스케일과 역누적 곡선으로 분석한다
필요 데이터
DN 값 컬럼 1개 + 개수(Count) 컬럼 1개 (실행 시 선택)
출력
DN-Count 로그 산점도 + 역누적 곡선 그래프, 역누적 표
필요 패키지
- matplotlib
- pandas
태그
science, visualization, statistics
작성자
SDSL | MDS 1.0
영상 센서의 DN(Digital Number)별 픽셀 수를 로그 스케일과 역누적 곡선으로 분석한다
Analyzes pixel counts per DN on log scale with a reverse-cumulative curve
README
영상 센서의 DN(Digital Number)별 픽셀 수를 로그 스케일과 역누적 곡선으로 분석한다
DN 값 컬럼 1개 + 개수(Count) 컬럼 1개 (실행 시 선택)
DN-Count 로그 산점도 + 역누적 곡선 그래프, 역누적 표
science, visualization, statistics
SDSL | MDS 1.0
# MDS_TITLE: DN 히스토그램 누적 분석
# MDS_REQUIRES: matplotlib, pandas
# MDS_DESC: 영상 센서의 DN(Digital Number)별 픽셀 수를 로그 스케일과 역누적 곡선으로 분석한다
# MDS_DESC[en]: Analyzes pixel counts per DN on log scale with a reverse-cumulative curve
# MDS_TAGS: science, visualization, statistics
# MDS_INPUT: DN 값 컬럼 1개 + 개수(Count) 컬럼 1개 (실행 시 선택)
# MDS_OUTPUT: DN-Count 로그 산점도 + 역누적 곡선 그래프, 역누적 표
# MDS_AUTHOR: SDSL
# MDS_VERSION: 1.0
def apply_plot_style() -> None:
try:
plt.style.use('seaborn-v0_8-whitegrid')
except OSError:
plt.style.use('seaborn-whitegrid')
plt.rcParams['font.family'] = 'Malgun Gothic'
plt.rcParams['axes.unicode_minus'] = False
return None
def reverse_cumulative(df: pd.DataFrame, dn_col: str, count_col: str) -> pd.DataFrame:
dff = df[[dn_col, count_col]].dropna().copy()
dff = dff.groupby(dn_col, as_index=False)[count_col].sum().sort_values(dn_col)
dff['역누적_Count'] = dff[count_col][::-1].cumsum()[::-1]
return dff.reset_index(drop=True)
def plot_histogram(table: pd.DataFrame, dn_col: str, count_col: str) -> None:
apply_plot_style()
fig, axes = plt.subplots(1, 2, figsize=(13, 5))
axes[0].scatter(table[dn_col], table[count_col], s=22, alpha=0.7, color='#4C72B0',
edgecolors='white', linewidths=0.4)
axes[0].set_yscale('log')
axes[0].set_title('DN vs Count (Log Scale)', fontsize=12, fontweight='semibold')
axes[0].set_xlabel(dn_col)
axes[0].set_ylabel('Count (log)')
axes[1].plot(table[dn_col], table['역누적_Count'], linewidth=1.6, color='#DD8452')
axes[1].fill_between(table[dn_col], table['역누적_Count'], alpha=0.12, color='#DD8452')
axes[1].set_yscale('log')
axes[1].set_title('DN 이상 픽셀 수 (역누적)', fontsize=12, fontweight='semibold')
axes[1].set_xlabel(dn_col)
axes[1].set_ylabel('역누적 Count (log)')
for ax in axes:
ax.grid(True, alpha=0.3, which='both')
plt.tight_layout()
plt.show()
return None
def run_dn_histogram(df: pd.DataFrame) -> pd.DataFrame | None:
numeric_cols = df.select_dtypes(include='number').columns.tolist()
if len(numeric_cols) < 2:
mIO.print('수치형 컬럼이 2개 이상 필요합니다 (DN, Count).')
return None
dn_col = mIO.combo('DN 컬럼을 선택하세요', numeric_cols, default=numeric_cols[0])
count_col = mIO.combo('Count 컬럼을 선택하세요', numeric_cols, default=numeric_cols[1])
if dn_col is None or count_col is None or dn_col == count_col:
mIO.print('서로 다른 DN / Count 컬럼을 선택해야 합니다.')
return None
table = reverse_cumulative(df, dn_col, count_col)
plot_histogram(table, dn_col, count_col)
return table
result = run_dn_histogram(df)