Functions/GenXdev.AI.Queries/Invoke-ImageFacesUpdate.ps1
################################################################################ <# .SYNOPSIS Updates face recognition metadata for image files in a specified directory. .DESCRIPTION This function processes images in a specified directory to identify and analyze faces using AI recognition technology. It creates or updates metadata files containing face information for each image. The metadata is stored in a separate file with the same name as the image but with a ':faces.json' suffix. .PARAMETER ImageDirectory The directory path containing images to process. Can be relative or absolute. Default is the current directory. .PARAMETER Recurse If specified, processes images in the specified directory and all subdirectories. .PARAMETER OnlyNew If specified, only processes images that don't already have face metadata files. .PARAMETER RetryFailed If specified, retries processing previously failed images (empty metadata files). .EXAMPLE Invoke-ImageFacesUpdate -ImageDirectory "C:\Photos" -Recurse .EXAMPLE Invoke-ImageFacesUpdate "C:\Photos" -RetryFailed -OnlyNew #> function Invoke-ImageFacesUpdate { [CmdletBinding()] [Alias("Update-ImageFaces")] param( ############################################################################### <# .SYNOPSIS Specifies the directory containing images to process. .DESCRIPTION The directory path containing images to process. Can be relative or absolute. Default is the current directory. .PARAMETER ImageDirectory The directory path containing images to process. Can be relative or absolute. Default is the current directory. .EXAMPLE Invoke-ImageFacesUpdate -ImageDirectory "C:\Photos" #> [Parameter( Position = 0, Mandatory = $false, HelpMessage = "The image directory path." )] [string] $ImageDirectory = ".\", ############################################################################### <# .SYNOPSIS If specified, processes images in the specified directory and all subdirectories. .DESCRIPTION When this switch is provided, the function will search for images not only in the specified directory but also in all of its subdirectories. .PARAMETER Recurse If specified, processes images in the specified directory and all subdirectories. .EXAMPLE Invoke-ImageFacesUpdate -Recurse #> [Parameter( Mandatory = $false, HelpMessage = "Recurse directories." )] [switch] $Recurse, ############################################################################### <# .SYNOPSIS If specified, only processes images that don't already have face metadata files. .DESCRIPTION When this switch is provided, the function will skip processing images that already have a corresponding face metadata file. .PARAMETER OnlyNew If specified, only processes images that don't already have face metadata files. .EXAMPLE Invoke-ImageFacesUpdate -OnlyNew #> [Parameter( Mandatory = $false, HelpMessage = "Skip if already has meta data." )] [switch] $OnlyNew, ############################################################################### <# .SYNOPSIS If specified, retries processing previously failed images (empty metadata files). .DESCRIPTION When this switch is provided, the function will reprocess images that have empty metadata files (indicating a previous processing failure). .PARAMETER RetryFailed If specified, retries processing previously failed images (empty metadata files). .EXAMPLE Invoke-ImageFacesUpdate -RetryFailed #> [Parameter( Mandatory = $false, HelpMessage = "Will retry previously failed images." )] [switch] $RetryFailed ) begin { # convert the possibly relative path to an absolute path for reliable access $path = GenXdev.FileSystem\Expand-Path $ImageDirectory # ensure the target directory exists before proceeding with any operations if (-not [System.IO.Directory]::Exists($path)) { Microsoft.PowerShell.Utility\Write-Host "The directory '$path' does not exist." return } Microsoft.PowerShell.Utility\Write-Verbose "Processing images in directory: $path" } process { # retrieve all supported image files (jpg, jpeg, png) from the specified directory # applying recursion only if the -Recurse switch was provided Microsoft.PowerShell.Management\Get-ChildItem -Path "$path\*.jpg", "$path\*.jpeg", "$path\*.png" ` -Recurse:$Recurse -File -ErrorAction SilentlyContinue | Microsoft.PowerShell.Core\ForEach-Object { # if retry mode is active, handle previously failed images if ($RetryFailed) { if ([System.IO.File]::Exists("$($PSItem):faces.json")) { # if metadata file exists but is empty ({}), delete it to force reprocessing # this addresses files that failed in previous processing attempts if ([System.IO.File]::ReadAllText( "$($PSItem):faces.json").StartsWith("{}")) { [System.IO.File]::Delete("$($PSItem):faces.json") Microsoft.PowerShell.Utility\Write-Verbose ("Deleted empty metadata for retry: " + "$($PSItem)") } } } # store the full path to the current image for better readability $image = $PSItem.FullName Microsoft.PowerShell.Utility\Write-Verbose "Processing image: $image" # remove read-only attribute if present to ensure file can be modified if ($PSItem.Attributes -band [System.IO.FileAttributes]::ReadOnly) { $PSItem.Attributes = $PSItem.Attributes -bxor [System.IO.FileAttributes]::ReadOnly } # check if a metadata file already exists for this image $metadataFilePath = "$($image):faces.json" $fileExists = [System.IO.File]::Exists($metadataFilePath) # process image if either we're updating all images or this is a new image without metadata if ((-not $OnlyNew) -or (-not $fileExists)) { # create an empty metadata file as a placeholder if one doesn't exist if (-not $fileExists) { $null = [System.IO.File]::WriteAllText($metadataFilePath, "{}") Microsoft.PowerShell.Utility\Write-Verbose "Created new metadata file for: $image" } # obtain face recognition data using AI analysis # convert the results to JSON with deep object serialization $faces = GenXdev.AI\Get-ImageRecognizedFaces ` -ImagePath $image | Microsoft.PowerShell.Utility\ConvertTo-Json -Depth 20 ` -WarningAction SilentlyContinue Microsoft.PowerShell.Utility\Write-Verbose "Received face analysis for: $image" try { # save the processed face data to a metadata file # re-parse and re-serialize to ensure consistent JSON format [System.IO.File]::WriteAllText( $metadataFilePath, ($faces | Microsoft.PowerShell.Utility\ConvertFrom-Json | Microsoft.PowerShell.Utility\ConvertTo-Json -Compress -Depth 20 ` -WarningAction SilentlyContinue)) Microsoft.PowerShell.Utility\Write-Verbose "Successfully saved face metadata for: $image" } catch { # log any errors that occur during metadata processing Microsoft.PowerShell.Utility\Write-Warning "$PSItem`r`n$faces" } } } } end { } } ################################################################################ |