在图像上绘制矩形 view.image 未正确缩放 - iOS
Draw rectangles on image view.image not scaling properly - iOS
- 我从
imageView.image
(一张照片)开始。
- 我提交(POST)
imageView.image
到远程服务(Microsoft face detection)进行处理。
- 远程服务 returns JSON
CGRect
为图像上检测到的每个人脸。
- 我将 JSON 送入我的 UIView 以绘制矩形。我用
{0, 0, imageView.image.size.width, imageView.image.size.height}
的框架启动我的 UIView。 <-- 我的思路,一个frame相当于imageView.image
的大小
- 将我的 UIView 添加为
self.imageView
或 self.view
的子视图(两者都试过了)
最终结果:
绘制了矩形,但它们在 imageView.image
上显示不正确。也就是说,为每个面孔生成的 CGRects 应该与远程服务返回的图像坐标 space 相关,但一旦我添加自定义视图它们就会消失。
我相信我可能遇到某种缩放问题,因为如果我将 CGRects / 2 中的每个值除以(作为测试),我可以获得一个近似值,但仍然有偏差。微软文档指出检测到的人脸返回时带有矩形,指示图像中人脸的位置像素。然而,在绘制我的路径时,它们不是被视为点吗?
此外,我不应该使用与 imageView.image
的框架等效的框架启动我的视图,以便视图与提交的图像匹配相同的坐标 space 吗?
这是一个屏幕截图示例,说明如果我尝试通过将每个 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];
}];
我们有几个问题:
Microsoft returns 像素和 iOS 使用点数。它们之间的区别仅在于屏幕尺寸。例如在 iPhone 5 : 1 pt = 2 px 和 3GS 1px = 1 pt。查看 iOS 文档以获取更多信息。
您的 UIImageView 的框架不是图像框架。当 Microsoft returns 人脸框架时,它 returns 它在图像框架中而不是在 UIImageView 框架中。所以我们遇到了坐标系的问题。
如果使用自动版式,请注意时间。当调用 ViewDidLoad: 时,由约束设置的视图框架与您在屏幕上看到的框架不同。
解决方案:
我只是一个只读 Objective C 开发人员,所以我不能给你代码。我可以 Swift 但这不是必需的。
将像素转换为点。这很简单:使用比例。
使用您所做的定义脸部框架。然后你必须将你确定的坐标从图像框架坐标系移动到 UIImageView 坐标系。这不太容易。这取决于您的 UIImageView 的 contentMode。但是我很快就在互联网上找到了有关它的信息。
如果使用AutoLayout,在AutoLayout完成后添加人脸的边框来计算布局。所以当 ViewDidLayoutSubview: 被调用时。
或者,更好的是,使用约束在 UIImageView 中设置框架。
希望说得够清楚。
一些链接:
Displayed Image Frame In UIImageView
- 我从
imageView.image
(一张照片)开始。 - 我提交(POST)
imageView.image
到远程服务(Microsoft face detection)进行处理。 - 远程服务 returns JSON
CGRect
为图像上检测到的每个人脸。 - 我将 JSON 送入我的 UIView 以绘制矩形。我用
{0, 0, imageView.image.size.width, imageView.image.size.height}
的框架启动我的 UIView。 <-- 我的思路,一个frame相当于imageView.image
的大小
- 将我的 UIView 添加为
self.imageView
或self.view
的子视图(两者都试过了)
最终结果:
绘制了矩形,但它们在 imageView.image
上显示不正确。也就是说,为每个面孔生成的 CGRects 应该与远程服务返回的图像坐标 space 相关,但一旦我添加自定义视图它们就会消失。
我相信我可能遇到某种缩放问题,因为如果我将 CGRects / 2 中的每个值除以(作为测试),我可以获得一个近似值,但仍然有偏差。微软文档指出检测到的人脸返回时带有矩形,指示图像中人脸的位置像素。然而,在绘制我的路径时,它们不是被视为点吗?
此外,我不应该使用与 imageView.image
的框架等效的框架启动我的视图,以便视图与提交的图像匹配相同的坐标 space 吗?
这是一个屏幕截图示例,说明如果我尝试通过将每个 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];
}];
我们有几个问题:
Microsoft returns 像素和 iOS 使用点数。它们之间的区别仅在于屏幕尺寸。例如在 iPhone 5 : 1 pt = 2 px 和 3GS 1px = 1 pt。查看 iOS 文档以获取更多信息。
您的 UIImageView 的框架不是图像框架。当 Microsoft returns 人脸框架时,它 returns 它在图像框架中而不是在 UIImageView 框架中。所以我们遇到了坐标系的问题。
如果使用自动版式,请注意时间。当调用 ViewDidLoad: 时,由约束设置的视图框架与您在屏幕上看到的框架不同。
解决方案:
我只是一个只读 Objective C 开发人员,所以我不能给你代码。我可以 Swift 但这不是必需的。
将像素转换为点。这很简单:使用比例。
使用您所做的定义脸部框架。然后你必须将你确定的坐标从图像框架坐标系移动到 UIImageView 坐标系。这不太容易。这取决于您的 UIImageView 的 contentMode。但是我很快就在互联网上找到了有关它的信息。
如果使用AutoLayout,在AutoLayout完成后添加人脸的边框来计算布局。所以当 ViewDidLayoutSubview: 被调用时。 或者,更好的是,使用约束在 UIImageView 中设置框架。
希望说得够清楚。
一些链接:
Displayed Image Frame In UIImageView