Last active
April 11, 2019 02:53
-
-
Save vexx32/baafe3e133e6a6d34be6975908a77f87 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Requires -Modules ThreadJob | |
using namespace System.Collections.Generic | |
function Invoke-AutoCrop { | |
<# | |
.SYNOPSIS | |
Uses the Python AutoCrop tool to crop images down to faces found in the image. | |
.DESCRIPTION | |
Using the AutoCrop tool, images are stripped down to just detected faces and either saved over the original | |
image(s), or into a new location. | |
Be aware that this cropping is destructive. Copies should be made prior to cropping if originals need | |
to be kept intact, as AutoCrop neglects to save the originals. | |
.PARAMETER Path | |
Enter the path to the folder which holds the images to crop. | |
.PARAMETER Destination | |
Enter a destination to save the cropped images to. If none is specified, the images will be overwritten in-place. | |
.PARAMETER RejectPath | |
Enter a destination to move images which do not contain faces to. if none is specified, this defaults to the same | |
directory as -Destination. | |
.PARAMETER CroppedSizeRatio | |
The percentage of the image that contains a face. For example, if the face takes up a third of the image size, | |
you would enter -CroppedSizeRatio 33 | |
.PARAMETER Width | |
The final width of the cropped images in pixels. Default is 500px. | |
.PARAMETER Height | |
The final height of the cropped images in pixels. Defaults to 500px. | |
.PARAMETER PadTop | |
Weight the placement upwards. Default is 50, use a higher number to move the cropped region upwards. | |
.PARAMETER PadBottom | |
Weight the placement downwards. Default is 50, use a higher number to move the cropped region downwards. | |
.PARAMETER PadLeft | |
Weight the placement leftwards. Default is 50, use a higher number to move the cropped region leftwards. | |
.PARAMETER PadRight | |
Weight the placement rightwards. Default is 50, use a higher number to move the cropped region rightwards. | |
.EXAMPLE | |
Invoke-AutoCrop -Path . -Destination .\Cropped | |
.NOTES | |
This function assumes the AutoCrop utility has been installed already. AutoCrop is dependent on Python 3. | |
After installing Python 3, execute the following command to install AutoCrop. | |
PS> pip install autocrop | |
If Python is installed but AutoCrop is not, this command will first attempt to install it. | |
#> | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] | |
[Alias('InputFolder')] | |
[string[]] | |
$Path, | |
[Parameter()] | |
[Alias('OutputFolder')] | |
[string] | |
$Destination, | |
[Parameter()] | |
[Alias('RejectFolder')] | |
[string] | |
$RejectPath, | |
[Parameter()] | |
[Alias('FacePercent')] | |
[int] | |
$CroppedSizeRatio = 10, | |
[Parameter()] | |
[int] | |
$Width, | |
[Parameter()] | |
[int] | |
$Height, | |
[Parameter()] | |
[int] | |
$PadTop, | |
[Parameter()] | |
[int] | |
$PadBottom, | |
[Parameter()] | |
[int] | |
$PadLeft, | |
[Parameter()] | |
[int] | |
$PadRight | |
) | |
begin { | |
if (-not (Get-Command -Name autocrop -ErrorAction SilentlyContinue)) { | |
if (Get-Command -Name pip -ErrorAction SilentlyContinue) { | |
Write-Warning "AutoCrop utility is not installed. Attempting to install." | |
pip install autocrop | |
} | |
else { | |
$Params = @{ | |
ErrorAction = 'Stop' | |
Message = 'Python 3 install could not be located. Please ensure Python 3 is installed and available on $env:Path' | |
Category = 'NotInstalled' | |
ErrorId = 'Invoke-AutoCrop.Python3.NotInstalled' | |
RecommendedAction = 'Install Python 3' | |
} | |
Write-Error @Params | |
} | |
} | |
if ($Destination) { | |
$Destination = if (Test-Path -Path $Destination) { | |
Get-Item -Path $Destination | |
} | |
else { | |
New-Item -Path $Destination -ItemType Directory | |
} | |
} | |
if ($RejectPath) { | |
$RejectPath = if (Test-Path -Path $RejectPath) { | |
Get-Item -Path $RejectPath | |
} | |
else { | |
New-Item -Path $RejectPath -ItemType Directory | |
} | |
} | |
$JobList = [List[object]]::new() | |
} | |
process { | |
if ($MyInvocation.ExpectingInput) { | |
$Path = , $Path | |
} | |
foreach ($InputPath in $Path) { | |
$InputPath = Get-Item -Path $InputPath | |
$Job = Start-ThreadJob -ScriptBlock { | |
param( | |
$Path, $Destination, $RejectPath, | |
$CroppedSizeRatio, $Width, $Height, | |
$PadTop, $PadBottom, $PadLeft, $PadRight | |
) | |
Start-Process -FilePath 'autocrop' -Wait -NoNewWindow -ArgumentList @( | |
'-i "{0}"' -f $Path | |
'-o "{0}"' -f $Destination | |
"--facePercent $CroppedSizeRatio" | |
switch ($true) { | |
{ $RejectPath } { | |
'-r "{0}"' -f $RejectPath | |
} | |
{ $Width } { | |
"-w $Width" | |
} | |
{ $Height } { | |
"-h $Height" | |
} | |
{ $PadTop } { | |
"--padUp $PadTop" | |
} | |
{ $PadBottom } { | |
"--padDown $PadBottom" | |
} | |
{ $PadLeft } { | |
"--padLeft $PadLeft" | |
} | |
{ $PadRight } { | |
"--padRight $PadRight" | |
} | |
} | |
) | |
} -ArgumentList @( | |
$InputPath | |
$Destination | |
$RejectPath | |
$CroppedSizeRatio | |
$Width | |
$Height | |
$PadTop | |
$PadBottom | |
$PadLeft | |
$PadRight | |
) | |
$JobList.Add( | |
[PSCustomObject]@{ | |
Path = $InputPath | |
Job = $Job | |
} | |
) | |
} | |
} | |
end { | |
while ($JobList.State -contains 'Running') { | |
$CompletedCount = $JobList.Where{ $_.State -eq 'Completed' }.Count | |
$TotalCount = $JobList.Count | |
Write-Progress -Activity "Processing Images..." -Status "$CompletedCount of $TotalCount folders processed." -PercentComplete ($CompletedCount / $TotalCount) | |
} | |
foreach ($Job in $JobList) { | |
$Output = $Job | Receive-Job | |
$Pattern = @( | |
'(?<FileCount>[0-9]+) input files' | |
'(?<CroppedFaces>[0-9]+) faces cropped' | |
'(?<RejectedFiles>[0-9]+) rejected' | |
) -join ', ' | |
if ($Output[-1] -match $Pattern) { | |
$Matches.Remove(0) | |
[PSCustomObject] $Matches | Select-Object -Property @( | |
@{ Name = 'Folder'; Expression = { $Job.Path } } | |
'FileCount' | |
'CroppedFaces' | |
'RejectedFaces' | |
) | |
} | |
} | |
[Console]::Beep(440,333) | |
[Console]::Beep(494,333) | |
[Console]::Beep(698,333) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment