• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar
  • Skip to footer

The Coding Couple

Pair programming is a lifetime commitment.

  • Home
  • Categories
    • Arduino
    • JavaScript
    • Python
    • Raspberry Pi
  • About Us
    • Privacy Policy
  • Contact

Counting Pixels by Color in Python with Pillow (a PIL fork)

October 7, 2019 by Ashley

I’m a maker and love creating 8-bit art, mostly with wood. I have a new project in the works where I need an exact count of each pixel per a color. I started to manually count them before I stopped myself and thought, why don’t I just write a script to automate this!? Thus pixel-color-count.py was born!

Pixel Color Count

Given a valid image file, the Python script will iterate through each pixel in an image keeping a running tally of how many times the color of the pixel has appeared in the image.

Once the loop is done, the script will print to the console a list of each color and the number of times the color was present in the image.

Sample Output of pixel-color-count.py

Sample out generated from running the Python script

Built With

Pillow

I used Pillow, a fork of PIL (Python Image Library), for the image manipulation. This is my second project using Pillow. It’s a really great library for programmatically editing or manipulating images.

with Image.open(args.image) as image:
        color_count = {}
        width, height = image.size
        rgb_image = image.convert('RGB')

The main functionality from the Image module I’m using is the getpixel method.

rgb = rgb_image.getpixel((x, y))

webcolors

A second dependency for the project is more of a nice to have: webcolors. Given a color in RGB format, webcolors will return a human readable name for it if applicable.

name = webcolors.rgb_to_name(rgb)

webcolors.rgb_to_name will throw a ValueError is it cannot find a name for a RGB color. In my script, I fall back to displaying the color as a tuple.

What’s left to implement?

In my first iteration of the script, I started to implement an optional command line argument for ignored colors. The idea behind this is there may be some colors I don’t care to count therefore I wouldn’t want my output cluttered.

parser.add_argument('-i', '--ignore-color', type=tuple, help='Skip counting pixels of this color')

If the time permits, I’d love to go back and implement this feature. I hit a snag when I tried to use tuples as an argument type with argparse.

UPDATE #1: The --ignore-color command line option is partially implemented, but there’s no input validation. I basically accept the input as a string and use ast.literal_eval to convert it to a tuple.

Version 2 of the script, I plan on outputting a new version of the original image with a pixel legend and count per unique pixel color.

UPDATE #2: A version 2 of the script now exists that outputs an image featuring a legend with a color square matched with the color name and pixel count.

Legend Image sample output for the Pixel Color Count script

And, maybe for a version 3 turn it into a web accessible app.

UPDATE #3: A web version of the pixel color counter now exists. View the source for the project here.

For now, the script does just what I need and has saved me a lot of effort over counting the manual way!

pixel-color-count.py

Check the GitHub repo for new updates to the script. Here’s there first iteration:

# pixel-color-count.py – Gets a sum of pixels per unique color
# maintainer – Ashley Grenon @townsean
import argparse
try:
from PIL import Image
except ImportError:
exit("This script requires the PIL module. Install with pip install Pillow")
try:
import webcolors
except ImportError:
# https://pypi.org/project/webcolors/
exit("This script uses webcolors for displaying named colors. Install with pip install webcolors")
def main():
parser = argparse.ArgumentParser(description='Calculates the sum of pixels per a color')
parser.add_argument('image', nargs='?', default='.', help='The image to sum the pixels per a color of')
# parser.add_argument('-i', '–ignore-color', type=tuple, help='Skip counting pixels of this color')
args = parser.parse_args()
with Image.open(args.image) as image:
color_count = {}
width, height = image.size
rgb_image = image.convert('RGB')
# iterate through each pixel in the image and keep a count per unique color
for x in range(width):
for y in range(height):
rgb = rgb_image.getpixel((x, y))
if rgb in color_count:
color_count[rgb] += 1
else:
color_count[rgb] = 1
print('Pixel Count per Unique Color:')
print('-' * 30)
color_index = 1
for color, count in color_count.items():
# if color == args.ignore-color:
# pass
try:
print('{}.) {}: {}'.format(color_index, webcolors.rgb_to_name(color), count))
except ValueError:
print('{}.) {}: {}'.format(color_index, color, count))
color_index += 1
if __name__ == '__main__':
main()
view raw pixel-color-count.py hosted with ❤ by GitHub

Find us online!

  • Instagram: @thecodingcouple
  • Twitter: @thecodingcouple
  • GitHub: @thecodingcouple

Related Posts

  • Pokéball Single DIV CSS Drawing | TutorialPokéball Single DIV CSS Drawing | Tutorial
  • Using WSL on Corporate VPNUsing WSL on Corporate VPN
  • CSS Magic with a Single DivCSS Magic with a Single Div
  • Fractions in Python | Today I LearnedFractions in Python | Today I Learned
  • Uncaught TypeError: util.inherits is not a functionUncaught TypeError: util.inherits is not a function
  • Tinkering Around with Adafruit’s PyBadge LCTinkering Around with Adafruit’s PyBadge LC

Filed Under: Programming Languages, Python

Previous Post: « JavaScript’s Null Coalescing Operator | Today I Learned
Next Post: DevSpace 2019 Recap »

Primary Sidebar

Social Media

  • GitHub
  • Instagram
  • Twitter
  • YouTube

Recent Posts

  • Pokémon Color Picker | A web app built with HTML/CSS + JavaScript
  • Pokéball Single DIV CSS Drawing | Tutorial
  • Error: [🍍]: “getActivePinia()” was called but there was no active Pinia
  • Trijam #261 Game Jam Diary: One Wrong Move
  • Using WSL on Corporate VPN

Recent Comments

  • Lizzy on Creation Crate Month 2: An Arduino Powered Memory Game
  • Ashley Grenon on Creation Crate Month 2: An Arduino Powered Memory Game
  • Lizzy on Creation Crate Month 2: An Arduino Powered Memory Game
  • kelly on Creation Crate Month 2: An Arduino Powered Memory Game
  • Ashley on Creation Crate Month 3: An Arduino Powered Distance Detector

Follow us on Instagram!

This error message is only visible to WordPress admins

Error: No feed found.

Please go to the Instagram Feed settings page to create a feed.

Categories

  • Arduino
  • Conferences
  • Debugging
  • Game Jams
  • HTML and CSS
  • JavaScript
  • Programming Languages
  • Python
  • Raspberry Pi
  • Today I Learned

Archives

  • May 2024
  • April 2024
  • March 2024
  • May 2022
  • December 2021
  • May 2021
  • March 2020
  • January 2020
  • December 2019
  • November 2019
  • October 2019
  • June 2019
  • April 2019
  • September 2017
  • April 2017
  • August 2016
  • July 2016
  • June 2016
  • May 2016
  • April 2016
  • March 2016
  • April 2015
  • January 2015

Tags

adafruit arduino brackets c# code smell codestock coding standards conventions creation crate debugging developer devspace electronics es6 es2015 game development game jam gotcha hackathon hoisting html html5 javascript led naming conventions nintendo phaser pluralsight pokemon programmer python raspberry pi retro retropie scope self improvement single div single div drawing subscription box TIL today I learned troubleshooting vue vuejs windbg

Footer

About Us

We are the Coding Couple.  Two people who met in college and decided they wanted to pair program for the rest of their ...

Read More »

Most Recent Posts

Pokémon Color Picker | A web app built with HTML/CSS + JavaScript

Pokéball Single DIV CSS Drawing | Tutorial

Error: [🍍]: “getActivePinia()” was called but there was no active Pinia

Trijam #261 Game Jam Diary: One Wrong Move

Social Media

  • GitHub
  • Instagram
  • Twitter
  • YouTube

Copyright Notice

© The Coding Couple, 2015 – 2023. Excerpts and links may be used, provided that full and clear credit is given to The Coding Couple with appropriate and specific direction to the original content.

Copyright © 2025 · Foodie Pro Theme by Shay Bocks · Built on the Genesis Framework · Powered by WordPress