注釈
こんにちは、SunFounder Raspberry Pi & Arduino & ESP32 Enthusiast Community on Facebookへようこそ!他の愛好家と一緒に、Raspberry Pi、Arduino、ESP32の世界により深く入り込みましょう。
参加する理由
専門家サポート: 購入後の問題や技術的な課題を、コミュニティと私たちのチームの助けを借りて解決します。
学習と共有: ヒントやチュートリアルを交換して、スキルを向上させましょう。
限定プレビュー: 新製品の発表や先行プレビューに早期アクセスできます。
特別割引: 最新製品を特別割引でお楽しみいただけます。
季節限定キャンペーンとプレゼント: プレゼント企画やホリデーキャンペーンに参加しましょう。
👉 一緒に発見し、創造する準備はできましたか? [こちら] をクリックして、今すぐ参加しましょう!
7. Canny エッジ検出
この章では、Raspberry Pi + Picamera2 を使ってリアルタイム動画を取得し、OpenCV の Canny アルゴリズム によるエッジ検出を行います。 エッジ検出はコンピュータビジョンの基本処理のひとつであり、Canny アルゴリズムは安定性が高く、ノイズにも強い手法として広く知られています。
1. Canny アルゴリズムは何をするのか?
画像における エッジ とは、通常、濃度(グレースケール値)が大きく変化する位置を指します。たとえば:
物体の輪郭
明るい領域と暗い領域の境界
構造を表すエッジ線
Canny エッジ検出の目的は、次のとおりです:
不要な干渉を抑えながら、 エッジ情報を正確に抽出する こと
後続の 輪郭検出 、 物体分割 、 幾何形状認識 (たとえば円や長方形の検出)のための信頼できる基盤を提供すること
ロボットビジョンでは、 経路検出 や 障害物認識 によく利用されること
2. コードの実行
重要
開始する前に、次の項目を確認してください:
パンチルトが組み立てられている
Raspberry Pi のデスクトップにアクセスできる
コードパッケージがインストールされている
Fusion HAT+ がインストールされ、設定されている
OpenCV がインストールされている
詳細については 0. OpenCV のセットアップ を参照してください。
ターミナルを開き、次のコマンドを入力します:
cd ~/ai-lab-kit/opencv_python python3 cv_7_canny.py
Tip
動画ファイルを処理するための
cv_7_canny_video.pyと、リアルタイム映像と動画を組み合わせて表示するcv_7_canny_conbine.pyも用意しています。プログラムを実行すると、次の 2 つの OpenCV ウィンドウが表示されます:
Camera – ライブカメラ映像を表示
Canny Edges – 検出されたエッジをリアルタイムで表示
トラックバーを使ってエッジ検出のしきい値を調整できます。 q キーを押すか、いずれかのウィンドウを閉じると終了します。
3. 完全なコード
from picamera2 import Picamera2
import cv2
# Empty callback function for trackbars (required by OpenCV API)
def _noop(x):
pass
# -----------------------------
# Camera setup
# -----------------------------
picam2 = Picamera2()
# Create a preview configuration:
# size: resolution of the camera image
# format: XRGB8888 (4-channel image, similar to BGRA)
picam2.configure(
picam2.create_preview_configuration(
main={"size": (640, 480), "format": "XRGB8888"}
)
)
# Start the camera
picam2.start()
# -----------------------------
# Create OpenCV windows
# -----------------------------
WIN_CAM = "Camera" # window for original image
WIN_EDGE = "Canny Edges" # window for edge detection result
cv2.namedWindow(WIN_CAM)
cv2.namedWindow(WIN_EDGE)
# -----------------------------
# Create trackbars to tune Canny thresholds
# -----------------------------
# low_th: lower threshold for Canny
# high_th: higher threshold for Canny
cv2.createTrackbar("low_th", WIN_EDGE, 50, 255, _noop)
cv2.createTrackbar("high_th", WIN_EDGE, 150, 255, _noop)
print("Press 'q' to exit")
# -----------------------------
# Main loop
# -----------------------------
while True:
# Capture one frame from the camera (BGRA format)
frame_bgra = picam2.capture_array()
# Convert BGRA to BGR for OpenCV processing
frame_bgr = cv2.cvtColor(frame_bgra, cv2.COLOR_BGRA2BGR)
# Convert the frame to grayscale
gray = cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2GRAY)
# Apply Gaussian blur to reduce noise
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# Read current threshold values from trackbars
low_th = cv2.getTrackbarPos("low_th", WIN_EDGE)
high_th = cv2.getTrackbarPos("high_th", WIN_EDGE)
# Ensure high_th is always larger than low_th
if high_th <= low_th:
high_th = low_th + 1
cv2.setTrackbarPos("high_th", WIN_EDGE, high_th)
# Perform Canny edge detection
edges = cv2.Canny(blurred, low_th, high_th)
# Show original camera image
cv2.imshow(WIN_CAM, frame_bgr)
# Show edge detection result
cv2.imshow(WIN_EDGE, edges)
# Process GUI events and keyboard input
key = cv2.waitKey(1) & 0xFF
# Press 'q' to exit the program
if key == ord("q"):
break
# Exit if the user closes any OpenCV window
if (cv2.getWindowProperty(WIN_CAM, cv2.WND_PROP_VISIBLE) < 1 or
cv2.getWindowProperty(WIN_EDGE, cv2.WND_PROP_VISIBLE) < 1):
break
# -----------------------------
# Cleanup
# -----------------------------
picam2.stop() # Stop the camera
cv2.destroyAllWindows() # Close all OpenCV windows
4. コード解説
トラックバー用のコールバック関数を定義する:
def _noop(x): pass
OpenCV のトラックバーにはコールバック関数が必要です。 今回は特に処理を行わないため、空の関数で十分です。
Picamera2 を初期化し、プレビュー形式を設定する:
picam2 = Picamera2() picam2.configure( picam2.create_preview_configuration( main={"size": (640, 480), "format": "XRGB8888"} ) ) picam2.start()
これにより、Raspberry Pi カメラが 640×480 で起動します。
XRGB8888は 4 チャンネル形式なので、取得されるフレームは BGRA ライクな形式になります。2 つの OpenCV ウィンドウを作成する:
WIN_CAM = "Camera" WIN_EDGE = "Canny Edges" cv2.namedWindow(WIN_CAM) cv2.namedWindow(WIN_EDGE)
ひとつのウィンドウには元のカメラ画像を表示し、もうひとつには Canny の結果を表示します。
Canny のしきい値をリアルタイム調整するためのトラックバーを作成する:
cv2.createTrackbar("low_th", WIN_EDGE, 50, 255, _noop) cv2.createTrackbar("high_th", WIN_EDGE, 150, 255, _noop)
low_th: Canny の低しきい値high_th: Canny の高しきい値
これらのスライダーを動かすことで、エッジ検出の感度を調整できます。
フレームを取得し、OpenCV 処理用に変換する:
frame_bgra = picam2.capture_array() frame_bgr = cv2.cvtColor(frame_bgra, cv2.COLOR_BGRA2BGR)
カメラ出力は 4 チャンネルのため、標準的な 3 チャンネル BGR 形式へ変換します。
グレースケール化し、画像をぼかす:
gray = cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (5, 5), 0)
Canny はグレースケール画像に対して動作します。
Gaussian blur はノイズを低減し、不要な偽エッジが出すぎるのを防ぎます。
トラックバーの値を読み取り、妥当な状態に保つ:
low_th = cv2.getTrackbarPos("low_th", WIN_EDGE) high_th = cv2.getTrackbarPos("high_th", WIN_EDGE) if high_th <= low_th: high_th = low_th + 1 cv2.setTrackbarPos("high_th", WIN_EDGE, high_th)
Canny では
high_thがlow_thより大きい必要があります。 この処理では、ユーザーが値を近づけすぎた場合でも、自動的に補正します。Canny エッジ検出を実行する:
edges = cv2.Canny(blurred, low_th, high_th)
Canny は画像中の強いエッジを強調して抽出します。 しきい値を低くするとエッジは多く検出されますが、ノイズも増えやすくなります。
2 つのウィンドウを表示する:
cv2.imshow(WIN_CAM, frame_bgr) cv2.imshow(WIN_EDGE, edges)
一方のウィンドウにはライブカメラ映像を表示し、もう一方には検出されたエッジを表示します。
終了条件(
qキーまたはウィンドウを閉じる):key = cv2.waitKey(1) & 0xFF if key == ord("q"): break if (cv2.getWindowProperty(WIN_CAM, cv2.WND_PROP_VISIBLE) < 1 or cv2.getWindowProperty(WIN_EDGE, cv2.WND_PROP_VISIBLE) < 1): break
初学者でも、キーボード操作とウィンドウのクローズの 2 通りで停止できるようになっています。
後片付け:
picam2.stop() cv2.destroyAllWindows()
リソースを解放するため、最後に必ずカメラを停止し、OpenCV のウィンドウをすべて閉じてください。
5. なぜ Canny は有用なのか?
Canny の出力は、その後のビジョンタスクに非常に適しています:
Application |
Description |
|---|---|
Contour detection |
|
Object segmentation |
エッジを手がかりとして、ターゲットと背景を分離できる |
Shape recognition |
Hough 変換と組み合わせて、円や直線などを検出できる |
Robot navigation |
地面、道路、障害物の輪郭を検出して経路計画を支援できる |
OCR / Target localization |
文字領域、QR コード、マーカーなどは明確なエッジ特徴を持つことが多い |
Canny は単に「見た目が面白い」処理ではなく、より広い CV パイプラインへの 入口 となる重要な処理です。
6. しきい値選択のヒント
Scenario |
low_th |
high_th |
Notes |
|---|---|---|---|
安定した室内照明 |
50 |
150 |
一般的なケースで、安定した結果が得られる |
強い照明・高コントラスト |
100 |
200 |
偽エッジを減らすため、しきい値を高めに設定する |
暗所・ノイズが多い環境 |
30 |
100 |
より多くのディテールを残すため、しきい値を低めにする |
非常にぼやけたエッジ |
20 |
80 |
さらに低く設定して、エッジに対する感度を上げる |
トラックバーを使って適切な範囲をすばやく調整し、その後プログラム内に固定値として書き込むとよいでしょう。
7. 発展練習
cv2.findContoursを Canny の出力に適用して、物体の輪郭を描いてみましょう。Gaussian カーネルのサイズを変更して、エッジ精度がどう変化するか観察してみましょう。
明るい環境と暗い環境で異なるしきい値を試し、ダブルしきい値の効果を理解してみましょう。
cv2.HoughLines(直線)やcv2.HoughCircles(円)と組み合わせて、エッジ画像から図形検出を行ってみましょう。