我试图找到一个起点,但我似乎无法找到正确的答案。我非常感谢一些指导。我也不知道正确的术语,因此标题。
答案 0 :(得分:9)
嗯,假设你的图像只包含一个黑色背景和一个包里面,一个非常常见的方法来执行你要求的是阈值图像,然后找到所有白色像素的质心
我进行了谷歌搜索,我能想到的最接近你想要的东西是这样的:
由于某些原因,此图像是RGB,即使它是灰度,因此我们要将其转换为灰度图像。我假设你不能使用任何内置的MATLAB函数,所以rgb2gray
已经出局了。尽管rgb2gray
实现了SMPTE Rec. 709标准,您仍然可以自己实现它。
一旦我们读入图像,您就可以对图像进行阈值处理,然后找到所有白色像素的质心。这可以使用find
来确定非零行和列位置,然后您只需分别找到它们的平均值。一旦我们这样做,我们就可以显示图像并绘制质心所在的红色圆圈。就这样:
im = imread('http://ak.picdn.net/shutterstock/videos/3455555/preview/stock-footage-single-blank-gray-shopping-bag-loop-rotate-on-black-background.jpg');
%// Convert colour image to grayscale
im = double(im);
im = 0.299*im(:,:,1) + 0.587*im(:,:,2) + 0.114*im(:,:,3);
im = uint8(im);
thresh = 30; %// Choose threshold here
%// Threshold image
im_thresh = im > thresh;
%// Find non-zero locations
[rows,cols] = find(im_thresh);
%// Find the centroid
mean_row = mean(rows);
mean_col = mean(cols);
%// Show the image and the centroid
imshow(im); hold on;
plot(mean_col, mean_row, 'r.', 'MarkerSize', 18);
当我运行上面的代码时,这就是我们得到的:
还不错!现在您的下一个问题是处理多个对象的情况。正如您已明智地确定的那样,此代码仅检测一个对象。对于多个对象的情况,我们将不得不做一些不同的事情。您需要做的是通过ID识别图像中的所有对象。这意味着我们需要创建一个ID矩阵,其中该矩阵中的每个像素表示该对象所属的 对象。之后,我们遍历每个对象ID并找到每个质心。这是通过为每个ID创建一个掩码,找到该掩码的质心并保存该结果来执行的。这就是所谓的connected components。
regionprops
是在MATLAB中执行此操作的最常用方法,但是由于您想自己实现这一点,我将推迟到我之前写的关于如何查找二进制文件的连接组件的帖子图像:
How to find all connected components in a binary image in Matlab?
请注意,该算法不是最有效的,因此可能需要几秒钟,但我确定你不介意等待:)所以让我们处理这个案子现在有多个对象。我还在Google上找到了这张图片:
http://cdn.c.photoshelter.com/img-get2/I0000dqEHPhmGs.w/fit=1000x750/84483552.jpg
我们将图像设置为正常阈值,然后执行连接组件分析会有什么不同,然后我们遍历每个标签并找到质心。但是,我要强制执行的另一个限制是我们要检查连接组件结果中找到的每个对象的区域。如果它小于某个数字,这意味着该对象可能归因于量化噪声,我们应该跳过这个结果。
因此,假设您在上面的链接帖子中获取了代码并将其放入名为conncomptest
的函数中,该函数具有以下原型:
B = conncomptest(A);
因此,请参考引用帖子中的代码,并将其放入名为conncomptest.m
的函数中,并使用函数标题:
function B = conncomptest(A)
其中A
是输入二进制图像,B
是ID矩阵,你可以这样做:
im = imread('http://cdn.c.photoshelter.com/img-get2/I0000dqEHPhmGs.w/fit=1000x750/84483552.jpg');
im = double(im);
im = 0.299*im(:,:,1) + 0.587*im(:,:,2) + 0.114*im(:,:,3);
im = uint8(im);
thresh = 30; %// Choose threshold here
%// Threshold image
im_thresh = im > thresh;
%// Perform connected components analysis
labels = conncomptest(im_thresh);
%// Find the total number of objects in the image
num_labels = max(labels(:));
%// Find centroids of each object and show the image
figure;
imshow(im);
hold on;
for idx = 1 : num_labels
%// Find the ith object mask
mask = labels == idx;
%// Find the area
arr = sum(mask(:));
%// If area is less than a threshold
%// don't process this object
if arr < 50
continue;
end
%// Else, find the centroid normally
%// Find non-zero locations
[rows,cols] = find(mask);
%// Find the centroid
mean_row = mean(rows);
mean_col = mean(cols);
%// Show the image and the centroid
plot(mean_col, mean_row, 'r.', 'MarkerSize', 18);
end
我们得到:
答案 1 :(得分:2)
我无意贬低Ray(@rayryeng)的优秀建议,并且像往常一样,精心制作,推理和说明答案,但我注意到你对Matlab以外的解决方案感兴趣并且实际上想要开发自己的代码,所以我会为你提供一些额外的选择。
你可以看一下优秀的ImageMagick,它安装在大多数Linux发行版中,可用于OS X,其他优秀的操作系统和Windows。它包含“连接组件”方法,如果您将其应用于此图像:
在命令行中这样:
convert bags.png -threshold 20% \
-define connected-components:verbose=true \
-define connected-components:area-threshold=600 \
-connected-components 8 -auto-level output.png
输出将是:
Objects (id: bounding-box centroid area mean-color):
2: 630x473+0+0 309.0,252.9 195140 srgb(0,0,0)
1: 248x220+0+0 131.8,105.5 40559 srgb(249,249,249)
7: 299x231+328+186 507.5,304.8 36620 srgb(254,254,254)
3: 140x171+403+0 458.0,80.2 13671 srgb(253,253,253)
12: 125x150+206+323 259.8,382.4 10940 srgb(253,253,253)
8: 40x50+339+221 357.0,248.0 1060 srgb(0,0,0)
显示6个对象,每行一个,并给出每个对象的边界框,质心和平均颜色。因此,第3行表示一个299像素宽,231像素高的盒子,其左上角位于图像左上角的328处,左上角位置为186像素。
如果我在边界框中绘图,你可以在这里看到它们:
还会为您列出质心。
上面命令中的outout图像是这样的,显示每个形状以不同的灰色阴影着色。请注意,最暗的一个是黑色的,所以非常难以看到 - 几乎不可能: - )
正如您所说,如果您希望查看自己编写的连接组件代码,可以在我的另一个答案中查看我的代码... here
无论如何,我希望这会有所帮助,你可以看到它只是雷已经提供的优秀答案的补充。