ExifTool Forum

ExifTool => The "exiftool" Application => Topic started by: grimmo on February 23, 2020, 09:14:04 AM

Title: Extract an jpg image corresponding to the face detected area from digikam
Post by: grimmo on February 23, 2020, 09:14:04 AM
Hello, I would like to extract all the face images shown by digikam after face tagging of a certain person. The corresponding informations are in xmp files written by digikam. They contain the location of the face area, picture size and person's name; so everything needed should be inside the xmp file.

I tried to get along with "man exiftool", however did not manage to understand if such a thing is possible in exiftool. Would be great if such a routine already exists.

Thanks for any help in advance.
Title: Re: Extract an jpg image corresponding to the face detected area from digikam
Post by: StarGeek on February 23, 2020, 10:52:29 AM
Exiftool can only manipulate metadata. It has no ability to affect the actual image data.

You would have to use the data in the XMP file to calculate the region you want to extract and then use something like Imagemagick to extract the actual regions.  The problem would be that the data is usually not saved as an exact pixel location/size.  It's usually saved as percentages of the total image.
Title: Re: Extract an jpg image corresponding to the face detected area from digikam
Post by: grimmo on February 27, 2020, 01:08:06 PM
Thanks!
But is there an easy way with exiftool to extract/read the image size and the face region?
Title: Re: Extract an jpg image corresponding to the face detected area from digikam
Post by: Phil Harvey on February 27, 2020, 01:21:32 PM
Yes.
Title: Re: Extract an jpg image corresponding to the face detected area from digikam
Post by: grimmo on February 27, 2020, 01:29:35 PM
Would you also tell me how?
Title: Re: Extract an jpg image corresponding to the face detected area from digikam
Post by: Phil Harvey on February 27, 2020, 01:32:10 PM
For the image size:

exiftool -imagesize FILE

But for the face tags, I can't help because I don't know what tags Digikam writes.  See FAQ 2 and FAQ 3 (https://exiftool.org/faq.html#Q2) for help with this.

- Phil
Title: Re: Extract an jpg image corresponding to the face detected area from digikam
Post by: grimmo on February 27, 2020, 01:38:42 PM
Great, already got some information, guess I have to study the FAQs...

Thanks! I might come back.
Title: Re: Extract an jpg image corresponding to the face detected area from digikam
Post by: StarGeek on February 27, 2020, 02:23:00 PM
After some searching online, it looks like digikam might be saving regions as MWG regions.  I did see some posts where it might not do so by default, so there may be a setting for that.

To get the data, you would use
exiftool -s -XMP-mwg-rs:all File.jpg

The output will be something like this.  This is an example of an image with two faces taged.
RegionAppliedToDimensionsH      : 2028
RegionAppliedToDimensionsUnit   : pixel
RegionAppliedToDimensionsW      : 1383
RegionAreaH                     : 0.124757763, 0.148424506
RegionAreaUnit                  : normalized, normalized
RegionAreaW                     : 0.151842527, 0.181490806
RegionAreaX                     : 0.650041962, 0.327916381
RegionAreaY                     : 0.100343328, 0.113168536
RegionName                      : John Smith, Jane Smith
RegionType                      : Face, Face


All these numbers are given as a percent of the actual image size, so that way they are accurate even if the image has been resized. RegionAreaX and RegionAreaY indicate the center point of the region.  In this case, the center point John Smith is 0.650041962 x 0.100343328 and for Jane Smith is 0.327916381 x 0.113168536.  Note that the numbers are ordered by the the names.  The first number in each of the tags belongs to the first name, the second number to the second name, etc.

Working out the math
John Smith
X position=RegionAreaX*ImageWidth=0.650041962*1383=899 (rounding off)
Y Position=RegionAreaY*ImageHeight=0.100343328*2028=203
So the center point of the John Smith region is about 899x203.

Now it's important to note that this is the point around which the region is centered, not the upper left coordinate of the region.

Continuing with John Smith
Region Width = RegionAreaW*ImageWidth=0.151842527*1383=210
Region Height = RegionAreaH*ImageHeight=0.124757763*2028=253

To get the upper left corner of the region, you subtract half these numbers from the center point.
X Coord = 899-(210/2)=899-105=794
Y Coord = 203-(253/2)=203-127=76

As an example, using ImageMagick to extract the region, the command would be
magick File.Jpg -crop 210x253+794+76 thumb1.jpg

The final item to watch for is the orientation.  All of these applies to an image that has an EXIF:Orientation value of 1-Horizontal.  If the Orientation is different, then the image must be rotated properly before extracting the image.
Title: Re: Extract an jpg image corresponding to the face detected area from digikam
Post by: StarGeek on February 27, 2020, 03:52:31 PM
Since I had already done this for a previous project and it was just a cut/paste with a couple of edits, here is a config file that will read the MWG regions and output the thumbnail coordinates for use with ImageMagick.  ImageMagick crop uses the format of Width x Height + XCoord + YCoord but without spaces.  The X and Y coordinates are the upper left corner of the crop.

To use it, drop the file into the same directory as exiftool and this would be the command to use
exiftool -config ImageMagickThumbMWG.config -ImageMagickThumbMWG <FileOrDir>

example output for the previous post's image
Image Magick Thumb MWG          : 209x253+794+76, 251x301+328+79

Edit: Removed older version, see updated version (https://exiftool.org/forum/index.php?topic=10879.msg58748#msg58748).
Title: Re: Extract an jpg image corresponding to the face detected area from digikam
Post by: grimmo on February 28, 2020, 07:42:57 AM
I am so happy! Thanks a lot, this saved me a lot of time.

Your instructions and math from the previous post work perfect! It gives me exactly what digikam is showing for the face tagged region.

I am trying to figure out what the problem is with the config file; it doesn't produce any output.
It's probably related to the fact that
exiftool -s -XMP-mwg-rs:all File.jpg
doesn't work for me, because the xmp information is given in a separate xmp file:
exiftool -s -XMP-mwg-rs:all File.JPG.xmp
gives me
RegionName                      : name
RegionType                      : Face
RegionAreaX                     : 0.335612
RegionAreaY                     : 0.57581
RegionAreaW                     : 0.413845
RegionAreaH                     : 0.551505
RegionAreaUnit                  : normalized

I did read image dimensions by
exiftool -TAG -ExifImageHeight file.JPG.xmp
and
exiftool -TAG -ExifImageWidth file.JPG.xmp
and now after replacing that in your config file
exiftool -config ImageMagickThumbMWG.config -ImageMagickThumbMWG file.JPG.xmp
gives what you intended (for my image)
Image Magick Thumb MWG          : 1906x1906+593+1036

Great thanks!
I have to think how to proceed. But I would like to come back to you.
Title: Re: Extract an jpg image corresponding to the face detected area from digikam
Post by: StarGeek on February 28, 2020, 10:45:09 AM
Glad you figured out where the data was.  I don't use Digikam, so I didn't know where it would store the data.
Title: Re: Extract an jpg image corresponding to the face detected area from digikam
Post by: grimmo on March 15, 2020, 07:32:23 AM
Hello StarGeek, I figured out what I exactly want to do:


Maybe together with the query for a certain RegionName it would be nice to also check for the right EXIF:Orientation and rotate if necessary.


Title: Re: Extract an jpg image corresponding to the face detected area from digikam
Post by: grimmo on March 28, 2020, 09:48:09 AM
I managed to allow that second command would work with the output of the first command:
exiftool -config ImageMagickThumbMWG.config -T -ImageMagickThumbMWG image.jpg.xmp > test.txt
writes just the relevant crop information to the txt file. Alternatively you could use instead of -T also -b or -s -S.
magick P1000407.JPG -crop @test.txt thumb1.jpg
reads from this txt file and crops the face thumb.

Now when I have two faces detected in one image it does not work anymore, e.g.
exiftool -config ImageMagickThumbMWG.config -b -ImageMagickThumbMWG image.jpg.xmp
gives me
204x202+1160+813
182x181+1599+946

or
exiftool -config ImageMagickThumbMWG.config -T -ImageMagickThumbMWG image.jpg.xmp
gives me
204x202+1160+813, 182x181+1599+946

Is there an easy way to apply the script ImageMagickThumbMWG.config just to the spacial information needed, e.g. to Person2 from
exiftool -s -XMP-mwg-rs:all image.jpg.xmp
given
RegionName                      : Person1, Person2
RegionType                      : Face, Face
RegionAreaX                     : 0.441877, 0.591737
RegionAreaY                     : 0.427404, 0.484127
RegionAreaW                     : 0.0714286, 0.0637255
RegionAreaH                     : 0.0947712, 0.0849673
RegionAreaUnit                  : normalized, normalized


Any help?
Title: Re: Extract an jpg image corresponding to the face detected area from digikam
Post by: StarGeek on March 28, 2020, 11:08:45 AM
How about this.  Using your "Magick" command example

C:\>exiftool -config ImageMagickThumbMWG.config -g1 -a -s -IMCommandMWG  Y:\!temp\mmm\ACDsee-Regions_JSilva_092517_8623.jpg -b
magick "Y:/!temp/mmm/ACDsee-Regions_JSilva_092517_8623.jpg" -crop 151x180+352+125 "Y:/!temp/mmm/Natasha Romanoff_Thumb.jpg"
magick "Y:/!temp/mmm/ACDsee-Regions_JSilva_092517_8623.jpg" -crop 148x177+539+164 "Y:/!temp/mmm/Harley Quinn_Thumb.jpg"
magick "Y:/!temp/mmm/ACDsee-Regions_JSilva_092517_8623.jpg" -crop 138x167+453+35 "Y:/!temp/mmm/Arthur Dent_Thumb.jpg"
magick "Y:/!temp/mmm/ACDsee-Regions_JSilva_092517_8623.jpg" -crop 144x173+232+11 "Y:/!temp/mmm/Indiana Jones_Thumb.jpg"
magick "Y:/!temp/mmm/ACDsee-Regions_JSilva_092517_8623.jpg" -crop 158x190+669+90 "Y:/!temp/mmm/John Smith_Thumb.jpg""

C:\Programs\My_Stuff>cd /d Y:\!temp\mmm\

Y:\!temp\mmm>exiftool -config ImageMagickThumbMWG.config -g1 -a -s -IMCommandMWG  ACDsee-Regions_JSilva_092517_8623.jpg -b
magick "./ACDsee-Regions_JSilva_092517_8623.jpg" -crop 151x180+352+125 "./Natasha Romanoff_Thumb.jpg"
magick "./ACDsee-Regions_JSilva_092517_8623.jpg" -crop 148x177+539+164 "./Harley Quinn_Thumb.jpg"
magick "./ACDsee-Regions_JSilva_092517_8623.jpg" -crop 138x167+453+35 "./Arthur Dent_Thumb.jpg"
magick "./ACDsee-Regions_JSilva_092517_8623.jpg" -crop 144x173+232+11 "./Indiana Jones_Thumb.jpg"
magick "./ACDsee-Regions_JSilva_092517_8623.jpg" -crop 158x190+669+90 "./John Smith_Thumb.jpg"


You can then redirect that into a bat file and run it directly.  Requires the -b (binary) option (https://exiftool.org/exiftool_pod.html#b--binary) to create the batch file.
Title: Re: Extract an jpg image corresponding to the face detected area from digikam
Post by: grimmo on March 29, 2020, 05:30:26 AM
Thanks!
But I am sorry, I do not understand what you were trying to do and if that is what I wanted. I cannot get your modified script to output anything and it is really hard for me to read the script's language; I cannot interpret the new part of the script.

I thought I was almost there with what I described yesterday; I can combine the two commands in the terminal, and it works perfectly:

exiftool -config ImageMagickThumbMWG.config -T -ImageMagickThumbMWG 100_2325.jpg.xmp > test/test.txt && magick 100_2325.jpg -crop @test/test.txt test/thumb1.jpg

The above command even works, in case more Persons were detected in a single image. Then the above commands just crops the thumb of the first person. I thought there would be a simple way to just address RegionAreaW and RegionAreaH, RegionAreaX and RegionAreaY for Person2 from e.g.
QuoteRegionName                      : Person1, Person2
RegionType                      : Face, Face
RegionAreaX                     : 0.441877, 0.591737
RegionAreaY                     : 0.427404, 0.484127
RegionAreaW                     : 0.0714286, 0.0637255
RegionAreaH                     : 0.0947712, 0.0849673
RegionAreaUnit                  : normalized, normalized

and feed you first script just with the needed information for Person2 (0.0637255, 0.0849673, 0.591737, 0.484127).

Can't these normalized coordinates be addressed "column-like", if one knows which column is needed? In order just use the normalized spacial information for a certain person (e.g. RegionName=Chris).
If you find the value Chris at second position in RegionName then just feed the script with second position of RegionAreaW and RegionAreaH, RegionAreaX and RegionAreaY? Maybe even predefine this person's name inside the script.

Title: Re: Extract an jpg image corresponding to the face detected area from digikam
Post by: grimmo on March 29, 2020, 07:38:28 AM
Quote from: StarGeek on March 28, 2020, 11:08:45 AM
How about this.  Using your "Magick" command example

C:\>exiftool -config ImageMagickThumbMWG.config -g1 -a -s -IMCommandMWG  Y:\!temp\mmm\ACDsee-Regions_JSilva_092517_8623.jpg -b


Should it be-G1 instead of g1
exiftool -config ImageMagickThumbMWG.config -G1 -a -s -IMCommandMWG  Y:\!temp\mmm\ACDsee-Regions_JSilva_092517_8623.jpg -b

Then it runs, but still do not understand what it is supposed to do? Execute the magick commands you have pasted?
Title: Re: Extract an jpg image corresponding to the face detected area from digikam
Post by: StarGeek on March 29, 2020, 10:46:21 AM
Quote from: grimmo on March 29, 2020, 07:38:28 AM
Should it be-G1 instead of g1
exiftool -config ImageMagickThumbMWG.config -G1 -a -s -IMCommandMWG  Y:\!temp\mmm\ACDsee-Regions_JSilva_092517_8623.jpg -b[/quote]

-G1 and -g1 have the same function but just a difference in the display (see -G (groupNames) option (https://exiftool.org/exiftool_pod.html#G-NUM-:NUM...--groupNames)).  But in this command the whole -G1 -a -s is ignored due to the -b (binary) option (https://exiftool.org/exiftool_pod.html#b--binary).

QuoteThen it runs, but still do not understand what it is supposed to do? Execute the magick commands you have pasted?

No, this just constructs the the magick command for each of the regions.  Using your example command
exiftool -config ImageMagickThumbMWG.config  -IMCommandMWG  -b 100_2325.jpg.xmp > test/test.bat && test/test.bat

That would automatically create and run a bat file that would extract all the regions in the image.

Quote from: grimmo on March 29, 2020, 05:30:26 AM
Can't these normalized coordinates be addressed "column-like", if one knows which column is needed? In order just use the normalized spacial information for a certain person (e.g. RegionName=Chris).
If you find the value Chris at second position in RegionName then just feed the script with second position of RegionAreaW and RegionAreaH, RegionAreaX and RegionAreaY? Maybe even predefine this person's name inside the script.

I think that would require a separate script, using Windows batch, Powershell, or some other language for example,  to parse out the data and construct the command for you. 
Title: Re: Extract an jpg image corresponding to the face detected area from digikam
Post by: grimmo on April 02, 2020, 11:56:56 AM
Many thanks StarGeek; I have a solution that works enough for me. There is room for improvements, but I am really not an experienced programmer and have not much time to fiddle at the moment.

So here is what works for me:
exiftool -config ImageMagickThumbMWG.config -T -ImageMagickThumbMWG *.xmp -w Person_thumbs/%f.txt
As explained I have xmp files with the face region inside, separated from the image file. Digikam uses the image file name including the format extension and saves it as a .xmp file. So this command extracts with StarGeeks script the image region for each image with a associated xmp file and writes a .txt in a subfolder.

This image region can be extracted/read with the following command (rather script but I use as a command; found it somewhere) by ImageMagick and the face region gets cropped and saved in this subfolder.
First you search all the image files present (would be better to just handle the xmp files, but it still works):

list=$(ls *.jpg *.JPG)

then you have a list of all files

for img in $list; do name=$(magick $img -format "%t" info:); suffix=$(magick $img -format "%e" info:); magick $img -crop @Person_thumbs/${name}.${suffix}.txt "./Person_thumbs/Person_${name}.${suffix}"; done

In case you have more than one person tagged in an image, you just get the face of the first person in the txt file. Just delete the first face region and rerun the last command and you get the second face.
Title: Re: Extract an jpg image corresponding to the face detected area from digikam
Post by: grimmo on April 28, 2020, 01:34:35 PM
Hi again

I have some .dng files where I want to crop also the faces with the help of your script. The face tag info is again inside the sidecar file written by digikam. However for some reason there is no information for width and height of the .dng file inside this sidecar.

And I did not find any way to force digikam to write it.

However the size information can be read directly from the .dng
exiftool -s -ImageHeight IMGP0901.DNG
ImageHeight                     : 3300

Do you see some simple way to read the size info from the image file and the face tag info from the sidecar file and use it together in your script? I mean just two lines of eiftool code or so? I do not want you to modify your script again...
Title: Re: Extract an jpg image corresponding to the face detected area from digikam
Post by: StarGeek on April 28, 2020, 02:37:28 PM
You could copy the width/height to the sidecar file
exiftool -TagsFromFile %d%f.dng -ImageHeight -ImageWidth -ext xmp /path/to/files/
Title: Re: Extract an jpg image corresponding to the face detected area from digikam
Post by: grimmo on June 07, 2020, 07:15:59 AM
Thanks for your answer! One question, if I would copy this information several times, would then ImageWidth and Height appear several times in the xmp. I know I could try but maybe you already know the answer?
Title: Re: Extract an jpg image corresponding to the face detected area from digikam
Post by: StarGeek on June 07, 2020, 11:37:45 AM
With the command above, ImageHeight/ImageWidth would be overwritten each time.