计算圆圈内的黑色像素
Count black pixels within a circle
我有一个半径矢量和数百个 [X,Y]
坐标的第二个矢量。对于每个可能的坐标-半径对,我都计算了输入二值图像上圆圈(其中心位于坐标中)内的所有黑色像素。
最快的方法是什么?我唯一的想法是遍历图像的每个像素,检查圆方程,然后检查像素颜色,但它似乎并没有针对数百个这样的操作进行优化。
这是一种实现方式:
Advantages:
No loops
, meshgrid/ndgrid
. Instead used faster bsxfun
and pdist2
Dots are counted only once, even when the circles overlap.
Variable radius
used (radius of all circle is not same)
代码:
%// creating a binary image with little black dots
A = randi(600,256);
imbw = A ~= 1;
%// Your binary image with black dots
imshow(imbw);
%// getting the index of black dots
[dotY, dotX] = find(~imbw);
nCoords = 10; %// required number of circles
%// generating its random coordinates as it is unknown here
Coords = randi(size(A,1),nCoords,2);
%// calculating the distance from each coordinate with every black dots
out = pdist2(Coords,[dotX, dotY]).'; %//'
%// Getting only the black dots within the radius
%// using 'any' avoids calculating same dot twice
radius = randi([10,25],1,size(Coords,1));
pixelMask = any(bsxfun(@lt, out, radius),2);
nPixels = sum(pixelMask);
%// visualizing the results by plotting
hold on
scatter(dotX(pixelMask),dotY(pixelMask));
viscircles([Coords(:,1),Coords(:,2)],radius.'); %//'
hold off
输出:
>> nPixels
nPixels =
19
由于矩阵语法,Matlab 非常适合处理图像。它也适用于索引,所以大多数时候你可以避免 "iterating through pixels"(虽然有时你仍然需要)。
无需检查每个圆圈内的所有像素,也不必检测有多少像素被计算了两次,另一种方法是创建一个与您的图像大小相同的蒙版。为您的每个圆圈空白此蒙版(因此重叠像素仅 'blanked' 一次),然后将蒙版应用于原始图片并计算剩余的照明像素。
举个例子,我要拿一些样本数据,图片:
load trees
BW = im2bw(X,map,0.4);
imshow(BW)
和 20 个随机 point/circle 坐标(您可以轻松更改点数和 min/max 半径):
%// still building sample data
s = size(BW) ;
npt = 20 ; Rmin=5 ; Rmax=20 ; %// problem constants
x = randi([1 s(2)] ,npt,1); %// random X coordinates
y = randi([1 s(1)] ,npt,1); %// Y
r = randi([Rmin Rmax],npt,1); %// radius size between 5 to 20 pixels.
然后我们构建您的自定义掩码:
%// create empty mask with enough overlap for the circles on the border of the image
mask = false( s+2*Rmax ) ;
%// prepare grid for a sub-mask of pixels, as wide as the maximum circle
xmask = -Rmax:Rmax ;
[xg,yg] = ndgrid(xmask,xmask) ;
rg = sqrt( (xg.^2+yg.^2) ) ; %// radius of each pixel in the subgrid
for ip=1:npt
mrow = xmask+Rmax+y(ip) ; %// calc coordinates of subgrid on original mask
mcol = xmask+Rmax+x(ip) ; %// calc coordinates of subgrid on original mask
cmask = rg <= r(ip) ; %// calculate submask for this radius
mask(mrow,mcol) = mask(mrow,mcol) | cmask ; %// apply the sub-mask at the x,y coordinates
end
%// crop back the mask to image original size (=remove border overlap)
mask = mask(Rmax+1:end-Rmax,Rmax+1:end-Rmax) ;
imshow(mask)
然后您只需敷上面膜并数数即可:
%% // Now apply on original image
BWm = ~BW & mask ; %// note the ~ (not) operator because you want the "black" pixels
nb_black_pixels = sum(sum(BWm)) ;
imshow(BWm)
nb_black_pixels =
5283
我有一个半径矢量和数百个 [X,Y]
坐标的第二个矢量。对于每个可能的坐标-半径对,我都计算了输入二值图像上圆圈(其中心位于坐标中)内的所有黑色像素。
最快的方法是什么?我唯一的想法是遍历图像的每个像素,检查圆方程,然后检查像素颜色,但它似乎并没有针对数百个这样的操作进行优化。
这是一种实现方式:
Advantages:
No
loops
,meshgrid/ndgrid
. Instead used fasterbsxfun
andpdist2
Dots are counted only once, even when the circles overlap.
Variable
radius
used (radius of all circle is not same)
代码:
%// creating a binary image with little black dots
A = randi(600,256);
imbw = A ~= 1;
%// Your binary image with black dots
imshow(imbw);
%// getting the index of black dots
[dotY, dotX] = find(~imbw);
nCoords = 10; %// required number of circles
%// generating its random coordinates as it is unknown here
Coords = randi(size(A,1),nCoords,2);
%// calculating the distance from each coordinate with every black dots
out = pdist2(Coords,[dotX, dotY]).'; %//'
%// Getting only the black dots within the radius
%// using 'any' avoids calculating same dot twice
radius = randi([10,25],1,size(Coords,1));
pixelMask = any(bsxfun(@lt, out, radius),2);
nPixels = sum(pixelMask);
%// visualizing the results by plotting
hold on
scatter(dotX(pixelMask),dotY(pixelMask));
viscircles([Coords(:,1),Coords(:,2)],radius.'); %//'
hold off
输出:
>> nPixels
nPixels =
19
由于矩阵语法,Matlab 非常适合处理图像。它也适用于索引,所以大多数时候你可以避免 "iterating through pixels"(虽然有时你仍然需要)。
无需检查每个圆圈内的所有像素,也不必检测有多少像素被计算了两次,另一种方法是创建一个与您的图像大小相同的蒙版。为您的每个圆圈空白此蒙版(因此重叠像素仅 'blanked' 一次),然后将蒙版应用于原始图片并计算剩余的照明像素。
举个例子,我要拿一些样本数据,图片:
load trees
BW = im2bw(X,map,0.4);
imshow(BW)
和 20 个随机 point/circle 坐标(您可以轻松更改点数和 min/max 半径):
%// still building sample data
s = size(BW) ;
npt = 20 ; Rmin=5 ; Rmax=20 ; %// problem constants
x = randi([1 s(2)] ,npt,1); %// random X coordinates
y = randi([1 s(1)] ,npt,1); %// Y
r = randi([Rmin Rmax],npt,1); %// radius size between 5 to 20 pixels.
然后我们构建您的自定义掩码:
%// create empty mask with enough overlap for the circles on the border of the image
mask = false( s+2*Rmax ) ;
%// prepare grid for a sub-mask of pixels, as wide as the maximum circle
xmask = -Rmax:Rmax ;
[xg,yg] = ndgrid(xmask,xmask) ;
rg = sqrt( (xg.^2+yg.^2) ) ; %// radius of each pixel in the subgrid
for ip=1:npt
mrow = xmask+Rmax+y(ip) ; %// calc coordinates of subgrid on original mask
mcol = xmask+Rmax+x(ip) ; %// calc coordinates of subgrid on original mask
cmask = rg <= r(ip) ; %// calculate submask for this radius
mask(mrow,mcol) = mask(mrow,mcol) | cmask ; %// apply the sub-mask at the x,y coordinates
end
%// crop back the mask to image original size (=remove border overlap)
mask = mask(Rmax+1:end-Rmax,Rmax+1:end-Rmax) ;
imshow(mask)
然后您只需敷上面膜并数数即可:
%% // Now apply on original image
BWm = ~BW & mask ; %// note the ~ (not) operator because you want the "black" pixels
nb_black_pixels = sum(sum(BWm)) ;
imshow(BWm)
nb_black_pixels =
5283