AI画像エンジニアが挑む!汚れ検知システムの開発と実装
SENSYN ROBOTICS Advent Calendar 2025、18日目を担当します、AIチームの項と申します。普段はAI、特に画像認識技術を使って、お客様の課題を解決する仕事をしています。
今回は、AI画像エンジニアの仕事の一例として、製造業の現場で非常にニーズの高い「汚れ検知」のシステムを開発した際の技術的な道のりをご紹介します。
はじめに:なぜ「汚れ検知」が重要なのか
製造業やインフラメンテナンスの現場では、設備の表面状態をクリーンに保つことが、品質維持や安全稼働の観点から非常に重要です。従来、こうした検査は熟練した作業員の「目視」に頼ってきました。
しかし、目視検査には以下のような課題があります。
- 属人性: 人によって「汚れている」の基準が異なり、評価がばらつく。
- コスト: 検査のために人員を割く必要があり、広範囲の検査には時間がかかる。
- 危険性: 高所や狭所など、人が立ち入るのが危険な場所での検査が難しい。
これらの課題を解決するため、私たちは画像認識AIを用いた自動汚れ検知システムの開発に取り組みました。
課題:そもそも「汚れ」とは何か?
一口に「汚れ」と言っても、その種類は様々です。乾いた粉塵、水に濡れた粉塵、油が付着した粉塵など、現場の環境によって多岐にわたります。
私たちの目標は、これらの多様な汚れを定量的に評価すること。つまり、「少し汚れている」「かなり汚れている」といったレベルを、誰が見ても同じ基準で判断できる仕組みを作ることです。
アプローチ1:色情報(HSV)に基づく検知 - シンプルなれど落とし穴
最初に思いつくのは、「汚れの色」に着目する方法です。汚れは通常、元の設備の表面とは色が異なります。この色の違いを検知するアプローチです。
画像の色空間をRGBからHSV(色相・彩度・明度)に変換することで、照明の明るさ(明度)の影響をある程度分離し、色そのものの違い(色相・彩度)を捉えやすくなります。
import cv2
import numpy as np
# 画像を読み込み
img = cv2.imread("image.jpg")
# RGBからHSVに変換
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 汚れの色の範囲を定義(例:茶色っぽい汚れ)
lower_color = np.array([5, 50, 50])
upper_color = np.array([25, 255, 255])
# 範囲内の色を持つ領域をマスクとして抽出
mask = cv2.inRange(hsv, lower_color, upper_color)
# マスク内の白色ピクセル(汚れ)の数を数える
dirt_pixels = cv2.countNonZero(mask)
print(f"汚れピクセル数: {dirt_pixels}")
この方法はシンプルで実装も簡単ですが、実環境では大きな壁にぶつかりました。「影」です。
暗い影の部分が、油汚れのような「黒っぽい汚れ」として誤検知されてしまうのです。HSVの閾値を厳しくすれば影は減りますが、今度は本当に検知したい汚れまで見逃してしまいます。このトレードオフの関係が、色ベースの手法の限界でした。
アプローチ2:エッジの「鮮明度」に着目する - 発想の転換
色情報だけに頼るのが難しいなら、別の観点が必要です。そこで私たちは、「汚れは、対象物の輪郭をぼやかす」という性質に着目しました。
このアイデアを実証するため、検査対象の設備にあらかじめ白黒のコントラストがはっきりした基準マーカー(ArUcoマーカーなど)を設置します。
- クリーンな状態: マーカーのエッジ(白と黒の境界)はくっきり鮮明。
- 汚れた状態: マーカーが汚れで覆われると、エッジがぼやけて不鮮明になる。
この「エッジの鮮明度」を数値化できれば、汚れの度合いを客観的に評価できるはずです。
どうやって「鮮明度」を測るか?
鍵は「輝度値の分散」です。
- 画像からマーカー部分を切り出します。
- グレースケール画像に変換します。
- エッジ検出処理(例: Canny法)を行い、エッジ周辺のピクセルを取得します。
- これらのピクセルの輝度値(0〜255の値)の分散(または標準偏差)を計算します。
- 鮮明なエッジ(クリーン): ピクセル値が0(黒)と255(白)の両極端に集中するため、輝度値の分散は大きくなります。
- ぼやけたエッジ(汚れている): 中間的なグレーのピクセルが増えるため、輝度値の分散は小さくなります。
この「分散の大小」を汚れの指標とすることで、影のような単なる明るさの変化に惑わされにくい、より安定した検知が可能になりました。
最後の仕上げ:輝度正規化でさらにロバストに
このエッジ鮮明度アプローチも万能ではありません。画像全体が極端に暗い、あるいは明るい環境では、計算される分散値が影響を受けてしまいます。
そこで、最終的な仕上げとして輝度正規化を導入します。具体的には、マーカー部分を切り出した後、その領域の最小輝度値が0、最大輝度値が255になるようにスケーリングします(Min-Max正規化)。
# マーカー領域の画像を `marker_img` とする
# 輝度正規化
normalized_img = cv2.normalize(marker_img, None, 0, 255, cv2.NORM_MINMAX)
# この正規化された画像に対して、エッジ鮮明度の計算を行う
# ...
これにより、撮影時の全体的な照明条件の違いを吸収し、どんな環境でも一貫した基準で汚れレベルを評価できる、非常にロバストなシステムが完成しました。
最終的な処理フロー
- 画像から基準マーカーを検出する。
- マーカー領域を切り出す。
- 切り出した画像に対し、輝度正規化を適用する。
- エッジを検出し、その周辺ピクセルの輝度値の分散を計算する。
- 計算された分散値を閾値と比較し、「クリーン」「軽度の汚れ」「重度の汚れ」のように判定する。
まとめ
本記事では、AI画像エンジニアが「汚れ検知」という課題にどう立ち向かったか、その試行錯誤の過程をご紹介しました。
- シンプルな色ベースの手法からスタートし、その限界を理解する。
- 「汚れがエッジをぼやかす」という新しい観点から、エッジの鮮明度を評価する手法を考案する。
- 輝度正規化によって、照明変動に対するロバスト性を高める。
このように、1つの課題に対して様々なアプローチを試し、それぞれの長所・短所を分析しながら、より良い解決策へと昇華させていくプロセスは、AI開発の面白さであり、醍醐味でもあります。
この記事が、AIや画像認識の世界に興味を持つきっかけになれば幸いです。
明日のSENSYN ROBOTICS Advent Calendar 2025もお楽しみに!

