如何在二值图像中找到像素簇的质心
How to find the centroids of pixel clusters within a binary image
我在 MATLAB 中编写了一些代码,使用设定的阈值将(星星)图像转换为二值图像,然后标记高于该阈值的每个像素(星星)簇。标签产生输出:
例如
[1 1 1 0 0 0 0 0 0
1 1 0 0 0 2 2 2 0
0 0 0 3 3 0 2 0 0
0 0 0 3 3 0 0 0 0]
因此,每个由 1、2、3 等组成的簇代表一颗星。我使用 link: How to find all connected components in a binary image in Matlab? 中提供的答案来标记像素。
我也不能使用图像处理工具箱。
我到目前为止的代码如下所示。
我现在如何找到图像中每个像素簇的质心?
clc
clear all
close all
img=imread('star.jpg');
binary_image=convert2binary(img);
imshow(binary_image);
visited = false(size(binary_image));
[rows, cols] = size(binary_image);
B = zeros(rows, cols);
ID_counter = 1;
for row = 1:rows
for col = 1:cols
if binary_image(row, col) == 0
visited(row, col) = true;
elseif visited(row, col)
continue;
else
stack = [row col];
while ~isempty(stack)
loc = stack(1,:);
stack(1,:) = [];
if visited(loc(1),loc(2))
continue;
end
visited(loc(1),loc(2)) = true;
B(loc(1),loc(2)) = ID_counter;
[locs_y, locs_x] = meshgrid(loc(2)-1:loc(2)+1, loc(1)-1:loc(1)+1);
locs_y = locs_y(:);
locs_x = locs_x(:);
out_of_bounds = locs_x < 1 | locs_x > rows | locs_y < 1 | locs_y > cols;
locs_y(out_of_bounds) = [];
locs_x(out_of_bounds) = [];
is_visited = visited(sub2ind([rows cols], locs_x, locs_y));
locs_y(is_visited) = [];
locs_x(is_visited) = [];
is_1 = binary_image(sub2ind([rows cols], locs_x, locs_y));
locs_y(~is_1) = [];
locs_x(~is_1) = [];
stack = [stack; [locs_x locs_y]];
end
ID_counter = ID_counter + 1;
end
end
end
function [binary] = convert2binary(img)
[x, y, z]=size(img);
if z==3
img=rgb2gray(img);
end
img=double(img);
sum=0;
for i=1:x
for j=1:y
sum=sum+img(i, j);
end
end
threshold=100 % or sum/(x*y);
binary=zeros(x,y);
for i=1:x
for j=1:y
if img(i, j) >= threshold
binary(i, j) = 1;
else
binary(i, j)=0;
end
end
end
end
质心是一阶矩。它由
计算
sum(x*v)/sum(v) , sum(y*v)/sum(v)
对于二值图像,您可以这样做(我使用的是普通循环,而不是矢量化代码,因此我们稍后可以轻松扩展它):
img = [1 1 1 0 0 0 0 0 0
1 1 0 0 0 2 2 2 0
0 0 0 3 3 0 2 0 0
0 0 0 3 3 0 0 0 0]; % Op's example data
bin = img==1; % A binary image
% Algorithm
sum_v = 0;
sum_iv = 0;
sum_jv = 0;
for jj=1:size(bin,2)
for ii=1:size(bin,1)
sum_v = sum_v + bin(ii,jj);
sum_iv = sum_iv + ii * bin(ii,jj);
sum_jv = sum_jv + jj * bin(ii,jj);
end
end
centroid = [sum_iv, sum_jv] / sum_v;
您当然可以遍历标记图像 img
的每个标签,并应用上面的代码。但这是非常低效的。相反,我们可以循环遍历图像一次并同时计算所有质心。我们将 sum_v
等转换为向量,每个标签包含一个 运行 总和:
N = max(img(:)); % number of labels
sum_v = zeros(N,1);
sum_iv = zeros(N,1);
sum_jv = zeros(N,1);
for jj=1:size(img,2)
for ii=1:size(img,1)
index = img(ii,jj);
if index>0
sum_v(index) = sum_v(index) + 1;
sum_iv(index) = sum_iv(index) + ii;
sum_jv(index) = sum_jv(index) + jj;
end
end
end
centroids = [sum_iv, sum_jv] ./ sum_v;
我在 MATLAB 中编写了一些代码,使用设定的阈值将(星星)图像转换为二值图像,然后标记高于该阈值的每个像素(星星)簇。标签产生输出: 例如
[1 1 1 0 0 0 0 0 0
1 1 0 0 0 2 2 2 0
0 0 0 3 3 0 2 0 0
0 0 0 3 3 0 0 0 0]
因此,每个由 1、2、3 等组成的簇代表一颗星。我使用 link: How to find all connected components in a binary image in Matlab? 中提供的答案来标记像素。 我也不能使用图像处理工具箱。 我到目前为止的代码如下所示。
我现在如何找到图像中每个像素簇的质心?
clc
clear all
close all
img=imread('star.jpg');
binary_image=convert2binary(img);
imshow(binary_image);
visited = false(size(binary_image));
[rows, cols] = size(binary_image);
B = zeros(rows, cols);
ID_counter = 1;
for row = 1:rows
for col = 1:cols
if binary_image(row, col) == 0
visited(row, col) = true;
elseif visited(row, col)
continue;
else
stack = [row col];
while ~isempty(stack)
loc = stack(1,:);
stack(1,:) = [];
if visited(loc(1),loc(2))
continue;
end
visited(loc(1),loc(2)) = true;
B(loc(1),loc(2)) = ID_counter;
[locs_y, locs_x] = meshgrid(loc(2)-1:loc(2)+1, loc(1)-1:loc(1)+1);
locs_y = locs_y(:);
locs_x = locs_x(:);
out_of_bounds = locs_x < 1 | locs_x > rows | locs_y < 1 | locs_y > cols;
locs_y(out_of_bounds) = [];
locs_x(out_of_bounds) = [];
is_visited = visited(sub2ind([rows cols], locs_x, locs_y));
locs_y(is_visited) = [];
locs_x(is_visited) = [];
is_1 = binary_image(sub2ind([rows cols], locs_x, locs_y));
locs_y(~is_1) = [];
locs_x(~is_1) = [];
stack = [stack; [locs_x locs_y]];
end
ID_counter = ID_counter + 1;
end
end
end
function [binary] = convert2binary(img)
[x, y, z]=size(img);
if z==3
img=rgb2gray(img);
end
img=double(img);
sum=0;
for i=1:x
for j=1:y
sum=sum+img(i, j);
end
end
threshold=100 % or sum/(x*y);
binary=zeros(x,y);
for i=1:x
for j=1:y
if img(i, j) >= threshold
binary(i, j) = 1;
else
binary(i, j)=0;
end
end
end
end
质心是一阶矩。它由
计算sum(x*v)/sum(v) , sum(y*v)/sum(v)
对于二值图像,您可以这样做(我使用的是普通循环,而不是矢量化代码,因此我们稍后可以轻松扩展它):
img = [1 1 1 0 0 0 0 0 0
1 1 0 0 0 2 2 2 0
0 0 0 3 3 0 2 0 0
0 0 0 3 3 0 0 0 0]; % Op's example data
bin = img==1; % A binary image
% Algorithm
sum_v = 0;
sum_iv = 0;
sum_jv = 0;
for jj=1:size(bin,2)
for ii=1:size(bin,1)
sum_v = sum_v + bin(ii,jj);
sum_iv = sum_iv + ii * bin(ii,jj);
sum_jv = sum_jv + jj * bin(ii,jj);
end
end
centroid = [sum_iv, sum_jv] / sum_v;
您当然可以遍历标记图像 img
的每个标签,并应用上面的代码。但这是非常低效的。相反,我们可以循环遍历图像一次并同时计算所有质心。我们将 sum_v
等转换为向量,每个标签包含一个 运行 总和:
N = max(img(:)); % number of labels
sum_v = zeros(N,1);
sum_iv = zeros(N,1);
sum_jv = zeros(N,1);
for jj=1:size(img,2)
for ii=1:size(img,1)
index = img(ii,jj);
if index>0
sum_v(index) = sum_v(index) + 1;
sum_iv(index) = sum_iv(index) + ii;
sum_jv(index) = sum_jv(index) + jj;
end
end
end
centroids = [sum_iv, sum_jv] ./ sum_v;