我想为我的团队提供一个非常简单的C ++接口来进行OpenCV头部跟踪。
哪种架构最适合此应用程序?
我应该提供“事件驱动的”API,还是应该让客户端在想要头部位置(yuck)时查询该库? 我应该要求客户端应用程序定义回调函数吗?我可以做一些类似于[TUIO API in Processing] [1]的东西,你将类传递给TUIO类,然后TUIO事件调度程序在该类中查找你的回调方法(你的类成为委托)? C ++的方法是什么?
如果要求指向具有给定签名的静态方法的函数指针呢?
该规范将遵循TUIO和Community Core Vision的领导。我们正在寻找带有Haar分类器的头部,而不是blob(触摸桌上的指尖)。每个新头都获得一个持久ID。然后我们只发送三个事件:addHeadObject(id, x, y)
,removeHeadObject(id)
,updateHeadObject(id, x, y)
。可能有更多参数用于通信确定性等.updateHeadObject事件将以帧速率发生,最高可达每秒30次。通过增加一些轮询速率无法提高更新速率,因此来自摄像头设备的帧事件必须最终驱动API。
答案 0 :(得分:0)
我将遵循TUIO C ++界面中使用的委托模式。 http://www.tuio.org/?cpp
MyHeadTrackerListener listener; // defines a listener
HeadTrackerClient client; // creates the client
client.addHeadTrackerListener(&listener); // registers the listener
client.connect(); // starts the client
正如TUIO文档中所述:
您的应用程序需要实现TuioListener接口,并且 必须添加到TuioClient才能接收消息。
TuioListener需要实现以下方法:
addTuioObject(TuioObject * tobj)当对象变为时调用它 可见removeTuioObject(TuioObject * tobj)从中删除了一个对象 表updateTuioObject(TuioObject * tobj)移动了一个对象 表面addTuioCursor(TuioCursor * tcur)这个时候调用 检测到新光标removeTuioCursor(TuioCursor * tcur)一个光标 从表updateTuioCursor(TuioCursor * tcur)中删除了一个游标 正在桌面上刷新(TuioTime bundleTime)这个 在每个包之后调用方法,使用它重新绘制屏幕 示例
我的客户端将需要实现一些头部跟踪事件回调方法。根据这个大纲看起来很简单,但我不知道在C ++中这样做是否正常。
答案 1 :(得分:0)
如果库正在控制程序流,那么回调可能是最简单的解决方案。如果您愿意,将其抽象为coroutine也可以很好地转换为多线程解决方案。我在实施和维护方面提供了这一点,而不是性能。
我过去使用boost::signal
作为达到目的的手段取得了成功,值得一看。
您的公共界面可能是等效的,但可能更详细一些。我希望大多数这些类都有纯虚拟接口,但是对于演示,简单结构更容易阅读。
struct Head {
int transient_id;
int x, y;
};
struct Frame {
std::vector<Head> heads;
};
struct HeadTracker {
boost::signal<void(const Frame &)> updates;
};
我不确定你是否绝对需要在头部进入或离开相关性时发射事件。更新提供x
和y
,因此相关性更改仅为transient_id
。如果客户端不知道它有哪个transient_id
,它可能只是请求详细信息。虽然简化处理可能会有所帮助。
我对您的标识符的确定度有一些担忧,因为它们理论上(或可能是常规的)会发生变化。我不清楚你是否在追踪特定人物的身份(transient_id#35523是Jane Doe),或者只是那个形状是否是头脑。
如果Jane走出门,然后回来,每个系统会有两个不同的人。这会简化一些事情,我建议不管怎样在幕后建模。
struct Head {
int transient_id;
int x, y;
float is_head; // [0.0, 1.0]
};
将场景中的这个圆形形状识别为头部是一个有点二进制的问题。这应该完全独立于任何身份认同。如果你只是看到某个人的头脑后面,那个头部属于任何一个人的信念会随着时间的推移而发展。
您可以为每个框架上的每个人设置统计信息。这是一个数据表,而不是单个值。虽然你可能只想在任何特定时间对有限数量的人采取行动。
struct Person {
int person_id;
std::string name;
};
struct Head {
int transient_id;
int x, y;
size_t getNumRanks();
std::pair<Person, float> getPersonWithCertainty(size_t rank);
};
struct HeadTracker {
boost::signal<void(const Frame &)> updates;
};
将排名置于Head
可能会有些误导(无论多么方便),具体取决于系统行为。如果你有过去帧的历史,那么它可能是准确的。如果您在任何给定时间只有一个统计量,那么它可能属于HeadTracker
。
计算排名似乎对于实时系统而言非常强烈,但可能并非如此。我不确定你说的是什么,但考虑一下它当然很有趣。 :)