So I got two functions, one that analyze an image if it's grayscale and one that convert an image to grayscale. These use .NET System.Drawing.Bitmap GetPixel and SetPixel. It works but is quite slow and I read some that you lock the bitmap in memory for faster work.
Found some examples in C# but since having no experiencing in C# I'm a bit lost. example http://www.vcskicks.com/fast-image-processing2.php
Is it possible to do this in powershell?
here's the fuctions in powershell:
Function Test-ImageGrayScale {
$error.clear()
$filename = $image
$image = New-Object System.Drawing.Bitmap $filename
#keep count of the values
$red = 0
$green = 0
$blue = 0
$total = 0
foreach ($x in 0..($image.Width - 1)) {
foreach ($y in 0..($image.Height - 1)) {
$pixelColor = $image.GetPixel($x, $y)
$red += $pixelColor.R
$green += $pixelColor.G
$blue += $pixelColor.B
$total++
}
}
#Calculate average
$red /= $total
$green /= $total
$blue /= $total
if ($red -eq $green -or $green -eq $blue -or $red -eq $blue) {
Write-Output "Image is Grayscale!"
}
else {
Write-Output "Image is in Color!"
}
}
Function Convert-GrayScale {
$filename = Get-ChildItem $image
$image = New-Object System.Drawing.Bitmap $image
# Output Image
$bitmap = New-Object System.Drawing.Bitmap($image.Width, $image.Height)
foreach ($x in 0..($image.Width - 1)) {
foreach ($y in 0..($image.Height - 1)) {
$pixelColor = $image.GetPixel($x, $y)
$red = $pixelColor.R
$green = $pixelColor.G
$blue = $pixelColor.B
$gray = ($red * .2126) + ($green * .7152) + ($blue * .0722)
$bitmap.SetPixel($x, $y, [System.Drawing.Color]::FromArgb($gray, $gray, $gray))
}
}
$global:outFile = $Outpath + "\" + "GrayScale_" + $filename.basename + ".jpg"
$bitmap.Save($global:outFile)
$bitmap.Dispose()
}
This might be faster:
function ConvertTo-GrayScale {
# adapted from https://stackoverflow.com/questions/2038865/accelerating-bitmap-grayscale-conversion-is-openmp-an-option-in-c
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)]
[Alias('FullName')]
[string]$Path
)
$bitmap = [System.Drawing.Bitmap]::FromFile($Path)
$grayBitmap = [System.Drawing.Bitmap]::new($bitmap.Width, $bitmap.Height)
$graphics = [System.Drawing.Graphics]::FromImage($grayBitmap)
$rect = [System.Drawing.Rectangle]::new(0, 0, $bitmap.Width, $bitmap.Height)
$unit = [System.Drawing.GraphicsUnit]::Pixel
# create a grayscale matrix
[single[][]] $matrix = (0.299, 0.299, 0.299, 0, 0),
(0.587, 0.587, 0.587, 0, 0),
(0.114, 0.114, 0.114, 0, 0),
(0, 0, 0, 1, 0),
(0, 0, 0, 0, 1)
$colorMatrix = [System.Drawing.Imaging.ColorMatrix]::new($matrix)
$attributes = [System.Drawing.Imaging.ImageAttributes]::new()
$attributes.SetColorMatrix($colorMatrix)
# draw the original image on to the new one, using the grayscale color matrix
$graphics.DrawImage($bitmap, $rect, 0, 0, $bitmap.Width, $bitmap.Height, $unit, $attributes)
# create a new name for the image by appending `_gray` to the basename
$fileIn = Get-Item -Path $Path
$fileOut = '{0}_gray{1}' -f (Join-Path -Path $fileIn.DirectoryName -ChildPath $fileIn.BaseName), $fileIn.Extension
# save the grayscaled image
$grayBitmap.Save($fileOut)
#clean-up
$graphics.Dispose()
$grayBitmap.Dispose()
$attributes.Dispose()
$bitmap.Dispose()
}
New version to accept a series of files so you can pipe directly from Get-ChildItem
:
function ConvertTo-GrayScale {
# adapted from https://stackoverflow.com/questions/2038865/accelerating-bitmap-grayscale-conversion-is-openmp-an-option-in-c
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[Alias('FullName')]
[string[]]$Path
)
begin {
# create a grayscale matrix
[single[][]] $matrix = (0.299, 0.299, 0.299, 0, 0),
(0.587, 0.587, 0.587, 0, 0),
(0.114, 0.114, 0.114, 0, 0),
(0, 0, 0, 1, 0),
(0, 0, 0, 0, 1)
# to make the colors inverted for a negative image, use
# [single[][]] $matrix = (-1, 0, 0, 0, 0),
# (0, -1, 0, 0, 0),
# (0, 0, -1, 0, 0),
# (0, 0, 0, 1, 0),
# (0, 0, 0, 0, 1)
$colorMatrix = [System.Drawing.Imaging.ColorMatrix]::new($matrix)
$attributes = [System.Drawing.Imaging.ImageAttributes]::new()
$attributes.SetColorMatrix($colorMatrix)
$unit = [System.Drawing.GraphicsUnit]::Pixel
}
process {
foreach ($file in $Path) {
Write-Verbose "Processing file '$file'"
$bitmap = [System.Drawing.Bitmap]::FromFile($file)
$grayBitmap = [System.Drawing.Bitmap]::new($bitmap.Width, $bitmap.Height)
$graphics = [System.Drawing.Graphics]::FromImage($grayBitmap)
$rect = [System.Drawing.Rectangle]::new(0, 0, $bitmap.Width, $bitmap.Height)
# draw the original image on to the new one, using the grayscale color matrix
$graphics.DrawImage($bitmap, $rect, 0, 0, $bitmap.Width, $bitmap.Height, $unit, $attributes)
# create a new name for the image by appending `_gray` to the basename
$fileIn = Get-Item -Path $file
$fileOut = '{0}_gray{1}' -f (Join-Path -Path $fileIn.DirectoryName -ChildPath $fileIn.BaseName), $fileIn.Extension
# save the grayscaled image
Write-Verbose "Saving file '$fileOut'"
$grayBitmap.Save($fileOut)
#clean-up
$graphics.Dispose()
$grayBitmap.Dispose()
$bitmap.Dispose()
}
}
end {
$attributes.Dispose()
}
}
Demo:
Get-ChildItem -Path D:\Test -File | ConvertTo-GrayScale -Verbose