GImage and Pixels

Jed Rembold & Fred Agbo

March 8, 2024

Announcements

  • Project 2: Breakout is due next week Tuesday at 10pm!
  • Midterm grading posted
    • any concern? Reach out to me.
    • My version of the solution will be shared when all folks takes the exam Grading for Problem Set 4 will be returned next week!
  • Polling continues on this link https://www.polleverywhere.com/agbofred203

Review!

What is the third element (index 2) in the below list?

[i * 4 for i in "Oct 21, 2022" if not i.isalpha() and not i.isspace()]


  1. 21
  2. ",,,,"
  3. "tttt"
  4. "2222"

Picturing Multidimensional Arrays

  • Multidimensional arrays are commonly pictured as each inner list being stacked beneath the previous
  • In such a representation, the outermost/first elements/indices represent the row, and the inner/second elements/indices represent the column

[ [2, 9, 4], [7, 5, 3], [6, 1, 8] ]


Initialize a Chessboard

image/svg+xml
 

Initialize a Chessboard

image/svg+xml r n b q k r n b p p p p p p p p R N B Q K R N B P P P P P P P P 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
 

Initialize a Chessboard

image/svg+xml r n b q k r n b p p p p p p p p R N B Q K R N B P P P P P P P P 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 [ ] , , , , , , , [ ] , , , , , , , [ ] , , , , , , , [ ] , , , , , , , [ ] , , , , , , , [ ] , , , , , , , [ ] , , , , , , , [ ] , , , , , , , [ ]
 

The GImage Class

  • You can display an image from a file in PGL using the GImage class. GImage(filename, x, y)
    • filename is the string containing the name of the file which contains the image
    • x and y are the coordinates of the upper left corner of the image
  • Best to use one of the common image formats
    • Graphical Interchange Format (GIF): fish.gif
    • Joint Photographic Experts Group (JPEG): fish.jpg
    • Portable Network Graphics (PNG): fish.png

Images and Copyrights

  • Most images that you might find on the web are protected by copyright under international law.
  • Ensure you have the necessary permissions before using an image
    • On the web, the image hosting site will often specify what rules apply to that image
      • Example: Images from www.nasa.gov can be freely used as long as you add an attribution line
    • Non-commercial use of an image can sometimes fall under “fair use” doctrine, but academic integrity and common courtesy both demand you cite or acknowledge any material you have obtained from others.

Example: VLA Moonset

from pgl import GImage, GWindow, GLabel

def image_example():
    gw = GWindow(800, 550)
    image = GImage("VLA_Moonset.jpg")
    image.scale(gw.get_width() / image.get_width())
    gw.add(image)

    citation = GLabel("Image Credit: Jeff Hellermann, NRAO / AUI / NSF")
    citation.set_font("15px 'Sans-Serif'")
    x = gw.get_width() - citation.get_width() - 10
    y = image.get_height() + citation.get_ascent()
    gw.add(citation, x, y)

2D Arrays → Images

  • Image data is commonly stored in two-dimensional arrays

  • Each element stores information about the pixel that exists at that location

  • The GImage class lets you convert between the image itself and the array representing the image contents by using the get_pixel_array method, which returns a two-dimensional array of integers.

  • We could get the pixels from our example image using:

    image = GImage("VLA_Moonset.jpg")
    pixels = image.get_pixel_array()
  • The first index of the pixel array gets you the row, the second index gets you the column

Pixel Contents

  • Each element in a pixel array is an integer in which the 32 bits are interpreted as:

  • The first byte (8 bits) is the transparency or alpha
  • The next three bytes indicate the amount of red, green, and blue in the pixel, where each value varies from 0 to 255
    • Form the RGB of a color, generally expressed in hexadecimal form
      • 100101010x95
      • 001110010x39
      • 011000110x63
    • Overall color: #953963 or

Combining Light Colors

Additive Colors

Transparency

  • The first byte (8 bits) of the pixel value gives the transparency, which indicates how much of the background is allowed to show through
  • Often denoted with the Greek letter alpha: \(\alpha\)
  • Varies from 0 to 255 like the other 8 bit values:
    • 0 is entirely transparent
    • 255 is entirely opaque

Breaking out the Colors

  • You do not need to convert the pixel values yourself! PGL has built-in ways to extract the various colors
Function Description
GImage.get_red(pixel) Returns the integer (0-255) corresponding to the red portion of the pixel
GImage.get_green(pixel) Returns the integer (0-255) corresponding to the green portion of the pixel
GImage.get_blue(pixel) Returns the integer (0-255) corresponding to the blue portion of the pixel
GImage.get_alpha(pixel) Returns the integer (0-255) corresponding to the alpha portion of the pixel
GImage.create_rgb_pixel(r,g,b) Returns a 32-bit integer corresponding to the desired color

Reading

  • Programs often need to work with collections of data that are too large to reasonably exist typed all out in the code
    • Easier to read in the values of a list from some external data file
  • A file is the generic name for any named collection of data maintained on some permanent storage media attached to a computer
  • Files can contain information encoded in many different ways
    • Most common is the text file
    • Contains character data like you’d find in a string

Strings vs Text Files

  • While strings and text files both store characters, there are some important differences:
    • The longevity of the data stored
      • The value of a string variable lasts only as long as the string exists, is not overridden, or is not thrown out when a function completes
      • Information in a text file exists until the file is deleted
    • How data is read in
      • You have access to all the characters in a string variable pretty much immediately
      • Data from text files is generally read in sequentially, starting from the beginning and proceeding until the end of the file is reached

Reading Text Files

  • The general approach for reading a text file is to first open the file and associate that file with a variable, commonly called its file handle

  • We will also use the with keyword to ensure that Python cleans up after itself (closes the file) when we are done with it (Many of us could use a with irl)

    with open(filename) as file_handle:
      # Code to read the file using the file_handle
  • Python gives you several ways to actually read in the data

    • read reads the entire file in as a string
    • readline or readlines reads a single line or lines from the file
    • read alongside splitlines gets you a list of line strings
    • Can use the file handle as an iterator to loop over

Entire file ⟶ String

  • The read method reads the entire file into a string, with includes newline characters (\n) to mark the end of lines

  • Simple, but can be cumbersome to work with the newline characters, and, for large files, it can take a large amount of memory

  • As an example, the file:

    One fish
    two fish
    red fish
    blue fish

    would get read as

"One fish\ntwo fish\nred fish\nblue fish"

Line by Line

  • Of the ways to read the file in a string at a time, using the file handler as an iterator and looping is probably best and certainly most flexible

  • Leads to code that looks like:

    with open(filename) as f:
        for line in f:
            # Do something with the line
  • Note that most strategies preserve the newline character, which you very likely do not want, so be ready to strip them out before doing more processing

Powers Combined

  • So long as your files are not gigantic, using read and then the splitlines method can be a good option

  • This does remove the newline characters, since it splits the string at them

    with open(filename) as f:
        lines = f.read().splitlines()
    # Then you can do whatever you want with the list of lines

Example: Name Mangling

  • Let’s look at an example with some more meat to it
  • I have a text file with all your first names. I’d like to:
    • Read in the names
    • Select two at random
    • Combine the first half of one name with the second half of the other
    • Print out both potential hybrid names
  • We’ll practice breaking a problem into steps along the way here

Example Code:

import random

def name_mangler(filename):
    """
    Reads from a roster of first names and then randomly chooses two to cut in half
    and recombine with the other. Then prints off both combinations.

    Inputs:
        filename (string): The filename containing the names

    Outputs:
        None
    """

    def get_names(filename):
        """Reads in the roster. """
        with open(filename) as fh:
            names = fh.read().splitlines()
        return names

    def choose_two(name_list):
        """ Chooses two different names from the list. """
        name1 = random.choice(name_list)
        name2 = random.choice(name_list)
        while name1 == name2:
            name2 = random.choice(name_list)
        return [name1, name2]

    def slice_and_combine(name1, name2):
        """ Slices and recombines both names, printing to the screen. """
        name1_mid = len(name1)//2
        name2_mid = len(name2)//2
        print(name1[:name1_mid] + name2[name2_mid:])
        print(name2[:name2_mid] + name1[name1_mid:])

    names = get_names(filename)
    chosen = choose_two(names)
    slice_and_combine(chosen[0], chosen[1])

if __name__ == '__main__':
    name_mangler('class_first_names.csv')
// reveal.js plugins