pandasとの連携 -- 2値ブローブ特徴量の一覧表示とフィルタリング¶
pandas を用いて2値ブローブ特徴量の一覧表示とフィルタリングを行うサンプルコードです。 本サンプルではブローブ特徴量をCSV形式で保存し、独自に定義したブローブ特徴量の楕円度が上位3位以内の黒ブローブをプロットします。
本サンプルの実行には予め pandas をインストールしておく必要があります。 pip コマンドを使用する場合、次のようにインストールしてください。
pip install pandas==1.0.5
コード¶
import math
import pyfie
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
# 利便のため PyFIE 関数が返すエラーコードに応じて例外を発生させる機能を有効化
pyfie.ctrl.enable_f_err_exception(True)
def main():
# 入力画像読み込み
hbin = pyfie.imread("fast_bin.png")
# 二値ブローブ解析
params = pyfie.F_MEASURE_PARAMS(
max_runs = 0,
max_blobs = 0,
max_rows = 0,
color_mode = pyfie.f_measure_color_mode.F_MEASURE_WHITEFG_BLACKBG,
neighborhood = 8,
precalc_features = 0,
keep_results_after_overflow = False
)
measure = pyfie.fnFIE_measure_execute(
hbin, (0, 0), params, None
)
filter_num = 1
filters = pyfie.F_MEASURE_FILTER_RANGE.ARRAY(filter_num)
filters.value = [
(pyfie.F_FEATURE_AREA, 10, 100000000)
]
# ブローブ番号配列の取得
blob_numbers = pyfie.UINT.PTR()
blob_num = pyfie.UINT()
pyfie.fnFIE_measure_get_list(
measure, filters, filter_num, blob_numbers.ref, blob_num.ref
)
# 検出されたブローブをプロットしてファイルに保存
hbin.imshow()
pyfie.mpltools.plot_measure_results(measure, blob_numbers, blob_num)
plt.savefig("blobs.png")
plt.close()
# テーブル化したいブローブ特徴量
features = [
pyfie.F_FEATURE_COLOR,
pyfie.F_FEATURE_CENTERX,
pyfie.F_FEATURE_CENTERY,
pyfie.F_FEATURE_XDIFF,
pyfie.F_FEATURE_YDIFF,
pyfie.F_FEATURE_AREA,
pyfie.F_FEATURE_MAJORAXIS,
pyfie.F_FEATURE_MINORAXIS,
pyfie.F_FEATURE_CONVEX_AREA,
pyfie.F_FEATURE_PERIM,
]
# ブローブ特徴量のテーブルを作成
feature_table = get_feature_table(measure, blob_numbers, blob_num, features)
# pandas データフレームに変換
df = pd.DataFrame(feature_table, index=blob_numbers[:blob_num], dtype=np.float)
# 「楕円度」を表す独自のブローブ特徴量を追加。
# 楕円度はおおむね0から1の値を取り、1に近いほど楕円らしいことを示す
df["ellipticity"] = df["area"] / (df["majoraxis"] * df["minoraxis"] * math.pi)
# 楕円度を含むブローブ特徴量の一覧をCSVファイルに保存
df.to_csv("blob_features.csv")
# 色が黒 (0) であり、楕円度が上位3位以内のブローブ番号を取得
NUM = 3
most_elliptic_blobnos = df[df["color"] == 0]["ellipticity"].nlargest(NUM).index
# 上記ブローブのバウンディングボックスをプロットしてファイルに保存
hbin.imshow()
pyfie.mpltools.plot_measure_results(measure, most_elliptic_blobnos, len(most_elliptic_blobnos))
plt.savefig("elliptic_blobs.png")
# ----- 二値ブローブ特徴量取得のためのユーティリティ関数 ここから -----
def get_feature_table(hmeasure, blob_numbers, nblobs, features):
"""Pandas互換のブローブ特徴量のテーブルを作成する。"""
feature_table = {}
for feature_id in features:
feature_vals = []
for i in range(nblobs):
blobno = blob_numbers[i]
feature_val = _get_blob_prop(hmeasure, blobno, feature_id)
feature_vals.append(feature_val)
feature_name = _get_abbreviated_measure_feature_name(feature_id)
feature_table[feature_name] = feature_vals
return feature_table
def _get_blob_prop(hmeasure, blobno, feature_type):
def get_1(func, value_type):
v = value_type()
err = func(hmeasure, blobno, v)
if err != pyfie.F_ERR_NONE:
raise RuntimeError("faild to get a blob property")
return v
def get_d(func):
return get_1(func, pyfie.DOUBLE)
def get_ui(func):
return get_1(func, pyfie.UINT)
def get_n(func, value_types, idx):
vs = [value_type() for value_type in value_types]
err = func(hmeasure, blobno, *vs)
if err != pyfie.F_ERR_NONE:
raise RuntimeError("faild to get blob properties")
return vs[idx]
def get_i2(func, idx):
return get_n(func, [pyfie.INT] * 2, idx)
def get_i4(func, idx):
return get_n(func, [pyfie.INT] * 4, idx)
def get_ll2(func, idx):
return get_n(func, [pyfie.DLONG] * 2, idx)
def get_d2(func, idx):
return get_n(func, [pyfie.DOUBLE] * 2, idx)
def get_d3(func, idx):
return get_n(func, [pyfie.DOUBLE] * 3, idx)
def get_d4(func, idx):
return get_n(func, [pyfie.DOUBLE] * 4, idx)
def get_hu_moment(idx):
hu = pyfie.DOUBLE.ARRAY(7)
pyfie.fnFIE_measure_get_hu_moments(hmeasure, blobno, hu)
return hu[idx]
if feature_type == pyfie.F_FEATURE_COLOR:
return get_ui(pyfie.fnFIE_measure_get_color)
elif feature_type == pyfie.F_FEATURE_XMIN:
return get_i4(pyfie.fnFIE_measure_get_xyrange, 0)
elif feature_type == pyfie.F_FEATURE_YMIN:
return get_i4(pyfie.fnFIE_measure_get_xyrange, 1)
elif feature_type == pyfie.F_FEATURE_XMAX:
return get_i4(pyfie.fnFIE_measure_get_xyrange, 2)
elif feature_type == pyfie.F_FEATURE_YMAX:
return get_i4(pyfie.fnFIE_measure_get_xyrange, 3)
elif feature_type == pyfie.F_FEATURE_XMIN_AT_YMIN:
return get_i4(pyfie.fnFIE_measure_get_maxminpos, 0)
elif feature_type == pyfie.F_FEATURE_XMAX_AT_YMAX:
return get_i4(pyfie.fnFIE_measure_get_maxminpos, 1)
elif feature_type == pyfie.F_FEATURE_YMIN_AT_XMAX:
return get_i4(pyfie.fnFIE_measure_get_maxminpos, 2)
elif feature_type == pyfie.F_FEATURE_YMAX_AT_XMIN:
return get_i4(pyfie.fnFIE_measure_get_maxminpos, 3)
elif feature_type == pyfie.F_FEATURE_XDIFF:
return get_i2(pyfie.fnFIE_measure_get_xydiff, 0)
elif feature_type == pyfie.F_FEATURE_YDIFF:
return get_i2(pyfie.fnFIE_measure_get_xydiff, 1)
elif feature_type == pyfie.F_FEATURE_M10:
assert feature_type == pyfie.F_FEATURE_SUMX
return get_ll2(pyfie.fnFIE_measure_get_moment1, 0)
elif feature_type == pyfie.F_FEATURE_M01:
assert feature_type == pyfie.F_FEATURE_SUMY
return get_ll2(pyfie.fnFIE_measure_get_moment1, 1)
elif feature_type == pyfie.F_FEATURE_M20:
assert feature_type == pyfie.F_FEATURE_SUMX2
return get_n(pyfie.fnFIE_measure_get_moment2, [pyfie.UDLONG, pyfie.UDLONG, pyfie.DLONG], 0)
elif feature_type == pyfie.F_FEATURE_M02:
assert feature_type == pyfie.F_FEATURE_SUMY2
return get_n(pyfie.fnFIE_measure_get_moment2, [pyfie.UDLONG, pyfie.UDLONG, pyfie.DLONG], 1)
elif feature_type == pyfie.F_FEATURE_M11:
assert feature_type == pyfie.F_FEATURE_SUMXY
return get_n(pyfie.fnFIE_measure_get_moment2, [pyfie.UDLONG, pyfie.UDLONG, pyfie.DLONG], 2)
elif feature_type == pyfie.F_FEATURE_AREA:
return get_ui(pyfie.fnFIE_measure_get_area)
elif feature_type == pyfie.F_FEATURE_CENTERX:
return get_d2(pyfie.fnFIE_measure_get_center, 0)
elif feature_type == pyfie.F_FEATURE_CENTERY:
return get_d2(pyfie.fnFIE_measure_get_center, 1)
elif feature_type == pyfie.F_FEATURE_RECT1AREA:
return get_ui(pyfie.fnFIE_measure_get_rect1_area)
elif feature_type == pyfie.F_FEATURE_RECT1LRATIO:
return get_d(pyfie.fnFIE_measure_get_rect1_lratio)
elif feature_type == pyfie.F_FEATURE_RECT1SRATIO:
return get_d(pyfie.fnFIE_measure_get_rect1_sratio)
elif feature_type == pyfie.F_FEATURE_LSIZE:
return get_d2(pyfie.fnFIE_measure_get_rect2_size, 0)
elif feature_type == pyfie.F_FEATURE_WSIZE:
return get_d2(pyfie.fnFIE_measure_get_rect2_size, 1)
elif feature_type == pyfie.F_FEATURE_RECT2AREA:
return get_d(pyfie.fnFIE_measure_get_rect2_area)
elif feature_type == pyfie.F_FEATURE_RECT2LRATIO:
return get_d(pyfie.fnFIE_measure_get_rect2_lratio)
elif feature_type == pyfie.F_FEATURE_RECT2SRATIO:
return get_d(pyfie.fnFIE_measure_get_rect2_sratio)
elif feature_type == pyfie.F_FEATURE_MAJORAXIS:
return get_d4(pyfie.fnFIE_measure_get_equivalent_ellipse, 0)
elif feature_type == pyfie.F_FEATURE_MINORAXIS:
return get_d4(pyfie.fnFIE_measure_get_equivalent_ellipse, 1)
elif feature_type in (pyfie.F_FEATURE_AXISTHETA, pyfie.F_FEATURE_AXISTHETA_CYCLIC):
return get_d4(pyfie.fnFIE_measure_get_equivalent_ellipse, 2)
elif feature_type == pyfie.F_FEATURE_AXISRATIO:
return get_d4(pyfie.fnFIE_measure_get_equivalent_ellipse, 3)
elif feature_type == pyfie.F_FEATURE_DIAMETER_EQUIDISK:
return get_d(pyfie.fnFIE_measure_get_equivalent_disk)
elif feature_type == pyfie.F_FEATURE_DIAMETER_EQUICIRCLE:
return get_d(pyfie.fnFIE_measure_get_equivalent_circle)
elif feature_type == pyfie.F_FEATURE_CIRCULARITY1:
return get_d(pyfie.fnFIE_measure_get_circularity1)
elif feature_type == pyfie.F_FEATURE_CIRCULARITY2:
return get_d(pyfie.fnFIE_measure_get_circularity2)
elif feature_type == pyfie.F_FEATURE_CIRCULARITY3:
return get_d(pyfie.fnFIE_measure_get_circularity3)
elif feature_type == pyfie.F_FEATURE_CONVEX_AREA:
return get_d2(pyfie.fnFIE_measure_get_convexfeature, 0)
elif feature_type == pyfie.F_FEATURE_CONVEX_PERIM:
return get_d2(pyfie.fnFIE_measure_get_convexfeature, 1)
elif feature_type == pyfie.F_FEATURE_CONVEX_AREARATIO:
return get_d2(pyfie.fnFIE_measure_get_convexratio, 0)
elif feature_type == pyfie.F_FEATURE_CONVEX_PERIMRATIO:
return get_d2(pyfie.fnFIE_measure_get_convexratio, 1)
elif feature_type == pyfie.F_FEATURE_FERET_MAX:
return get_d4(pyfie.fnFIE_measure_get_feret_diameter_maxmin, 0)
elif feature_type == pyfie.F_FEATURE_FERET_MIN:
return get_d4(pyfie.fnFIE_measure_get_feret_diameter_maxmin, 2)
elif feature_type in (pyfie.F_FEATURE_FMAX_THETA, pyfie.F_FEATURE_FMAX_THETA_CYCLIC):
return get_d4(pyfie.fnFIE_measure_get_feret_diameter_maxmin, 1)
elif feature_type in (pyfie.F_FEATURE_FMIN_THETA, pyfie.F_FEATURE_FMIN_THETA_CYCLIC):
return get_d4(pyfie.fnFIE_measure_get_feret_diameter_maxmin, 3)
elif feature_type == pyfie.F_FEATURE_DPMIN:
return get_d4(pyfie.fnFIE_measure_get_distance_to_boundary, 1)
elif feature_type == pyfie.F_FEATURE_DPMAX:
return get_d4(pyfie.fnFIE_measure_get_distance_to_boundary, 0)
elif feature_type == pyfie.F_FEATURE_DPAVE:
return get_d4(pyfie.fnFIE_measure_get_distance_to_boundary, 2)
elif feature_type == pyfie.F_FEATURE_DPSIGMA:
return get_d4(pyfie.fnFIE_measure_get_distance_to_boundary, 3)
elif feature_type == pyfie.F_FEATURE_DCMAX:
return get_d3(pyfie.fnFIE_measure_get_distance_to_childs, 0)
elif feature_type == pyfie.F_FEATURE_DCMIN:
return get_d3(pyfie.fnFIE_measure_get_distance_to_childs, 1)
elif feature_type == pyfie.F_FEATURE_DCAVE:
return get_d3(pyfie.fnFIE_measure_get_distance_to_childs, 2)
elif feature_type == pyfie.F_FEATURE_DSMAX:
return get_d3(pyfie.fnFIE_measure_get_distance_to_siblings, 0)
elif feature_type == pyfie.F_FEATURE_DSMIN:
return get_d3(pyfie.fnFIE_measure_get_distance_to_siblings, 1)
elif feature_type == pyfie.F_FEATURE_DSAVE:
return get_d3(pyfie.fnFIE_measure_get_distance_to_siblings, 2)
elif feature_type == pyfie.F_FEATURE_NS:
return get_ui(pyfie.fnFIE_measure_get_sibling_num)
elif feature_type == pyfie.F_FEATURE_PERIM:
return get_d(pyfie.fnFIE_measure_get_perimeter)
elif feature_type == pyfie.F_FEATURE_ST:
return get_ui(pyfie.fnFIE_measure_get_area_with_hole)
elif feature_type == pyfie.F_FEATURE_SC:
return get_ui(pyfie.fnFIE_measure_get_hole_area)
elif feature_type == pyfie.F_FEATURE_HOLES:
return get_ui(pyfie.fnFIE_measure_get_hole_num)
elif feature_type == pyfie.F_FEATURE_HRATIO:
return get_d(pyfie.fnFIE_measure_get_hole_ratio)
elif feature_type == pyfie.F_FEATURE_PPS:
return get_d(pyfie.fnFIE_measure_get_pps)
elif feature_type == pyfie.F_FEATURE_M30:
return get_d4(pyfie.fnFIE_measure_get_moment3, 0)
elif feature_type == pyfie.F_FEATURE_M03:
return get_d4(pyfie.fnFIE_measure_get_moment3, 1)
elif feature_type == pyfie.F_FEATURE_M21:
return get_d4(pyfie.fnFIE_measure_get_moment3, 2)
elif feature_type == pyfie.F_FEATURE_M12:
return get_d4(pyfie.fnFIE_measure_get_moment3, 3)
elif feature_type == pyfie.F_FEATURE_MG20:
return get_d3(pyfie.fnFIE_measure_get_central_moment2, 0)
elif feature_type == pyfie.F_FEATURE_MG02:
return get_d3(pyfie.fnFIE_measure_get_central_moment2, 1)
elif feature_type == pyfie.F_FEATURE_MG11:
return get_d3(pyfie.fnFIE_measure_get_central_moment2, 2)
elif feature_type == pyfie.F_FEATURE_MG30:
return get_d4(pyfie.fnFIE_measure_get_central_moment3, 0)
elif feature_type == pyfie.F_FEATURE_MG03:
return get_d4(pyfie.fnFIE_measure_get_central_moment3, 1)
elif feature_type == pyfie.F_FEATURE_MG21:
return get_d4(pyfie.fnFIE_measure_get_central_moment3, 2)
elif feature_type == pyfie.F_FEATURE_MG12:
return get_d4(pyfie.fnFIE_measure_get_central_moment3, 3)
elif feature_type == pyfie.F_FEATURE_HU_MOMENT0:
return get_hu_moment(0)
elif feature_type == pyfie.F_FEATURE_HU_MOMENT1:
return get_hu_moment(1)
elif feature_type == pyfie.F_FEATURE_HU_MOMENT2:
return get_hu_moment(2)
elif feature_type == pyfie.F_FEATURE_HU_MOMENT3:
return get_hu_moment(3)
elif feature_type == pyfie.F_FEATURE_HU_MOMENT4:
return get_hu_moment(4)
elif feature_type == pyfie.F_FEATURE_HU_MOMENT5:
return get_hu_moment(5)
elif feature_type == pyfie.F_FEATURE_HU_MOMENT6:
return get_hu_moment(6)
else:
raise ValueError("Unknown feature type: " + feature_type)
def _get_abbreviated_measure_feature_name(feature_id):
feature_name = str(pyfie.f_measure_feature_type(feature_id))
prefix = "F_FEATURE_"
if feature_name.startswith(prefix):
feature_name = feature_name[len(prefix):]
return feature_name.lower()
# ----- 二値ブローブ特徴量取得のためのユーティリティ関数 ここまで -----
if __name__ == "__main__":
main()
処理結果例¶
入力画像
ブローブ特徴量の一覧
color |
centerx |
centery |
xdiff |
ydiff |
area |
majoraxis |
minoraxis |
convex_area |
perim |
ellipticity |
|
---|---|---|---|---|---|---|---|---|---|---|---|
1 |
1.00 |
76.81 |
72.54 |
150.00 |
150.00 |
17056.00 |
94.89 |
91.30 |
22201.00 |
596.00 |
0.63 |
2 |
1.00 |
72.07 |
120.57 |
6.00 |
8.00 |
28.00 |
4.14 |
2.53 |
20.50 |
21.07 |
0.85 |
3 |
0.00 |
61.20 |
66.76 |
103.00 |
120.00 |
4006.00 |
68.51 |
23.07 |
5112.00 |
576.00 |
0.81 |
4 |
0.00 |
71.30 |
121.55 |
25.00 |
29.00 |
381.00 |
16.06 |
11.47 |
449.50 |
116.00 |
0.66 |
5 |
0.00 |
96.85 |
120.41 |
28.00 |
30.00 |
445.00 |
18.35 |
13.07 |
629.50 |
188.00 |
0.59 |
6 |
0.00 |
122.48 |
115.90 |
25.00 |
29.00 |
273.00 |
18.04 |
9.45 |
432.00 |
114.00 |
0.51 |
7 |
0.00 |
49.11 |
117.83 |
26.00 |
28.00 |
311.00 |
17.89 |
9.03 |
429.00 |
128.00 |
0.61 |
ブローブ画像
楕円度(独自定義)が上位3位以内の黒ブローブの画像