ラベリングした縞画像​の最小平均縞間隔を求​められる様な関数はあ​りますか?

はじめまして、今井と申します。
Matlabは初心者のため、皆様のお知恵を拝借させていただきたく、投稿させていただきます。
現在この様な縞画像の「縞の間隔」と「縞の移動速度」を求める為に、プログラムを作製しています。
画像は一定間隔毎に撮影しており時系列データとなっていますが、まずはテスト段階のため1枚で試しています。
お伺いしたい点は
1.ラベリングした縞(線)の最小平均縞間隔を求める関数として、なにか適切なものはあるのか?
2.ラベリングした縞(線)の距離を測る以外で、この「縞の間隔」と「縞の移動速度」を求めるには、どの様な手法が考えられるか?
3.例えば、円柱に貼り付けたシールをMATLAB上で平面化することは可能か?
以下詳細です。
まず参考として「MATLAB画像処理入門―使い方の基本から、画像処理まで (I・O BOOKS) 高井 信勝著」に掲載されている
「第7章 「指紋」の「稜線解析」」をそのまま打ち込んだところ、無事に最小平均縞間隔は算出できましたが、
この380×288pxの画像で処理に1時間近くかかり、非常に効率が悪い点が問題となっています。
現在の環境は
MATLAB・Image Processing Toolbox:R2014b
ですが、プログラムの各処理部分に対して調査したところ、
最新のMATLABには一部が関数として用意されているため、もう少し早く処理が可能かと考えております。
具体的には
画像輝度均一化:imflatfield
画像2値化:imbinarize
細線化&クリーニング:bwskel
ラベリング:bwconncomp labelmatrix
線の最小平均縞間隔算出
なのですが、ここの部分を私は関数で見つけられませんでしたので、もし適切な関数があれば教えてください。
またこの様な方法以外に、「縞の間隔」と「縞の移動速度」を求める手法がありましたら、合わせてご教示ください。
一応、線の最小平均縞間隔算出プログラム部分の抜粋を掲載しておきます。
%線間隔と方位データの算出
[M,N]=size(LaYpart)
distance=[] %(m0,n0)から最小距離(大きさ)を納める初期配列(空ベクトル)
angle=[] %線方位角を納める初期配列(空ベクトル)
for m0=1:M
for n0=1:N
if LaYpart(m0,n0)~=0
dis=[] %(m,n)の画素からの画素間距離(初期の空ベクトル)
for m=1:M
for n=1:N
if LaYpart(m,n)~=0 && LaYpart(m,n)~=LaYpart(m0,n0)
dis=[dis, sqrt((m-m0)^2+(n-n0)^2)] %異なる連結成分の距離データ
end
end
end
min_dis=min(dis) %最小距離
distance=[distance,min_dis] %画素(m0,n0)からの最小画素間距離の集合「d」
%最小距離の方位
for m=1:M
for n=1:N
if LaYpart(m,n)~=0 && LaYpart(m,n)~=LaYpart(m0,n0)
dis12=sqrt((m0-m)^2+(n0-n)^2)
if dis12==min_dis
ang=atan((n0-n)/(m0-m))
break
end
end
end
end
angle=[angle,ang] %画素(m0,n0)からの最小画素間距離の角度「θ」
end
end
end
最後の質問ですが、この縞は曲面にできています。
そこで、予めチェッカーの様なキャリブレーションシールを曲面に貼り付けて撮影し、
その後画角を変えずに連続撮影した際、最初のキャリブレーション画像を用いて、
平面に伸ばしたような画像に変換することは可能でしょうか???
もしくは、実際には画像を平面化処理しなくても、キャリブレーションの値だけ持ち越して、
上記の縞間隔や縞移動速度算出に反映できるでも構いません。
それでは、よろしくお願いいたします。

 採用された回答

Atsushi Ueno
Atsushi Ueno 2022 年 6 月 23 日
編集済み: Atsushi Ueno 2022 年 6 月 25 日

1 投票

I = imread('image1.png'); %【画像変更済】
I = rgb2gray(I); % グレースケール化
%I = imflatfield(I,20); % 画像輝度均一化 % 処理しない方が連結要素の認識結果が良かった
I = imbinarize(I); % 画像2値化
I = bwskel(I); % 細線化&クリーニング
CC = bwconncomp(I) % 連結要素を得る
CC = struct with fields:
Connectivity: 8 ImageSize: [194 144] NumObjects: 9 PixelIdxList: {[142×1 double] [138×1 double] [139×1 double] [138×1 double] [133×1 double] [131×1 double] [139×1 double] [130×1 double] [124×1 double]}
%%
% 線の最小平均縞間隔算出 %線間隔と方位データの算出
distance = []; % (m0,n0)から最小距離(大きさ)を納める初期配列(空ベクトル)
angle = []; % 線方位角を納める初期配列(空ベクトル)
idx = 1;
for PxIdx1 = CC.PixelIdxList % 連結要素を全て走査
for p1 = PxIdx1{:}' % 連結要素内の画素インデックスを走査
dis = []; % (m,n)の画素からの画素間距離(初期の空ベクトル
ang = []; % (m,n)の画素からの画素間角度
for PxIdx2 = CC.PixelIdxList([1:idx-1 idx+1:end]) % 現在の連結要素以外を走査【誤記修正済】
for p2 = PxIdx2{:}' % 比較する連結要素内の画素インデックスを走査
[row1,col1] = ind2sub(CC.ImageSize,p1); % 線形インデックスを座標に変換
[row2,col2] = ind2sub(CC.ImageSize,p2); % 線形インデックスを座標に変換
dis(end+1) = hypot(row1-row2,col1-col2); % 画素間距離
ang(end+1) = atan2(row1-row2,col1-col2); % 画素間距離の角度
end
end
min_dis = min(dis);
distance = [distance, min_dis];
angle = [angle, ang(dis == min_dis)]; % 最小画素間距離の角度「θ」
end
idx = idx + 1;
end
plot(distance);
Image Processing Toolboxにありそうですが、良さげな関数が見つからないです。絶対に何かあると思います。
もしくは画素同士の総当たりを避けられるような効率の良いアルゴリズムの検討が必要です。
質問のプログラムを改良しました。画素同士の総当たりである点は同じですが、無駄な計算を無くしています。
【計算量を減らすための改善点】
  • ラベル行列 LaYpart を作らず bwconncomp 構造体内の分類済座標を使う
  • 連結要素(縞)の座標だけ走査する(全画素の走査が不要になる)
  • 同一連結要素(縞)同士の座標は比較しない(座標の一致判定が不要になる)
  • 連結要素同士の総当たりリーグを上三角だけにする(縞同士で二試合繰り返さない)←【誤記です】
  • 画素間距離の角度を得る為に画素間距離を計算し直さない(同じ演算処理を繰り返さない)
最小の画素間距離リストをグラフにすると、見た目に縞の間隔が判ります。質問の画像内に縞は16本見えますが、bwconncomp関数の出力(連結要素数)は24です。つまり二値化の際に縞が分割されてしまっています。最初の画像輝度均一化や二値化処理も試行錯誤しないと綺麗な結果にはならないようです。あと画素間距離と画素間距離の角度は数が一致しません(同一の画素間距離が重複する場合がある為)。
まだまだ改良が必要です(もう寝る)

9 件のコメント

竜彦 今井
竜彦 今井 2022 年 6 月 23 日
Ueno様
深夜にご回答いただき、ありがとうございました。
また計算量軽減の為にプログラムも改良していただけたということで、重ねてお礼申し上げます。
MATLABには明るくありませんが、私もなにか良さそうな関数があるはずと思い質問させていただいた次第でした。
距離の解析に時間がかかるのは、画素を総当りで処理しているからなのですね。
なお私が試した際には、画像2枚目にある通り画像の左上の縞がきれいな部分を取り出したので、画像とラベリング数がうまく一致したかと考えています。
画像右側にある少し縞が歪んだ部分の影響とは思いますが、bwconncomp関数の出力がうまく行かない場合があるということで、ここはもともとの縞画像がキレイに撮影されている必要があるということで勉強になりました。
一応私が行った解析範囲と同じくらいの位置にカットした画像も添付しておきますので、よろしければ検証用にお使いください。
検討していただいた改善点はパッと読んでもまだ理解ができていないので、明日私の方でも実際に動かしてどの様な挙動となるのか確認してみたいと思います。
ちなみに画素間距離角度については、参考にしていた書籍に記載されていたのでそのままコピーしましたが、実際には不要で、必要なのは最短平均距離となります。
私もそろそろ休みたいと思います。改めて、ありがとうございました!
Atsushi Ueno
Atsushi Ueno 2022 年 6 月 25 日
【解説】bwconncomp関数の出力CCの内、下記の情報を利用しています。認識された縞の画素だけを走査出来ますし、縞ごとに区別されているので探す効率も良くなります。(今回の場合ラベル行列の生成は不要)
  • ImageSize:入力画像のサイズ(縦画素数, 横画素数)
  • NumObjects:認識された連結要素(縞)の数
  • PixelIdxList:各連結要素(縞)を構成する画素の座標(線形インデックス)のベクトルcell配列
【その他】回答のプログラムに誤りがありました。最小画素間距離をグラフで表示した際に最後の方の最小画素間距離が大きくなっているのはこのバグの為です。縞画像を変更すると共に修正しておきます。
【誤】連結要素同士の総当たりリーグを上三角だけにする(縞同士で二試合繰り返さない)
【正】連結要素同士の総当たりリーグにする
%【誤】for PxIdx2 = CC.PixelIdxList(idx+1:end) % 現在の連結要素以降を走査
%【正】for PxIdx2 = CC.PixelIdxList([1:idx-1 idx+1:end]) % 現在の連結要素以外を走査
Atsushi Ueno
Atsushi Ueno 2022 年 6 月 25 日
回答内容を改良しました。画素間距離角度については不要との事だったので削除しました。
【計算量を減らすための改善点】
  • (追記)「for文の使用」から「ベクトル/行列データとMATLAB関数の使用」に変える
I = imread('image1.png'); %【画像変更済】
I = rgb2gray(I); % グレースケール化
%I = imflatfield(I,20); % 画像輝度均一化 % 処理しない方が連結要素の認識結果が良かった
I = imbinarize(I); % 画像2値化
I = bwskel(I); % 細線化&クリーニング
CC = bwconncomp(I); % 連結要素を得る
%%
% 線の最小平均縞間隔算出
distance = []; % 各縞の全ての点から他の縞への最小距離を納める初期配列(空ベクトル)
idx = 1;
for PxIdx1 = CC.PixelIdxList % 連結要素を全て走査
[row1,col1] = ind2sub(CC.ImageSize,PxIdx1{:}'); % 線形インデックスを座標に変換
min_dis = []; % 連結要素(縞1本分)の最小画素間距離(初期の空ベクトル)
for PxIdx2 = CC.PixelIdxList([1:idx-1 idx+1:end]) % 現在の連結要素以外を走査【誤記修正済】
[row2,col2] = ind2sub(CC.ImageSize,PxIdx2{:}); % 線形インデックスを座標に変換
dis = hypot(row1-row2,col1-col2); % 縞1本から他の縞1本への距離を計算
min_dis = [min_dis; min(dis,[],1)]; % 縞1本の各画素の「他の縞1本への最短距離」を格納
end
distance = [distance, min(min_dis,[],1)]; % 縞1本の各画素の「他の縞への最短距離」を格納
idx = idx + 1;
end
mean(distance) % 線の最小平均縞間隔
ans = 21.8098
plot(distance); % 全縞の各画素から他の縞への最短距離を表示。この平均が上記になる
竜彦 今井
竜彦 今井 2022 年 6 月 26 日
Ueno様
お世話になっております。今井です。
細かな解説とともにさらなる改良を施していただけたということで、本当にありがとうございます!!
ちょっと週末出てしまっているので、戻り次第確認させていただきます。
取り急ぎ、お礼のご連絡とさせていただきます!!
竜彦 今井
竜彦 今井 2022 年 6 月 27 日
Ueno様
お世話になっております。今井です。
戻りましたので早速確認させていただこうと思ったのですが、bwconncompの値が必要なのですね…
当方未だR2014bのため検証することはできませんが、実現可能というところまで確認できたことは非常に価値ある結果をいただきました。
早急にR2022aを導入する準備をしたいと思います。
ちなみになのですが、一番最初に私が提示したプログラム(総当りで検証)と比較すると、おおよそでいいのですがどれ位処理速度は向上されましたでしょうか???
ぜひ参考にお聞かせいただければと思います。
よろしくお願いいたします。
Atsushi Ueno
Atsushi Ueno 2022 年 6 月 28 日
>bwconncompの値が必要なのですね…当方未だR2014bのため検証することはできませんが
MATLAB・Image Processing Toolbox:R2014bでも試行錯誤で動かせます。取り敢えず前半を下記の様に変更してみました。R2014b当時のImage Processing Toolboxでも完成されたソフトウェア群なので、R2022aのより古い関数でも目的の画像処理は可能だと思います。
  • imflatfield: R2018b で導入 ⇒ 無くても取り敢えず動く
  • imbinarize: R2016a で導入 ⇒ 取り敢えずI = I > mean(mean(I));とかでも2値化出来る
  • bwskel: R2018a で導入  ⇒ I = bwmorph(I,'thin',Inf);でも何とかなる
  • bwconncomp: R2009a で導入 ⇒ MATLAB・Image Processing Toolbox:R2014bで動く
I = imread('image1.png'); %【画像変更済】
I = rgb2gray(I); % グレースケール化
%I = imflatfield(I,20); % 画像輝度均一化 % 処理しない方が連結要素の認識結果が良かった
I = I > mean(mean(I));% I = imbinarize(I); % 画像2値化
I = bwmorph(I,'thin',Inf); % I = bwskel(I); % 細線化&クリーニング
CC = bwconncomp(I); % 連結要素を得る
imshow(I)
>一番最初に私が提示したプログラム(総当りで検証)と比較すると、おおよそでいいのですがどれ位処理速度は向上されましたでしょうか???
私は全てこの場で検証しています。(MATLAB Answers上で動くMATLAB Onlineを使ってます)。一番最初に提示されたプログラムはエラー(55秒で時間切れ)になってしまいました。なので少なくとも55秒間は掛かります。自分が提案したプログラムのfor文前後にtic/tocを書いて測定すると下記の結果となりました。
回答のfor文4重のプログラム:Elapsed time is 0.913183 seconds.
コメントのfor文2重のプログラム:Elapsed time is 0.026571 seconds.
竜彦 今井
竜彦 今井 2022 年 6 月 28 日
Ueno様
失礼いたしました、私の調べ方が悪くてR2014bにはbwconncompが搭載されていないと勘違いをしておりました。
(関数の搭載されたバージョンは私の方でももう一度調べてみます。)
また具体的な計算速度もご提示いただきありがとうございました。
一番計算負荷の高かった距離計算部分がだいぶ早くなるだけでも十分意味があるため、非常に助かります。
さて、早速ご返答いただいたプログラムを合体させて私のPC環境で試してみたのですが、1点だけエラーが出てしまうようです。
一方で、私もこの投稿を書きながらMATLAB Answers上で動くMATLAB Onlineで実行してみたところ、こちらではエラーは出ませんでした。
内容は以下のとおりです↓
エラー: -
行列の次元は一致しなければなりません。
エラー: test (line 15)
dis = hypot(row1-row2,col1-col2); % 縞1本から他の縞1本への距離を計算
プログラムはこの様に記載しました。
I = imread('image1.png'); %【画像変更済】
I = rgb2gray(I); % グレースケール化
%I = imflatfield(I,20); % 画像輝度均一化 % 処理しない方が連結要素の認識結果が良かった
I = I > mean(mean(I));% I = imbinarize(I); % 画像2値化
I = bwmorph(I,'thin',Inf); % I = bwskel(I); % 細線化&クリーニング
CC = bwconncomp(I); % 連結要素を得る
imshow(I)
%%
% 線の最小平均縞間隔算出
distance = []; % 各縞の全ての点から他の縞への最小距離を納める初期配列(空ベクトル)
idx = 1;
for PxIdx1 = CC.PixelIdxList % 連結要素を全て走査
[row1,col1] = ind2sub(CC.ImageSize,PxIdx1{:}'); % 線形インデックスを座標に変換
min_dis = []; % 連結要素(縞1本分)の最小画素間距離(初期の空ベクトル)
for PxIdx2 = CC.PixelIdxList([1:idx-1 idx+1:end]) % 現在の連結要素以外を走査【誤記修正済】
[row2,col2] = ind2sub(CC.ImageSize,PxIdx2{:}); % 線形インデックスを座標に変換
dis = hypot(row1-row2,col1-col2); % 縞1本から他の縞1本への距離を計算
min_dis = [min_dis; min(dis,[],1)]; % 縞1本の各画素の「他の縞1本への最短距離」を格納
end
distance = [distance, min(min_dis,[],1)]; % 縞1本の各画素の「他の縞への最短距離」を格納
idx = idx + 1;
end
mean(distance) % 線の最小平均縞間隔
plot(distance);
私の方でも考えてみましたが、確かにcol1・col2・row1・row2それぞれが形とサイズが違うようです。
せっかく丁寧に作製していただいたところなので、ぜひこちらも解決のヒントをいただければ幸いです。
度々申し訳ございませんが、ご教示のほどよろしくお願いいたします。
Atsushi Ueno
Atsushi Ueno 2022 年 6 月 29 日
編集済み: Atsushi Ueno 2022 年 6 月 29 日
おっとこれはすいません。結論から申し上げますと、下記を修正すればエラーは解消します。
dis = hypot( row1-row2, col1-col2 ); % 【変更前】% 縞1本から他の縞1本への距離を計算
dis = hypot(bsxfun(@minus,row1,row2),bsxfun(@minus,col1,col2)); % 【変更後】% 縞1本から他の縞1本への距離を計算
【解説】下記ポイントを把握せずbsxfun関数を使い、下記の"算術展開(arithmetic expands)"を実行しました。R2016b以降では下記のa+bで済みますが、それ以前ではbsxfun(@plus,a,b)とする必要があり、その為エラーが出てしまっています。
% MATLAB® R2016b 以降では、bsxfun の代わりに演算子を直接使用できます。
% これは、互換性のあるサイズの配列の暗黙的な拡張を演算子が個別にサポートしているためです。
a = [1 2 3 4]
a = 1×4
1 2 3 4
b = [5; 6; 7]
b = 3×1
5 6 7
a + b % R2016b以降では下記bsxfun関数と同じ動き。R2016bより前のバージョンではエラーになる
ans = 3×4
6 7 8 9 7 8 9 10 8 9 10 11
bsxfun(@plus,a,b)
ans = 3×4
6 7 8 9 7 8 9 10 8 9 10 11
竜彦 今井
竜彦 今井 2022 年 6 月 29 日
Ueno様
お世話になっております。今井です。
早速試してみましたが、無事に私のPC環境でも結果表示する事ができました。
配列同士と足すという関数でも、バージョン違いで動作が異なる場合があるとは、使いこなしている方でないとわからない部分でしたので、とても助かりました。
おかげ様で最初のプログラムからは相当高速化することができ、複数枚数の解析へとステップアップできそうです。
この度はプログラム作成から内容解説まで、本当に丁寧ご回答いただきありがとうございました。
一旦クローズということで本回答を採用させていただきます。
当方まだまだ勉強中ですが、引き続き精進していきますので、また何か困った際にはぜひよろしくお願いします。

サインインしてコメントする。

その他の回答 (0 件)

カテゴリ

ヘルプ センター および File Exchangeコンピューター ビジョンと Simulink についてさらに検索

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!