Оригинальные статьи: раз и два.
Все там написано хорошо и правильно, но счастья все равно нет.
Картинка для привлечения внимания:
Задача простая — отметить людей на фотографии и иметь возможность пользоваться этим в максимальном количестве мест любым удобным для меня способом.
Лица отмечать буду в пикасе, потому как привязка к гугловским контактам, кроссплатформенность, авто определение, хранение тегов внутри файла (с нюансами). А вот смотреть и использовать эти теги хочу везде в gallery3 потому что она это умеет, в lightroom потому что именно им пользуюсь как каталогизатором, в microsoft explorer потому как он у меня есть и в Microsoft Live Photo Gallery, просто потому что это второй популярный формат и почему бы и его тоже не использовать.
Кто тоже хочет заморочиться — добро пожаловать под кат.
Проблема номер 1 где пикаса хранит информацию о лицах?
Вариантов три:
- Либо это связка из двух файлов: contacts.xml в профиле пользователя и picasa.ini в папке с фотографиями. Этот вариант верен если вы тегировали лица в пикасе версии меньше чем 3.9 и в последней пикасе, о с выключенной галкой «Store name tags in photo».
- Второй вариант хранение лиц в XMP-mwg-rs если вы использовали только последнюю пикасу и включили галку «Store name tags in photo» до того как начали отмечать лица, надо помнить, что по умолчанию она включена.
- И наконец третий вариант, самый распространенный: лица хранятся и там и там и что с этим делать вообще непонятно.
По понятным причинам второй вариант самый оптимальный, но как оказалось не все так просто, пикасе нельзя просто сказать: «Запиши все теги в файлы» гугл пожадничал поставить такую кнопку. Вариантов решить эту проблему есть несколько как чисто пикасовых так и используя внешние утилиты.
picface
почти работает, недавно обновлялась, но у меня многократно вылетала не доделав начатое до конца, а поскольку архив у меня примерно 60К фотографий, все это происходит долго и муторно.
самый популярный avpicfacexmptagger
Умеет делать почти все, что надо, но достаточно однобоко, давно не обновлялся, придумали свою собственную схему для xmp, можно подумать существующих мало. Но в принципе для приведения архива к состоянию два использовать можно.
Я использовал рекомендацию от самого гугла, вам нужна только пикаса версии 3.9 с включенной галкой «Store name tags in photo». Для гарантированной записи всех лиц в xmp надо пройтись по всем людям и переименовать во что-то, а потом переименовать обратно. Быстро, просто, работает. На вкладке people два раза кликаете по первому имени и переименовываете его в ‘x’ потом два раза кликаете по ‘x’ и переименовываете его обратно. Все у меня оттегировано полторы сотни людей и это заняло всего пару минут. Пикасу после этого лучше сразу не закрывать, а дать ей какое-то время записать данные на диск, потому как прогресса никакого она не показывает.
Следующим шагом мы хотим извлечь имена записаные пикасой в xmp-mwg-rs в теге RegionName и записать его в теги PersonInImage и RegionPersonDisplayName после этого мы сможем использовать эти теги при поиске во всех каталогизаторах и даже microsoft explorer будет нам показывать в информации имена людей на фотографии. Сделать это проще всего при помощи exiftool который можно скачать здесь.
exiftool -RegionName>PersonInImage photo.jpg exiftool -RegionName>RegionPersonDisplayName photo.jpg
после этого мы видим информацию о людях во множестве сторонних програм
Так же можно конвертировать информацию о положении лиц на кадре из стандарта пикасы в стандарт от микрософта, отличаются они не только именами, но даже методом как считаются квадраты, одни задают длинну и высоту от верхнего левого угла квадрата, а другие от центра. Для конвертации нам нужен конфиг для exiftool.
ExifTool_config_convert_regions
%Image::ExifTool::UserDefined = ( 'Image::ExifTool::Composite' => { MyRegion => { Require => { 0 => 'RegionInfoMP', 1 => 'ImageWidth', 2 => 'ImageHeight', }, ValueConv => q{ my ($rgn, @newRgns); foreach $rgn (@{$val[0]{Regions}}) { my @rect = split /\s*,\s*/, $$rgn{Rectangle}; my %newRgn = ( Area => { X => $rect[0] + $rect[2]/2, Y => $rect[1] + $rect[3]/2, W => $rect[2], H => $rect[3], Unit => 'normalized', }, Name => $$rgn{PersonDisplayName}, Type => 'Face', ); push @newRgns, \%newRgn; } return { AppliedToDimensions => { W => $val[1], H => $val[2], Unit => 'pixel' }, RegionList => \@newRgns, }; }, }, MyRegionMP => { Require => 'RegionInfo', ValueConv => q{ my ($rgn, @newRgns); foreach $rgn (@{$val[0]{RegionList}}) { my @rect = @{$$rgn{Area}}{'X','Y','W','H'}; $rect[0] -= $rect[2]/2; $rect[1] -= $rect[3]/2; push @newRgns, { PersonDisplayName => $$rgn{Name}, Rectangle => join(', ', @rect), }; } return { Regions => \@newRgns }; }, }, }, ); 1; #end
Конфиг найден на просторах интернета и он позволяет конвертировать регионы в обе стороны, но нам достаточно в одну. Для этого выполняем exiftool со следующими параметрами:
exiftool -config ExifTool_config_convert_regions "-regioninfomp\<MyRegionMP"' photo.jpg
после этого лицо правильно отображается в Microsoft Live Photo Gallery и другом софте который придерживается той же схемы
Уже практически профит, но еще бы автоматизировать это дело для всех необходимых фотографий, а кроме того прописать имена в ключевые слова: теги Subject и HierarchialSuject да, здесь тоже не обошлось без двойных форматов. Для этих целей я написал плагинчик для лайтрума, это дает возможность запустить его только на нужных фотографиях, и добавлять ключевые слова, не опасаясь их задвоить или стереть уже существующие, ну и просто потому что я пользуюсь именно лайтрумом как каталогизатором всего архива.
За код просьба не бить, а лучше подсказать как его улучшить, это мой первый плагин для LR и вообще первый раз когда я увидел lua.
В плагине всего два файла
Info.lua
return { LrSdkVersion = 3.0, LrSdkMinimumVersion = 1.3, -- minimum SDK version required by this plug-in LrToolkitIdentifier = 'com.adobe.lightroom.sdk.helloworld', LrPluginName = LOC "$$$/PicasaFaceToTag/PluginName=Picasa Faces to Tags", -- Add the menu item to the Library menu. LrLibraryMenuItems = { { title = "Write Picasa Faces to Tags", file = "PersonInImage.lua"}, }, VERSION = { major=4, minor=1, revision=0, build=831116, }, }
PersonInImage.lua
--[[---------------------------------------------------------------------------- ------------------------------------------------------------------------------]] -- Access the Lightroom SDK namespaces. local LrTasks = import 'LrTasks' local LrProgressScope = import 'LrProgressScope' local LrApplication = import 'LrApplication' local catalog = LrApplication.activeCatalog() local photos = catalog:getTargetPhotos() local LrPathUtils = import 'LrPathUtils' local logger = import 'LrLogger'("lr") logger:enable('print') local function faceToTag() --[[Convert faces from picasa xmp tag to microsoft xmp ]] exeFile = LrPathUtils.child( _PLUGIN.path, "exiftool.exe" ) cfgFile = LrPathUtils.child( _PLUGIN.path, "ExifTool_config_convert_regions" ) redirect = LrPathUtils.getStandardFilePath('temp') .. "exiftool.stdout" local total = ( # catalog:getTargetPhotos() ) local exifArgs = {"-b -RegionName \>" .. redirect, --'-overwrite_original "-RegionName\>PersonInImage"', '-overwrite_original "-RegionName\>RegionPersonDisplayName"', '-config '..cfgFile..' -overwrite_original "-regioninfomp\<MyRegionMP"'} local progressScope = LrProgressScope{ title = "Write Picasa Faces to Tags", caption = "Updateting " .. total .. " photos." , } progressScope:setCancelable( true ) local parrent catalog:withWriteAccessDo("Create parrent keyword", function () parrent = catalog:createKeyword("names", {}, false, nil, true) --logger:debug("parrent keyword created: " .. tostring(parrent)) end) for completed, photo in ipairs(photos) do progressScope:setPortionComplete(completed, total) progressScope:setCaption("Updated " .. tostring(completed) .. " of " .. tostring(total) .. " photos") if progressScope:isCanceled() then progressScope:done() break end local path = photo:getRawMetadata('path') logger:debug(path) -- write filename to debug log for i,exifArg in ipairs(exifArgs) do local exeCmd ='"' .. exeFile.." "..exifArg.." "..path .. '"' local status = LrTasks.execute(exeCmd) if io.open(redirect):read() == nil then break end --check is there any names in the file --logger:debug(exeCmd) if status ~= 0 then logger:debug("Error "..exeCmd) progressScope:done() end end for name in io.lines(redirect) do if name ~= nil then -- check is there any pleople on photo logger:debug(name) catalog:withWriteAccessDo("Adding name keywords", function () local keyword = catalog:createKeyword(name, {}, true, parrent, true) logger:debug("keyword created: " .. tostring(keyword)) photo:addKeyword(keyword) --photo:setRawMetadata('personShown', keyword) --doesn't work logger:debug("keyword added: " .. name) end) end end end progressScope:done() end LrTasks.startAsyncTask(faceToTag)
Все именные теги хранятся в иерархической структуре внутри тега «names», программы которые не работают с xmp схемой лайтрума будут видеть их просто плоским списком + тег «names». Для работы плагину в папку надо положить exiftool.exe и его конфиг. Все скопом можно скачать с github
Плагин работает, но у него есть недостатки:
- Не удается записать PersonInImage, если его писать exiftool он перезаписывается лайтрумом, а записать его непосредственно через SDK не получается по непонятным причинам. photo:setRawMetadata(‘personShown’, keyword) вылетает с ошибкой. Можно разнести это в две разных кнопки и перечитывать метаданные вручную, но это тоже некрасиво.
- работает медленно примерно 1 секунда на фото, при большем архиве это проблема, возможно если переписать через cookbooks.adobe.com/post_ExifTool___making_it_scream_-19501.html будет быстрее.
- Поскольку плагин пишет одновременно и через exiftool и через lightroom SDK по окончании работы регулярно возникает конфликт метаданных, и их надо сохранять вручную Ctrl+s. Если кто-то знает как заставить лайтрум писать и читать метаданные програмно — отпишитесь. Я пока придумал вариант только с эмуляцией хотеев lrBind но это не красиво.
- Это уже проблема не плагина, всей системы, если протегировать рав, а после этого его экспортировать, информация о лицах теряется, но теги сохраняются, а это уже профит.
ЗЫ. Я смог найти два плагина которые делают _почти_ тоже самое, берут лица из пикасы и пишут их в теги, но все они берут лица только из picasa.ini и не работают с лицами записанными в XMP.
ссылка на оригинал статьи http://habrahabr.ru/post/193946/
Добавить комментарий