【问题标题】:Convert a vector<dlib::point> to an NSArray so it can be passed to a Swift class将 vector<dlib::point> 转换为 NSArray 以便可以将其传递给 Swift 类
【发布时间】:2018-08-14 11:53:13
【问题描述】:

我正在使用 dlib 的面部标志检测器,并希望将面部标志坐标存储在可在 Swift 中使用的数组中。

目前我已将地标坐标存储在向量中:

std::vector<dlib::point> facialLandmarks;

for (unsigned long k = 0; k < shape.num_parts(); k++) {
            dlib::point p = shape.part(k);

            facialLandmarks.push_back(p);
        }

我现在想编写一个函数,将向量转换为 NSArray,以便我可以返回该数组并在我的 Swift 代码中使用它。

当我尝试以下操作时:

 NSArray* facialLandmarksArray = &facialLandmarks[0];

我收到一个错误:

Cannot initialize a variable of type 'NSArray *__strong' with an rvalue of type 'std::__1::__vector_base<dlib::vector<long, 2>, std::__1::allocator<dlib::vector<long, 2> > >::value_type *' (aka 'dlib::vector<long, 2> *')

我真的对 Objective-C 或 C++ 知之甚少,但需要将其用于 Dlib。任何帮助将不胜感激!

【问题讨论】:

  • 我不知道 Swift,但是查看文档,您如何确定您需要 NSArray 而不是 Array
  • @Cheersandhth.-Alf 那段代码实际上是 Obj-C,问题中没有 Swift 代码。 Array 是 Swift 类型,Obj-C 只有 NSArray
  • @DávidPásztor:谢谢。
  • 我已经创建了一个桥接头,这样我就可以将一个 Objective-C 类 (DlibWrapper.mm) 与我的 Swift 代码的其余部分一起使用。它运行良好,但现在我不知道如何将面部地标坐标存储在可以传递给我的 Swift 类之一的数据结构中。
  • @Hardy143 下面的答案对你有用吗?

标签: c++ objective-c nsarray


【解决方案1】:

NSArrays 只能包含 Objective-C 对象,不能包含 C++ 对象。所以你必须先将你的积分转换为NSValues。这样的事情应该可以工作:

NSMutableArray* facialLandmarksArray = [NSMutableArray arrayWithCapacity: facialLandmarks.size()];

for (auto const& pt: facialLandmarks) {
    [facialLandmarksArray addObject: [NSValue valueWithCGPoint:CGPointMake(pt.x, pt.y)]];
}

并确保将其编译为 Objective-C++(文件以 *.mm 结尾)。

但是,请注意,这不适用于大型向量。 SwiftC++ 都能够确保此类数组/向量的值存储在 consecutive memory 中,通过 Objective-C 进行桥接破坏这个地方。

【讨论】:

  • 使用这种方法,每个点被复制两次:从形状部分构建facialLandmarks 向量时,以及从facialLandmarks 构建facialLandmarksArray 时。这可以通过消除facialLandmarks 向量并直接从形状部分填充facialLandmarksArray 来减少到一个副本。
  • 另一个观察结果:dlib::pointtypedefvector&lt;long,2&gt;,所以pt.xpt.y 不起作用。我在看dlib.net/linear_algebra.html#point;那是正确的图书馆吗?好吧,错误消息还表明point就是typedef
  • @Tobi 非常感谢您的回答。它似乎工作得很好。然而有一件事是在 Swift 中循环遍历数组并打印它打印为 NSPoint: {297, 238} 的值。是否可以在没有 NSPoint 文本的情况下打印它?我想将此数据写入一个txt文件。
  • @Hardy143 我知道 C++Objective-C 之间的桥接,但对 Swift 部分了解不多...也许您可以将其表述为一个新问题,让 Swift 社区回答打印问题。
【解决方案2】:

这里有几个挑战:

1) 我们希望最小化地标点的复制,因为这样的复制会影响软件性能和内存占用。

2) 我们如何在 Swift 代码中使用 C++ vector 的成员,在这种情况下为 dlib::point 类型的实例?

解决这些挑战取决于用例。需要考虑的一些问题:

1) 性能/内存占用有多重要?如果这不是问题,那么在将值提供给 Swift 时复制这些值是可以的。当然,这也取决于 C++ 代码是否必须使用 Swift 更改的值。

2) 我们讨论了多少个地标点?如果是一百点左右,那么复制它们不太可能对性能造成影响。

3) Swift 代码是仅仅使用 C++ 库返回的地标点的值,还是会修改这些值并期望 C++ 代码“看到”这些变化?

4) 通常,Swift 代码会访问每个地标点多少次?如果每个点被多次访问,那么最好将所有点一次复制到一个可以在 Swift 中使用的结构中,而不是在每次访问时创建一个副本,而不是在每次 Swift 访问它时复制一个坐标。

5) 可以容忍多少复杂性?你愿意写很多 C++ 代码吗?您是否愿意在 Swift 中使用指针类型,例如UnsafeMutablePointer?

这里有一些关于如何做到这一点的想法:

1) 在 Objective-C++ 中构造一个可在 Swift 中使用的集合,并将地标点坐标值复制到该结构中。 @Tobi 的回答就是一个例子。

2) 与上面的 (1) 类似,但 Swift 可访问的集合包含指向坐标值的指针。

3) 编写一个 Objective-C++ 类,其接口可从 Swift 访问,并且所有 C++ 特定代码都隐藏在实现中。该接口可以允许 Swift 代码读取(和写入,如果需要)特定地标点的特定坐标。

4) (3) 的变体,其中 Swift 代码访问指向坐标值的指针。在 Swift 端使用这些时需要小心,以避免复制坐标值。

如果你提供一些关于你的用例的细节,我可以试着举一个例子。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-12-04
    • 1970-01-01
    • 1970-01-01
    • 2012-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多