iOS: выделение непрозрачных частей частично прозрачного изображения - PullRequest
7 голосов
/ 02 февраля 2012

У меня есть приложение, которое требует, чтобы сплошной черный контур был нарисован вокруг частично прозрачного UIImage. Не вокруг рамки изображения, а вокруг всех непрозрачных частей самого изображения. Т.е., подумайте о прозрачном PNG с непрозрачным белым «Х» на нем - мне нужно обвести «Х» черным.

Чтобы сделать вещи более хитрыми, ПОСЛЕ того, как контур нарисован, непрозрачность исходного изображения будет скорректирована, но контур должен оставаться непрозрачным - поэтому генерируемый мной контур должен включать в себя только контур, а не оригинальное изображение.

Моя текущая техника такова:

  • Создайте новый UIView, который имеет размеры исходного изображения.
  • Дублируйте UIImage 4 раза и добавьте дубликаты как подпредставления UIView, с каждым UIImage, смещенным по диагонали от исходного положения на пару пикселей.
  • Превратите это UIView в изображение (с помощью типичного UIGraphicsGetImageFromCurrentImageContext метода).
  • Используя CGImageMaskCreate и CGImageCreateWithMask, вычтите исходное изображение из этого нового изображения, чтобы остались только контуры.

Это работает. Даже с 4 смещенными изображениями результат выглядит довольно хорошо. Тем не менее, это ужасно неэффективно, и вызывает хорошую твердую 4-секундную задержку на iPhone 4.

Итак, мне нужен хороший, быстрый и эффективный способ добиться того же, что полностью поддерживается iOS 4.0.

Есть отличные идеи? :)

Ответы [ 4 ]

3 голосов
/ 10 февраля 2012

Я хотел бы отметить, что, хотя несколько человек предложили обнаружение краев, это не является подходящим решением. Обнаружение кромок предназначено для нахождения кромок в данных изображения, где нет очевидного точного представления кромки в данных.

Для вас края более четкие, вы ищете хорошо очерченный контур. Край в вашем случае - это любой пиксель, который находится на полностью прозрачном пикселе и рядом с пикселем, который не полностью прозрачен, просто так! итерируйте каждый пиксель изображения и установите его черным, если они удовлетворяют этим условиям.

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

Ура, надеюсь, это поможет.

2 голосов
/ 06 февраля 2012

Ради новых идей:

Вариант в вашей текущей реализации будет использовать поддержку CALayer для теней, которую он вычисляет из фактического содержания пикселей в слое, а не просто из его ограничивающего прямоугольника, и для которого он использует графический процессор. Вы можете попытаться увеличить shadowOpacity до некоторого огромного значения, чтобы попытаться устранить растушевку; если вам не удастся выполнить рендеринг в подходящий CGContext, выньте только альфа-слой и вручную обработайте его, чтобы применить пороговый тест для альфа-значений, выдвинув их либо до полностью непрозрачного, либо до полностью прозрачного.

Вы можете выполнить этот последний шаг обработки на графическом процессоре даже под ES 1 различными способами. Вы бы использовали альфа-тест, чтобы применить фактический порог, затем вы могли бы, скажем, залить буфер глубины до 1,0, отключить вывод цвета и тест глубины, нарисовать версию с тенью на глубине 0,5, нарисовать версию без затем тень на глубине 1,0, затем включите тестирование цветопередачи и глубины и нарисуйте сплошной черный полноэкранный четырехугольник на глубине 0,75. Так что это похоже на использование буфера глубины для эмуляции трафарета (поскольку графический процессор Apple использовался до того, как устройство с поддержкой ES 2 не поддерживало трафаретный буфер).

Это, конечно, предполагает, что CALayer тени появляются за пределами композитора, что я не проверял.

В качестве альтернативы, если вы хотите ограничить поддержку устройств ES 2 (все 3GS +), вы можете загрузить свое изображение в виде текстуры и выполнить весь процесс на графическом процессоре. Но это технически оставило бы некоторые устройства с поддержкой iOS 4 без поддержки, поэтому я полагаю, что это не вариант.

1 голос
/ 04 февраля 2012

Вам просто нужно реализовать алгоритм распознавание краев , но вместо того, чтобы использовать яркость или цвет для определения расположения краев, используйте непрозрачность.Есть несколько способов сделать это.Например, вы можете посмотреть на каждый пиксель и его соседей, чтобы определить области, где непрозрачность пересекает любой установленный вами порог.Всякий раз, когда вам нужно посмотреть на каждый пиксель изображения в MacOS X или iOS, подумайте Core Image .Есть полезная серия постов в блоге , начинающаяся с этой , в которой рассматривается реализация пользовательского фильтра Core Image - я бы начал с создания фильтра обнаружения краев.

0 голосов
/ 11 февраля 2012

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

UIGraphicsBeginImageContextWithOptions(image.size,NO,0.0);
//draw your image 4 times and mask it whatever you like, you can just copy & paste
//current drawing code here.
....
outlinedimage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

это будет намного быстрее, чем ваш UIView.

...