首页 > 解决方案 > 使用 powershell 更快地获取/设置像素

问题描述

所以我有两个函数,一个分析图像是否是灰度的,一个将图像转换为灰度。这些使用 .NET System.Drawing.Bitmap GetPixel 和 SetPixel。它可以工作,但速度很慢,我读到一些你将位图锁定在内存中以便更快地工作。

在 C# 中找到了一些示例,但由于没有 C# 经验,我有点迷茫。例如http://www.vcskicks.com/fast-image-processing2.php

是否可以在 powershell 中执行此操作?

这是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()
    
    }

标签: .netpowershellbitmapdraw

解决方案


这可能会更快:

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()
}

接受一系列文件的新版本,因此您可以直接从以下位置进行管道传输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()
    }
}

演示:

Get-ChildItem -Path D:\Test -File | ConvertTo-GrayScale -Verbose

推荐阅读