Рисование прямоугольников на изображении. Изображение не масштабируется должным образом - iOS

  1. Я начинаю с imageView.image (фото).
  2. Я отправляю (POST) imageView.image в удаленную службу (Microsoft Face Detection) для обработки.
  3. Удаленная служба возвращает JSON из CGRect для каждого обнаруженного лица на изображении.
  4. Я загружаю JSON в свой UIView, чтобы рисовать прямоугольники. Я запускаю свой UIView с кадра {0, 0, imageView.image.size.width, imageView.image.size.height}. ‹- на мой взгляд, рамка, эквивалентная размеру imageView.image
  5. Добавить мой UIView как подвид self.imageView ИЛИ self.view (пробовал оба)

Конечный результат: прямоугольники нарисованы, но они не отображаются правильно на imageView.image. То есть CGRects, сгенерированные для каждой из граней, должны относиться к координатному пространству изображения, возвращенному удаленной службой, но они не отображаются, как только я добавляю свое пользовательское представление.

Я считаю, что у меня может быть какая-то проблема с масштабированием, поскольку, если я разделю каждое значение в 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];

   }];

person Rob    schedule 06.07.2015    source источник
comment
В каком методе вы добавляете свой UIView в качестве подпредставления вашего imageView?   -  person GaétanZ    schedule 06.07.2015
comment
Обновил вопрос. Я добавляю подвиды (по одному на лицо / прямоугольник) по мере перебора массива dicts.   -  person Rob    schedule 06.07.2015
comment
Каковы размеры фотографии и средства просмотра изображений, в котором она отображается? У меня был тот же сценарий, что и у вас, для веб-страницы - исходная фотография была 1920х1080, а изображение - 480x270. Поэтому размеры лица, возвращаемые FaceApi, должны были быть увеличены на 0,25 при рисовании блоков.   -  person Alex S    schedule 06.07.2015
comment
@AlexS ответ от Poql строится так же. Я добавлял нарисованный прямоугольник как часть неправильного кадра / представления   -  person Rob    schedule 13.07.2015


Ответы (1)


У нас есть несколько проблем:

  1. Microsoft возвращает пиксель, а iOS использует баллы. Разница между ними как раз в размере экрана. Например, на iPhone 5: 1 точка = 2 пикселя, а на 3GS 1 пиксель = 1 точка. Обратитесь к документации iOS для получения дополнительной информации.

  2. Фрейм вашего UIImageView не является фреймом изображения. Когда Microsoft возвращает кадр лица, он возвращает его в кадре изображения, а не в кадре UIImageView. Итак, у нас возникла проблема с системой координат.

  3. Будьте осторожны со временем, если используете Autolayout. При вызове ViewDidLoad: рамка представления, заданная ограничениями, отличается от кадра, когда вы видите его на экране.

Решение :

Я просто разработчик Objective C только для чтения, поэтому не могу дать вам код. Я мог бы использовать Swift, но в этом нет необходимости.

  1. Преобразуйте пиксели в точки. Это просто: используйте соотношение.

  2. Определите рамку лица, используя то, что вы сделали. Затем вам нужно переместить координаты, которые вы определили из системы координат кадра изображения, в систему координат UIImageView. Это не так просто. Это зависит от contentMode вашего UIImageView. Но я быстро нахожу информацию об этом в Интернете.

  3. Если вы используете AutoLayout, добавьте рамку лица, когда AutoLayout завершит расчет макетов. Итак, когда вызывается ViewDidLayoutSubview:. Или, что лучше, используйте ограничения для установки вашего фрейма в UIImageView.

Я надеюсь быть достаточно ясным.

Некоторые ссылки:

  1. Концепции рисования iOS

  2. Отображаемый фрейм изображения в UIImageView

person GaétanZ    schedule 06.07.2015
comment
Спасибо @Poql, это определенно направило меня в правильном направлении. определив фрейм ImageView.image и используя его в качестве фрейма для моего пользовательского представления, я смог выровнять свои фреймы, однако я до сих пор не могу понять, как рассчитать соотношение пикселей к точкам. Смотрите мое второе правка, я получаю те же размеры в пикселях, что и в точках. Разве я не должен получать x2 пикселя на точку на iPhone 6? В итоге я жестко закодировал коэффициент масштабирования 2 и разделил на него свои прямоугольники, и это достаточно близко, но было бы неплохо найти правильный способ. - person Rob; 13.07.2015
comment
В документе говорится о свойстве contentScaleFactor в UIImage, UIScreen, UIView и CALayer. Деление на него должно делать свою работу. - person GaétanZ; 15.07.2015