大点云中大点循环的优化
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));
所有我有以下实现点云的线检测霍夫变换(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));