Подтвердить что ты не робот

Обнаружение затрагивает только непрозрачные пиксели UIImageView, эффективно

Как бы вы обнаруживали касания только непрозрачных пикселей UIImageView, эффективно?

Рассмотрим изображение, подобное приведенному ниже, отображаемое с помощью UIImageView. Цель состоит в том, чтобы распознаватели жестов реагировали только тогда, когда прикосновение происходит в непрозрачной (черной в этом случае) области изображения.

enter image description here

Идеи

  • Переопределить hitTest:withEvent: или pointInside:withEvent:, хотя этот подход может быть ужасно неэффективным, поскольку эти методы вызываются много раз во время события касания.
  • Проверка прозрачности одного пикселя может привести к неожиданным результатам, поскольку пальцы больше одного пикселя. Проверка круговой области пикселей вокруг точки попадания или попытка найти прозрачный путь к краю может работать лучше.

Bonus

  • Было бы неплохо различать внешние и внутренние прозрачные пиксели изображения. В этом примере прозрачные пиксели внутри нуля также должны считаться действительными.
  • Что произойдет, если изображение имеет преобразование?
  • Можно ли ускорить обработку изображений?
4b9b3361

Ответ 1

Здесь моя быстрая реализация: (на основе Получение значения альфа-пикселя для UIImage)

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    //Using code from /questions/35052/retrieving-a-pixel-alpha-value-for-a-uiimage

    unsigned char pixel[1] = {0};
    CGContextRef context = CGBitmapContextCreate(pixel,
                                                 1, 1, 8, 1, NULL,
                                                 kCGImageAlphaOnly);
    UIGraphicsPushContext(context);
    [image drawAtPoint:CGPointMake(-point.x, -point.y)];
    UIGraphicsPopContext();
    CGContextRelease(context);
    CGFloat alpha = pixel[0]/255.0f;
    BOOL transparent = alpha < 0.01f;

    return !transparent;
}

Это предполагает, что изображение находится в том же координатном пространстве, что и point. Если масштабирование продолжается, вам может потребоваться преобразовать point, прежде чем проверять данные пикселя.

Появляется для работы довольно быстро для меня. Я измерял ок. 0,1-0,4 мс для вызова этого метода. Он не делает внутреннее пространство и, вероятно, не оптимален.

Ответ 2

В github вы можете найти проект Ole Begemann, который расширяет UIButton, так что он обнаруживает только штрихи, в которых изображение кнопки не прозрачным.

Так как UIButton является подклассом UIView, его адаптация к UIImageView должна быть простой.

Надеюсь, что это поможет.

Ответ 3

Ну, если вам нужно сделать это очень быстро, вам нужно предварительно просчитать маску.

Здесь, как его извлечь:

UIImage *image = [UIImage imageNamed:@"some_image.png"];
NSData *data = (NSData *) CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
unsigned char *pixels = (unsigned char *)[data bytes];
BOOL *mask = (BOOL *)malloc(data.length);
for (int i = 0; i < data.length; i += 4) {
  mask[i >> 2] = pixels[i + 3] == 0xFF; // alpha, I hope
}
// TODO: save mask somewhere

Или вы можете использовать контекстное решение 1x1 для предварительного расчета маски. Наличие маски означает, что вы можете проверить любую точку с затратами на один доступ к индексированной памяти.

Что касается проверки большей площади, чем одного пикселя, я бы проверял пиксели по кругу с центром в точке касания. Около 16 очков на круге должно быть достаточно.

Обнаружение также внутренних пикселей: еще один шаг предварительной калькуляции - вам нужно найти выпуклую оболочку маски. Вы можете сделать это, используя алгоритм "Graham scan" http://softsurfer.com/Archive/algorithm_0109/algorithm_0109.htm Затем либо заполните эту область в маске, либо сохраните многоугольник и вместо этого используйте тест "точка-в-полигон".

И, наконец, если изображение имеет преобразование, вам нужно преобразовать координаты точки из пространства экрана в пространство изображения, а затем вы можете просто проверить предварительно рассчитанную маску.