Search code examples
imagepowershellcolorsmetadata

colour count of an image


I am trying to make an upscale texture mod for an old game "Recoil".

For this, I need to find the height, width, pixel format and colour count of a few 1000 images, so that I can feed this information to excel and find the best textures to be upscaled.

I have been able to get the height, width and pixel format via a PowerShell script, which I can then copy to excel as this script provides a table. the script works on the whole folder.

Function Get-Image{
Param(
     [Parameter(ValueFromPipeline=$true)]
     [System.IO.FileINfo]$file
)
begin{        
     [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") |Out-Null 
}
process{
      if( $file.Exists){
           $img=[System.Drawing.Image]::FromFile($file)
           $image=$img.Clone()
           $img.Dispose()
           $image | Add-Member `
                          -MemberType NoteProperty `
                          -Name Filename `
                          -Value $file.FUllname `
                          -PassThru
      }else{
           Write-Host "File not found: $file" -fore yellow       
      }   
 }    
end{}
}
dir C:\test\*.png | Get-Image
dir C:\test\*.png -Recurse | Get-Image  | select filename, Width, Height,     PixelFormat | ft -auto

the result of the above code

I need help finding a way to get a colour count of the images. I have found a manual way to do it via a Photoshop filter but it is not a viable way to do all the images. photoshop filter example

If I can get the Colour count in a similar way to the code provided it would be the best.

edit: I need a way to get Colour count of all images in the folder.

the images themselves are small (the biggest being 512x512). I just need the number of colours, no need for the breakdown of RGB.

ps- I have literally no knowledge of programming and scripting ( even the above script someone Reddit helped me out with)

Hopefully, I have been able to explain my query clearly. Thank you for your time and consideration.

Edit 2 so this code works but I found an issue. Is there any way to make it not count the alphas? Issue: colour count difference in the Photoshop Filter (telegraphic- Colour Count) and the new code. Reason: Photoshop Filter counts colours only (without alpha), and the PowerShell script counts pixels (with alpha). Format32bppArgb - has the issue Format24bppRgb - it counts it fine. below is the present code

Function Get-Image{
Param(
[Parameter(ValueFromPipeline=$true)]
[System.IO.FileINfo]$file
)
begin{
[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") |Out-Null
}
process {
if ($file.Exists) {
# Load image
$img = [System.Drawing.Image]::FromFile($file)
$image = $img.Clone()
$img.Dispose()

 # Count colors
    $colorSet = [System.Collections.Generic.HashSet[System.Drawing.Color]]::new()
    foreach ($x in 0..($image.Width - 1)) {
        foreach ($y in 0..($image.Height - 1)) {
            [void]$colorSet.Add($image.GetPixel($x, $y))
        }
    }

    # Add file name and color count properties to image object
    $fileNameProp = @{ MemberType = 'NoteProperty'; Name = 'Filename'; Value = $file.FullName; PassThru = $true}
    $colorCountProp = @{ MemberType = 'NoteProperty'; Name = 'ColorCount'; Value = $colorSet.Count; PassThru = $true}
    $image | Add-Member @fileNameProp | Add-Member @colorCountProp
     }else{
           Write-Host "File not found: $file" -fore yellow       
      }   
 }    
end{}
}
dir D:\Games\Setups\RECOIL_fixed_edition_v0.5\SourceFile\zbd\Dataset_D\Dataset_D\ammoarcgun\*.png | Get-Image
dir D:\Games\Setups\RECOIL_fixed_edition_v0.5\SourceFile\zbd\Dataset_D\Dataset_D\ammoarcgun\*.png -Recurse | Get-Image  | select filename, Width, Height,   PixelFormat, ColorCount | ft -auto

Solution

  • Use the GetPixel() method to fetch the color used for each pixel, then count the unique colors you encounter:

    $hashset = [System.Collections.Generic.HashSet[System.Drawing.Color]]::new()
    
    foreach($x in 0..($image.Width - 1)){
      foreach($y in 0..($image.Height - 1)){
        [void]$hashset.Add($image.GetPixel($x, $y))
      }
    }
    
    Write-Host "Image has $($hashset.Count) unique colors"
    

    You could add this routine to your existing function like so:

    process {
        if ($file.Exists) {
            # Load image
            $img = [System.Drawing.Image]::FromFile($file)
            $image = $img.Clone()
            $img.Dispose()
    
            # Count colors
            $colorSet = [System.Collections.Generic.HashSet[System.Drawing.Color]]::new()
            foreach ($x in 0..($image.Width - 1)) {
                foreach ($y in 0..($image.Height - 1)) {
                    [void]$colorSet.Add($image.GetPixel($x, $y))
                }
            }
    
            # Add file name and color count properties to image object
            $fileNameProp = @{ MemberType = 'NoteProperty'; Name = 'Filename'; Value = $file.FullName; PassThru = $true}
            $colorCountProp = @{ MemberType = 'NoteProperty'; Name = 'ColorCount'; Value = $colorSet.Count; PassThru = $true}
            $image | Add-Member @fileNameProp | Add-Member @colorCountProp
        }
        else {
            Write-Host "File not found: $file" -fore yellow       
        }   
    }
    

    And now you can do:

    dir C:\test\*.png -Recurse | Get-Image | ft Filename, Width, Height, PixelFormat, ColorCount -AutoSize
    

    If you want to ignore the alpha-channel in each pixel, change this line:

    [void]$colorSet.Add($image.GetPixel($x, $y))
    

    to

    $pixel = $image.GetPixel($x, $y)
    [void]$colorSet.Add([System.Drawing.Color]::FromArgb($pixel.R, $pixel.G, $pixel.B))