今回は画像の輪郭抽出を行ったのち、その輪郭のConvex Hull(凸包)まで一気に処理せんとの野望あり。というか処理例がそうなっていただけのことなのですが凸包いけませぬ。毎度の処理例途中でのエラー、いろいろ突いてみるもなんともはや動きませぬ。元より素人、分かっておらんからの~。そこで手前の輪郭抽出でお茶を濁しました。
※「手習ひデジタル信号処理」投稿順 Indexはこちら
※Windows11上の Scilab2024.0.0およびScilab上のScilab IPCVツールボックスを使用させていただいております。
Structural Analysis and Shape Descriptors
今回は、Structural Analysis and Shape Descriptors というタイトルのもとにまとめられているセクションを練習してみん、との希望であります。HELPファイルを見ると以下の3関数の記載があります。
-
- imconvexHull — Finds the convex hull of a point set.
- imdrawcontours — Draw contours from the contour image.
- imfindcontours — Finds contours in a binary image.
段取りとしては、まず imfindcontours関数 で「輪郭」を抽出し、そこから得られたデータについて imconvexHull 関数を使って「凸包」を計算する形です。ま、途中の輪郭についてimdrawcontours関数でも適用して輪郭も描画してやれば1撃でセクション完了でないかと素人老人の目論見です。
しかし、 imconvexHull 関数のHelpファイル記載の処理例を実行した時点で目論見は脆くも潰えました。
imfindcontours関数自体はエラーなく実行可能だったのですが、その結果を処理するところで「お約束の」エラー。今回も「押したり引いたりすれば」動くかといろいろやってみたのですが末尾まで「完走」できませぬ。その上、肝心の imconvexHull 関数について以下の疑問点もあがって参りました。
Sklansky’s algorithm.
Helpファイルを参照すると、imconvexHull 関数は上記のアルゴリズム(噂によるとシンプルで美しいらしいです)を採用しているとのことですが、このアルゴリズムだとすると
ただしい凸包が得られないケースがある
らしいです。Convex Hullのアルゴリズムとその歴史については、カナダ『McGill大』様の以下のページに詳しいです。
A History of Linear-time Convex Hull Algorithms for Simple Polygons
そして上記ページを拝見すると Sklansky 様の2つのアルゴリズムの両方に、
Incorrect
と記されておるのです。キビシー。Sklansky 様はConvex Hullアルゴリズム研究の初期に活躍され、シンプルで美しいアルゴリズムを見つけたものの、正しくなかった、ということみたいです。知らんけど。
IPCVの輪郭抽出関係関数
Helpファイルには輪郭抽出関係で以下の2関数がリストされてます。
-
- imdrawContours
- imfindContours
これまたScilabにアリガチなあるあるですが、Helpファイルには見当たらない(けれど使用可能な)以下2関数も存在してます。
-
- implotContours
- imcontour2label
今回は、上記の4関数を使って「輪郭抽出とそのプロット」を練習してお茶を濁すことにいたしました。
今回の処理例とその結果
素人老人が動かせた部分をツギハギした処理例コードが以下に。
S = imread(fullpath(getIPCVpath() + "/images/hand.jpg")); Sbw = im2bw(~S,0.5); Sc = imfindContours(Sbw); Slabel = imcontour2label(S,Sc); So = imdrawContours(Slabel); scf(0); clf; subplot(151); title('Original'); imshow(S); subplot(152); title('im2bw'); imshow(Sbw); subplot(153); title('imfindContours'); plot(Sc(1)(:,1),Sc(1)(:,2)); subplot(154); title('implotContours'); implotContours(S,Sc,5); subplot(155); title('imdrawContours'); imshow(im2uint8(So));
真ん中のplotの上下が逆転しているのは、画像そのものではなく、imfindContours関数が返してきた座標点を、plot関数を使ってXYプロットしているためです。なお、今回の入力画像に対して、imfindContours関数は、2つの輪郭を抽出してまとめて返してくれるので Sc(1)のように最初のオブジェクトを抽出してプロットしてます。またSc(2)は親指の付け根のとこにある「光の加減」で見えてるらしいポッチなオブジェクトでした。
その辺が分かり易いのが、implotContours関数で、元画像に重ねて輪郭線を表示できます。便利なんだけれどもHelpファイルに使い方の記載がないです。トホホ。