用 C++ 设计事件驱动的头部跟踪库

发布于 2024-12-06 14:40:53 字数 1539 浏览 1 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

人生戏 2024-12-13 14:40:54

我将遵循 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) 从表中删除了一个游标
在桌面上移动刷新(TuioTimebundleTime)这个
方法在每个包之后调用,用它来重新绘制屏幕
示例

我的客户将需要实现一些头部跟踪事件回调方法。按照这个大纲看起来很简单,但是不知道在C++中这样做是否正常。

I will follow the delegation pattern used in the TUIO C++ interface. 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

As it says in the TUIO documentation:

Your application needs to implement the TuioListener interface, and
has to be added to the TuioClient in order to receive messages.

A TuioListener needs to implement the following methods:

addTuioObject(TuioObject *tobj) this is called when an object becomes
visible removeTuioObject(TuioObject *tobj) an object was removed from
the table updateTuioObject(TuioObject *tobj) an object was moved on
the table surface addTuioCursor(TuioCursor *tcur) this is called when
a new cursor is detected removeTuioCursor(TuioCursor *tcur) a cursor
was removed from the table updateTuioCursor(TuioCursor *tcur) a cursor
was moving on the table surface refresh(TuioTime bundleTime) this
method is called after each bundle, use it to repaint your screen for
example

My client will be required to implement some head tracking event callback methods. It seems simple according to this outline, but I didn't know if it was normal to do it this way in C++.

无语# 2024-12-13 14:40:54

如果库控制程序流,那么回调可能是最简单的解决方案。如果您愿意,将其抽象为 协程 也可以很好地转换为多线程解决方案。我提出这一点是为了实现和维护的简便性,而不是性能。

我过去已经成功地使用 boost::signal 作为达到此目的的手段,值得一看。

您的公共界面可能是等效的,尽管可能更详细一些。我希望这些类中的大多数都是纯虚拟接口,但为了演示,普通结构更容易阅读。

struct Head {
  int transient_id;
  int x, y;
};

struct Frame {
  std::vector<Head> heads;
};

struct HeadTracker {
  boost::signal<void(const Frame &)> updates;
};

我不确定当头部进入或离开相关性时您绝对需要触发事件。更新给出了 xy,因此相关性更改只是 transient_id。如果客户端不知道它拥有哪个 transient_id,它可以只请求详细信息。尽管它可能有助于简化处理。

我对标识符的确定程度有些担忧,因为理论上(或者可能经常)它们会发生变化。我不清楚您是否正在跟踪特定人的身份(transient_id #35523 是 Jane Doe),或者只是该形状是否是头部。

如果简走出门,然后再回来,每个系统都会有两个不同的人。这会简化事情,无论如何我都会建议在幕后以这种方式进行建模。

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

对于实时系统来说,计算排名似乎相当繁重,但也许并非如此。我不确定你说的是不是这个,但想想确实很有趣。 :)

If the library is controlling the program flow, then callbacks are likely the easiest solution. Abstracting it as a coroutine would also transition well into a multi-threaded solution if you wanted. I offer this in terms of implementation and maintenance ease, not performance.

I have had success using boost::signal as the means to this end in the past, it is worth looking at.

Your public interface may be something equivalent, though perhaps a little more detailed. I would expect pure virtual interfaces for most of these classes, but for demonstration plain structs are a little easier to read.

struct Head {
  int transient_id;
  int x, y;
};

struct Frame {
  std::vector<Head> heads;
};

struct HeadTracker {
  boost::signal<void(const Frame &)> updates;
};

I am not certain you absolutely need to fire an event when a head enters or leaves relevance. The updates give x and y, so relevance changes are only the transient_id. If a client didn't know which transient_id it had, it could just request the details. Though it may be helpful to simplify processing.

I have some concerns about degrees of certainty with your identifiers, as they will theoretically (or maybe routinely) change. It isn't clear to me if you are tracking identity of specific people (transient_id #35523 is Jane Doe) or just whether that shape is a head.

If Jane stepped out of the door, then back in, there would be two different people per the system. This would simplify things and I would recommend modelling it this way behind the scenes anyway.

struct Head {
  int transient_id;
  int x, y;
  float is_head; // [0.0, 1.0]
};

Identifying this round shape in the scene as a head is one problem which is somewhat binary. This should exist entirely independently of any belief in identity. If you only saw the back of someone's head the belief that the head belonged to any one person would evolve as time went on.

You could have a statistic for every person on each frame. That is a table of data, not a single value. Though you would probably only want to act upon a finite number of them at any given time.

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

Putting the rankings in Head may be somewhat misleading (however convenient) depending on the system behavior. If you had history of past frames then it is probably accurate. If you only ever had one statistic at any given time, then it probably belongs in HeadTracker.

Computing the rankings seems like it would be pretty intense for a real-time system, but maybe it isn't. I'm not certain that is what you are talking about, but it's certainly fun to think about. :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文