In this article, we are going to learn how to invert the colors of an image using Pygame in Python programming language.
Pygame is a multiplatform Python module and framework designed for creating video games in Python. It includes several libraries that manage audio and visuals. Right now, Pygame is one of the best Python game development modules. This tutorial assumes that the reader has a basic understanding of Pygame.
Concept
To invert an image you take the value of each pixel and subtract it from 255 to get the new value. Once you do this across the whole image you have an inverted version of it. We will use Pygame’s blit’s inbuilt flags to accomplish this.
Installing Pygame
If not already installed, install Pygame by running the command below in the terminal.
pip install pygame
Step-by-Step Implementation:
We will create a window that displays an image. When the image is clicked it will invert the colors. We will use Pygame’s blit flags to achieve this.
Step 1: We will first create a Pygame window.
Python
# importing modules in import pygame as py import os # initialize pygame py.init() # setting window height and width width, height = 400 , 300 screen = py.display.set_mode((width, height)) # setting background to white and setting window title screen.fill(( 255 , 255 , 255 )) py.display.set_caption( "Image Invert" ) # update window py.display.flip() # Main loop running = True while (running): for event in py.event.get(): # When quit even is called (by pressing 'X' button) if event. type = = py.QUIT: # running is set to false exiting loop running = False # when loop ends program closes py.quit() |
This creates a basic white window titled “Image Invert” that is sized 400×300.
Output:
Step 2: Load the Image Function
Next, we will create the function that loads the image into our program. The function will also be responsible for scaling the image.
Python
# creating the image loading function def loadimage(img, scale = 1 ): pass |
The function takes in the image file name and how much we should scale the image. Next, we will find the image and turn it into a Pygame surface.
Python
def loadimage(img, scale = 1 ): # get image path imagePath = os.path.join(os.path.dirname(__file__), img) # turn into a pygame surface logo = py.image.load(imagePath).convert() |
Note: This only works if the image is in the same folder as the program.
Then we scale the image and return the Pygame surface.
Python
def loadimage(img, scale = 1 ): # get image location imagePath = os.path.join(os.path.dirname(__file__), img) # turn into a pygame surface logo = py.image.load(imagePath).convert() # scale image if need by getting current size # and multiplying by scale to get desired size size = logo.get_size() size = (size[ 0 ] * scale, size[ 1 ] * scale) # scaling up to desired size logo = py.transform.scale(logo, size) # return image return logo |
Code so far:
Python
# importing modules in import pygame as py import os # initialize pygame py.init() # setting window height and width width, height = 400 , 300 screen = py.display.set_mode((width, height)) # setting background to white and setting window title screen.fill(( 255 , 255 , 255 )) py.display.set_caption( "Image Invert" ) # creating the image loading function def loadimage(img, scale = 1 ): # get image location imagePath = os.path.join(os.path.dirname(__file__), img) # turn into a pygame surface logo = py.image.load(imagePath).convert() # scale image if need by getting current size # and multiplying by scale to get desired size size = logo.get_size() size = (size[ 0 ] * scale, size[ 1 ] * scale) # scaling up to desired size logo = py.transform.scale(logo, size) # return image return logo # update window py.display.flip() # Main loop running = True while (running): for event in py.event.get(): # When quit even is called (by pressing 'X' button) if event. type = = py.QUIT: # running is set to false exiting loop running = False # when loop ends program closes py.quit() |
Step 3: Loading in the image and detecting a click
Next, we load the image in and set the screen size to match. Then we display the image.
Python3
# importing modules import pygame as py import os # initialize pygame py.init() # setting window height and width width, height = 400 , 300 screen = py.display.set_mode((width, height)) # setting background to white and setting window title screen.fill(( 255 , 255 , 255 )) py.display.set_caption( "Image Invert" ) # creating the image loading function def loadimage(img, scale = 1 ): # get image location imagePath = os.path.join(os.path.dirname(__file__), img) # turn into a pygame surface logo = py.image.load(imagePath).convert() # scale image if need by getting current size # and multiplying by scale to get desired size size = logo.get_size() size = (size[ 0 ] * scale, size[ 1 ] * scale) # scaling up to desired size logo = py.transform.scale(logo, size) # return image return logo # update window py.display.flip() # load image in for the first time. # Change string to match your picture's name logo = loadimage( "gfglogo.png" , 2 ) # get image's height and width width, height = logo.get_size() # set window size to same size screen = py.display.set_mode((width, height)) # display image to screen screen.blit(logo, ( 0 , 0 )) # update screen py.display.flip() # main loop running = True while (running): for event in py.event.get(): if event. type = = py.QUIT: running = False # Add a new event type that only gets # triggered when a mouse button is pressed if event. type = = py.MOUSEBUTTONDOWN: # Save the x, y positions of the mouse click x, y = event.pos # Check if the click is within # the bounding box of the image if logo.get_rect().collidepoint(x, y): print ( "Image Clicked" ) py.quit() |
Output after Click:
Step 4: Inverting the image
Finally, we create the code to invert the image. Replace the print() statement with the following code.
Python
if logo.get_rect().collidepoint(x, y): # create a blank surface the same size inv = py.Surface(logo.get_size()) # fill it with white inv.fill(( 255 , 255 , 255 )) # Blit the logo to the screen but use "BLEND_RGBA_SUB" inv.blit(logo, ( 0 , 0 ), None , py.BLEND_RGBA_SUB) # set logo as inv logo = inv # display logo screen.blit(logo, ( 0 , 0 )) # update screen py.display.flip() |
The BLEND_RGBA_SUB flag takes the original image and subtracts the new image. For example, if the Original (inv) image pixel has a value of (255,255,255) and the new image has a value of (100,0,100) then the result will be (155,255,155), creating the inverse.
Pygame blit() has 10 flags
- BLEND_RGBA_ADD
- BLEND_RGBA_SUB
- BLEND_RGBA_MULT
- BLEND_RGBA_MIN
- BLEND_RGBA_MAX
- 5 more RGB versions of the above
Below is the complete implementation:
Python
# importing modules in import pygame as py import os import numpy # initialize pygame py.init() # setting window height and width width, height = 400 , 300 screen = py.display.set_mode((width, height)) # setting background to white and setting window title screen.fill(( 255 , 255 , 255 )) py.display.set_caption( "Image Invert" ) # image loading function def loadimage(img, scale = 1 ): # get image location imagePath = os.path.join(os.path.dirname(__file__), img) logo = py.image.load(imagePath).convert() # scale image if need by getting current # size and multiplying by scale to get desired size size = logo.get_size() size = (size[ 0 ] * scale, size[ 1 ] * scale) # scaling up to desired size logo = py.transform.scale(logo, size) # return image return logo # load image in for the first time. # Change string to match your picture's name logo = loadimage( "gfglogo.png" , 2 ) # get image's height and width width, height = logo.get_size() # set window size to same size screen = py.display.set_mode((width, height)) # display image to screen screen.blit(logo, ( 0 , 0 )) # update screen py.display.flip() # main loop running = True while (running): for event in py.event.get(): # detect quit event if event. type = = py.QUIT: running = False # Add a new event type that only gets # triggered when a mouse button is pressed if event. type = = py.MOUSEBUTTONDOWN: # Set the x, y positions of the mouse click x, y = event.pos if logo.get_rect().collidepoint(x, y): # create a blank surface the same size inv = py.Surface(logo.get_size()) # fill it with white inv.fill(( 255 , 255 , 255 )) # Blit the logo to the screen but use "BLEND_RGBA_SUB" inv.blit(logo, ( 0 , 0 ), None , py.BLEND_RGBA_SUB) # set logo as inv logo = inv # display logo screen.blit(logo, ( 0 , 0 )) # update screen py.display.flip() py.quit() |
Output before click:
Output after the click: