Я пытаюсь определить лица и извлечь лицевые ориентиры с камеры iphone (в формате BGRA) с помощью dlib.
До сих пор я сделал это, чтобы обнаружить морщины лица из AVMetaData и нарисовать 68 dlib ориентиров в пределах этих границ на изображении. Когда угол наклона обнаруженной головки (данные угла наклона извлекаются также из AVMetadata) составляет примерно от -30 до 30 градусов, все работает нормально. Однако, если обнаруженная головка поворачивается на 30 градусов, ориентиры на лице не будут совмещены должным образом. Эти 68 точек больше не будут вращаться вдоль головы, говоря, что я держу свой iphone в режиме альбомной ориентации с кнопкой «Домой» слева и фронтальной камерой, лицо с 68 нарисованными точками остается фронтальным.
Я тестировал openGL (рендеринг вне экрана) и openCV для рендеринга видеоизображений, все они дают одинаковые результаты. Подход к рендерингу кажется мне неуместным.
Мои вопросы
- Как правильно выровнять эти сгенерированные dlib 68 точек, несмотря на угол крена головы?
- Или, возможно, dlib точно обнаружит лица, которые перевернутся на 30 градусов?
- (NSMutableArray <NSMutableArray <NSValue *> *>*)detecitonOnSampleBuffer:(CMSampleBufferRef)sampleBuffer inRects:(NSArray<NSValue *> *)rects {
dlib::array2d<dlib::bgr_pixel> img;
dlib::array2d<dlib::bgr_pixel> img_gray;
// MARK: magic
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
CVPixelBufferLockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly);
size_t width = CVPixelBufferGetWidth(imageBuffer);
size_t height = CVPixelBufferGetHeight(imageBuffer);
char *baseBuffer = (char *)CVPixelBufferGetBaseAddress(imageBuffer);
// set_size expects rows, cols format
img.set_size(height, width);
// copy samplebuffer image data into dlib image format
img.reset();
long position = 0;
while (img.move_next()) {
dlib::bgr_pixel& pixel = img.element();
// assuming bgra format here
long bufferLocation = position * 4; //(row * width + column) * 4;
char b = baseBuffer[bufferLocation];
char g = baseBuffer[bufferLocation + 1];
char r = baseBuffer[bufferLocation + 2];
dlib::bgr_pixel newpixel(b, g, r);
pixel = newpixel;
position++;
}
// unlock buffer again until we need it again
CVPixelBufferUnlockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly);
// convert the face bounds list to dlib format
std::vector<dlib::rectangle> convertedRectangles = [self convertCGRectValueArray:rects bound:CGSizeMake(height, width)];
dlib::assign_image(img_gray, img);
NSMutableArray *facesLandmarks = [NSMutableArray arrayWithCapacity:0];
for (unsigned long j = 0; j < convertedRectangles.size(); ++j) {
/* original codes start from here */
dlib::rectangle oneFaceRect = convertedRectangles[j];
// detect all landmarks
dlib::full_object_detection shape = predictor(img, oneFaceRect);
NSMutableArray *eachFaceLandmarks = [NSMutableArray arrayWithCapacity:0];
for (int i = 0; i < shape.num_parts(); i++) {
dlib::point p = shape.part(i);
[eachFaceLandmarks addObject:[NSValue valueWithCGPoint:CGPointMake(p.x(), p.y())]];
}
//
[facesLandmarks addObject:eachFaceLandmarks];
}
return facesLandmarks;
}