領域に内接する最大の楕円を自動設定する方法
Show older comments
二値化した画像に対して、ある領域に内接する最大の楕円を自動で設定したいです。
現状、面積を求めたいのですが画像が欠けており囲まれていないため、面積がうまく算出できません。そこでその領域に最大の楕円を設定できれば近似的に面積を算出できると考えています。マニュアルで楕円を設定することは可能ですがそれが最大のものかはわかりません。なので、自動的に最大のものを設定したいです。
ご教授いただきたいです。
Accepted Answer
More Answers (2)
交感神経優位なあかべぇ
on 25 Feb 2023
Edited: 交感神経優位なあかべぇ
on 25 Feb 2023
楕円の作成ではないですが、画像内のそれぞれの囲まれてる黒の部分を塗りつぶしする方法でなら、面積が求められるかなぁと思い、試してみました。
画像内の黄色のエリアの面積は、areaの2番目(30708)になります。(areaの1番目(93228)は,青いエリアになります)
img = imread('https://jp.mathworks.com/matlabcentral/answers/uploaded_files/1300565/%E4%BA%8C%E5%80%A4%E5%8C%96%E5%89%8D%E3%81%AE%E7%94%BB%E5%83%8F.png');
allAreamap = GetAreamap(img); % 画像の黒い部分に塗りつぶしを行った範囲のそれぞれの2値の画像を取得
area = arrayfun(@(i) nnz(allAreamap(:,:,i)), 1 : size(allAreamap, 3));
area = sort(area, 'descend') % 面積の大きいもの順に表示
% 塗りつぶし画像の描画
colors = lines;
imshow(img);
hold on;
for i = 1 : size(allAreamap, 3)
areaData = allAreamap(:,:,i);
areaImg = repmat(0xFF, [size(img, [1,2]), 3]);
color = uint8(colors(i,:) * 255);
tmpImg = reshape(areaImg, prod(size(img, [1,2])), 3);
tmpImg(areaData,:) = repmat(color, nnz(areaData), 1);
areaImg = reshape(tmpImg, size(img));
image(areaImg, 'AlphaData', areaData);
end
function allAreamap = GetAreamap(img)
tmpImg = img(:,:,1) > 50 | img(:,:,2) > 50 | img(:,:,3) > 50;
img = true(size(img, [1,2]) + 2);
img(2:end-1, 2:end-1) = tmpImg;
nonMap = ~img;
allAreamap = false([size(img), 0]);
setIdx = 0;
while true
[row,col] = find(nonMap, 1);
if ~isempty(row)
area = FillInArea(row, col, img);
nonMap = xor(nonMap, area);
setIdx = setIdx + 1;
allAreamap(:,:,setIdx) = area;
else
break;
end
end
allAreamap = allAreamap(2:end-1,2:end-1,:);
end
function areamap = FillInArea(row, col, img)
areamap = false(size(img));
spread = false([size(img), 4]);
while true
areamap(row, col) = true;
spread(row, col, :) = true(4,1);
if img(row - 1, col) || areamap(row - 1, col)
spread(row, col, 1) = false;
end
if img(row, col - 1) || areamap(row, col - 1)
spread(row, col, 2) = false;
end
if img(row + 1, col) || areamap(row + 1, col)
spread(row, col, 3) = false;
end
if img(row, col + 1) || areamap(row, col + 1)
spread(row, col, 4) = false;
end
spread(row - 1, col, 3) = false;
spread(row, col - 1, 4) = false;
spread(row + 1, col, 1) = false;
spread(row, col + 1, 2) = false;
if any(spread(row, col, :))
idxOffset = GetNextIdx(spread(row, col, :));
row = row + idxOffset(1);
col = col + idxOffset(2);
else
spreadTruemap = any(spread, 3);
[row, col] = find(spreadTruemap, 1);
if ~isempty(row)
idxOffset = GetNextIdx(spread(row, col, :));
row = row + idxOffset(1);
col = col + idxOffset(2);
else
break;
end
end
end
end
function idxOffset = GetNextIdx(logicalArray)
idx = find(logicalArray, 1);
switch idx
case 1
idxOffset = [-1, 0];
case 2
idxOffset = [0,-1];
case 3
idxOffset = [1,0];
case 4
idxOffset = [0,1];
end
end
1 Comment
Image Processing Toolboxがありましたら、穴の塗りつぶしを行うimfill関数が使用できますので、もう少し簡潔に記述できます。
img = imread('https://jp.mathworks.com/matlabcentral/answers/uploaded_files/1300565/%E4%BA%8C%E5%80%A4%E5%8C%96%E5%89%8D%E3%81%AE%E7%94%BB%E5%83%8F.png');
allAreamap = GetAreamap(img); % 画像の黒い部分に塗りつぶしを行った範囲のそれぞれの2値の画像を取得
area = arrayfun(@(i) nnz(allAreamap(:,:,i)), 1 : size(allAreamap, 3));
area = sort(area, 'descend') % 面積の大きいもの順に表示
% 塗りつぶし画像の描画
colors = lines;
imshow(img);
hold on;
for i = 1 : size(allAreamap, 3)
areaData = allAreamap(:,:,i);
areaImg = repmat(0xFF, [size(img, [1,2]), 3]);
color = uint8(colors(i,:) * 255);
tmpImg = reshape(areaImg, prod(size(img, [1,2])), 3);
tmpImg(areaData,:) = repmat(color, nnz(areaData), 1);
areaImg = reshape(tmpImg, size(img));
image(areaImg, 'AlphaData', areaData);
end
function allAreamap = GetAreamap(img)
img = img(:,:,1) > 50 | img(:,:,2) > 50 | img(:,:,3) > 50; % 2値画像の作成
allAreamap = false([size(img), 0]); % 塗りつぶしたエリアを表す画像の宣言(3次元目のそれぞれの塗りつぶし画像をコピー)
while true
[row,col] = find(~img, 1); % 穴があるピクセルを検索
if ~isempty(row)
area = imfill(img, [row, col]);% 穴が存在していたら塗りつぶしの実施
allAreamap(:,:,end + 1) = xor(area, img); % 塗りつぶしたエリアだけを抽出しコピー
img = area;
else
break; % 穴が全て埋まったら、終了
end
end
end
こんにちは、皆様の回答を限りなくシンプルにしたものを考えていました。あけべぇさんの結果(30708)と似た結果になっています。こういうのでもいいかもしれませんね(?)。
img = imread('https://jp.mathworks.com/matlabcentral/answers/uploaded_files/1300565/%E4%BA%8C%E5%80%A4%E5%8C%96%E5%89%8D%E3%81%AE%E7%94%BB%E5%83%8F.png');
% グレースケールに変換
gray = rgb2gray(img);
% 穴埋めをして差分を求める
Ifill = imfill(gray,'holes');
% 変化のあった箇所を可視化
diff = -single(gray)+single(Ifill);
% 5%を閾値として、塗った面積を求める
length(find(diff>prctile(diff(diff>0),5)))
% 可視化
figure;imagesc(diff)
Categories
Find more on Vector Volume Data in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!



