@skoik

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

画像の中のエッジの端の検出

※同じ質問を
teratail
stackoverflow
にもしております.

解決したいこと

以下のような画像があります.この画像の中心に一番近いエッジの端を検出したいです.

1.png

以下のような赤丸付近の座標を知りたいということです.(誤差は上下左右5ピクセル以内に抑えたいです.)

colored_1.png

発生している問題・エラー

エッジを検出した後の処理.もしくはエッジを検出せずに行う方法.

該当するソースコード

import os
import cv2
import glob
import numpy as np
from PIL import Image

def load_bmp(bmp_file):
    return np.array(Image.open(bmp_file).convert("L")).astype(np.float32)

def save_bmp(matrix, bmp_dir, bmp_name=""):
    uint8_bmp = Image.fromarray(matrix.astype(np.uint8))
    uint8_bmp.save(os.path.join(bmp_dir, bmp_name + ".bmp"))

def save_nor_bmp(matrix, bmp_dir, bmp_name=""):
    nor_bmp = cv2.normalize(matrix, None, 0, 255, cv2.NORM_MINMAX)
    uint8_bmp = Image.fromarray(nor_bmp.astype(np.uint8))
    uint8_bmp.save(os.path.join(bmp_dir, bmp_name + ".bmp"))

cd = os.path.dirname(os.path.abspath(__file__))
bmp_dir = os.path.join(cd, "bmp")
bmp_files = glob.glob(os.path.join(bmp_dir, "*.bmp"))
edge_dir = os.path.join(cd, "edge")

itera = 0
for bmp_file in bmp_files:
    bmp = load_bmp(bmp_file)
    uint8_bmp = np.uint8(bmp)
    
    edges = cv2.Canny(uint8_bmp, 900, 1000)
    nor_edges = cv2.normalize(edges, None, 0, 1, cv2.NORM_MINMAX)
    kernel = np.ones((3, 3), np.uint8)
    dilated_edges = cv2.dilate(nor_edges.astype(np.uint8), kernel, iterations=1)

    save_nor_bmp(dilated_edges, edge_dir, "edge_image"+str(itera+1))

    itera += 1

自分で試したこと

現在はopenCVのCanny関数によりエッジを検出し,その後見やすくするために同じくopenCVのdilate関数によって線を太くしています.
個人的に調べてはいるものの,どれもエッジの検出までしか行っていませんでした.
なにかアルゴリズム・アイデア等があれば教えていただきたいです.

edge_image1.png

0 likes

2Answer

次は、以下の4種類のパターンを探すでしょうか。その後、どのedgeは中心に近いか算出するかと思います。
image.png

0Like

検出したい点がどのような特徴があるのか、他の点とどのように区別できるのかという視点で考えてみましょう。
例えば一例ですが今回の画像の場合は、
検出したい点は周りに黒から白までの色が満遍なく存在しますね。
この特徴はノイズが多い画像ではあらゆる点が満たしますが、今回のようなノイズが少ない画像であれば他の点には存在しない(あるいは他の点より強い)特徴です。
このような情報の偏りのなさ、複雑さを図る指標としてエントロピーが挙げられます。
そしてPythonでは局所的なエントロピーを簡単に計算できる関数が用意されたライブラリも存在しています。
以下はAIにこのアイデアをベースに書いてもらったサンプルプログラムになります。

import os
import cv2
import glob
import numpy as np
from PIL import Image
# scikit-imageのインポート
from skimage.filters.rank import entropy
from skimage.morphology import disk

# --- 定義済み関数 ---

def load_bmp(bmp_file):
    # グレースケールで読み込み、float32に変換
    return np.array(Image.open(bmp_file).convert("L")).astype(np.float32)

def save_bmp(matrix, bmp_dir, bmp_name=""):
    # そのままuint8で保存
    uint8_bmp = Image.fromarray(matrix.astype(np.uint8))
    uint8_bmp.save(os.path.join(bmp_dir, bmp_name + ".bmp"))

def save_nor_bmp(matrix, bmp_dir, bmp_name=""):
    # 0-255に正規化してuint8で保存
    nor_bmp = cv2.normalize(matrix, None, 0, 255, cv2.NORM_MINMAX)
    uint8_bmp = Image.fromarray(nor_bmp.astype(np.uint8))
    uint8_bmp.save(os.path.join(bmp_dir, bmp_name + ".bmp"))

# --- パス設定 ---

cd = os.path.dirname(os.path.abspath(__file__))
bmp_dir = os.path.join(cd, "bmp")
bmp_files = glob.glob(os.path.join(bmp_dir, "*.bmp"))
edge_dir = os.path.join(cd, "edge")
# エントロピー画像保存ディレクトリ
entropy_dir = os.path.join(cd, "entropy")
os.makedirs(entropy_dir, exist_ok=True) 

# 局所エントロピー計算のための構造要素(半径9の円)
# 処理の高速化のため、ループ外で定義
entropy_footprint = disk(9)

itera = 0
for bmp_file in bmp_files:
    # 画像読み込み
    bmp = load_bmp(bmp_file)
    # Cannyやskimage.entropyのためにuint8に変換
    uint8_bmp = np.uint8(bmp)
    
    # 局所エントロピーの計算
    entropy_map = entropy(uint8_bmp, entropy_footprint)
    
    # エントロピー画像を正規化して保存
    save_nor_bmp(entropy_map, entropy_dir, "entropy_image_"+str(itera+1))
    
    # Cannyエッジ検出
    edges = cv2.Canny(uint8_bmp, 900, 1000)
    # エッジを0-1に正規化
    nor_edges = cv2.normalize(edges, None, 0, 1, cv2.NORM_MINMAX)
    kernel = np.ones((3, 3), np.uint8)
    # 膨張処理
    dilated_edges = cv2.dilate(nor_edges.astype(np.uint8), kernel, iterations=1)

    # 膨張済みエッジ画像を保存
    save_nor_bmp(dilated_edges, edge_dir, "edge_image"+str(itera+1))

    itera += 1

そしてその出力がこちらです。
image.png

後は極大値を探す実装を加えればよいでしょう。サブピクセルの精度に挑戦するのであればパラボラフィッティングなども加えてみてください。
現在ではもととなるアイデアさえあればそれほど複雑でない実装はAIが行ってくれるので大変便利ですね。

0Like

Your answer might help someone💌