Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f866256ad | ||
|
|
86018d5cc0 | ||
|
|
d657fc6ccd | ||
|
|
875f79b92d | ||
|
|
3a110bb6d3 | ||
|
|
e73327c164 |
14
CHANGELOG.md
14
CHANGELOG.md
@@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file. Dates are d
|
||||
|
||||
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
||||
|
||||
#### [v0.39.23](https://github.com/RhetTbull/osxphotos/compare/v0.39.22...v0.39.23)
|
||||
|
||||
> 18 January 2021
|
||||
|
||||
- Fixed face region orientation [`875f79b`](https://github.com/RhetTbull/osxphotos/commit/875f79b92d9510e59fe8ca0aa21a42abc7600f70)
|
||||
- Updated documentation for new face region properties [`3a110bb`](https://github.com/RhetTbull/osxphotos/commit/3a110bb6d3d23d1c9fd8612b4201144046fed567)
|
||||
|
||||
#### [v0.39.22](https://github.com/RhetTbull/osxphotos/compare/v0.39.21...v0.39.22)
|
||||
|
||||
> 18 January 2021
|
||||
|
||||
- Beta fix for Digikam reading XMP [`3799594`](https://github.com/RhetTbull/osxphotos/commit/379959447373f951ffca372598ea8f1d5834fe52)
|
||||
- Add @martinhrpi as a contributor [`db43017`](https://github.com/RhetTbull/osxphotos/commit/db430173b59732f944ca52b53c928370684580df)
|
||||
|
||||
#### [v0.39.21](https://github.com/RhetTbull/osxphotos/compare/v0.39.20...v0.39.21)
|
||||
|
||||
> 18 January 2021
|
||||
|
||||
16
README.md
16
README.md
@@ -2268,6 +2268,22 @@ UUID of the photo this face is associated with.
|
||||
#### `photo`
|
||||
[PhotoInfo](#photoinfo) object representing the photo that contains this face.
|
||||
|
||||
#### `mwg_rs_area`
|
||||
Returns named tuple with following coordinates as used in Metdata Working Group (mwg) face regions in XMP files.
|
||||
|
||||
* `x` = `stArea:x`
|
||||
* `y` = `stArea:y`
|
||||
* `h` = `stArea:h`
|
||||
* `w` = `stArea:w`
|
||||
|
||||
#### `mpri_reg_rect`
|
||||
Returnes named tuple with following coordinates as used in Microsoft Photo Region Rectangle (mpri) in XMP files.
|
||||
|
||||
* `x` = x coordinate of top left corner of rectangle
|
||||
* `y` = y coordinate of top left corner of rectangle
|
||||
* `h` = height of rectangle
|
||||
* `w` = width of rectangle
|
||||
|
||||
#### `face_rect()`
|
||||
Returns list of x, y coordinates as tuples `[(x0, y0), (x1, y1)]` representing the corners of rectangular region that contains the face. Coordinates are in same format and [reference frame](https://pillow.readthedocs.io/en/stable/handbook/concepts.html#coordinate-system) as used by [Pillow](https://pypi.org/project/Pillow/) imaging library. **Note**: face_rect() and all other properties/methods that return coordinates refer to the *current version* of the image. E.g. if the image has been edited ([`PhotoInfo.hasadjustments`](#hasadjustments)), these refer to [`PhotoInfo.path_edited`](#pathedited). If the image has no adjustments, these coordinates refer to the original photo ([`PhotoInfo.path`](#path)).
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
""" version info """
|
||||
|
||||
__version__ = "0.39.22"
|
||||
__version__ = "0.39.24"
|
||||
|
||||
@@ -235,10 +235,15 @@ class FaceInfo:
|
||||
Reference:
|
||||
https://photo.stackexchange.com/questions/106410/how-does-xmp-define-the-face-region
|
||||
"""
|
||||
x = self.center_x
|
||||
y = 1.0 - self.center_y
|
||||
h = self.size_pixels / self.photo.height
|
||||
w = self.size_pixels / self.photo.width
|
||||
x, y = self.center_x, self.center_y
|
||||
x, y = self._fix_orientation((x, y))
|
||||
|
||||
if self.photo.orientation in [5, 6, 7, 8]:
|
||||
w = self.size_pixels / self.photo.height
|
||||
h = self.size_pixels / self.photo.width
|
||||
else:
|
||||
h = self.size_pixels / self.photo.height
|
||||
w = self.size_pixels / self.photo.width
|
||||
|
||||
return MWG_RS_Area(x, y, h, w)
|
||||
|
||||
@@ -256,12 +261,19 @@ class FaceInfo:
|
||||
Reference:
|
||||
https://docs.microsoft.com/en-us/windows/win32/wic/-wic-people-tagging
|
||||
"""
|
||||
x = self.center_x - self.size_pixels / self.photo.width / 2
|
||||
y = 1.0 - self.center_y - self.size_pixels / self.photo.height / 2
|
||||
x, y = self.center_x, self.center_y
|
||||
x, y = self._fix_orientation((x, y))
|
||||
|
||||
# though the docs clearly say height, width, these appear to be flipped
|
||||
h = self.size_pixels / self.photo.width
|
||||
w = self.size_pixels / self.photo.height
|
||||
if self.photo.orientation in [5, 6, 7, 8]:
|
||||
w = self.size_pixels / self.photo.width
|
||||
h = self.size_pixels / self.photo.height
|
||||
x = x - self.size_pixels / self.photo.height / 2
|
||||
y = y - self.size_pixels / self.photo.width / 2
|
||||
else:
|
||||
h = self.size_pixels / self.photo.width
|
||||
w = self.size_pixels / self.photo.height
|
||||
x = x - self.size_pixels / self.photo.width / 2
|
||||
y = y - self.size_pixels / self.photo.height / 2
|
||||
|
||||
return MPRI_Reg_Rect(x, y, h, w)
|
||||
|
||||
@@ -308,6 +320,33 @@ class FaceInfo:
|
||||
_, _, yaw = self.roll_pitch_yaw()
|
||||
return yaw
|
||||
|
||||
def _fix_orientation(self, xy):
|
||||
""" Translate an (x, y) tuple based on image orientation
|
||||
|
||||
Arguments:
|
||||
xy: tuple of (x, y) coordinates for point to translate
|
||||
in format used by Photos (percent of height/width)
|
||||
|
||||
Returns:
|
||||
(x, y) tuple of translated coordinates
|
||||
"""
|
||||
# Reference: https://github.com/neilpa/phace/blob/7594776480505d0c389688a42099c94ac5d34f3f/cmd/phace/draw.go#L79-L94
|
||||
|
||||
orientation = self.photo.orientation
|
||||
x, y = xy
|
||||
if orientation in [1, 2]:
|
||||
y = 1.0 - y
|
||||
elif orientation in [3, 4]:
|
||||
x = 1.0 - x
|
||||
elif orientation in [5, 6]:
|
||||
x, y = 1.0 - y, 1.0 - x
|
||||
elif orientation in [7, 8]:
|
||||
x, y = y, x
|
||||
else:
|
||||
logging.warning(f"Unhandled orientation: {orientation}")
|
||||
|
||||
return (x, y)
|
||||
|
||||
def _make_point(self, xy):
|
||||
""" Translate an (x, y) tuple based on image orientation
|
||||
and convert to image coordinates
|
||||
@@ -322,22 +361,11 @@ class FaceInfo:
|
||||
# Reference: https://github.com/neilpa/phace/blob/7594776480505d0c389688a42099c94ac5d34f3f/cmd/phace/draw.go#L79-L94
|
||||
|
||||
orientation = self.photo.orientation
|
||||
x, y = xy
|
||||
x, y = self._fix_orientation(xy)
|
||||
dx = self.photo.width
|
||||
dy = self.photo.height
|
||||
if orientation in [1, 2]:
|
||||
y = 1.0 - y
|
||||
elif orientation in [3, 4]:
|
||||
x = 1.0 - x
|
||||
elif orientation in [5, 6]:
|
||||
x, y = 1.0 - y, 1.0 - x
|
||||
if orientation in [5, 6, 7, 8]:
|
||||
dx, dy = dy, dx
|
||||
elif orientation in [7, 8]:
|
||||
x, y = y, x
|
||||
dx, dy = dy, dx
|
||||
else:
|
||||
logging.warning(f"Unhandled orientation: {orientation}")
|
||||
|
||||
return (int(x * dx), int(y * dy))
|
||||
|
||||
def _make_point_with_rotation(self, xy):
|
||||
@@ -385,6 +413,8 @@ class FaceInfo:
|
||||
"right_eye": self.right_eye,
|
||||
"size": self.size,
|
||||
"face_rect": self.face_rect(),
|
||||
"mpri_reg_rect": self.mpri_reg_rect._asdict(),
|
||||
"mwg_rs_area": self.mwg_rs_area._asdict(),
|
||||
"roll": roll,
|
||||
"pitch": pitch,
|
||||
"yaw": yaw,
|
||||
|
||||
@@ -1715,6 +1715,7 @@ def _xmp_sidecar(
|
||||
use_persons_as_keywords: treat person names as keywords
|
||||
keyword_template: (list of strings); list of template strings to render as keywords
|
||||
description_template: string; optional template string that will be rendered for use as photo description
|
||||
extension: which extension to use for SidecarForExtension property
|
||||
merge_exif_keywords: boolean; if True, merged keywords found in file's exif data (requires exiftool)
|
||||
merge_exif_persons: boolean; if True, merged persons found in file's exif data (requires exiftool)
|
||||
"""
|
||||
|
||||
@@ -6,7 +6,8 @@ import sys
|
||||
|
||||
import osxphotos
|
||||
|
||||
photosdb = osxphotos.PhotosDB()
|
||||
db = sys.argv[1]
|
||||
photosdb = osxphotos.PhotosDB(dbfile=db)
|
||||
|
||||
face_photos = [p for p in photosdb.photos() if p.face_info]
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user