gpt4 book ai didi

c# - 如何对轮廓进行排序?

转载 作者:行者123 更新时间:2023-12-02 02:36:41 26 4
gpt4 key购买 nike

我想知道是否有人可以阐明一种能够在每帧的基础上对轮廓进行排序的策略。

我正在尝试检测“事件” - 在本例中,事件被定义为 4 帧的运动增长。

如果轮廓“增长”/在 4 个连续帧中具有更大的轮廓区域,则会记录一个事件,并且我必须存储并输出增长的第一帧的轮廓中心位置。

如果只检测到一个事件,我可以通过对轮廓区域列表执行成对检查来粗略地检测事件的起源,如果这是真的,则通过采用 (currentFrameNo - 4) 位置元素轮廓位置列表。

但是,尝试检测多个事件似乎是完全不同的游戏。

在任何给定的帧上,可能会找到 (n) 个轮廓。每个轮廓都被传递到一个候选对象中,并具有表征轮廓的属性,例如帧号、位置和轮廓大小。

最终,我需要一种在每帧的基础上对这些轮廓进行排序的方法,这样我就可以根据它们的相对位置来组织它们,然后对轮廓的“正确列表”执行成对检查。

我不确定是否需要多个(4+)列表,每个可能的事件一个,然后在每一帧上根据最近的中心位置将候选者传递到一个单独的列表,或者我是否应该继续将它们添加到单个列表,然后查询该列表。

我希望在使用 linq/排序集合方面有更多经验的人可以帮助确定合适的方法。

感谢您花时间阅读这篇文章。

public class CandidateList
{
public List<Candidate> candidates;

public CandidateList()
{
candidates = new List<Candidate> candidates;
}

public void Add(Candidate candidate)
{
candidates.Add(candidate)
}
}

public class Candidate
{
//Attributes shown in constructor.

public Candidate(VectorOfPoint contour, int frameNumber, double contourSize, Point location)
{
Contour = contour;
FrameNumber = frameNumber;
ContourSize = contourSize;
Location = location;
Location_x = Location.X;
Location_y = Location.Y;
}
}

_vc = new VideoCapture(someURLorFilePath);
_candidates = new CandidateList();
_vc.ImageGrabbed += ProcessFrame;

public void ProcessFrame(object sender, EventArgs e)
{
Mat _frame = new Mat();
// read frame.. + other operations to get desired data.

Mat _contourOutput = _frame.Clone();
VectorOfVectorOfPoint _contours = new VectorOfVectorOfPoint();

CvInvoke.FindContours(_contourOutput, _contours, new Mat(), RetrType.External, ChainApproxMethod.ChainApproxSimple);

// If there are any contours
if (_contours.Size > 0)
{
// Iterate through contours
for (var i = 0; i < _contours.Size; i++)
{
// Find contour area of each contour (VectorOfPoint)
double _contourArea = CvInvoke.ContourArea(_contours[i]);

// Find centre of contour
Moments M = CvInvoke.Moments(_contours[i]);

Point _contourCentre = new Point(Convert.ToInt16(M.M10 / M.M00), Convert.ToInt16(M.M01 / M.M00));

// Create a candidate based on frame number, contourSize and location
Candidate _candidate = new Candidate(_contours[i], _currentFrameNo, _contourArea, _contourCentre);
_candidates.Add(_candidate)

}
}

_currentFrameNo ++
}



以下图片描绘了我必须处理的一个很可能发生的情况:

第 1 帧 - 四名候选人。

Frame 1 - four candidates

第 2 帧 - 四位候选者,位置略有偏移

Frame 2 - four candidates

第 3 帧 - 四位候选者,位置略有偏移

Frame 3 - four candidates

第 4 帧 - 四名候选人,移动位置 检测到两个事件。从第 1 帧检索中心位置。

Frame 4 - Two events detected.

最佳答案

您可以使用 circular buffers 的列表存储每个候选人的历史记录:

public class CandidateBufferList
{
private List<CircularBuffer<Candidate>> _candidateList = new List<CircularBuffer<Candidate>>();
private void Add(Candidate candidate)
{
//Find a matching buffer for the candidate based on distance. More on this later
//here maxDistance is the maximum distance a candidate can move each frame
var matches = _candidateList.Where(cb => Distance(candidate.Location, cb.Last.Location) < maxDistance);
int matchCount = matches.Count();

if (matchCount == 0)
{
var cb = new CircularBuffer<Candidate>();
cb.Add(candidate);
_candidateList.Add(cb);
}
else if (matchCount == 1)
{
var match = matches.First();
if (match.Last.FrameNumber == candidate.FrameNumber)
{
// Ambiguous match 1.
throw new Exception("A candidate was already added to this buffer this frame.");
}
match.Add(candidate);
}
else
{
// Ambiguous match 2.
throw new Exception("More than one matching buffer was found for this candidate");
}
}

public void Update(int frameNumber, List<Candidate> candidates)
{
candidates.ForEach(c => Add(c));
//Remove buffers that didn't match this frame.
_candidateList.RemoveAll(cb => cb.Last.FrameNumber != frameNumber);
}

public List<Point> GetEvents()
{
return _candidateList
.Where(cb => ContourHasGrouwn(cb))
.Select(cb => cb.First.Location)
.ToList();
}

private bool ContourHasGrouwn(CircularBuffer<Candidate> cb)
{
//if contour is not older than 4 frames
if (!cb.IsFull) return false;

for (int i = 1; i < cb.Size; i++)
{
if (cb[i].ContourSize < cb[i - 1].ContourSize) return false;
}
return true;
}
}

在每个 ProcessFrame 上:

//CandidateBufferList candidatesHistory
//List<Candidate> candidatesThisFrame
candidatesHistory.Update(frameNumber, candidatesThisFrame);
var events = candidatesHistory.GetEvents();

我想我应该提到,如果您尝试仅通过距离查找匹配项,可能会或可能不会出现问题,具体取决于您的具体问题:

  • 候选人可能更接近另一个候选人中心,例如。一个新的候选者被添加到靠近另一个候选者的中心(模糊匹配 1)

  • 候选人可能会获得多个匹配项,您可以选择距离最小的匹配项,但如何确定这是正确的? (不明确匹配 2)

  • 更糟糕的是,您可以有 2 个候选对象,并且在下一帧中两者都可以更接近对方的中心。
<小时/>

这是CircularBuffer实现:

class CircularBuffer<T>
{
private const int _size = 4;
private int _index;
private T[] _elements = new T[_size];

public int Size => _size;
public int Count { get; private set; }
public bool IsFull => Count == Size;

public T this[int i] => _elements[(_index + i)%_size];
public T First => this[0];
public T Last => this[_size-1];

public void Add(T element)
{
_elements[_index] = element;
_index = (_index+1) % _size;
if (Count < _size) Count++;
}
}

关于c# - 如何对轮廓进行排序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60325511/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com