• Правдоподобная реконструкция Инстаграм-подобных фильтров

    • Перевод

    Существует куча софта, который позволяет пользователям применять различные цветовые фильтры к своим фотография. Пионером в этом деле был Инстаграм и иногда хочется сделать в своем приложении уже знакомые пользователям фильтры. И я хочу представить набор утилит, который позволит в полу-автоматическом режиме очень точно воспроизводить цветовые фильтры из других приложений в своём приложении.


    https://github.com/homm/color-filters-reconstruction


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


    Для примера, одно из следующих изображений было получено с применением фильтра Clarendon на оригинальном изображении в самом Инстаграме, а другое с помощью наложения восстановленного фильтра. Попробуйте угадать, какое восстановлено.



    Для сравнения, это результат применения того же фильтра из коммерческого набора «Инстаграм-подобных фильтров», который вы без труда сможете нагуглить:


    Читать дальше →
  • Фундаментальная уязвимость HTML при встраивании скриптов

      Чтобы описать суть проблемы, мне нужно рассказать, как вообще устроен HTML. Вы наверняка в общих чертах представляли себе, но я все равно коротко пробегусь по основным моментам, которые понадобятся для понимания. Если кому-то не терпится, сразу переходите к сути.


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


      <p name="value">

      Тут [name] — это имя атрибута, а [value] — это его значение. В статье я буду использовать квадратные скобки вокруг кода, чтобы было понятно, где он начинается и заканчивается. После имени стои́т знак равенства, а после него — значение, заключенное в кавычки. Значение атрибута начинается сразу после первого символа кавычки и заканчивается сразу перед следующим символом кавычки, где бы он не находился. Это значит, что если вместо [value] вы запишете [OOO "Рога и копыта".], то значение атрибута name будет [OOO ], а еще у вашего элемента будет три других атрибута с именами: [рога], [и] и [копыта"."], но без значений.


      <p name="OOO "Рога и копыта"."></p>

      Если это не то, чего вы ожидали, вам нужно как-то изменить значение атрибута, чтобы в нем не встречалась кавычка. Самое простое, что можно придумать — просто вырезать кавычки.


      <p name="OOO Рога и копыта."></p>
      Читать дальше →
    • Качественное уменьшение изображений за константное время

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


        Для начала давайте порассуждаем логически. Если вы делаете ресайз изображения, наверное вы хотите чтобы результат хотя бы отдаленно напоминал оригинал. Для этого нужно учесть как можно больше информации из исходного изображения. Вы слышали о методе «ближайшего соседа»? В этом методе для каждой точки конечного изображения просто берется какая-то одна точка из исходного изображения в неизменном виде.



        Уменьшение изображения 4928×3280 до 256×170 ближайшим соседом.


        Рекомендую смотреть примеры из статьи в браузере в масштабе 100% и без ретины. То есть по максимуму исключить ресайз при просмотре.

        Результат не представляет ничего хорошего. Изображение дерганое, зернистое, даже трудно понять что на нем изображено. Особенно если на исходном изображении было много мелких деталей или оно само было зернистым. Почему так получается? Потому что в конечном изображении было учтено очень мало информации из исходного. Если условно отметить на исходном изображении те точки, которые попадают в конечное, получится вот такая сеточка:



        Точки, которые попадут в конечное изображение размером 20×13.
        Читать дальше →
      • Root хуже Михалкова

          Рут – это мифическое существо в экосистеме Linux. Он может всё: зайти в любой каталог, удалить любой файл, завершить любой процесс, открыть любой порт. В общем это суперчеловек, чрезвычайно могущественный и очень полезный. Но задумывались ли вы когда-нибудь, какую цену мы платим руту? Не думали же вы, что он работает за просто так.


          Вы знаете команду df? Она показывает все подключенные сейчас диски и статистику по ним: сколько место занято, сколько свободно. Например:


          $ df -m
          Filesystem     1M-blocks   Used Available Use% Mounted on
          udev                 224      1       224   1% /dev
          tmpfs                 48      1        47   2% /run
          /dev/dm-0           9204   7421      1294  86% /

          Вы когда-нибудь замечали, что для локальных дисков сумма Used и Available чаще всего меньше общего размера диска? Ненамного, но меньше.

          Читать дальше →
        • Как я сделал самый быстрый ресайз изображений. Часть 3, числа с фиксированной точкой

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


            В предыдущих частях:


            Часть 0
            Часть 1, общие оптимизации
            Часть 2, SIMD

            Читать дальше →
          • Как я сделал самый быстрый ресайз изображений. Часть 2, SIMD

              Это продолжение цикла статей о том, как я занимался оптимизацией и получил самый быстрый ресайз на современных x86 процессорах. В каждой статье я рассказываю часть истории, и надеюсь подтолкнуть еще кого-то заняться оптимизацией своего или чужого кода. В предыдущих сериях:


              Часть 0
              Часть 1, общие оптимизации


              В прошлый раз мы получили ускорение в среднем в 2,5 раза без изменения подхода. В этот раз я покажу, как применять SIMD-подход и получить ускорение еще в 3,5 раза. Конечно, применение SIMD для обработки графики не является ноу-хау, можно даже сказать, что SIMD был придуман для этого. Но на практике очень мало разработчиков используют его даже в задачах обработки изображений. Например, довольно известные и распространенные библиотеки ImageMagick и LibGD написаны без использования SIMD. Отчасти так происходит потому, что SIMD-подход объективно сложнее и не кроссплатформенный, а отчасти потому, что по нему мало информации. Довольно просто найти азы, но мало детальных материалов и разбора реальных задач. От этого на Stack Overflow очень много вопросов буквально о каждой мелочи: как загрузить данные, как распаковать, запаковать. Видно, что всем приходится набивать шишки самостоятельно.

              Читать дальше →
            • Как я сделал самый быстрый ресайз изображений. Часть 1, общие оптимизации

                В пилотной части я рассказал о задаче как можно подробнее. Рассказ получился долгим и беспредметным — в нем не было ни одной строчки кода. Но без понимания задачи очень сложно заниматься оптимизацией. Конечно, некоторые техники можно применять, имея на руках только код. Например, кешировать вычисления, сокращать ветвления. Но мне кажется, что некоторые вещи без понимания задачи просто никогда не сделать. Это и отличает человека от оптимизирующего компилятора. Поэтому ручная оптимизация все еще играет огромную роль: у компилятора есть только код, а у человека есть понимание задачи. Компилятор не может принять решение, что значение "4" достаточно случайно, а человек может.



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

                Читать дальше →
              • Как я сделал самый быстрый ресайз изображений. Часть 0

                  Здравствуйте, меня зовут Саша, я написал самый быстрый ресайз изображений для современных х86 процессоров. Я так утверждаю, поскольку все остальные библиотеки, которые я сумел найти и протестировать, оказались медленнее. Я занялся этой задачей, когда работал над оптимизацией ресайза картинок на лету в Uploadcare. Мы решили открыть код и в результате появился проект Pillow-SIMD. Любой желающий с легкостью может использовать его в приложении на языке Python.


                  Любой код выполняется на конкретном железе и хорошей оптимизации можно добиться, только понимая его архитектуру. Всего я планирую выпустить 4 или 5 статей, в которых расскажу как применять знание архитектуры железа для оптимизации реальной задачи. Своим примером я хочу побудить вас оптимизировать другие прикладные задачи. Первые две статьи выйдут в течение недели, остальные — по мере готовности.

                  Читать дальше →
                • Ресайз картинок в браузере. Все может стать еще хуже

                     


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



                    Как выяснилось, виной тому стала жадность и алчность производителей браузеров, которые решили сэкономить на алгоритмах ресайза изображений и применить самые низкокачественные фильтры. Тогда Маню удалось спасти — она прошла курс последовательных не кратных двум уменьшений, что снизило алиазинг и вернуло её былую резкость. Но теперь ей снова угрожает опасность.

                    Читать дальше →
                  • Pillow-SIMD

                      Ускорение операций в 2.5 раза по сравнению с Pillow и в 10 по сравнению с ImageMagick



                      Pillow-SIMD — это «форк-последователь» библиотеки работы с изображениями Pillow (которая сама является форком библиотеки PIL, ныне покойной). «Последователь» означает, что проект не становится самостоятельным, а будет обновляться вместе с Pillow и иметь ту же нумерацию версий, только с суффиксом. Я надеюсь более-менее оперативно выпускать версии Pillow-SIMD сразу после выхода версий Pillow.


                      Почему SIMD


                      Есть несколько способов улучшения производительности обработки изображений (да и всех остальных вещей, наверное, тоже).


                      1. Можно использовать более хорошие алгоритмы, которые дают такой же результат.
                      2. Можно сделать более быструю реализацию существующего алгоритма.
                      3. Можно подключить больше вычислительных ресурсов для решения той же задачи: дополнительные ядра CPU, GPU.
                      Читать дальше →
                    • Ресайз картинок в браузере. Все очень плохо

                        Если вы когда-нибудь сталкивались с задачей ресайза картинок в браузере, то вы наверное знаете, что это очень просто. В любом современном браузере есть такой элемент, как холст (<canvas>). На него можно нанести изображение нужных размеров. Пять строчек кода и картинка готова:

                        function resize(img, w, h) {
                          var canvas = document.createElement('canvas');
                          canvas.width = w;
                          canvas.height = h;
                          canvas.getContext('2d').drawImage(img, 0, 0, w, h);
                          return canvas;
                        }
                        

                        Из холста картинку можно сохранить в JPEG и, например, отправить на сервер. Можно было на этом закончить статью, но сперва давайте взглянем на результат. Если вы поставите рядом такой холст и обычный элемент <img>, в который загружена та же картинка (исходник, 4 Мб), то вы увидите разницу.

                        img
                        Читать дальше →
                      • Pillow 2.7 — Существенное улучшение качества и производительности

                        • Перевод
                        Первого января 2015 года по расписанию вышла новая версия библиотеки для работы с изображениями Pillow 2.7. Так как многие изменения в ней были сделаны командой Uploadcare, мы рады представить вам расширенную версию заметок о релизе этой версии.

                        Для начала вспомним, с чего все началось. Pillow — дружественный форк (как называют его авторы) популярной библиотеки PIL, Python Imaging Library. Последняя версия PIL 1.1.7 вышла в 2009 году и в основном содержала исправления ошибок. Изначально Pillow задумывался как проект только по приведению в порядок сборки PIL, и разработчики рекомендовали отправлять все баги, не связанные со сборкой, в оригинальный PIL. Но время шло, PIL стремительно устаревала, багов не уменьшалось, тут еще Python 3 маячил на горизонте. Поэтому с версией Pillow 2.0 все изменилось. «Pillow 2.0.0 добавляет поддержку Python 3 и включает много багфиксов со всего интернета» гласит описание проекта на PyPI. И с тех пор понеслось. Каждые три месяца выходили версии с огромным количеством багфиксов и другими улучшениями от различных разработчиков. Самым значительным нововведением за это время было, пожалуй, поддержка форматов WebP и JPEG2000. Теперь пришло время следующего большого шага.
                        Читать дальше →
                        • +55
                        • 31,6k
                        • 2
                      • Разоблачение рекламной статьи Intel

                          Некоторе время занимаясь реализацией различных алгоритмов обработки изображений, я не мог не узнать о пакете Intel Integrated Performance Primitives (Intel IPP). Это набор высокопроизводительных функций обработки одно-, двух- и трехмерных данных, использующих возможности современных процессоров на полную. Это такие кирпичики с универсальными интерфейсами, из которых можно строить свои приложения и библиотеки. Продукт этот, безусловно, коммерческий, поскольку входит в поставку других средств разработки и отдельно не распространяется.

                          С тех пор, как я узнал об этом пакете, меня не покидало желание узнать, насколько быстро в нем реализован ресайз изображений. Каких-то официальных бенчмарков или данных о производительности в документации нет, как нет и бенчмарков от сторонних разработчиков. Самое близкое, что мне удавалось найти — бенчмарки кодека JPEG от проекта libjpeg-turbo.

                          И вот, позавчера, в процессе подготовки статьи «Методы ресайза изображений» (прочтение которой очень желательно для понимания дальнейшего изложения) в очередной раз наткнулся на статью, о которой и пойдет речь:

                          libNthumb, The NHN* Performance Primitive for Real-Time Creation of Thumbnail Image with Intel IPP Library
                          Читать дальше →
                        • Ликбез: методы ресайза изображений

                            Почему изображение, масштабированное с бикубической интерполяцией, выглядит не как в Фотошопе. Почему одна программа ресайзит быстро, а другая — нет, хотя результат одинаковый. Какой метод ресайза лучше для увеличения, а какой для уменьшения. Что делают фильтры и чем они отличаются.

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


                            Этот человек сидит среди ромашек, чтобы привлечь ваше внимание к статье.
                            Читать дальше →
                          • Вы не можете закачать файлы на сервер в мобильном Safari 8.0

                            • Перевод
                            Печально, но факт. Новая версия iOS содержит баг, который делает невозможным отправку любых файлов на сервер из браузера. Когда вы выбираете файл в любой форме на HTML странице и пытатесь его отправить, браузер посылает запрос без файла. Он показывает, что ждет ответа на запрос, но на самом деле ответ не приходит.

                            Более того, баг касается не только HTML-форм. Если вы отправляете файл из Javascript, конструируя объект FormData (часть API XMLHttpRequest Level 2), это приводит к тому же результату. И даже если вы делаете то же самое из нативного приложения, которое является оберткой над HTML-браузером (например, Apache Cordova), то получаете такой же результат.

                            Почему же не приходит ответ. Если бы файл просто не отсылался, мы могли бы ожидать, что на сервер приходил бы пустой файл или сервер возвращал бы ошибку, что форма отправлена без файла. Однако сервер просто не шлет никакого ответа (даже 400 bad request) и не закрывает соединение. Все дело в том, какой именно запрос шлет Safari.
                            Читать дальше →
                          • Эффективная многопоточность в Python

                            Хочу поделиться простым рецептом, как можно эффективно выполнять большое число http-запросов и других задач ввода-вывода из обычного Питона. Самое правильное, что можно было бы сделать — использовать асинхронные фреймворки вроде Торнадо или gevent. Но иногда этот вариант не подходит, потому что встроить event loop в уже существующий проект проблематично.

                            В моем случае уже существовало Django-приложение, из которого примерно раз в месяц нужно было выгрузить немного очень мелких файлов на AWS s3. Шло время, количество файлов стало приближаться к 50 тысячам, и выгружать их по очереди стало утомительным. Как известно, s3 не поддерживает множественное обновление за один PUT-запрос, а установленная опытным путем максимальная скорость запросов с сервера ec2 в том же датацентре не превышает 17 в секунду (что очень не мало, кстати). Таким образом, время обновления для 50 тысяч файлов стало приближаться к одному часу.

                            Питонисты с детства знают, что от использования потоков (тредов операционной системы) нет никакого толка из-за глобального лока интерпретатора. Но немногие догадываются, что как и любой лок, этот время от времени освобождается. В частности, это происходит при операциях ввода-вывода, в том числе и сетевых. А значит, потоки можно использовать для распараллеливания http-запросов — пока один поток ожидает ответа, другой спокойно обрабатывает результат предыдущего или готовит следующий.

                            Получается, всего-то нужен пул потоков, который будет выполнять запросы. К счастью, такой пул уже написан. Начиная с версии 3.2 для унификации всей асинхронной работы в Питоне появилась библиотека concurrent.futures. Для второй версии Питона есть бекпорт под именем futures. Код до безобразия прост:

                            from concurrent.futures import ThreadPoolExecutor
                            
                            with ThreadPoolExecutor(concurrency) as executor:
                                for _ in executor.map(upload, queryset):
                                    pass
                            

                            Здесь concurrency — число рабочих потоков, upload — функция, выполняющую саму задачу, queryset — итератор объектов, которые по одному будут передаваться в задачу. Уже этот код при concurrency в 150 смог пропихнуть на сервера Амазона ≈450 запросов в секунду.
                            Читать дальше →
                          • Http запросы — мы все это делаем неправильно

                              В проекте, над которым я работаю, мы используем огромное количество сторонних библиотек. Многие из них — адаптеры для различных сервисов. Что их объединяет, это то, что они работают с сетью. Json поверх http, soap поверх http, какие-то свои протоколы поверх http. Т.е. все так или иначе используют http. И как ни удивительно, мало кто из них пользуется преимуществами его последней версии. Я не поленился заглянуть в википедию, прошло ровно 14 лет как была принята спецификация http 1.1. И потому я решил обратиться с призывом:
                              image

                              Да, речь пойдет о keep alive. Суть в том, что, начиная с http 1.1, клиент и сервер могут договориться не закрывать установленное tcp-соединение после завершения запроса, а переиспользовать его для следующих запросов. Это нужно потому, что на установку соединения требуется время. Иногда это время больше, чем время самого запроса. И если все серверы уже давным-давно такую возможность поддерживают, а все браузеры и большинство других клиентов её используют, то у разработчиков различных библиотек для популярных языков программирования здесь почему-то пробел.
                              Читать дальше →
                            • Устранение утечек памяти в приложении на Питоне

                                imageНедавно мне довелось разобраться и устранить несколько утечек памяти в популярном фреймворке Торнадо. Не беда, если вы никогда его не использовали, потому что описанное будет мало связано с ним. Рассказать я хочу о методах, которые я использовал для поиска и устранения утечек.

                                Все сказанное будет по большей части справедливо только для самой популярной реализации Питона — CPython. Как известно, в нем есть два механизма освобождения памяти. Первый из них — подсчет ссылок. Каждый раз, когда вы явно или не явно создаете новый объект, его счетчик ссылок равен единице. Если вы присваиваете этот объект новой переменной или передаете в качестве аргумента, его счетчик ссылок увеличивается. При выходе из функции количество ссылок на объекты, которые были в локальных переменных и аргументах, уменьшается. Если для какого-то объекта количество ссылок становится равным нулю, он немедленно уничтожается.

                                Это схема отлично работает до тех пор, пока не появляются объекты, ссылающиеся друг на друга. Самый простой пример — узлы какого-то дерева, хранящие ссылки на свои дочерние и родительский узлы. Узлы продолжат ссылаться друг на друга, даже когда не останется других внешних ссылок ни на один из них. Самое неприятное, что такие узлы могут ссылаться на какие-то другие данные и не давать их освободить. Чтобы устранить такие циклические ссылки, в Питоне существует второй механизм освобождения памяти — сборщик мусора. Он запускается время от времени, ставя выполнение остального кода на паузу, и анализирует все неосвобожденные объекты.

                                Формально, циклические ссылки нельзя назвать утечками: сборка мусора рано или поздно уничтожит такие объекты. Беда только в том, что Питон не может сам определить, когда еще рано, а когда уже поздно. В моем случае система просто прибивала процесс с Питоном, если сборка мусора не начиналась вовремя.
                                Читать дальше →
                                • +92
                                • 31,7k
                                • 8
                              • Хостинг картинок за полчаса

                                • Tutorial
                                Сегодня проекты, особенно на начальном этапе, строятся из готовых блоков. Например, умный хостинг или сервис быстрой отправки сообщений в браузер пользователю. Складывая такие блоки по-разному, можно получить совершенно неожиданный результат. И чем больше разных блоков вам доступно, тем разнообразнее могут получаться проекты. Иногда появляются блоки, которыми можно заменить сразу несколько других блоков. И сами эти блоки — такие же проекты, состоящие из других блоков.

                                imageНасколько просто сейчас сделать такой сервис, как хостинг изображений? В принципе, его и раньше было несложно сделать. Но прогресс не стоит на месте, и за то же самое время теперь можно учесть больше нюансов. Я уже рассказывал о проекте Uploadcare. Это сервис, позволяющий облегчить работу с файлами: загрузку, хранение, обработку и раздачу конечному пользователю. Его и будем использовать в качестве основного блока.

                                Пример будет написан на Питоне. Во-первых, потому что Питон я знаю лучше всего, во-вторых библиотека pyuploadcare обновляется в первую очередь. На самом деле, для Uploadcare есть библиотеки под разные языки, и все они в open source. Если в нужном вам модуле отсутствует какая-то функциональность, можно дождаться, когда она появится, или дописать самому.
                                Читать дальше →
                              • Uploadcare — файловое хранилище для сайтов и приложений

                                  image
                                  Привет! Хочу рассказать о проекте, который наверняка окажется полезным многим разработчикам. В двух словах объяснить, зачем он нужен, достаточно сложно, но я попробую. Uploadcare — сервис для приложений и сайтов, упрощающий получение файлов от пользователей, их хранение и передачу по сети.

                                  Тот, кто хоть раз делал форму с <input type="file">, знает, что ничего сложного в этом нет, но есть неприятные моменты, возникающие по пути. Вот только некоторые из них:

                                  — нельзя сохранить форму с файлом по ajax;
                                  — нельзя показать форму с уже выбранным файлом;
                                  — если вы ожидаете картинку, нужно убедиться, что загружена картинка;
                                  — сервер должен быть готов принимать большое тело запроса;
                                  — в некоторых фреймворках загруженный файл является источником повышенной опасности;
                                  — удобная загрузка нескольких файлов реализуется достаточно сложно;
                                  — индикация процесса загрузки реализуется еще сложнее;
                                  — на диске сервера может закончиться место;
                                  Читать дальше →