Создать маску из части изображения в iOS

Я разрабатываю приложение-раскраску для iPad (iOS4+). Приложение должно позволять окрашивать только одну область изображения за раз.

Я имею в виду, что если пользователь коснется любого места на экране и начнет двигать пальцем, цвет должен применяться только к тем пикселям, которые находятся в той же области, что и первая точка касания. Например, если пользователь коснется центра левого изображения и начнет двигать пальцем по всему изображению, он должен получить что-то вроде правого изображения.

введите здесь описание изображения

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

Подскажите, пожалуйста, как сделать такую ​​маску?

Решение может использовать Core Graphics и Open GL.


person Bobrovsky    schedule 31.01.2012    source источник
comment
Похоже на задачу для алгоритма флуд-заполнения.   -  person Till    schedule 31.01.2012
comment
@Пожалуйста, не могли бы вы рассказать об этом подробнее?   -  person Bobrovsky    schedule 31.01.2012
comment
@Borbrovsky использует заливку для поиска границ и создает маску из результата.   -  person Till    schedule 31.01.2012


Ответы (1)


Как предложил @Till, я реализовал алгоритм заполнения очереди. Мне пришлось выполнить некоторые оптимизации удерживать потребление памяти и скорость выполнения в разумных пределах.

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

  • Создайте массив байтов маски (image_width * image_height bytes)
  • Заполните весь массив значениями 0xFF
  • Используйте алгоритм заливки, чтобы найти все пиксели в области и координаты прямоугольника, содержащего область.
  • Для каждого найденного пикселя установите соответствующее значение в массиве байтов маски равным 0
  • Создайте другой (меньший массив) байтов маски и скопируйте часть (определяемую вычисленным прямоугольником) массива байтов маски в новый массив.
  • Создайте маску, используя следующий код
    NSData* maskData = // construct NSData from mask bytes

    CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData((CFMutableDataRef)maskData);

    int width = maskRight - maskLeft + 1;
    int height = maskBottom - maskTop + 1;
    CGImageRef maskImage = CGImageMaskCreate(width, height, 8, 8, width, dataProvider, NULL, YES);
    CGDataProviderRelease(dataProvider);
  • Вы можете использовать маску позже, используя код, подобный следующему
    CGContextSaveGState(context);

    CGContextTranslateCTM(context, 0.0, 768);
    CGContextScaleCTM(context, 1.0, -1.0);

    CGRect r = CGRectApplyAffineTransform(maskImageRect, CGContextGetCTM(context));
    CGContextClipToMask(context, r, maskImage);

    CGContextTranslateCTM(context, 0.0, 768);
    CGContextScaleCTM(context, 1.0, -1.0);

    // mask is setup, draw here 

    CGContextRestoreGState(context);

Используя этот код, вы можете создать маску любой формы. Вы даже можете создать полупрозрачную маску, если хотите. Для создания полупрозрачной маски необходимо в массиве байтов маски для прозрачных областей установить значения, отличные от 0 (0 - полностью прозрачная, 255 - полностью непрозрачная).

person Bobrovsky    schedule 09.02.2012