大点云中大点循环的优化

Optimization of Loop of Large Points in Large Point Cloud

所有我有以下实现点云的线检测霍夫变换(3-space中的点集合)

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));
}

注意,CastVote中的点云可以包含大量的点,VotingSpace增量成为

if (!VotingSpace.ContainsKey(index))
    VotingSpace.TryAdd(index, 0);

if (add)
    VotingSpace[index]++;
else
    VotingSpace[index]--;

但是,有时 TryAdd 会失败,导致我的调用算法失败。我试图对 TryAdd 进行重试,但这似乎无助于解决索引丢失的问题。我怎样才能使这个 class 尽可能简单地成为最佳多线程,并以与原始方式完全相同的方式工作?

使用并发集合时,您通常会使用它们提供的特殊原子 API。在这种情况下,您可能应该使用 ConcurrentDictionary.AddOrUpdate 方法:

VotingSpace.AddOrUpdate(index,
    addValueFactory: (key) => add ? 1 : -1,
    updateValueFactory: (key, existingValue) => existingValue + (add ? 1 : -1));