- PVSM.RU - https://www.pvsm.ru -
Давно, в 2005 году, мне купили первый телефон с камерой — Siemens M65. После того, как было сделано приличное количество снимков, возникла нужда их упорядочить — была написана небольшая программа на Delphi, которая упорядочивала и позволяла просматривать изображения по дате — путём выбора нужного года, месяца и числа. Шло время, увеличивались мощности телефонов, количество мегапикселей, появилась поддержка видео — и всё это по мере появления было встроено в программу. Позже появилась версия программы и под Mac OS X, которая была написана с использованием фреймворков, доступных в этой ОС для работы с изображениями(Core Image) и видео(AV Foundation). О первом фреймворке и создании для него своего фильтра поговорим более подробно.
Core Image [1] — технология обработки изображений, которая появилась в Mac OS X 10.4 — позволяет проводить попиксельные операции с исходным изображением при помощи так называемых плагинов. Встроенных плагинов достаточно много — при некотором количестве времени на основе Core Image можно сделать некоторый аналог фотошопа со слоями, режимами наложения, корректировками уровней, яркости итп. Причем всё просчёты будут произведены на GPU [2] (при его наличии), что даст существенную скорость в обработке изображений.
Core Image Filter — плагин для обработки изображений, который имеет как минимум 2 функции — принимать входное изображение, и выдавать результат. На странице описания [3] встроенных плагинов есть примеры того, как будет выглядеть изображение до и после фильтра. Так же плагины делятся на категории:
Доступны так же другие категории, полный список по ссылке [3].
Наша же цель — написать собственный плагин-фильтр. А в качестве примера я решил выбрать создание анаглифного [4] изображения для просмотра его красно-бирюзовыми очками. Всё это было реализовано в моей программе, речь о которой шла в начале статьи. Для начала запускаем xcode. Далее определяемся — будем ли мы писать плагин как отдельный проект, либо же добавим его в существующий. В моём случае я добавил новый проект в существующий — для этого чуть ниже окна TARGETS жмём Add Target:
и выбираем: Mac OS X -> System Plug-in -> Image Unit Plug-in:
Далее вводим имя фильтра(мой вариант — AnaglyphFilter), и сразу добавляем его в сборку проекта(Product — Edit Scheme — Build, список Targets). Я так же добавил зависимость сборки главного проекта от фильтра(чтобы фильтр был собран наверняка при сборке проекта, Build Phases — Target Dependencies) и автоматическое копирование фильтра в папку Resources, всё того же главного проекта(Build Phases — Add Build Phase — Add Copy Files). Теперь можно приступить непосредственно к программированию фильтра. Но для начала немного о содержании плагина.
После создания нового плагина можно заметить следующие файлы в папке <имя плагина> в дереве проекта:
Шаблон, который сделал нам xcode нужно модифицировать под наши нужды. В фильтре будут 2 входных параметра — основное изображение(левое), и правое. На выходе же будет совмещённое анаглифное изображение. Для начала оставляем только нужные нам параметры. Открываем файл AnaglyphFilterFilter.h и приводим класс AnaglyphFilterFilter к следующему виду:
@interface AnaglyphFilterFilter : CIFilter
{
CIImage *inputImage;//входное изображение(левое)
CIImage *rightImage;//правое изображение
}
@end
В файле AnaglyphFilterFilter.m есть несколько процедур, привожу описание:
- (CGRect)regionOf:(int)sampler destRect:(CGRect)rect userInfo:(NValue*)value
{
return rect;
}
- (NSDictionary *)customAttributes
{
return [NSDictionary dictionaryWithObjectsAndKeys:
[NSDictionary dictionaryWithObjectsAndKeys:
[CIImage class],kCIAttributeClass,
[CIImage emptyImage], kCIAttributeDefault,
nil],@"rightImage",
nil];
}
- (CIImage *)outputImage
{
CISampler *leftSamp = [CISampler samplerWithImage:inputImage];
CISampler *rightSamp = [CISampler samplerWithImage:rightImage];
return [self apply:_AnaglyphFilterFilterKernel,leftSamp,rightSamp,
kCIApplyOptionDefinition,[src definition],nil];
}
Представляет из себя код на языке CIKL, который является разновидностью OpenGL Shading Language [6]. Подпрограммы, которые мы будем вызывать из основного кода, начинаются с ключего слова kernel и могут быть найдены по свойству name класса CIKernel. Но в нашем случае нам нужна только одна процедура, поэтому инициализация проходит следующим образом(в процедуре init):
_AnaglyphFilterFilterKernel = [[kernels objectAtIndex:0] retain];
Аналогично можно было бы получить процедуру по имени:
_AnaglyphFilterFilterKernel = [[kernels findKernelByName:@"procedureName"] retain];
Сама же процедура в файле .cikernel будет выглядеть примерно так:
kernel vec4 procedureName(sampler leftSamp, sampler rightSamp)
{
//код для работы с пикселями
//возврат результата
}
Существуют разные по сложности способы получения анаглифных изображений. Для нашего случая мы воспользуемся полноцветным режимом наложения картинок:
Подпрограмма на языке CIKL будет выглядеть следующим образом:
kernel vec4 anaglyphRedCyan(sampler leftSamp, sampler rightSamp)
{
//получаем пиксель левого изображения
vec4 l = sample(leftSamp,samplerCoord(leftSamp));
//убираем зеленый и синий каналы
l.g = l.b = 0.0;
//получаем пиксель правого изображения
vec4 r = sample(rightSamp,samplerCoord(rightSamp));
//убираем красный канал
r.r = 0.0;
//накладываем изображением методом "Экран"
vec4 ret;
//красный канал
ret.r = 1.0 - (1.0 - l.r)*(1.0 - r.r);
//зеленый канал
ret.g = 1.0 - (1.0 - l.g)*(1.0 - r.g);
//синий канал
ret.b = 1.0 - (1.0 - l.b)*(1.0 - r.b);
//прозрачность не используется
ret.a = 1.0;
//результат
return ret;
}
При загрузке основной программы нужно вставить код, который будет загружать наш фильтр(с учётом того, что мы положили его в папку Resources):
- (void)loadCoreImageFilters
{
NSString* path = [[NSBundle mainBundle] pathForResource:@"AnaglyphFilter" ofType:@"plugin"];
[CIPlugIn loadPlugIn:[NSURL fileURLWithPath:path] allowExecutableCode:YES];
}
Теперь использовать фильтр можно точно так же, как и остальные фильтры:
CIFilter* anaglyphFilter = [CIFilter filterWithName:@"AnaglyphFilter"];
[anaglyphFilter setDefaults];
[anaglyphFilter setValue:leftImage forKey:@"inputImage"];
[anaglyphFilter setValue:rightImage forKey:@"rightImage"];
CIImage* anaglyphImage = [anaglyphFilter valueForKey:@"outputImage"];
Работа с Core Image оказалась не такой сложной как может показаться. А вот и результаты работы:
Автор: m29A
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/6123
Ссылки в тексте:
[1] Core Image: http://en.wikipedia.org/wiki/Core_Image
[2] GPU: http://ru.wikipedia.org/wiki/Графический_процессор
[3] странице описания: http://developer.apple.com/library/mac/#documentation/graphicsimaging/reference/CoreImageFilterReference/Reference/reference.html
[4] анаглифного: http://ru.wikipedia.org/wiki/Анаглиф
[5] Core Image Kernel Language: https://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/CIKernelLangRef/ci_gslang_ext.html
[6] OpenGL Shading Language: http://ru.wikipedia.org/wiki/OpenGL_Shading_Language
Нажмите здесь для печати.