О сравнении изображений
Что мы обычно понимаем под этой задачей? Разгребание архива фоток, ~/Downloads, и прочих мест, где скапливаются картинки, оставленные "на потом". Ну лень же каждый день из-за 2х скачанных картинок с котиками вспоминать куда где у тебя хранится их подборка. Проходит неделя, месяц, картинок становится не две, а две сотни, и теперь лень чистить это дело, включая выгребание дубликатов и из самой коллекции. В результате - перманентный бардак.
Второе допущение которое я делаю - что этих картинок относительно немного, ну тысяча, две, максимум пять.
Вышеописанный случай с грехом пополам всё-таки покрывается продвинутым просмотрщиком изображений, хоть под линуксом их можно пересчитать по пальцам одной руки, и ещё половина пальцев останется. А что делать тому, у кого счёт идёт на десятки тысяч картинок? Готовых решений тут может и не быть, поэтому я рассмотрю возможные пути решения, приложения и их текущий статус.
libimage-seek-perl
Выглядит просто как топор, надо потестить.
Чтобы облегчить задачу, я брал не сами картинки, а их превьюшки, зажатые в квадрат 200x200 с сохранением пропорций и принудительной перегонкой в жпег. Код примерно следующий:
#!/usr/bin/perl
use strict;
use warnings;
use GD;
use Image::Seek qw(loaddb add_image savedb);
loaddb('test.db');
for (my $i = 1; $i <= 20; $i++) {
my $image = GD::Image->newFromJpeg("image$i.jpg") or die $!;
add_image($image, $i);
}
savedb('test.db');
cleardb(); # очистка памяти
Размер превьюшек - ~200 кб, размер базы - 390 kб. Терпимо, но есть пара ньюансов.
- База грузится в память вся целиком. И каждый раз при сохранении переписывается заново. Очевидно, о tie автор не знал или не осилил.
- Второе - очень легко наколбасить туда картинок и забыть список айдишников. А те три с половиной функции, что нам экспортируются в качестве api не позволяют этот список получить никак.
Поэтому не рекомендую, база должна порхать как бабочка и жалить как^W^W^W, гхм, о чём я говорил?
GNUift
Если кратко - монстр. С налёту полностью запустить не удалось, несмотря на предарительный напильник debian'овских мейнтейнеров. Посмотел по диагонали исходники, такое впечатление, что писалось в начале 200х или людьми, застрявшими где-то там. Boost, perl, общее впечатление сборки на коленке, например следующий фрагмент:
use lib '/usr/bin';
use CGIFTLink;
В этих 2х строчках нарушается сразу 2 правила "хорошего тона". Во-первых, 'use lib' вообще быть не должно, это хак. Во-вторых, библиотек CGIFT* - несколько, именоваться они должны как CGIFT::Link, ради компактного запихивания в директорию. Хороший пример - IO::*
Фрагмент логов запуска сервера укрепляет нас в мысли о 'наколеночности':
Not testing file:libxmlrpc_abyss.so.3.16 (File name does not match plugin name)
Not testing file:libpangomm-1.4.so.1.0.30 (File name does not match plugin name)
Lib:libGIFTQuHierarchy, to be linked from libGIFTQuHierarchy.so.0 already registered!
Not testing file:libbonoboui-2.so.0 (File name does not match plugin name)
Not testing file:purple-2 (File name does not match plugin name)
Not testing file:libwpg-0.2.so.2 (File name does not match plugin name)
Это оно так ищет свои библиотеки, гребя всё подряд из /usr/lib.
На протоколе общения с сервером (MRML) я остановлюсь особо.
- автор - GNU, что намекает на злостный overingineering, и всемирные амбиции, поразительно сочетающийся с наколеночностью в данном случае
- документации тупо нет в интернете, оффсайт mrml.net, который указан везде в ссылках - продан какому-то ООО "Вектор", связанному с займами.
- xml в качестве базы для протокола. Я не зря вспомнил 2000е, это было время эйфории и мыслей 'xml/sgml нас всех спасёт'. Ещё пример - xmpp.
- активная разработка закончена ~ в 2004 году, последующие 10 лет появилось несколько недоделанных клиентов ...и всё. Скорее всего причина в безблагодатности кодовой базы.
isk-daemon
Родоначальник библиотеки из первого пункта. То что выше - это порт на Perl::XS. Сама библиотека написана на c++, вебморда на питоне/twisted. Последний релиз - 2012год, притом, по зависимостям тянет libmagick++3, а в вышедшем в прошлом году wheezy - libmagick++5. По этой причине попробовать завести пока не получилось. Но выглядит адекватнее gnuift'а.
findimagedupes
Скриптик на перле, позволяющий худо-бедно искать и сравнивать изображения. Суть алгоритма описана в мане и примерно такова:
- resize 160x160
- grayscale
- blur
- black&white threshold
- resize 16x16
- reduce palette to 1bpp
Таким образом, мы имеем фиксированно 256 байт на каждую картинку + служебные данные вроде пути к ней и сколько-то на служебные данные db. Автор не стал придумывать велосипед и использовал bdb через tie.
Интересен способ, с помощью которого ускоряется сравнение изображений. В комплекте поставляется перловый модуль, но не простой, а со встроенным сишным кодом, который компилится при сборке. При этом не XS, а Inline. Я могу понять нежелание автора городить полноценнную либу и биндинг к ней, там ровно две сишные функции, и два дефайна, но это мешает заюзать эту функцию в других программах.
Ах да, чуть не забыл, для тяжёлых операций с графикой используется вся мощь GraphicsMagick