Skip to content

Instantly share code, notes, and snippets.

@vexx32
Last active April 11, 2019 02:53
Show Gist options
  • Save vexx32/baafe3e133e6a6d34be6975908a77f87 to your computer and use it in GitHub Desktop.
Save vexx32/baafe3e133e6a6d34be6975908a77f87 to your computer and use it in GitHub Desktop.
#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