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

2 views (last 30 days)
竜彦 今井
竜彦 今井 on 23 Jun 2022
Commented: 竜彦 今井 on 29 Jun 2022
はじめまして、今井と申します。
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
最後の質問ですが、この縞は曲面にできています。
そこで、予めチェッカーの様なキャリブレーションシールを曲面に貼り付けて撮影し、
その後画角を変えずに連続撮影した際、最初のキャリブレーション画像を用いて、
平面に伸ばしたような画像に変換することは可能でしょうか???
もしくは、実際には画像を平面化処理しなくても、キャリブレーションの値だけ持ち越して、
上記の縞間隔や縞移動速度算出に反映できるでも構いません。
それでは、よろしくお願いいたします。

Accepted Answer

Atsushi Ueno
Atsushi Ueno on 23 Jun 2022
Edited: Atsushi Ueno on 25 Jun 2022
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 Comments
Atsushi Ueno
Atsushi Ueno on 29 Jun 2022
Edited: Atsushi Ueno on 29 Jun 2022
おっとこれはすいません。結論から申し上げますと、下記を修正すればエラーは解消します。
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
竜彦 今井
竜彦 今井 on 29 Jun 2022
Ueno様
お世話になっております。今井です。
早速試してみましたが、無事に私のPC環境でも結果表示する事ができました。
配列同士と足すという関数でも、バージョン違いで動作が異なる場合があるとは、使いこなしている方でないとわからない部分でしたので、とても助かりました。
おかげ様で最初のプログラムからは相当高速化することができ、複数枚数の解析へとステップアップできそうです。
この度はプログラム作成から内容解説まで、本当に丁寧ご回答いただきありがとうございました。
一旦クローズということで本回答を採用させていただきます。
当方まだまだ勉強中ですが、引き続き精進していきますので、また何か困った際にはぜひよろしくお願いします。

Sign in to comment.

More Answers (0)

Community Treasure Hunt

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

Start Hunting!