将 vector<dlib::point> 转换为 NSArray,以便将其传递给 Swift class
Convert a vector<dlib::point> to an NSArray so it can be passed to a Swift class
我正在使用 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,以便我可以 return 数组并在我的 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。任何帮助将不胜感激!
NSArray
s 只能包含 Objective-C 对象,不能包含 C++ 对象。所以你必须先把你的点数转换成NSValue
s。这样的事情应该有效:
NSMutableArray* facialLandmarksArray = [NSMutableArray arrayWithCapacity: facialLandmarks.size()];
for (auto const& pt: facialLandmarks) {
[facialLandmarksArray addObject: [NSValue valueWithCGPoint:CGPointMake(pt.x, pt.y)]];
}
并确保将其编译为 Objective-C++(文件结尾为 *.mm)。
但是,请注意,这对于大向量来说效果不佳。 Swift 和 C++ 都能够确保 arrays/vectors 的值存储在 consecutive memory, 桥接 Objective-C 破坏本地.
这里的几个挑战是:
1) 我们希望尽量减少地标点的复制,因为这种复制会影响软件性能和内存占用。
2) 我们如何在 Swift 代码中使用 C++ vector
的成员,类型 dlib::point
的实例?
解决这些挑战取决于用例。需要考虑的一些问题:
1) performance/memory 足迹有多重要?如果这不是问题,则在将值提供给 Swift 时复制这些值是可以的。当然,这也取决于 C++ 代码是否必须使用 Swift.
更改的值
2) 我们在谈论多少个地标点?如果它是一百点左右,那么复制它们不太可能影响性能。
3) Swift 代码只是要使用 C++ 库返回的地标点的值,还是要修改这些值并期望 C++ 代码 "see" 这些更改?
4) Swift 代码通常会访问每个地标点多少次?如果每个点都被多次访问,那么最好将所有点复制一次到一个可以在 Swift 中使用的结构中,而不是每次访问都创建一个副本,而不是每次都复制一个坐标 [=48] =] 访问它。
5) 可以容忍多少复杂度?您愿意编写大量 C++ 代码吗?您是否喜欢使用 Swift 中的指针类型,例如UnsafeMutablePointer
?
这里有一些关于如何做到这一点的想法:
1) 在Objective-C++中构建一个可在Swift中使用的集合,并将地标点坐标值复制到该结构中。 @Tobi的回答就是一个例子。
2) 与上面的 (1) 类似,但 Swift 可访问集合包含指向坐标值的指针。
3) 编写一个 Objective-C++ class 其接口可从 Swift 访问并且所有特定于 C++ 的代码都隐藏在实现中。该接口可以允许 Swift 代码读取(和写入,如果需要的话)特定地标点的特定坐标。
4) (3) 的变体,其中 Swift 代码访问指向坐标值的指针。在 Swift 侧使用这些时需要小心,以避免复制坐标值。
如果你提供一些关于你的用例的细节,我可以试着想出一个例子。
我正在使用 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,以便我可以 return 数组并在我的 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。任何帮助将不胜感激!
NSArray
s 只能包含 Objective-C 对象,不能包含 C++ 对象。所以你必须先把你的点数转换成NSValue
s。这样的事情应该有效:
NSMutableArray* facialLandmarksArray = [NSMutableArray arrayWithCapacity: facialLandmarks.size()];
for (auto const& pt: facialLandmarks) {
[facialLandmarksArray addObject: [NSValue valueWithCGPoint:CGPointMake(pt.x, pt.y)]];
}
并确保将其编译为 Objective-C++(文件结尾为 *.mm)。
但是,请注意,这对于大向量来说效果不佳。 Swift 和 C++ 都能够确保 arrays/vectors 的值存储在 consecutive memory, 桥接 Objective-C 破坏本地.
这里的几个挑战是:
1) 我们希望尽量减少地标点的复制,因为这种复制会影响软件性能和内存占用。
2) 我们如何在 Swift 代码中使用 C++ vector
的成员,类型 dlib::point
的实例?
解决这些挑战取决于用例。需要考虑的一些问题:
1) performance/memory 足迹有多重要?如果这不是问题,则在将值提供给 Swift 时复制这些值是可以的。当然,这也取决于 C++ 代码是否必须使用 Swift.
更改的值2) 我们在谈论多少个地标点?如果它是一百点左右,那么复制它们不太可能影响性能。
3) Swift 代码只是要使用 C++ 库返回的地标点的值,还是要修改这些值并期望 C++ 代码 "see" 这些更改?
4) Swift 代码通常会访问每个地标点多少次?如果每个点都被多次访问,那么最好将所有点复制一次到一个可以在 Swift 中使用的结构中,而不是每次访问都创建一个副本,而不是每次都复制一个坐标 [=48] =] 访问它。
5) 可以容忍多少复杂度?您愿意编写大量 C++ 代码吗?您是否喜欢使用 Swift 中的指针类型,例如UnsafeMutablePointer
?
这里有一些关于如何做到这一点的想法:
1) 在Objective-C++中构建一个可在Swift中使用的集合,并将地标点坐标值复制到该结构中。 @Tobi的回答就是一个例子。
2) 与上面的 (1) 类似,但 Swift 可访问集合包含指向坐标值的指针。
3) 编写一个 Objective-C++ class 其接口可从 Swift 访问并且所有特定于 C++ 的代码都隐藏在实现中。该接口可以允许 Swift 代码读取(和写入,如果需要的话)特定地标点的特定坐标。
4) (3) 的变体,其中 Swift 代码访问指向坐标值的指针。在 Swift 侧使用这些时需要小心,以避免复制坐标值。
如果你提供一些关于你的用例的细节,我可以试着想出一个例子。