О насБлогКонтакты
Мобильная разработка3 ноября 2012 г. 4 мин 131Обновлено: 22 июня 2026 г.

Рождение Instagram-фильтров: алгоритмы обработки изображений в ранних мобильных приложениях

AunimedaAunimeda
📋 Содержание

Instagram запустился в октябре 2010. За 18 месяцев он изменил ожидания пользователей от мобильной камеры: фильтры для фото перешли из разряда новинок в обязательный элемент.

Каждый клиент с lifestyle-приложением хотел фильтры. «Как в Instagram, но для [нашей ниши]». Нам пришлось быстро изучить обработку изображений. Вот что мы на самом деле построили.


Математика пикселей

Каждый фильтр - это преобразование значений пикселей. JPEG-изображение - это сетка пикселей; каждый пиксель имеет значения красного, зелёного и синего каналов от 0 до 255.

До iOS 5 с Core Image (GPU-ускоренным фреймворком) мы обрабатывали изображения на CPU в циклах:

- (UIImage *)applyGrayscale:(UIImage *)image {
    // ... получение пиксельного буфера ...
    
    for (NSInteger y = 0; y < height; y++) {
        for (NSInteger x = 0; x < width; x++) {
            NSInteger byteIndex = (bytesPerRow * y) + (x * bytesPerPixel);
            
            unsigned char r = rawData[byteIndex];
            unsigned char g = rawData[byteIndex + 1];
            unsigned char b = rawData[byteIndex + 2];
            
            // Формула яркостного перевода в оттенки серого
            unsigned char gray = (unsigned char)(0.299 * r + 0.587 * g + 0.114 * b);
            
            rawData[byteIndex]     = gray;
            rawData[byteIndex + 1] = gray;
            rawData[byteIndex + 2] = gray;
        }
    }
    // ... создание нового изображения ...
}

На фото 2048×1536 пикселей (задняя камера iPhone 4) этот цикл проходил 3 145 728 пикселей. На чипе A4 это занимало 1.2 секунды. Приемлемо в фоновом потоке с индикатором загрузки. Неприемлемо для предварительного просмотра в реальном времени.


Деконструкция «vintage»-вида

Мы разобрали по пикселям, что делает фото похожим на Instagram-vintage. Эффект «старой фотографии» получался наложением нескольких независимых трансформаций:

1. Частичное обесцвечивание

float saturationFactor = 0.6; // 0 = полное Ч/Б, 1 = оригинал
float grayValue = 0.299 * r + 0.587 * g + 0.114 * b;
r = (unsigned char)(grayValue + saturationFactor * (r - grayValue));
g = (unsigned char)(grayValue + saturationFactor * (g - grayValue));
b = (unsigned char)(grayValue + saturationFactor * (b - grayValue));

2. Тёплый цветовой сдвиг

r = MIN(255, r + 20); // Поднимаем красный
b = MAX(0, b - 15);   // Опускаем синий

3. Кривая контраста (S-кривая)

// Предвычисленная таблица поиска - очень быстро в цикле
unsigned char lutTable[256];
for (int i = 0; i < 256; i++) {
    float t = i / 255.0f;
    float curved = t * t * (3.0f - 2.0f * t); // Кубическая S-кривая
    float result = t + 0.5f * (curved - t);
    lutTable[i] = (unsigned char)(CLAMP(result, 0.0f, 1.0f) * 255.0f);
}
r = lutTable[r]; g = lutTable[g]; b = lutTable[b];

4. Виньетка (тёмные края как у старой оптики)

float cx = (float)x / width - 0.5f;
float cy = (float)y / height - 0.5f;
float dist = sqrtf(cx * cx + cy * cy);
float vignette = 1.0f - CLAMP(dist * 1.4f - 0.3f, 0.0f, 0.8f);
r = (unsigned char)(r * vignette);
g = (unsigned char)(g * vignette);
b = (unsigned char)(b * vignette);

5. Зернистость плёнки - случайный шум в диапазоне ±8 на каждый канал.

Комбинация этих пяти операций давала что-то, что реально напоминало выцветшую фотографию 1970-х.


Core Image: GPU-ускорение (iOS 5)

Apple's Core Image переместил обработку фильтров на GPU. Та же операция обесцвечивания, которая занимала 1.2 секунды на CPU, выполнялась за 4мс на GPU:

- (UIImage *)applyCIVintage:(UIImage *)inputImage {
    CIImage *ciImage = [CIImage imageWithCGImage:inputImage.CGImage];
    CIContext *context = [CIContext contextWithOptions:nil];
    
    CIFilter *saturationFilter = [CIFilter filterWithName:@"CIColorControls"];
    [saturationFilter setValue:ciImage forKey:kCIInputImageKey];
    [saturationFilter setValue:@0.6 forKey:kCIInputSaturationKey];
    
    CIFilter *vignetteFilter = [CIFilter filterWithName:@"CIVignette"];
    [vignetteFilter setValue:saturationFilter.outputImage forKey:kCIInputImageKey];
    [vignetteFilter setValue:@1.5 forKey:kCIInputIntensityKey];
    
    CGImageRef cgResult = [context createCGImage:vignetteFilter.outputImage 
                                        fromRect:vignetteFilter.outputImage.extent];
    return [UIImage imageWithCGImage:cgResult];
}

Предварительный просмотр в реальном времени стал возможен: применяем фильтры к уменьшенной превьюшке (200×150) для предварительного просмотра, а полную обработку запускаем только при подтверждении выбора.


Чему нас научила обработка изображений

Алгоритмы пикселей - зажим, линейная интерполяция, кривые, свёртки - существуют в другом домене по сравнению с обычной бизнес-логикой.

Урок с GPU был фундаментальным: некоторые вычисления параллельны (каждый пиксель независим) и принадлежат GPU, а не CPU. Это мышление позже перешло в работу с WebGL, GLSL-шейдерами в 2014-2016 годах, и в итоге - в машинное обучение на GPU.

Гениальность Instagram была не в математике фильтров - математика 40-летней давности. Гениальность была в UX: одно нажатие, которое превращало посредственное фото в нечто достойное публикации. Техническая работа состояла в том, чтобы это одно нажатие ощущалось мгновенным.

Читайте также

Как разработать мобильное приложение с нуля в 2026 годуaunimeda
Мобильная разработка

Как разработать мобильное приложение с нуля в 2026 году

Полный процесс разработки мобильного приложения: от идеи до публикации в App Store и Google Play. Выбор технологий, этапы разработки, типичные ошибки и реальные сроки.

Разработка приложения-такси в Кыргызстане: архитектура, функционал и бюджетaunimeda
Мобильная разработка

Разработка приложения-такси в Кыргызстане: архитектура, функционал и бюджет

Полный технический разбор разработки приложения-такси для рынка Кыргызстана: архитектура системы, алгоритм матчинга, геолокация, интеграция оплаты, MVP и полный бюджет, операционные расходы.

Flutter vs React Native в 2026 году: что выбрать для разработки мобильного приложенияaunimeda
Мобильная разработка

Flutter vs React Native в 2026 году: что выбрать для разработки мобильного приложения

Сравниваем Flutter и React Native в 2026: производительность, экосистема пакетов, стоимость разработки в Бишкеке и рекомендации по выбору стека для разных типов проектов.

Нужна IT-разработка для вашего бизнеса?

Разрабатываем сайты, мобильные приложения и AI-решения для бизнеса в Кыргызстане. Бесплатная консультация.

Мобильные приложения

Получить консультацию Все статьи