问题在于:我有许多由不同厚度的痕迹组成的二进制图像。下面有两张图片来说明问题:
我需要的是测量图像中迹线的平均厚度(以像素为单位)。事实上,图像中痕迹的平均厚度是一种有点主观的度量。所以,我需要的是一个与迹线半径有一定关系的度量,如下图所示:
由于测量不需要非常精确,我愿意以精确度换取速度。换句话说,速度是解决这个问题的重要因素。
痕迹中可能存在交叉点。
迹线厚度可能不是恒定的,但平均测量值是可以的(即使最大迹线厚度也可以接受)。
跟踪总是比它宽得多。
答案 0 :(得分:19)
我建议使用这个算法:
答案 1 :(得分:8)
@ nikie的回答给我留下了深刻的印象,并试了一下......
我简化了算法以获得最大值,而不是平均值,因此避免了局部最大值检测算法。我认为如果中风表现良好就足够了(尽管对于自相交线,它可能不准确)。
Mathematica中的程序是:
m = Import["http://imgur.com/3Zs7m.png"] (* Get image from web*)
s = Abs[ImageData[m] - 1]; (* Invert colors to detect background *)
k = DistanceTransform[Image[s]] (* White Pxs converted to distance to black*)
k // ImageAdjust (* Show the image *)
Max[ImageData[k]] (* Get the max stroke width *)
生成的结果是
数值(28.46像素X 2)非常适合我56 px的测量值(尽管你的值是100px:*)
编辑 - 实施完整算法
嗯......有点......而不是搜索局部最大值,找到距离变换的固定点。几乎,但不完全不同于同样的事情:)
m = Import["http://imgur.com/3Zs7m.png"]; (*Get image from web*)
s = Abs[ImageData[m] - 1]; (*Invert colors to detect background*)
k = DistanceTransform[Image[s]]; (*White Pxs converted to distance to black*)
Print["Distance to Background*"]
k // ImageAdjust (*Show the image*)
Print["Local Maxima"]
weights =
Binarize[FixedPoint[ImageAdjust@DistanceTransform[Image[#], .4] &,s]]
Print["Stroke Width =",
2 Mean[Select[Flatten[ImageData[k]] Flatten[ImageData[weights]], # != 0 &]]]
正如您所看到的,结果与前一个结果非常相似,使用简化算法获得。
答案 2 :(得分:4)
来自Here。一个简单的方法!
3.1 估算笔宽度
可以从前景的区域A和周长L来容易地估计笔的厚度
T = A/(L/2)
本质上,我们将前景重新塑造成一个矩形并测量最长边的长度。笔的更强的建模,例如,作为产生圆形末端的盘,可以允许更高的精度,但是光栅化误差会损害重要性。
虽然精确度不是主要问题,但我们确实需要考虑偏差和奇点。
因此,我们应该使用考虑“圆度”的函数来计算面积A和周长L. 在MATLAB中
A = bwarea(.)
L = bwarea(bwperim(.; 8))
由于我手头没有MATLAB,我在Mathematica做了一个小程序:
m = Binarize[Import["http://imgur.com/3Zs7m.png"]] (* Get Image *)
k = Binarize[MorphologicalPerimeter[m]] (* Get Perimeter *)
p = N[2 Count[ImageData[m], Except[1], 2]/
Count[ImageData[k], Except[0], 2]] (* Calculate *)
输出为36 Px ...
周边图像如下
HTH!
答案 3 :(得分:2)
问题问题已经过了3年:) 按照@nikie的程序,这是一个笔画宽度的matlab实现。
clc;
clear;
close all;
I = imread('3Zs7m.png');
X = im2bw(I,0.8);
subplottight(2,2,1);
imshow(X);
Dist=bwdist(X);
subplottight(2,2,2);
imshow(Dist,[]);
RegionMax=imregionalmax(Dist);
[x, y] = find(RegionMax ~= 0);
subplottight(2,2,3);
imshow(RegionMax);
List(1:size(x))=0;
for i = 1:size(x)
List(i)=Dist(x(i),y(i));
end
fprintf('Stroke Width = %u \n',mean(List));
答案 4 :(得分:1)
假设迹线具有恒定的厚度,比它宽得多,不是太强烈弯曲并且没有交叉点/交叉点,我建议边缘检测算法也确定边缘的方向,然后是上升/具有一些三角法和最小化算法的跌倒检测器。这使您在曲线的相对直线部分获得最小厚度。
我猜这个错误高达25%。
首先使用边缘检测器,它为我们提供边缘所在的信息以及它具有的方向(45°或PI / 4步)。这是通过使用4个不同的3x3矩阵(Example)进行过滤来完成的 通常我会说它足以水平扫描图像,但你也可以垂直或对角扫描 假设逐行(水平)扫描,一旦我们找到边缘,我们检查它是否是上升(从背景到痕迹颜色)或下降(到背景)。如果边缘的方向与扫描方向成直角,请跳过它 如果您发现一个上升,一个下降且方向正确且两者之间没有任何干扰,请测量从上升到下降的距离。如果方向是对角线,则乘以2的平方根。将此度量与坐标数据一起存储。
然后,算法必须沿着边缘(当前无法找到网络资源)搜索相邻(通过其坐标)测量。如果存在局部最小值,每边可能有4到5个大小单位的填充(要使用的值 - 更大:信息越少,越小:噪声越大),此度量就有资格作为候选者。这是为了确保不考虑路径的末端或弯曲过多的部分。
最小值是测量值。合理性检查:如果迹线不是太纠结,那么该区域应该有很多值。
如果还有其他问题,请发表评论。 : - )
答案 5 :(得分:1)
这是一个适用于任何计算机语言而无需特殊功能的答案......
基本思路:尝试将圆圈装入图像的黑色区域。如果可以,请尝试更大的圈子。
算法:
现在结果数组包含每个测试宽度的匹配数
用图表来看看它。
对于宽度为1,这将等于迹线颜色的像素数。对于更大的宽度值,更少的圆形区域将适合迹线。结果数组将逐渐减少,直到突然下降。这是因为具有该宽度的圆形区域的滤波器矩阵现在仅适合交叉点
在下降之前是跟踪的宽度。如果宽度不是恒定的,那么下降就不会那么突然。
我这里没有MATLAB进行测试,并且不确定检测到这种突然下降的函数,但是我们确实知道减少是连续的,所以我采取了最大的二阶导数这样的(从零开始)结果数组
算法:
现在,widthFound是跟踪宽度,相对于宽度+ 1,找到了更多匹配。
我知道其他一些答案部分涵盖了这一点,但我的描述非常简单,您无需学习图像处理。
答案 6 :(得分:0)
我有一个有趣的解决方案:
average distance from edge particle to nearest free particle.