将CIDetector(面部检测)结果转换为UIImageView坐标

时间:2012-08-30 16:39:50

标签: ios uiimageview core-image face-detection

我一直在努力将CIDetector(面部检测)结果转换为相对于显示图像的UIImageView的坐标,这样我就可以使用CGPath绘制坐标。

我已经查看了这里的所有问题以及我能找到的所有教程,其中大多数都使用了在UIImageView(example)中显示时未缩放的小图像。 我遇到的问题是使用在UIImageView中显示时使用aspectFit缩放的大图像,并确定正确的比例+翻译值。

当测试不同尺寸/纵横比的图像时,我得到的结果不一致,所以我认为我的例程存在缺陷。我一直在努力解决这个问题,所以如果有人有一些提示或者可以X光检查我做错了什么,那将是一个很大的帮助。

我在做什么:

  • 获取面部坐标
  • 使用下面的frameForImage例程(在SO上找到)来获取UIImageView图像的比例和范围
  • 为比例+翻译创建转换
  • 将转换应用于CIDetector结果

//我的确定变换值的例程

NSDictionary* data = [self frameForImage:self.imageView.image inImageViewAspectFit:self.imageView];

CGRect scaledImageBounds = CGRectFromString([data objectForKey:@"bounds"]);
float scale = [[data objectForKey:@"scale"] floatValue];

CGAffineTransform transform = CGAffineTransformMakeScale(scale, -scale);

transform = CGAffineTransformTranslate(transform, 
          scaledImageBounds.origin.x / scale, 
          -(scaledImageBounds.origin.y / scale + scaledImageBounds.size.height / scale));

使用以下方法转换CIDetector结果:

     mouthPosition = CGPointApplyAffineTransform(mouthPosition, transform);

//错误结果的例子:比例似乎不正确

enter image description here

//下面的例程在SO上找到,用于确定使用'aspectFit`在UIImageView中缩放的图像的界限

-(NSDictionary*)frameForImage:(UIImage*)image inImageViewAspectFit:(UIImageView*)myImageView
{
    float imageRatio = image.size.width / image.size.height;
    float viewRatio = myImageView.frame.size.width / myImageView.frame.size.height;

    float scale;
    CGRect boundingRect;
    if(imageRatio < viewRatio)
    {
        scale = myImageView.frame.size.height / image.size.height;
        float width = scale * image.size.width;
        float topLeftX = (myImageView.frame.size.width - width) * 0.5;
        boundingRect = CGRectMake(topLeftX, 0, width, myImageView.frame.size.height);
    }
    else
    {
        scale = myImageView.frame.size.width / image.size.width;
        float height = scale * image.size.height;
        float topLeftY = (myImageView.frame.size.height - height) * 0.5;
        boundingRect = CGRectMake(0, topLeftY, myImageView.frame.size.width, height);
    }

    NSDictionary * data = [NSDictionary dictionaryWithObjectsAndKeys:
                           [NSNumber numberWithFloat:scale], @"scale",
                           NSStringFromCGRect(boundingRect), @"bounds",
                           nil];

    return data;
}

2 个答案:

答案 0 :(得分:4)

我完全理解你要做的事情,但是让我为你提供一种不同的方式来实现你想要的目标。

  • 您的图片尺寸过大
  • 你知道imageView的大小
  • 询问图片的CGImage
  • 确定'scale'因子,即imageView宽度除以图像宽度
  • 将此值与图像高度相乘,然后从imageViewHeight中减去结果,以获得imageView中的“空”高度,让我们称之为'fillHeight'
  • 将'fillHeight'除以2并舍入以获得
  • 下方使用的'offset'值
  • 使用UIGraphicsBeginImageContextWithOptions(imageView.size,NO,0)提供的上下文,绘制背景颜色,然后绘制CGImage

    CGContextDrawImage(context,CGRectMake(0,offset,imageView.size.width,rintf(image.size.height * scale)),[image CGImage]);

  • 使用以下方式获取此新图片:

    UIImage * image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); 返回图片;

  • 设置图片:imageView.image = image;

现在,您可以精确地映射回您的图像,因为您知道精确的缩放比例和偏移。

答案 1 :(得分:0)

这可能是您正在寻找的简单答案。如果你的x和y坐标被反转,你可以自己镜像它们。在下面的代码片段中,我循环浏览我返回的要素并需要反转y坐标,如果是前置摄像头则需要x坐标:

    for (CIFaceFeature *f in features) {
        float newy = -f.bounds.origin.y + self.frame.size.height - f.bounds.size.height;

        float newx = f.bounds.origin.x;
        if( isMirrored ) {
            newx = -f.bounds.origin.x + self.frame.size.width - f.bounds.size.width;
        }
        [[soups objectAtIndex:rnd] drawInRect:CGRectMake(newx, newy, f.bounds.size.width, f.bounds.size.height)];
    }