Все, что у меня есть следующая реализация линии, определяющей преобразование Хафа для облаков точек (набор точек в 3-х пространствах)
internal sealed class LineHoughTransform : ILineHoughTransform
{
private readonly double _dX;
private readonly double _maxX;
private readonly long _countX;
private readonly long _countB;
private readonly IDiscreetSphere _sphere;
public LineHoughTransform(Vector3 minParameterVector, Vector3 maxParameterVector, double dX, int sphereGranularity)
{
_dX = dX;
_sphere = new Icosahedron();
_sphere.Create(sphereGranularity);
_countB = _sphere.Points.Count;
_maxX = Math.Max(maxParameterVector.Norm(), minParameterVector.Norm());
var rangeX = 2 * _maxX;
if (_dX == 0.0)
_dX = rangeX / 64.0;
_countX = (long)(rangeX / _dX).RoundToNearest();
VotingSpace = new Dictionary<long, int>();
}
public int GetLine(ref Vector3 a, ref Vector3 b)
{
int votes = 0;
long index = 0;
foreach (var storedVote in VotingSpace)
{
if (storedVote.Value > votes)
{
votes = storedVote.Value;
index = storedVote.Key;
}
}
// Retrieve x' coordinate from VotingSpace[_countX * _countX * _countB].
double x = index / (_countX * _countB);
index -= (long)(x * _countX * _countB);
x = x * _dX - _maxX;
// Retrieve y' coordinate from VotingSpace[_countX * _countX * _countB].
double y = index / _countB;
index -= (long)y * _countB;
y = y * _dX - _maxX;
// Retrieve directional vector and Compute anchor point according to Eq. (3).
b = _sphere.Points[(int)index];
a.X = (float)(x * (1 - ((b.X * b.X) / (1 + b.Z))) - y * ((b.X * b.Y) / (1 + b.Z)));
a.Y = (float)(x * (-((b.X * b.Y) / (1 + b.Z))) + y * (1 - ((b.Y * b.Y) / (1 + b.Z))));
a.Z = (float)(-x * b.X - y * b.Y);
return votes;
}
public void Add(IPointCloud pointCloud)
{
CastVote(pointCloud, true);
}
public void Subtract(IPointCloud pointCloud)
{
CastVote(pointCloud, false);
}
private void CastVote(IPointCloud pointCloud, bool add)
{
if (pointCloud == null || pointCloud.Vertices == null)
return;
foreach (var vertex in pointCloud.Vertices)
PointVote(vertex.Point, add);
}
private void PointVote(Vector3 point, bool add)
{
// Loop over directions B.
for (int j = 0; j < _sphere.Points.Count; ++j)
{
// Denominator in Eq. (2).
Vector3 b = _sphere.Points[j];
double beta = 1 / (1 + b.Z);
// Compute x' and y' according to Eq. (2).
double newX = ((1 - (beta * (b.X * b.X))) * point.X) - (beta * (b.X * b.Y) * point.Y) - (b.X * point.Z);
double newY = (-beta * (b.X * b.Y) * point.X) + ((1 - (beta * (b.Y * b.Y))) * point.Y) - (b.Y * point.Z);
long x_i = (long)((newX + _maxX) / _dX).RoundToNearest();
long y_i = (long)((newY + _maxX) / _dX).RoundToNearest();
// Compute one-dimensional index from three indices.
// x_i * <number of planes> * <number of direction vectors> + y_i * <number of direction vectors> + <loop index>
long index = (x_i * _countX * _countB) + (y_i * _countB) + j;
if (!VotingSpace.ContainsKey(index))
VotingSpace.Add(index, 0);
if (add)
VotingSpace[index]++;
else
VotingSpace[index]--;
}
}
public Dictionary<long, int> VotingSpace { get; private set; }
}
Я хотел бы улучшить скорость этого кода, поэтому я попытался использовать
public ConcurrentDictionary<long, int> VotingSpace { get; private set; }
с
private void CastVote(IPointCloud pointCloud, bool add)
{
if (pointCloud == null || pointCloud.Vertices == null)
return;
Parallel.ForEach(pointCloud.Vertices, vertex => PointVote(vertex.Point, add));
}
Обратите внимание, что pointCloud в CastVote
может содержать огромное количество точек, и увеличение VotingSpace
становится
if (!VotingSpace.ContainsKey(index))
VotingSpace.TryAdd(index, 0);
if (add)
VotingSpace[index]++;
else
VotingSpace[index]--;
Однако иногда TryAdd
дает сбой, вызывая сбой моего алгоритма вызова. Я попытался повторить попытку на TryAdd
, но это не помогло решить проблему пропущенных индексов. Как я могу сделать этот класс оптимально многопоточным, максимально простым и работать точно так же, как и оригинал?