在图像视图上绘制矩形。图像无法正确缩放 - iOS

Posted

技术标签:

【中文标题】在图像视图上绘制矩形。图像无法正确缩放 - iOS【英文标题】:Draw rectangles on image view.image not scaling properly - iOS 【发布时间】:2015-07-06 04:48:46 【问题描述】:
    我从imageView.image(一张照片)开始。 我将imageView.image 提交(POST)到远程服务(Microsoft face detection)进行处理。 远程服务为图像上检测到的每个人脸返回 CGRect 的 JSON。 我将 JSON 输入我的 UIView 以绘制矩形。我用0, 0, imageView.image.size.width, imageView.image.size.height 的框架启动我的UIView。 我的想法,一个frame的大小相当于imageView.image 将我的 UIView 添加为 self.imageViewself.view 的子视图(都尝试过)

最终结果: 绘制了矩形,但它们在imageView.image 上显示不正确。也就是说,为每个人脸生成的 CGRect 应该是相对于图像的坐标空间,由远程服务返回,但是一旦我添加了我的自定义视图,它们就会消失。

我相信我可能会遇到某种缩放问题,因为如果我将 CGRects / 2 中的每个值除以(作为测试)我可以得到一个近似值但仍然关闭。 microsoft 文档指出,检测到的人脸返回时带有指示图像中人脸位置的矩形以像素为单位。然而,在绘制我的路径时,它们不是被视为点吗?

另外,我不应该使用与imageView.image 的框架等效的框架来启动我的视图,以便视图与提交的图像匹配相同的坐标空间吗?

这是一个屏幕截图示例,如果我尝试通过将每个 CGRect 除以 2 来缩小它们的大小。

我是 ios 的新手,我从书本中脱离出来,将其作为一种自我练习。我可以根据需要提供更多代码。提前感谢您的洞察力!

编辑 1

我为每个矩形添加一个子视图,因为我通过以下方法遍历包含每个面的矩形的面部属性数组,该方法在 (void)viewDidAppear:(BOOL)animated 期间被调用

- (void)buildFaceRects 

    // build an array of CGRect dicts off of JSON returned from analized image
    NSMutableArray *array = [self analizeImage:self.imageView.image];

    // enumerate over array using block - each obj in array represents one face
   [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) 

       // build dictionary of rects and attributes for the face
       NSDictionary *json = [NSDictionary dictionaryWithObjectsAndKeys:obj[@"attributes"], @"attributes", obj[@"faceId"], @"faceId", obj[@"faceRectangle"], @"faceRectangle", nil];

       // initiate face model object with dictionary
       ZGCFace *face = [[ZGCFace alloc] initWithJSON:json];

       NSLog(@"%@", face.faceId);
       NSLog(@"%d", face.age);
       NSLog(@"%@", face.gender);
       NSLog(@"%f", face.faceRect.origin.x);
       NSLog(@"%f", face.faceRect.origin.y);
       NSLog(@"%f", face.faceRect.size.height);
       NSLog(@"%f", face.faceRect.size.width);

       // define frame for subview containing face rectangle
       CGRect imageRect = CGRectMake(0, 0, self.imageView.image.size.width, self.imageView.image.size.height);

       // initiate rectange subview with face info
       ZGCFaceRectView *faceRect = [[ZGCFaceRectView alloc] initWithFace:face frame:imageRect];

       // add view as subview of imageview (?)
       [self.imageView addSubview:faceRect];

   ];


编辑 2:

    /* Image info */
    UIImageView *iv = self.imageView;
    UIImage *img = iv.image;
    CGImageRef CGimg = img.CGImage;

    // Bitmap dimensions [pixels]
    NSUInteger imgWidth = CGImageGetWidth(CGimg);
    NSUInteger imgHeight = CGImageGetHeight(CGimg);
    NSLog(@"Image dimensions: %lux%lu", imgWidth, imgHeight);

    // Image size pixels (size * scale)
    CGSize imgSizeInPixels = CGSizeMake(img.size.width * img.scale, img.size.height * img.scale);
    NSLog(@"image size in Pixels: %fx%f", imgSizeInPixels.width, imgSizeInPixels.height);

    // Image size points
    CGSize imgSizeInPoints = img.size;
    NSLog(@"image size in Points: %fx%f", imgSizeInPoints.width, imgSizeInPoints.height);



       // Calculate Image frame (within imgview) with a contentMode of UIViewContentModeScaleAspectFit
       CGFloat imgScale = fminf(CGRectGetWidth(iv.bounds)/imgSizeInPoints.width, CGRectGetHeight(iv.bounds)/imgSizeInPoints.height);
       CGSize scaledImgSize = CGSizeMake(imgSizeInPoints.width * imgScale, imgSizeInPoints.height * imgScale);
       CGRect imgFrame = CGRectMake(roundf(0.5f*(CGRectGetWidth(iv.bounds)-scaledImgSize.width)), roundf(0.5f*(CGRectGetHeight(iv.bounds)-scaledImgSize.height)), roundf(scaledImgSize.width), roundf(scaledImgSize.height));


       // initiate rectange subview with face info
       ZGCFaceRectView *faceRect = [[ZGCFaceRectView alloc] initWithFace:face frame:imgFrame];

       // add view as subview of image view
       [iv addSubview:faceRect];

   ];

【问题讨论】:

在哪种方法中将 UIView 添加为 imageView 的子视图? 我更新了问题。当我迭代一组dicts时,我添加了子视图(每个面/矩形一个) 照片的尺寸与显示它的图像查看器的尺寸是多少?对于网页,我有与您相同的场景-原始照片是 1920x1080,视图 img 是 480x270。因此,FaceApi 返回的人脸尺寸必须在绘制框时缩放 0.25。 @AlexS Poql 的响应建立在相同的基础上。我将绘制的矩形视图添加为错误框架/视图的子视图 【参考方案1】:

我们有几个问题:

    Microsoft 返回像素,iOS 使用点。它们之间的区别仅在于屏幕尺寸。例如在 iPhone 5 上:1 pt = 2 px 和 3GS 1px = 1 pt。查看 iOS 文档以获取更多信息。

    您的 UIImageView 的框架不是图像框架。微软返回人脸框架时,是在图片的框架中返回,而不是在 UIImageView 的框架中返回。所以我们遇到了坐标系统的问题。

    如果您使用自动布局,请注意时间。由约束设置的视图框架在调用 ViewDidLoad: 时与在屏幕上看到时不同。

解决方案:

我只是一个只读的 Objective C 开发人员,所以我不能给你代码。我可以在 Swift 中使用,但这不是必需的。

    将像素转换为点。这很简单:使用率。

    使用您所做的定义面部框架。然后你必须将你确定的坐标从图像帧坐标系移动到 UIImageView 坐标系。这不太容易。这取决于你的 UIImageView 的 contentMode。但我很快在互联网上找到了有关它的信息。

    如果您使用 AutoLayout,请在 AutoLayout 完成计算布局时添加面部框架。所以当 ViewDidLayoutSubview: 被调用时。 或者,更好的是,使用约束在 UIImageView 中设置框架。

我希望足够清楚。

一些链接:

    iOS Drawing Concepts

    Displayed Image Frame In UIImageView

【讨论】:

感谢@Poql,这无疑使我朝着正确的方向前进。通过确定 ImageView.image 框架并将其用作我的自定义视图的框架,我能够对齐我的框架,但是,我仍然无法弄清楚如何计算从像素到点的比率。请参阅我的第二次编辑,我得到的像素尺寸与我的点尺寸相同。我不应该在 iPhone 6 上获得每点 x2 像素吗?我最终硬编码了一个 2 的比例因子并将我的矩形除以它,它足够接近,但很高兴找出正确的方法。 该文档谈到了 UIImage、UIScreen、UIView 和 CALayer 中的 contentScaleFactor 属性。除以它应该可以完成工作。

以上是关于在图像视图上绘制矩形。图像无法正确缩放 - iOS的主要内容,如果未能解决你的问题,请参考以下文章

在 ios 的滚动视图中绘制缩放的图像视图?

拖动并缩放使用 UIBezierPath IOS/Swift 绘制的矩形

在iOS中使用动画将图像缩放到特定的矩形?

如何在 iPad 中用手指在图像视图上绘制矩形后将图像保存在照片库中?

IOS:在滚动视图中添加图像视图以进行缩放

UIImageView 在矩形中绘制图像大小而不是图像视图