News:

2023-03-15 Major improvements to the new Geolocation feature

Main Menu

Picasa.ini to XMP-mwg-rs/XMP-MP Region tags

Started by StarGeek, March 03, 2015, 05:16:54 PM

Previous topic - Next topic

Phil Harvey

Sure.  Just use the value of $Image::ExifTool::VERSION directly.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

StarGeek

Ok, I'd say this is ready for use.  It now has a version check so it can check to see if there's an userparam api call.  I would like to move that into the LoadContacts subroutine, but couldn't figure out how to access the userparam variable from with the subroutine.

Take a look, laugh at my coding techniques, fold, spindle, mutilate at will.

Documentation:

This ExifTool config file contains four tags that can be used to read .picasa.ini files, extract the face region info, and create MWG region tags (Media Work Group region, used by Picasa) and MP region tags (used by Microsoft Photo Library).  Before use, the path to Picasa's contacts.xml must be corrected, or if using ExifTool  9.89 or higher is used, it can be set on the command line with -api userparam=PicasaContactsFile=/path/to/contacts.xml
Tags:
-----
PicasaToMWGRegion : This will create the MWG region tag.
   Suggested Usage: ExifTool -config \path\to\.Picasa_Conversion_Config -if "$PicasaToMWGRegion" "-RegionInfo<PicasaToMWGRegion" <FILE/DIR>
PicasaToMPRegion  : This will create the MP region tag.
   Suggested Usage: ExifTool -config \path\to\.Picasa_Conversion_Config -if "$PicasaToMPRegion" "-RegionInfoMP<PicasaToMPRegion" <FILE/DIR>
PicasaToMWGRegionFiltered : This will create the MWG region tag but will filter out the regions that are still unnamed in Picasa.  Picasa defaults to naming these regions 'ffffffffffffffff'.
   Suggested Usage: ExifTool -config \path\to\.Picasa_Conversion_Config -if "$PicasaToMWGRegionFiltered" "-RegionInfo<PicasaToMWGRegionFiltered" <FILE/DIR>
PicasaToMPRegionFiltered  : This will create the MP region tag but will filter out the regions that are still unnamed in Picasa. Picasa defaults to naming these regions 'ffffffffffffffff'.
   Suggested Usage: ExifTool -config \path\to\.Picasa_Conversion_Config -if "$PicasaToMPRegionFiltered" "-RegionInfoMP<PicasaToMPRegionFiltered" <FILE/DIR>

This config file should probably be kept separate and not integrated into the main .ExifTool_config, as it would slow down regular processing of files.

If both MWG and MP region tags are desired, the commands can be combined
ExifTool -config \path\to\.Picasa_Conversion_Config -if "$PicasaToMWGRegion" "-RegionInfo<PicasaToMWGRegion" "-RegionInfoMP<PicasaToMPRegion" <FILE/DIR>
* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).

Phil Harvey

Looks good!  Just a few minor notes:

1) You can access $Image::ExifTool::VERSION in your subroutine in just the same way as you are doing in your ValueConv.

2) In your LoadContacts() subroutine, you open CONTACTS, but close INI.  Also, you should add "local *CONTACTS" to avoid name conflicts with CONTACTS elsewhere.

3) You shouldn't need the -if option in your command, because there will be nothing to copy if the tag doesn't exist, so the effect is the same.

4) You are no longer using @Image::ExifTool::myIniData, so you can remove this line.

5) You may not need to copy the entire FileHash entry into @TempArray.  Instead, just use a reference to the array:

my $TempArrayRef = $Image::ExifTool::FileHash{$Filename} or return undef;
foreach my $TempHash (@$TempArrayRef) {
...
}


6) Similarly, you should try to avoid copying the entire contact hash if you can, by doing something like this:

my $ContactHashRef = \%Image::ExifTool::ContactHash;
...
Name => $ContactHashRef->{$TempHash->{'ContactID'}},
...


- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

StarGeek

Quote from: Phil Harvey on March 08, 2015, 09:40:03 AM
1) You can access $Image::ExifTool::VERSION in your subroutine in just the same way as you are doing in your ValueConv.

At first I tried to have this whole part in the LoadContacts subroutine:
my $ContactFile = $Image::ExifTool::ContactXML;
if ($Image::ExifTool::VERSION >= 9.89)
{
if (defined($self->Options(UserParam => 'PicasaContactsFile')))
{
$ContactFile = $self->Options(UserParam => 'PicasaContactsFile');
}
}


The problem I had was accessing $self->Options(UserParam => 'PicasaContactsFile');.  In the LoadContacts subroutine it had no value.   Entirely possible I had something else wrong though.

Hmmm, I could replace it with
my $ContactFile = ($Image::ExifTool::VERSION >= 9.89 and defined($self->Options(UserParam => 'PicasaContactsFile')))
? $self->Options(UserParam => 'PicasaContactsFile')
: $Image::ExifTool::ContactXML;

right?

Quote2) In your LoadContacts() subroutine, you open CONTACTS, but close INI.  Also, you should add "local *CONTACTS" to avoid name conflicts with CONTACTS elsewhere.
Yet another D'oh moment with the closing.  Obviously I copy/pasted the other subroutine as the base.  Too inexperienced to know about local.  I don't think I have any other CONTACTS, but added it just in case.

Quote3) You shouldn't need the -if option in your command, because there will be nothing to copy if the tag doesn't exist, so the effect is the same.
Maybe it's a Windows executable thing, but without it I get a "Warning: No writable tags set from..." warning.  I was trying to avoid that.

Quote4) You are no longer using @Image::ExifTool::myIniData, so you can remove this line.
Another D'oh.  Done.

Quote5) You may not need to copy the entire FileHash entry into @TempArray.  Instead, just use a reference to the array:

my $TempArrayRef = $Image::ExifTool::FileHash{$Filename} or return undef;
foreach my $TempHash (@$TempArrayRef) {
...
}


6) Similarly, you should try to avoid copying the entire contact hash if you can, by doing something like this:

my $ContactHashRef = \%Image::ExifTool::ContactHash;
...
Name => $ContactHashRef->{$TempHash->{'ContactID'}},
...

Yeah, this is especially where I'm messing with stuff I'm not fully comprehending.   I spent an hour or so pounding at this like a Klingon engineer (keep hitting it until it works!!).  I had Dumper showing me what was in the variables, I could see where the problem was, but I had problems figuring out the proper way to fix it.  At that point it became all about making it work regardless of the consequences!

Updated version attached.
* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).

Phil Harvey

Quote from: StarGeek on March 08, 2015, 05:10:08 PM
The problem I had was accessing $self->Options(UserParam => 'PicasaContactsFile');.  In the LoadContacts subroutine it had no value.

Ah, yes.  You would need to pass $self into the subroutine so it could access the ExifTool object from there.

QuoteMaybe it's a Windows executable thing, but without it I get a "Warning: No writable tags set from..." warning.  I was trying to avoid that.

Ah, yes.  Not a Windows thing.  The -if will avoid the warning.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

Phil Harvey

I hope you don't mind, but I have edited your config file with an eye towards eventually including it in an ExifTool distribution.  To this end, many of the changes are purely aesthetic, and attempt to make the coding style conform more to that of ExifTool.

I have also changed some variable names and scoping to avoid possible future conflicts with ExifTool variables.

And I took the liberty to change the output 'ffffffffffffffff' name to 'unnamed', to be a bit nicer for the user.  Feel free to change this back if you wanted to leave it as 'ffffffffffffffff'.

Attached is my edited version.  I don't have the necessary Picasa files to test this, so I can't be sure that I didn't mess something up with my changes.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

StarGeek

Quote from: Phil Harvey on March 10, 2015, 08:52:20 AM
I hope you don't mind, but I have edited your config file with an eye towards eventually including it in an ExifTool distribution.  To this end, many of the changes are purely aesthetic, and attempt to make the coding style conform more to that of ExifTool.
Sounds good.  I would have been surprised if you didn't.  Feel free to edit and clarify anything you think needs to be fixed.

QuoteAnd I took the liberty to change the output 'ffffffffffffffff' name to 'unnamed', to be a bit nicer for the user.  Feel free to change this back if you wanted to leave it as 'ffffffffffffffff'.

This is something I thought about and couldn't decide upon a satisfactory solution.

Picasa normally won't store the unknowns in the file.  But if you use AvPicFaceXmpTagger, it will add the unknowns using the 'ffffffffffffffff' name.  So if Picasa has to reload a file due to a corrupt database or something similar, it will add this as a name.  'ffffffffffffffff' does stand out as something out of the ordinary and forces you to deal with it, but 'unnamed' is nicer to look.  Hmmm... I should check to see if Picasa leaves it in the file if tell Picasa to ignore that region. 

All this is basically why I use the filtered versions and just included the non filtered ones for completeness.  Maybe the names should be swapped.  Named the filtered versions with the basic name for regular use, since this would match how Picasa adds tags, and add "Unfiltered" or something similar to what are currently the basic tags. 

As a side note, Picasa does read the MPRegion tags seems to process them faster than the MWG Region tags.  When I added files that contained only one or other, it recognized regions in the file with the MPRegions instantly upon loading, but didn't recognize the MWG regions until I closed and restarted Picasa.

QuoteAttached is my edited version.  I don't have the necessary Picasa files to test this, so I can't be sure that I didn't mess something up with my changes.

I'll test it out.

There was one more tag (or maybe tags, filtered and unfiltered) I was going to add.  I was thinking about a adding a list type tag that was just the region names, so that way they could also be added to XMP:Subject and IPTC:Keywords in the same command, rather than adding the regions to a file then running -Subject<RegionName as a separate command.  This would also allow running an update on the files if needed.  Something like -if "$RegionName ne $PicasaIniRegionNames" "-RegionInfo<PicasaToMWGRegionFiltered".  Because, unless I'm mistaken, you can't use -if "$RegionInfo ne $PicasaToMWGRegionFiltered" to check for changes, correct?  At least my tests along those lines didn't work.


* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).

StarGeek

Quote from: Phil Harvey on March 10, 2015, 08:52:20 AM
Attached is my edited version.  I don't have the necessary Picasa files to test this, so I can't be sure that I didn't mess something up with my changes.

Something did break.   Under ExifTool version 9.67, it appears that 0 is being passed for various x and y coordinates.  Under  9.89, it responds with "Warning: ValueConv PicasaToMWGRegionFiltered: Can't call method "Options" on an undefined value".

Output of my old config using ver 9.67
c:\Server\My_stuff>exiftool -config C:\Programs\UnixUtils\.Picasa_Conversion_Config -struct -PicasaToMWGRegionFiltered -PicasaToMPRegionFiltered Z:\Pictures\Camera_Pictures\Camera_Pictures_Finished\Camera-Final\Comikaze_Expo\2012\2012-09-15_15.34.23.Jpg
Picasa To MWG Region Filtered   : {AppliedToDimensions={H=4928,Unit=pixel,W=3264},RegionList=[{Area={H=0.1331045,Unit=normalized,W=0.1678951,X=0.57077135,Y=0.13900205},Name=LeeAnna Vamp,Type=Face},{Area={H=0.1406119,Unit=normalized,W=0.1761654,X=0.38159,Y=0.20464635},Name=Jessica Nigri,Type=Face}]}
Picasa To MP Region Filtered    : {Regions=[{PersonDisplayName=LeeAnna Vamp,Rectangle=0.4868238|, 0.0724498|, 0.1678951|, 0.1331045},{PersonDisplayName=Jessica Nigri,Rectangle=0.2935073|, 0.1343404|, 0.1761654|, 0.1406119}]}


Output of your config using ver 9.67, which is passing the names properly but not the X, Y, W, and H variables
c:\Server\My_stuff>exiftool -config C:\Programs\UnixUtils\.Picasa_Conversion_Config_Phils -struct -PicasaToMWGRegionFiltered -PicasaToMPRegionFiltered Z:\Pictures\Camera_Pictures\Camera_Pictures_Finished\Camera-Final\Comikaze_Expo\2012\2012-09-15_15.34.23.Jpg
Picasa To MWG Region Filtered   : {AppliedToDimensions={H=4928,Unit=pixel,W=3264},RegionList=[{Area={H=0,Unit=normalized,W=0,X=0,Y=0},Name=LeeAnna Vamp,Type=Face},{Area={H=0,Unit=normalized,W=0,X=0,Y=0},Name=Jessica Nigri,Type=Face}]}
Picasa To MP Region Filtered    : {Regions=[{PersonDisplayName=LeeAnna Vamp,Rectangle=|, |, 0|, 0},{PersonDisplayName=Jessica Nigri,Rectangle=|, |, 0|, 0}]}


And output of your config with ver  9.89
c:\Server\My_stuff>exiftool_9.89 -config C:\Programs\UnixUtils\.Picasa_Conversion_Config_Phils -struct -PicasaToMWGRegionFiltered -PicasaToMPRegionFiltered Z:\Pictures\Camera_Pictures\Camera_Pictures_Finished\Camera-Final\Comikaze_Expo\2012\2012-09-15_15.34.23.Jpg
Warning: ValueConv PicasaToMWGRegionFiltered: Can't call method "Options" on an undefined value - Z:/Pictures/Camera_Pictures/Camera_Pictures_Finished/Camera-Final/Comikaze_Expo/2012/2012-09-15_15.34.23.Jpg


I'll PM you a link with sample contacts.xml, .picasa.ini and image file.

Yeah, and have a laugh at my directory structure.  I blame you Phil, because every time I learn some new and exciting way to use ExifTool, I start moving files to a new directory to keep track of what files have "completed" metadata and which don't.
* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).

Phil Harvey

Quote from: StarGeek on March 10, 2015, 02:35:52 PM
unless I'm mistaken, you can't use -if "$RegionInfo ne $PicasaToMWGRegionFiltered" to check for changes, correct?

Right.  That won't work.

I'll have to wait until tomorrow before I can take a look to see what I broke.  Writing complex code in ValueConv expressions is difficult because ExifTool hides the normal compile and runtime errors/warnings.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

Phil Harvey

#24
Thanks for the test files.

Yes, I did mess up a few things!!  There is no substitute for actually running the code... ;)

I also fixed a problem in your original version which prevented it from working on my system due to different newlines.

Attached is an updated version that works for me now.

Post back here after you have made any additional additions/improvements that you want.  When you are done, I'll go through the code once more to make the style ExifTool-like, then add it to the distribution.

- Phil

Edit: Changed the ValueConv expressions to code references.  This has a few advantages in this situation:

1) The code is no longer evaluated in the ExifTool namespace, so we can avoid creating Image::ExifTool variables.

2) The code is only compiled once when it is loaded.

3) Any compile problems are easier to track down.
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

StarGeek

This version passes the numbers correctly, but now the region names are showing up empty for me.
* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).

Phil Harvey

Hmmm.  It works for me.  :(  Does the exact same command work with your version but not mine?  The opposite is true for me because "chomp" doesn't remove what it needs to when parsing your contacts file on this platform.

Here is the command I used:

exiftool -config ~/Desktop/Picasa_Conversion_Config ../testpics/Picasa/testfiles/ -api userparam=PicasaContactsFile=../testpics/Picasa/testfiles/contacts/contacts.xml -picasa'*' -r -struct

If you don't get the names, it is probably because the contacts file isn't getting processed somehow.  Darn.

I'll debug this on Windows, but can't do this until tomorrow.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

StarGeek

Sorry, another of my stupid mistakes.  I realized the moment I saw your command that I had forgot to change the path to the contacts.xml file in your file I downloaded or set the userparam.

I've made a few minor changes.  I've changed the tag names so that the basic tag is filtered, and added Unfiltered to the names of the original tags.  This more closely mimics the behavior of Picasa rather than the behavior of AvPicFaceXmpTagger.  The more I thought about this, the more I felt this was a better choice.  If 'unnamed' or 'ffffffffffffffff' region is added to the file, Picasa will add that as a contact name, where normally it would leave it blank. 

I also added PicasaRegionNames.  This will allow for easy copying of the region names into tags such as keywords and subject.  It also allows easy updating of a full directory when changes are made.  It worked quite well last night.  I was tagging a directory, run an update in the background every now and then, and keep tagging while it ran.  This process makes me very happy, as it's much easier and quicker than my previous workflow.

Take a look at PicasaRegionNames but you shouldn't have to change anything, as all I did was copy/paste your version of PicasaToMPRegion, remove a bunch of lines and change about two lines.  I didn't include an unfiltered version, but it would be simple to add if needed.

Thanks for all your help, I'm quite happy with the way this has worked out.
* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).

StarGeek

I gave this config file a heavy workout today (well, yesterday at this point).  I kept running it in the background while I was tagging a bunch of directories, many of which already were tagged in Picasa, a few which already had the regions written into the files.  A bit over 39 K files in the directories, 10 K which ended up with region tags.   Only one error popped up a few times and that wasn't something that was ExifTool's fault.  Speed was much better than I expected.  Short version, results look very promising.  Tomorrow, I'll make a copy of a few of those folders, add them to a new Picasa database, let Picasa do its thing, and see if anything really bad shows up.


Long version with useless talk about the error:
The one error I came across, "Warning: No writable tags set", has to do with the way Picasa deals with zone data.  If there is already region data in the file, that data has priority and nothing is written to the .picasa.ini.  So there was no PicasaToMWGRegion or PicasaToMPRegion tags created from the .picasa.ini but the command I was using was doing a check that tested true (-if "$RegionName ne $PicasaRegionNames").  So, RegionName already existed in the file, Picasa didn't write it to the .picasa.ini file, and ExifTool has an undefined PicasaRegionNames and obviously, no PicasaToMWGRegion and PicasaToMPRegion tags to write.  Not a big deal, of course.

The good news is that if a new zone is added in Picasa to a file that already has tags, then the new data plus the old data is written to the .picasa.ini file, allowing this config file to update the image with the new zones.  I will have to check to see what happens if one of the zones already defined in the file ignored and see what changes happen.


* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).

Phil Harvey

#29
Quote from: StarGeek on March 11, 2015, 07:15:01 PM
I realized the moment I saw your command that I had forgot to change the path to the contacts.xml file in your file I downloaded or set the userparam.

Great.  I also realized that my attempted warning isn't working to print a message when the contacts file can't be opened.  I'll look into this.

It sounds like it is working well for you.  Excellent. 

- Phil

Edit:  I was playing with the new version.  I wonder how it is best to handle the case where a name is not found (ie. contact.xml not loaded).  I think I changed the behaviour so that it now returns nameless regions, but maybe that was the wrong thing to do.  Would it be better to return no region at all if there is no person name?

Edit2: OK.  I've gone ahead and implemented this for the filtered regions (returns no region if no name), which sort of makes sense to me.  I have also gone through and finished prettying up the code to match the ExifTool comment style, and changed the config file name to what I would like to use in the distribution.  I see this as good to go for the next release unless you want anything changed.  Attached is the updated version.
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).