読み込み中...

Pythonを用いた粒子解析の基礎知識と応用例21選

粒子解析 徹底解説 Python
この記事は約29分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

●Pythonによる粒子解析とは?

粒子解析は、微小な物体を識別し、その特性を数値化する技術です。

写真や動画に映る粒子を解析することで、様々な分野で活用されています。

医療分野では血液細胞の計測に、材料科学では新素材の開発に、環境調査ではマイクロプラスチックの検出に役立っています。

まるで顕微鏡を通して見る小宇宙のような、ミクロの世界を数値で表現する魔法のような技術なのです。

○粒子解析の基本概念と重要性

粒子解析の重要性は日々高まっています。

例えば、製薬会社が新薬の開発過程で粒子の挙動を観察する際に使用されます。

また、半導体製造において、ナノレベルの粒子を制御する際にも欠かせません。

精密な分析が可能になることで、研究や開発の質が飛躍的に向上するのです。

まさに、現代科学の縁の下の力持ちと言えるでしょう。

○Pythonが粒子解析に適している理由

Pythonは粒子解析に非常に適した言語です。

その理由はいくつかあります。

まず、NumPy、scikit-image、OpenCVなど、画像処理に特化したライブラリが豊富に揃っています。

次に、コードの可読性が高く、複雑な処理も直感的に記述できます。

さらに、機械学習との親和性が高く、高度な分析手法の実装も容易です。

Pythonは、まるで粒子解析のために生まれてきたかのような言語なのです。

○サンプルコード1:基本的な画像読み込みと表示

実際にPythonで画像を読み込み、表示するコードを見てみましょう。

import matplotlib.pyplot as plt
from skimage import io

# 画像の読み込み
image = io.imread('particle_image.jpg')

# 画像の表示
plt.imshow(image)
plt.axis('off')  # 軸を非表示に
plt.show()

このコードを実行すると、指定した画像ファイルが読み込まれ、ウィンドウに表示されます。

matplotlibライブラリを使用することで、グラフィカルな出力が簡単に得られます。

実行結果では、読み込んだ画像がポップアップウィンドウに表示されます。

画像に含まれる粒子の様子を視覚的に確認できるでしょう。まさに、粒子解析の第一歩を踏み出したわけです。

●粒子解析の前処理テクニック

粒子解析を行う上で、前処理は極めて重要です。

画像に含まれるノイズや不要な情報を取り除くことで、より精度の高い分析が可能になります。

前処理は、まるで料理の下ごしらえのようなもの。

丁寧に行うことで、最終的な結果の質が大きく向上するのです。

○サンプルコード2:ノイズ除去(ガウシアンフィルタ)

まず、ノイズ除去から始めましょう。

ガウシアンフィルタは、画像のボケを利用してノイズを軽減する手法です。

from skimage import filters

# ガウシアンフィルタの適用
denoised = filters.gaussian(image, sigma=1)

# 結果の表示
plt.imshow(denoised)
plt.axis('off')
plt.show()

sigmaパラメータを調整することで、ノイズ除去の強度を変更できます。

値が大きいほど強くノイズが除去されますが、同時に画像の細部も失われていきます。

まるで、絵画を霞がかった雰囲気に仕上げていくような作業です。

実行結果は、元の画像よりもやや滑らかになった画像が表示されます。

粒子の輪郭がより明確になり、細かいノイズが減少しているのが確認できるでしょう。

○サンプルコード3:二値化処理

次に、二値化処理を行います。

この処理により、粒子とそれ以外の領域をはっきりと区別することができます。

from skimage import filters

# 大津の二値化を適用
threshold = filters.threshold_otsu(denoised)
binary = denoised > threshold

# 結果の表示
plt.imshow(binary, cmap='gray')
plt.axis('off')
plt.show()

大津の二値化法は、画像のヒストグラムを自動的に分析し、最適な閾値を決定します。

この方法により、明暗の差が大きい画像でも適切に二値化を行えます。

まるで、白黒の世界に粒子を閉じ込めるような作業です。

実行結果は、白黒の二値画像が表示されます。

粒子の部分が白く、背景が黒く表現されているはずです。

この状態だと、粒子の形状がより明確になっています。

○サンプルコード4:モルフォロジー演算

さらに、モルフォロジー演算を適用して、粒子の形状をより整えることができます。

from skimage import morphology

# クロージング処理
closed = morphology.closing(binary, morphology.square(3))

# 結果の表示
plt.imshow(closed, cmap='gray')
plt.axis('off')
plt.show()

クロージング処理は、膨張と収縮を順に適用する操作です。

小さな穴や隙間を埋めつつ、全体的な形状を保持する効果があります。

まるで、粒子を優しく整形していくような作業です。

実行結果では、二値化画像よりもさらに粒子の形状が整った画像が表示されるはずです。

小さなノイズが消え、粒子の輪郭がよりスムーズになっているのが確認できるでしょう。

○サンプルコード5:ラベリング処理

最後に、ラベリング処理を行います。

個々の粒子を識別し、それぞれに番号を割り当てる作業です。

from skimage import measure

# ラベリング処理
labeled = measure.label(closed)

# 結果の表示
plt.imshow(labeled, cmap='nipy_spectral')
plt.axis('off')
plt.show()

measure.label関数により、連結した領域ごとに異なるラベル(番号)が付与されます。

表示の際にはカラーマップを使用し、各粒子が異なる色で表現されます。

まるで、粒子たちに名前をつけていくような作業です。

実行結果では、多色の画像が表示されます。

それぞれの色が個別の粒子を表しており、一目で粒子の数や分布が把握できるようになっています。

カラフルな粒子の世界が広がっているはずです。

●粒子の特徴量抽出方法

粒子解析の醍醐味は、まさにここにあります。

前処理で整えた画像から、粒子の特徴を数値として抽出する過程は、まるで宝探しのようなワクワク感があります。

一つ一つの粒子が持つ固有の特徴を、Pythonの力を借りて明らかにしていきましょう。

○サンプルコード6:面積と周囲長の計算

粒子の基本的な特徴として、面積と周囲長があります。

面積は粒子の大きさを、周囲長は形状の複雑さを表す指標となります。

import numpy as np
from skimage import measure

# ラベリング済みの画像を使用
props = measure.regionprops(labeled_image)

# 面積と周囲長の計算
areas = [prop.area for prop in props]
perimeters = [prop.perimeter for prop in props]

print(f"平均面積: {np.mean(areas):.2f}")
print(f"平均周囲長: {np.mean(perimeters):.2f}")

実行結果では、画像内の全粒子の平均面積と平均周囲長が表示されます。

例えば、「平均面積: 150.25」「平均周囲長: 43.75」のような出力が得られるでしょう。

○サンプルコード7:アスペクト比と円形度の算出

粒子の形状をより詳細に把握するために、アスペクト比と円形度を計算します。

アスペクト比は粒子の細長さを、円形度は粒子が円に近い度合いを表します。

# アスペクト比と円形度の計算
aspect_ratios = [prop.major_axis_length / prop.minor_axis_length for prop in props]
circularities = [4 * np.pi * prop.area / (prop.perimeter ** 2) for prop in props]

print(f"平均アスペクト比: {np.mean(aspect_ratios):.2f}")
print(f"平均円形度: {np.mean(circularities):.2f}")

実行結果では、「平均アスペクト比: 1.75」「平均円形度: 0.85」といった具合に、粒子の形状特性が数値化されて表示されます。

○サンプルコード8:重心座標の特定

粒子の位置を特定するには、重心座標が有用です。

画像内での粒子の分布を把握するのに役立ちます。

# 重心座標の計算
centroids = [prop.centroid for prop in props]

print("重心座標の例:")
for i, centroid in enumerate(centroids[:5]):
    print(f"粒子{i+1}: (y={centroid[0]:.2f}, x={centroid[1]:.2f})")

実行結果では、最初の5つの粒子の重心座標が表示されます。

例えば、「粒子1: (y=45.23, x=67.89)」のような形式で出力されるでしょう。

○サンプルコード9:粒子の向きと主軸の決定

粒子の向きや主軸を知ることで、粒子の配向性を分析できます。

材料科学や流体力学の研究で重要となる指標です。

# 向きと主軸の計算
orientations = [prop.orientation for prop in props]
major_axis_lengths = [prop.major_axis_length for prop in props]

print(f"平均向き (ラジアン): {np.mean(orientations):.2f}")
print(f"平均主軸長: {np.mean(major_axis_lengths):.2f}")

実行結果では、「平均向き (ラジアン): 0.78」「平均主軸長: 15.62」のように、粒子の向きと主軸に関する情報が表示されます。

●高度な粒子解析テクニック

基本的な特徴量抽出を押さえたところで、より高度な解析手法に挑戦してみましょう。

ここからが本当の粒子解析の醍醐味です。

複雑な現象を紐解く鍵が、ここにあるかもしれません。

○サンプルコード10:K-meansによる粒子クラスタリング

粒子の特徴量を基に、似た特性を持つ粒子同士をグループ化するK-meansクラスタリングを実施します。

from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler

# 特徴量の準備
features = np.column_stack((areas, perimeters, aspect_ratios, circularities))

# 特徴量の標準化
scaler = StandardScaler()
features_scaled = scaler.fit_transform(features)

# K-meansクラスタリングの実行
kmeans = KMeans(n_clusters=3, random_state=42)
clusters = kmeans.fit_predict(features_scaled)

print("クラスタ別の粒子数:")
for i in range(3):
    print(f"クラスタ{i+1}: {np.sum(clusters == i)}個")

実行結果では、「クラスタ1: 45個」「クラスタ2: 32個」「クラスタ3: 23個」のように、各クラスタに分類された粒子の数が表示されます。

○サンプルコード11:時系列データでの粒子追跡

動画データから粒子の動きを追跡する手法です。

時間経過に伴う粒子の挙動を分析できます。

from scipy.optimize import linear_sum_assignment

def track_particles(centroids_t1, centroids_t2, max_distance=50):
    distances = np.sqrt(((centroids_t1[:, np.newaxis] - centroids_t2) ** 2).sum(axis=2))
    row_ind, col_ind = linear_sum_assignment(distances)
    valid_tracks = distances[row_ind, col_ind] < max_distance
    return row_ind[valid_tracks], col_ind[valid_tracks]

# 2つの時点での重心座標(例として)
centroids_t1 = np.array(centroids[:10])
centroids_t2 = centroids_t1 + np.random.randn(*centroids_t1.shape) * 5

tracked_indices = track_particles(centroids_t1, centroids_t2)

print(f"追跡された粒子数: {len(tracked_indices[0])}")

実行結果では、「追跡された粒子数: 8」のように、2つの時点間で追跡できた粒子の数が表示されます。

○サンプルコード12:3D粒子解析の基本

3次元画像データを扱う場合の基本的な粒子解析手法です。

医療画像や材料科学で頻繁に用いられます。

from skimage import io, measure

# 3D画像の読み込み(例として)
image_3d = io.imread('3d_particle_image.tif')

# 3Dラベリング
labels_3d = measure.label(image_3d)

# 3D特徴量の抽出
props_3d = measure.regionprops(labels_3d)

print(f"検出された3D粒子数: {len(props_3d)}")
print(f"最大体積の粒子: {max(prop.volume for prop in props_3d)}")

実行結果では、「検出された3D粒子数: 127」「最大体積の粒子: 1250」のように、3D画像中の粒子に関する基本情報が表示されます。

○サンプルコード13:機械学習を用いた粒子分類

粒子の特徴量を基に、機械学習モデルを構築して粒子を自動分類します。

大量のデータを効率的に処理できます。

from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

# 特徴量とラベルの準備(例として)
X = np.column_stack((areas, perimeters, aspect_ratios, circularities))
y = np.random.choice(['A', 'B', 'C'], size=len(X))  # ダミーラベル

# データの分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# ランダムフォレストモデルの構築と学習
clf = RandomForestClassifier(n_estimators=100, random_state=42)
clf.fit(X_train, y_train)

# テストデータでの予測と精度評価
y_pred = clf.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)

print(f"分類精度: {accuracy:.2f}")

実行結果では、「分類精度: 0.85」のように、構築したモデルの性能が表示されます。

この値が高いほど、粒子の自動分類の精度が高いことを示します。

●結果の可視化テクニック

粒子解析の結果を効果的に伝えるには、適切な可視化が欠かせません。

数値データを視覚的に表現することで、直感的な理解が促進されます。

Pythonには、matplotlib や seaborn といった強力な可視化ライブラリが備わっています。

○サンプルコード14:粒子サイズ分布のヒストグラム作成

粒子のサイズ分布を把握するには、ヒストグラムが最適です。

横軸にサイズ、縦軸に頻度を取ることで、粒子サイズの全体像が一目瞭然となります。

import matplotlib.pyplot as plt
import seaborn as sns

# ヒストグラムの作成
plt.figure(figsize=(10, 6))
sns.histplot(areas, bins=30, kde=True)
plt.title('粒子サイズ分布')
plt.xlabel('面積')
plt.ylabel('頻度')
plt.show()

実行結果では、X軸に粒子の面積、Y軸に頻度を示すグラフが表示されます。

山の形状から、粒子サイズの分布傾向が読み取れます。

例えば、単峰性の分布なら均一なサイズの粒子が多いことを、双峰性なら2種類のサイズの粒子が混在していることを示唆します。

○サンプルコード15:散布図による空間分布の表現

粒子の空間的な分布を把握するには、散布図が有効です。

各粒子の位置を平面上にプロットすることで、密集度や偏りを視覚化できます。

# 散布図の作成
plt.figure(figsize=(10, 10))
plt.scatter([c[1] for c in centroids], [c[0] for c in centroids], alpha=0.5)
plt.title('粒子の空間分布')
plt.xlabel('X座標')
plt.ylabel('Y座標')
plt.gca().invert_yaxis()  # Y軸を反転(画像座標系に合わせる)
plt.show()

実行結果では、X-Y平面上に点々と粒子の位置が表示されます。

点の密集具合から、粒子が画像のどの部分に集中しているかが一目で分かります。

例えば、特定の領域に粒子が集中している場合、その原因を探る手がかりになります。

○サンプルコード16:箱ひげ図で統計的特徴を表現

複数の特徴量を比較する際には、箱ひげ図が便利です。

中央値、四分位数、外れ値などの統計情報を同時に表現できます。

# 箱ひげ図の作成
plt.figure(figsize=(12, 6))
data = [areas, perimeters, aspect_ratios, circularities]
labels = ['面積', '周囲長', 'アスペクト比', '円形度']
plt.boxplot(data, labels=labels)
plt.title('粒子特徴量の分布')
plt.ylabel('値')
plt.show()

実行結果では、4つの特徴量(面積、周囲長、アスペクト比、円形度)それぞれについて箱ひげ図が表示されます。

箱の中央線が中央値、箱の上端と下端が第1四分位数と第3四分位数、ひげの端が最小値と最大値を表します。

外れ値は点で表示されます。

○サンプルコード17:粒子形状の星座図表示

粒子の形状を直感的に把握するには、星座図(レーダーチャート)が効果的です。

複数の特徴量を多角形で表現することで、形状の特徴を一目で理解できます。

import numpy as np

# 星座図の作成
def radar_chart(data, labels, title):
    angles = np.linspace(0, 2*np.pi, len(labels), endpoint=False)
    data = np.concatenate((data, [data[0]]))  # 閉じた図形にするため
    angles = np.concatenate((angles, [angles[0]]))  # 同上

    fig, ax = plt.subplots(figsize=(6, 6), subplot_kw=dict(projection='polar'))
    ax.plot(angles, data)
    ax.fill(angles, data, alpha=0.25)
    ax.set_xticks(angles[:-1])
    ax.set_xticklabels(labels)
    ax.set_title(title)
    plt.show()

# 例として最初の粒子のデータを使用
sample_data = [props[0].area, props[0].perimeter, props[0].major_axis_length / props[0].minor_axis_length, 
               4 * np.pi * props[0].area / (props[0].perimeter ** 2)]
sample_labels = ['面積', '周囲長', 'アスペクト比', '円形度']

radar_chart(sample_data, sample_labels, '粒子形状の特徴')

実行結果では、4つの軸(面積、周囲長、アスペクト比、円形度)を持つ星形のグラフが表示されます。

各軸の値によって形作られる多角形の形状から、粒子の特徴を直感的に理解できます。

例えば、円に近い形状なら全体的にバランスの取れた粒子、いびつな形状なら特定の特徴が突出した粒子であることが分かります。

●よくあるエラーと対処法

粒子解析を行う上で、いくつかの典型的な問題に遭遇することがあります。

ここでは、よく遭遇するエラーとその対処法について解説します。

○コントラスト不足による誤検出の解決策

画像のコントラストが低い場合、粒子の境界が不明瞭となり、正確な検出が困難になります。

この問題を解決するには、コントラスト強調の前処理が有効です。

from skimage import exposure

# コントラスト強調
def enhance_contrast(image):
    p2, p98 = np.percentile(image, (2, 98))
    return exposure.rescale_intensity(image, in_range=(p2, p98))

# コントラスト強調を適用
enhanced_image = enhance_contrast(image)

# 結果の表示
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6))
ax1.imshow(image, cmap='gray')
ax1.set_title('原画像')
ax2.imshow(enhanced_image, cmap='gray')
ax2.set_title('コントラスト強調後')
plt.show()

このコードを実行すると、原画像とコントラスト強調後の画像が並べて表示されます。

コントラスト強調後の画像では、粒子の輪郭がより明確になっているはずです。

○オーバーラップした粒子の分離方法

粒子が密集している場合、個々の粒子を正確に分離することが難しくなります。

ウォーターシェッド法を用いることで、オーバーラップした粒子を効果的に分離できます。

from scipy import ndimage as ndi
from skimage.segmentation import watershed
from skimage.feature import peak_local_max

def separate_overlapping_particles(binary_image):
    # 距離変換
    distance = ndi.distance_transform_edt(binary_image)

    # ローカルマキシマムの検出
    coords = peak_local_max(distance, footprint=np.ones((3, 3)), labels=binary_image)
    mask = np.zeros(distance.shape, dtype=bool)
    mask[tuple(coords.T)] = True
    markers, _ = ndi.label(mask)

    # ウォーターシェッド法による分離
    labels = watershed(-distance, markers, mask=binary_image)

    return labels

# オーバーラップ粒子の分離を適用
separated_particles = separate_overlapping_particles(binary)

# 結果の表示
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6))
ax1.imshow(binary, cmap='gray')
ax1.set_title('二値化画像')
ax2.imshow(separated_particles, cmap='nipy_spectral')
ax2.set_title('分離後')
plt.show()

実行結果では、二値化画像と分離後の画像が並べて表示されます。

分離後の画像では、オーバーラップしていた粒子が個別に色分けされて表示されるはずです。

○大規模データセット処理時のメモリエラー対策

大規模な画像データセットを処理する際、メモリ不足によるエラーが発生することがあります。

この問題に対処するには、データの分割処理やメモリ効率の良いアルゴリズムの採用が効果的です。

def process_large_image(image_path, chunk_size=1000):
    # 画像を小さなチャンクに分割して処理
    with rasterio.open(image_path) as src:
        height = src.height
        width = src.width

        results = []

        for y in range(0, height, chunk_size):
            for x in range(0, width, chunk_size):
                window = rasterio.windows.Window(x, y, 
                                                 min(chunk_size, width - x),
                                                 min(chunk_size, height - y))
                chunk = src.read(1, window=window)

                # チャンクごとの処理(例:平均値の計算)
                chunk_result = np.mean(chunk)
                results.append(chunk_result)

        return np.mean(results)

# 大規模画像の処理
average_value = process_large_image('large_image.tif')
print(f"画像全体の平均値: {average_value}")

このコードを実行すると、大規模画像を小さなチャンクに分割して処理し、最終的に全体の平均値を算出します。

実際の出力では、「画像全体の平均値: 127.5」のような結果が表示されるでしょう。

●粒子解析の応用例

粒子解析の技術は、様々な分野で活用されています。

医療、材料科学、環境科学、工業製品の品質管理など、幅広い領域で重要な役割を果たしています。

ここでは、具体的な応用例とそれぞれのサンプルコードを紹介します。

○サンプルコード18:医療画像での細胞計数

医療分野では、顕微鏡画像中の細胞を正確に計数することが重要です。

血液検査や組織検査などで活用されるこの技術は、疾病の診断や治療効果の評価に欠かせません。

import cv2
import numpy as np
from skimage import measure

def count_cells(image_path):
    # 画像の読み込みとグレースケール変換
    image = cv2.imread(image_path)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # 二値化
    _, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

    # ノイズ除去
    kernel = np.ones((3,3), np.uint8)
    opening = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel, iterations=2)

    # 細胞の検出
    labels = measure.label(opening)
    cell_count = labels.max()

    return cell_count

# 細胞計数の実行
image_path = 'cell_image.jpg'
cell_count = count_cells(image_path)
print(f"検出された細胞数: {cell_count}")

実行結果では、「検出された細胞数: 127」のように、画像内の細胞数が表示されます。

この結果を基に、医師は患者の状態を正確に把握し、適切な治療方針を立てることができます。

○サンプルコード19:材料科学における粒度分布解析

材料科学では、粒子の大きさと分布が材料の特性に大きな影響を与えます。

例えば、金属材料の結晶粒サイズは、強度や延性といった機械的特性を左右します。

import numpy as np
import matplotlib.pyplot as plt
from skimage import measure, io

def analyze_grain_size(image_path):
    # 画像の読み込みと二値化
    image = io.imread(image_path, as_gray=True)
    binary = image > threshold_otsu(image)

    # ラベリングと領域プロパティの取得
    labels = measure.label(binary)
    props = measure.regionprops(labels)

    # 粒子サイズの取得
    sizes = [prop.area for prop in props]

    # 粒度分布のプロット
    plt.hist(sizes, bins=20)
    plt.title('粒度分布')
    plt.xlabel('粒子サイズ')
    plt.ylabel('頻度')
    plt.show()

    return np.mean(sizes), np.std(sizes)

# 粒度分布解析の実行
image_path = 'material_image.jpg'
mean_size, std_size = analyze_grain_size(image_path)
print(f"平均粒子サイズ: {mean_size:.2f}")
print(f"粒子サイズの標準偏差: {std_size:.2f}")

実行結果では、粒度分布のヒストグラムが表示され、「平均粒子サイズ: 150.25」「粒子サイズの標準偏差: 45.67」のような統計情報が出力されます。

材料科学者は、この情報を基に材料の特性を予測し、最適な製造条件を決定できます。

○サンプルコード20:環境科学でのマイクロプラスチック検出

環境科学の分野では、水中や土壌中のマイクロプラスチックの検出が重要な課題となっています。

画像解析を用いることで、効率的にマイクロプラスチックを検出し、環境汚染の実態を把握できます。

import cv2
import numpy as np
from skimage import measure, color

def detect_microplastics(image_path):
    # 画像の読み込み
    image = cv2.imread(image_path)
    hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

    # 色相に基づくマイクロプラスチックの検出
    lower_bound = np.array([0, 50, 50])
    upper_bound = np.array([10, 255, 255])
    mask = cv2.inRange(hsv, lower_bound, upper_bound)

    # ノイズ除去
    kernel = np.ones((5,5), np.uint8)
    opening = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=2)

    # マイクロプラスチックの計数と面積計算
    labels = measure.label(opening)
    props = measure.regionprops(labels)

    count = len(props)
    total_area = sum(prop.area for prop in props)

    return count, total_area

# マイクロプラスチック検出の実行
image_path = 'water_sample.jpg'
count, area = detect_microplastics(image_path)
print(f"検出されたマイクロプラスチック数: {count}")
print(f"マイクロプラスチックの総面積: {area} ピクセル")

実行結果では、「検出されたマイクロプラスチック数: 56」「マイクロプラスチックの総面積: 12345 ピクセル」のように、サンプル中のマイクロプラスチックに関する情報が表示されます。

環境科学者は、この結果を基に汚染の程度を評価し、対策を立てることができます。

○サンプルコード21:工業製品の品質管理への応用

工業製品の製造過程では、製品の品質を一定に保つことが重要です。

粒子解析技術を用いることで、製品の欠陥や異物を自動的に検出し、品質管理を効率化できます。

import cv2
import numpy as np
from skimage import measure

def quality_control(image_path, defect_threshold):
    # 画像の読み込みとグレースケール変換
    image = cv2.imread(image_path)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # エッジ検出
    edges = cv2.Canny(gray, 50, 150)

    # 欠陥の検出
    contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    defects = []
    for contour in contours:
        area = cv2.contourArea(contour)
        if area > defect_threshold:
            defects.append(contour)

    # 結果の可視化
    result = image.copy()
    cv2.drawContours(result, defects, -1, (0, 0, 255), 2)

    cv2.imshow('Defect Detection', result)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    return len(defects)

# 品質管理の実行
image_path = 'product_image.jpg'
defect_count = quality_control(image_path, defect_threshold=100)
print(f"検出された欠陥数: {defect_count}")

実行結果では、欠陥が赤い輪郭線で強調された画像が表示され、「検出された欠陥数: 3」のように欠陥の数が出力されます。

品質管理者は、この情報を基に製品の合格・不合格を判断し、製造プロセスの改善につなげることができます。

まとめ

Pythonを用いた粒子解析の世界は、まさに無限の可能性を秘めています。

基本的な画像処理から高度な機械学習まで、幅広いテクニックを駆使することで、様々な分野で革新的な成果を上げることができます。

本記事で紹介した21のサンプルコードは、粒子解析の入り口に過ぎません。

実際の応用では、各分野の専門知識と組み合わせることで、より精度の高い、意味のある解析が可能となります。