Please
He wants you to give me a seed point.

Enumerate "Data" Big Idea from College Board

Some of the big ideas and vocab that you observe, talk about it with a partner ...

  • "Data compression is the reduction of the number of bits needed to represent data"
  • "Data compression is used to save transmission time and storage space."
  • "lossy data can reduce data but the original data is not recovered"
  • "lossless data lets you restore and recover"

The Image Lab Project contains a plethora of College Board Unit 2 data concepts. Working with Images provides many opportunities for compression and analyzing size.

Image Files and Size

Here are some Images Files. Download these files, load them into images directory under _notebooks in your Blog. - Clouds Impression

Describe some of the meta data and considerations when managing Image files. Describe how these relate to Data Compression ...

  • File Type, PNG and JPG are two types used in this lab
  • Size, height and width, number of pixels
  • Visual perception, lossy compression

Python Libraries and Concepts used for Jupyter and Files/Directories

Introduction to displaying images in Jupyter notebook

IPython

Support visualization of data in Jupyter notebooks. Visualization is specific to View, for the web visualization needs to be converted to HTML.

pathlib

File paths are different on Windows versus Mac and Linux. This can cause problems in a project as you work and deploy on different Operating Systems (OS's), pathlib is a solution to this problem.

HACKS:Answering Questions

  • What are commands you use in terminal to access files?

Often, we use cd and the file path names to enter and exit folders and directories. Sometimes, to see what the exact file path name is, we'll use ls to list the contents of a folder. It's a Bash terminal.

  • What are the command you use in Windows terminal to access files?

I'm not a Windows user, but I do know that they also use cd but it works slightly differently. They also use dir instead of ls and cd instead of pwd.

  • What are some of the major differences?

The main difference as far as I know is that Windows runs Bash commands through WSL. File paths also have different prefixes and overall text in Windows because the File Explorer system is different from Mac's Finder.

  • Provide what you observed, struggled with, or leaned while playing with this code.

One thing I definitely saw was that image file names are a big deal, particularly when calling specific image paths. The volcano image always caused an error because the code said jpg but the image itself is a jpeg. Another thing I saw was the specific necessary formatting I had to put the image data within to display a specific image with the given functions below. The libraries require some rigid use.

  • Why is path a big deal when working with images?

Path is what tells the program where to look for the image in question. If it can't find where to look, the program can't apply effects to it.

  • How does the meta data source and label relate to Unit 5 topics?

In Unit 5, we talked about crediting intellectual property to the person/people responsible for it. Addressing image sources when defining them lets us credit the owner fo the intellectual property.

  • Look up IPython, describe why this is interesting in Jupyter Notebooks for both Pandas and Images?

IPython is intersting not only because Jupyter Notebooks used to be IPython Notebooks, but because IPython, in a similar vein, provides interactive Python cells like those in notebooks. These cells are an alternative method to display and alter images in Jupyter Notebooks.

IPython and Pandas can be used for such things as analyzing and displaying data sets. WOAH, DATA STRUCTURES...

from IPython.display import Image, display
from pathlib import Path  # https://medium.com/@ageitgey/python-3-quick-tip-the-easy-way-to-deal-with-file-paths-on-windows-mac-and-linux-11a072b58d5f

# prepares a series of images
def image_data(path=Path("images/"), images=None):  # path of static images is defaulted
    if images is None:  # default image
        images = [
            {'source': "Peter Carolin", 'label': "Clouds Impression", 'file': "clouds-impression.png"},
            {'source': "Peter Carolin", 'label': "Lassen Volcano", 'file': "lassen-volcano.jpeg"}
        ]
    for image in images:
        # File to open
        image['filename'] = path / image['file']  # file with path
    return images

def image_display(images):
    for image in images:  
        display(Image(filename=image['filename']))


# Run this as standalone tester to see sample data printed in Jupyter terminal
if __name__ == "__main__":
    # print parameter supplied image
    green_square = image_data(images=[{'source': "Internet", 'label': "Green Square", 'file': "green-square-16.png"}])
    image_display(green_square)
    
    # display default images from image_data()
    default_images = image_data()
    image_display(default_images)

    # BONUS: printing smiley face
    smiley_face = image_data(images=[{'source': "VectorStock", 'label': "Awesome Smiley", 'file': "awesomesmiley.jpeg"}])
    image_display(smiley_face)

Reading and Encoding Images (IMPLEMENTATIONS HERE)

PIL (Python Image Library)

Pillow or PIL provides the ability to work with images in Python. Geeks for Geeks shows some ideas on working with images.

PIL Implementation

See all of the stuff in the hacks later. (Click here)

base64

Image formats (JPG, PNG) are often called Binary File formats, it is difficult to pass these over HTTP. Thus, base64 converts binary encoded data (8-bit, ASCII/Unicode) into a text encoded scheme (24 bits, 6-bit Base64 digits). Thus base64 is used to transport and embed binary images into textual assets such as HTML and CSS.

  • How is Base64 similar or different to Binary and Hexadecimal?
  • Translate first 3 letters of your name to Base64.

base64 Implementation

Base64 is similar to binary and hexadecimal in that it works in specific amounts of bits that hold just enough information for their purposes. While binary has advantages at being a simple form of storing information, Base64 helps to store more complicated data.

First three letters of my name: "Dre" (capitalized)

First three letters in Base64: ("RHJl")

First three letters of my name: "dre" (not capitalized)

First three letters in Base64: ("ZHJl")

numpy

Numpy is described as "The fundamental package for scientific computing with Python". In the Image Lab, a Numpy array is created from the image data in order to simplify access and change to the RGB values of the pixels, converting pixels to grey scale.

io, BytesIO

Input and Output (I/O) is a fundamental of all Computer Programming. Input/output (I/O) buffering is a technique used to optimize I/O operations. In large quantities of data, how many frames of input the server currently has queued is the buffer. In this example, there is a very large picture that lags.

io, BytesIO Implementation

  • Where have you been a consumer of buffering?

Buffering is something scattered all over the internet. I most often experience it when watching YouTube or Netflix, since videos require a lot of frames of image data to be loaded over the internet. Many websites have this problem as well:I often find myself waiting for images to load in even on sites like College Board.

  • From your consumer experience, what effects have you experienced from buffering?

Buffering really primarily affects my decision to use a site or program or not. I can't think of any specific website as an example, but I have often stopped consistently playing certain video games because of load times. For example, I used to really enjoy playing Animal Crossing: New Horizons during COVID, but it wasn't optimized well enough for the Switch console and ended up buffering for more than a whole minute every time I tried to boot up the game.

Buffering can also be helpful for the functionality of a program in my experience. For example, most video games use an "input buffering" system to let an early button press function even after the press is over. This makes the experience more fluid.

  • How do these effects apply to images?

Since images are made up of a lot of data (since they are a complex visual form of media), the process of loading an image may be taxing and what information is being pulled and read may be buffered, resulting in lag like we see on many sites.

Data Structures, Imperative Programming Style, and Working with Images

Introduction to creating meta data and manipulating images. Look at each procedure and explain the the purpose and results of this program. Add any insights or challenges as you explored this program.

Interacting:Questions

  • Does this code seem like a series of steps are being performed?

Yes, because they really are.

  • Describe Grey Scale algorithm in English or Pseudo code.

Below, NumPy is used to convert an image to grayscale. This works by taking the average of the three RGB values, then setting each of them as the average. This works because, on the RGB scale, if all three of the RGB values are equal, then they combine to make a shade of gray. If they are all 255, it is black; if they are all 0, it is white.

A special case is put in place for if the image is a PNG. PNG images are special because they are rendered in the RGBA scale, not just RGB. This doesn't affect the color scale, however; the A value is kept the same while the RGB values are set as the average after the process.

  • Describe scale image. What is before and after on pixels in three images?

All of the images below are displayed with a width of 320 pixels, with height adjusted according to the width-height ratio. Before this filtration, the image is displayed with its width and height dictated by the actual resolution of the image, possibly with some slight restrictions from the CSS styling of this blog. Afterward, the width is always set to 320px, and the height is changed according to the initial height-width ratio.

  • Is scale image a type of compression? If so, does it line it up with College Board terms described?

Typically, image scaling is not considered a type of data compression, since it doesn't reduce the amount of data required to represent an image. Instead, image scaling involves changing the size of an image by either increasing or decreasing its resolution.

from IPython.display import HTML, display
from pathlib import Path  # https://medium.com/@ageitgey/python-3-quick-tip-the-easy-way-to-deal-with-file-paths-on-windows-mac-and-linux-11a072b58d5f
from PIL import Image as pilImage # as pilImage is used to avoid conflicts
from io import BytesIO
import base64
import numpy as np

# prepares a series of images
def image_data(path=Path("images/"), images=None):  # path of static images is defaulted
    if images is None:  # default image
        images = [
            {'source': "Internet", 'label': "Green Square", 'file': "green-square-16.png"},
            {'source': "Peter Carolin", 'label': "Clouds Impression", 'file': "clouds-impression.png"},
            {'source': "Peter Carolin", 'label': "Lassen Volcano", 'file': "lassen-volcano.jpeg"},
            {'source': "VectorStock", 'label': "Awesome Smiley", 'file': "awesomesmiley.jpeg"}
        ]
    for image in images:
        # File to open
        image['filename'] = path / image['file']  # file with path
    return images

# Large image scaled to baseWidth of 320
def scale_image(img):
    baseWidth = 320
    scalePercent = (baseWidth/float(img.size[0]))
    scaleHeight = int((float(img.size[1])*float(scalePercent)))
    scale = (baseWidth, scaleHeight)
    return img.resize(scale)

# PIL image converted to base64
def image_to_base64(img, format):
    with BytesIO() as buffer:
        img.save(buffer, format)
        return base64.b64encode(buffer.getvalue()).decode()

# Set Properties of Image, Scale, and convert to Base64
def image_management(image):  # path of static images is defaulted        
    # Image open return PIL image object
    img = pilImage.open(image['filename'])
    
    # Python Image Library operations
    image['format'] = img.format
    image['mode'] = img.mode
    image['size'] = img.size
    # Scale the Image
    img = scale_image(img)
    image['pil'] = img
    image['scaled_size'] = img.size
    # Scaled HTML
    image['html'] = '<img src="data:image/png;base64,%s">' % image_to_base64(image['pil'], image['format'])
    
# Create Grey Scale Base64 representation of Image
def image_management_add_html_grey(image):
    # Image open return PIL image object
    img = image['pil']
    format = image['format']
    
    img_data = img.getdata()  # Reference https://www.geeksforgeeks.org/python-pil-image-getdata/
    image['data'] = np.array(img_data) # PIL image to numpy array
    image['gray_data'] = [] # key/value for data converted to gray scale

    # 'data' is a list of RGB data, the list is traversed and hex and binary lists are calculated and formatted
    for pixel in image['data']:
        # create gray scale of image, ref: https://www.geeksforgeeks.org/convert-a-numpy-array-to-an-image/
        average = (pixel[0] + pixel[1] + pixel[2]) // 3  # average pixel values and use // for integer division
        if len(pixel) > 3:
            image['gray_data'].append((average, average, average, pixel[3])) # PNG format
        else:
            image['gray_data'].append((average, average, average))
        # end for loop for pixels
        
    img.putdata(image['gray_data'])
    image['html_grey'] = '<img src="data:image/png;base64,%s">' % image_to_base64(img, format)


# Jupyter Notebook Visualization of Images
if __name__ == "__main__":
    # Use numpy to concatenate two arrays
    images = image_data()
    
    # Display meta data, scaled view, and grey scale for each image
    for image in images:
        image_management(image)
        print("---- meta data -----")
        print(image['label'])
        print(image['source'])
        print(image['format'])
        print(image['mode'])
        print("Original size: ", image['size'])
        print("Scaled size: ", image['scaled_size'])
        
        print("-- original image --")
        display(HTML(image['html'])) 
        
        print("--- grey image ----")
        image_management_add_html_grey(image)
        display(HTML(image['html_grey'])) 
    print()
---- meta data -----
Green Square
Internet
PNG
RGBA
Original size:  (16, 16)
Scaled size:  (320, 320)
-- original image --
--- grey image ----
---- meta data -----
Clouds Impression
Peter Carolin
PNG
RGBA
Original size:  (320, 234)
Scaled size:  (320, 234)
-- original image --
--- grey image ----
---- meta data -----
Lassen Volcano
Peter Carolin
JPEG
RGB
Original size:  (2792, 2094)
Scaled size:  (320, 240)
-- original image --
--- grey image ----
---- meta data -----
Awesome Smiley
VectorStock
JPEG
RGB
Original size:  (216, 233)
Scaled size:  (320, 345)
-- original image --
--- grey image ----

Data Structures and OOP

Most data structures classes require Object Oriented Programming (OOP). Since this class is lined up with a College Course, OOP will be talked about often. Functionality in remainder of this Blog is the same as the prior implementation. Highlight some of the key difference you see between imperative and oop styles.

  • Read imperative and object-oriented programming on Wikipedia
  • Consider how data is organized in two examples, in relations to procedures
  • Look at Parameters in Imperative and Self in OOP

Additionally, review all the imports in these three demos. Create a definition of their purpose, specifically these ...

  • PIL
  • numpy
  • base64
from IPython.display import HTML, display
from pathlib import Path  # https://medium.com/@ageitgey/python-3-quick-tip-the-easy-way-to-deal-with-file-paths-on-windows-mac-and-linux-11a072b58d5f
from PIL import Image as pilImage # as pilImage is used to avoid conflicts
from io import BytesIO
import base64
import numpy as np


class Image_Data:

    def __init__(self, source, label, file, path, baseWidth=320):
        self._source = source    # variables with self prefix become part of the object, 
        self._label = label
        self._file = file
        self._filename = path / file  # file with path
        self._baseWidth = baseWidth

        # Open image and scale to needs
        self._img = pilImage.open(self._filename)
        self._format = self._img.format
        self._mode = self._img.mode
        self._originalSize = self.img.size
        self.scale_image()
        self._html = self.image_to_html(self._img)
        self._html_grey = self.image_to_html_grey()


    @property
    def source(self):
        return self._source  
    
    @property
    def label(self):
        return self._label 
    
    @property
    def file(self):
        return self._file   
    
    @property
    def filename(self):
        return self._filename   
    
    @property
    def img(self):
        return self._img
             
    @property
    def format(self):
        return self._format
    
    @property
    def mode(self):
        return self._mode
    
    @property
    def originalSize(self):
        return self._originalSize
    
    @property
    def size(self):
        return self._img.size
    
    @property
    def html(self):
        return self._html
    
    @property
    def html_grey(self):
        return self._html_grey
        
    # Large image scaled to baseWidth of 320
    def scale_image(self):
        scalePercent = (self._baseWidth/float(self._img.size[0]))
        scaleHeight = int((float(self._img.size[1])*float(scalePercent)))
        scale = (self._baseWidth, scaleHeight)
        self._img = self._img.resize(scale)
    
    # PIL image converted to base64
    def image_to_html(self, img):
        with BytesIO() as buffer:
            img.save(buffer, self._format)
            return '<img src="data:image/png;base64,%s">' % base64.b64encode(buffer.getvalue()).decode()
            
    # Create Grey Scale Base64 representation of Image
    def image_to_html_grey(self):
        img_grey = self._img
        numpy = np.array(self._img.getdata()) # PIL image to numpy array
        
        grey_data = [] # key/value for data converted to gray scale
        # 'data' is a list of RGB data, the list is traversed and hex and binary lists are calculated and formatted
        for pixel in numpy:
            # create gray scale of image, ref: https://www.geeksforgeeks.org/convert-a-numpy-array-to-an-image/
            average = (pixel[0] + pixel[1] + pixel[2]) // 3  # average pixel values and use // for integer division
            if len(pixel) > 3:
                grey_data.append((average, average, average, pixel[3])) # PNG format
            else:
                grey_data.append((average, average, average))
            # end for loop for pixels
            
        img_grey.putdata(grey_data)
        return self.image_to_html(img_grey)

        
# prepares a series of images, provides expectation for required contents
def image_data(path=Path("images/"), images=None):  # path of static images is defaulted
    if images is None:  # default image
        images = [
            {'source': "Internet", 'label': "Green Square", 'file': "green-square-16.png"},
            {'source': "Peter Carolin", 'label': "Clouds Impression", 'file': "clouds-impression.png"},
            {'source': "Peter Carolin", 'label': "Lassen Volcano", 'file': "lassen-volcano.jpeg"}
        ]
    return path, images

# turns data into objects
def image_objects():        
    id_Objects = []
    path, images = image_data()
    for image in images:
        id_Objects.append(Image_Data(source=image['source'], 
                                  label=image['label'],
                                  file=image['file'],
                                  path=path,
                                  ))
    return id_Objects

# Jupyter Notebook Visualization of Images
if __name__ == "__main__":
    for ido in image_objects(): # ido is an Imaged Data Object
        
        print("---- meta data -----")
        print(ido.label)
        print(ido.source)
        print(ido.file)
        print(ido.format)
        print(ido.mode)
        print("Original size: ", ido.originalSize)
        print("Scaled size: ", ido.size)
        
        print("-- scaled image --")
        display(HTML(ido.html))
        
        print("--- grey image ---")
        display(HTML(ido.html_grey))
        
    print()
---- meta data -----
Green Square
Internet
green-square-16.png
PNG
RGBA
Original size:  (16, 16)
Scaled size:  (320, 320)
-- scaled image --
--- grey image ---
---- meta data -----
Clouds Impression
Peter Carolin
clouds-impression.png
PNG
RGBA
Original size:  (320, 234)
Scaled size:  (320, 234)
-- scaled image --
--- grey image ---
---- meta data -----
Lassen Volcano
Peter Carolin
lassen-volcano.jpeg
JPEG
RGB
Original size:  (2792, 2094)
Scaled size:  (320, 240)
-- scaled image --
--- grey image ---

My Hacks

These are my hacks. I made sure to respond to every hack mentioned in this section of the template.

Early Seed award

Check out the awesome smiley face added throughout the file. He is BEGGING you to give me a seed point.

AP Prep

  • In the Blog add notes and observations on each code cell that request an answer.

I made sure to answer all unanswered questions throughout this note template. I added additional code comments to help understand the code being used, especially with the code above.

  • In this blog, add College Board practice problems for 2.2

See below...

College Board Practice Quiz

Here are the results from the 2.2 practice quiz.

3/3
I got 3/3.

All of the questions in this quiz were pretty self-explanatory and common sense.

2.2 College Board Practice Problems

Back when I finished my first draft of this blog and the hacks, I didn't realize that this section was referring to a College Board quiz; I thought we had to make our own practice questions. I did so below.

Q1. What is true about lossy compression and lossless compression?

  1. Lossy compression involves losing time by perfectly recreating the original file.
  2. Lossless compression involves creating a user report of any errors found in the file.
  3. Lossy compression involves discarding non-necessary information to decrease file size, while lossless compression just eliminates redundant data.
  4. Lossless compression is always preferable to lossy data because lossy data can create serious discrepancies between the original and the compressed version.

Q2. What is sequencing?

  1. A logic structure in which instructions are executed one at a time, in order.
  2. A method of programming which requires instructions to be connected to each other with distinct numerical instructions.
  3. A logic structure in which the most time-consuming functions are executed first and the least time-consuming last.
  4. A method of asynchronous programming used by large teams to connect separate strings of code for efficient collaboration.

One Lossy Image and One Lossless Image

  • Choose 2 images, one that will more likely result in lossy data compression and one that is more likely to result in lossless data compression. Explain.

This image should be lossily compressed...

Lossy Compression
This is a PNG image.

...while this image should likely be losslessly compressed. (Though it looks like it has already been lossily compressed before.)

Lossless Compression
This is a JPEG image.

Which kind of compression is based on many factors including file type. Typically, PNGs use lossless compression, and less is lost in simpler images. JPEG images trend toward lossier compression, especially with complex designs.

Ultimately, if an image is very simple, it would more likely be lossily compressed, since nothing of importance will be lost.

When it comes to non-images, videos are often more lossily compressed because the image data takes up a lot of space and individual frames being compressed may not come off as too obvious. Usually files in .zip or .7z format are losslessly compressed, while things such as MPEG and MP3 files are more often lossily compressed.

Project Addition

  • If your project has images in it, try to implement an image change that has a purpose. (Ex. An item that has been sold out could become gray scale)

This is the one I haven't done, since my part of the project doesn't use images. It is all HTML elements and CSS styling.

Custom PIL Use

  • Numpy, manipulating pixels. As opposed to Grey Scale treatment, pick a couple of other types like red scale, green scale, or blue scale. We want you to be manipulating pixels in the image.

I did redscale, bluescale, and greenscale below, along with a weird RGB scale that I was curious about.

Redscale, Bluescale, and Greenscale Filters

See the code below for redscale, bluescale, and greenscale filters.

from IPython.display import HTML, display
from pathlib import Path  # https://medium.com/@ageitgey/python-3-quick-tip-the-easy-way-to-deal-with-file-paths-on-windows-mac-and-linux-11a072b58d5f
from PIL import Image as pilImage # as pilImage is used to avoid conflicts
from io import BytesIO
import base64
import numpy as np

# prepares a series of images
def image_data(path=Path("images/"), images=None):  # path of static images is defaulted
    if images is None:  # default image
        images = [
            {'source': "Peter Carolin", 'label': "Clouds Impression", 'file': "clouds-impression.png"},
            {'source': "VectorStock", 'label': "Awesome Smiley", 'file': "awesomesmiley.jpeg"}
        ]
    for image in images:
        # File to open
        image['filename'] = path / image['file']  # file with path
    return images

# Large image scaled to baseWidth of 320
def scale_image(img):
    baseWidth = 320
    scalePercent = (baseWidth/float(img.size[0]))
    scaleHeight = int((float(img.size[1])*float(scalePercent)))
    scale = (baseWidth, scaleHeight)
    return img.resize(scale)

# PIL image converted to base64
def image_to_base64(img, format):
    with BytesIO() as buffer:
        img.save(buffer, format)
        return base64.b64encode(buffer.getvalue()).decode()

# Set Properties of Image, Scale, and convert to Base64
def image_management(image):  # path of static images is defaulted        
    # Image open return PIL image object
    img = pilImage.open(image['filename'])
    
    # Python Image Library operations
    image['format'] = img.format
    image['mode'] = img.mode
    image['size'] = img.size
    # Scale the Image
    img = scale_image(img)
    image['pil'] = img
    image['scaled_size'] = img.size
    # Scaled HTML
    image['html'] = '<img src="data:image/png;base64,%s">' % image_to_base64(image['pil'], image['format'])
    
# Create redscale Base64 image version
def image_management_add_html_red(image):
    # Image open return PIL image object
    img = image['pil']
    format = image['format']
    
    img_data = img.getdata()  # Reference https://www.geeksforgeeks.org/python-pil-image-getdata/
    image['data'] = np.array(img_data) # PIL image to numpy array
    image['red_data'] = [] # key/value for data converted to red scale

    # 'data' is a list of RGB data, the list is traversed and hex and binary lists are calculated and formatted
    for pixel in image['data']:
        # create red scale of image
        redval = pixel[0] # only preserving the red val
        if len(pixel) > 3:
            image['red_data'].append((redval, 0, 0, pixel[3])) # PNG format
        else:
            image['red_data'].append((redval, 0, 0))
        # end for loop for pixels
        
    img.putdata(image['red_data'])
    image['html_red'] = '<img src="data:image/png;base64,%s">' % image_to_base64(img, format)

# Create greenscale Base64 image version
def image_management_add_html_green(image):
    # Image open return PIL image object
    img = image['pil']
    format = image['format']
    
    img_data = img.getdata()  # Reference https://www.geeksforgeeks.org/python-pil-image-getdata/
    image['data'] = np.array(img_data) # PIL image to numpy array
    image['green_data'] = [] # key/value for data converted to red scale

    # 'data' is a list of RGB data, the list is traversed and hex and binary lists are calculated and formatted
    for pixel in image['data']:
        # create green scale of image
        greenval = pixel[1] # only preserving the green val
        if len(pixel) > 3:
            image['green_data'].append((0, greenval, 0, pixel[3])) # PNG format
        else:
            image['green_data'].append((0, greenval, 0))
        # end for loop for pixels
        
    img.putdata(image['green_data'])
    image['html_green'] = '<img src="data:image/png;base64,%s">' % image_to_base64(img, format)

# Create bluescale Base64 image version
def image_management_add_html_blue(image):
    # Image open return PIL image object
    img = image['pil']
    format = image['format']
    
    img_data = img.getdata()  # Reference https://www.geeksforgeeks.org/python-pil-image-getdata/
    image['data'] = np.array(img_data) # PIL image to numpy array
    image['blue_data'] = [] # key/value for data converted to red scale

    # 'data' is a list of RGB data, the list is traversed and hex and binary lists are calculated and formatted
    for pixel in image['data']:
        # create blue scale of image
        blueval = pixel[2] # only preserving the blue val
        if len(pixel) > 3:
            image['blue_data'].append((0, 0, blueval, pixel[3])) # PNG format
        else:
            image['blue_data'].append((0, 0, blueval))
        # end for loop for pixels
        
    img.putdata(image['blue_data'])
    image['html_blue'] = '<img src="data:image/png;base64,%s">' % image_to_base64(img, format)

# Jupyter Notebook Visualization of Images
if __name__ == "__main__":
    # Use numpy to concatenate two arrays
    images = image_data()
    
    # Display meta data, scaled view, and grey scale for each image
    for image in images:

        redcopy = image
        greencopy = image
        bluecopy = image

        image_management(image)
        print("-- original image --")
        display(HTML(image['html'])) 

        print("--- red image ----")
        image_management(redcopy)
        image_management_add_html_red(redcopy)
        display(HTML(redcopy['html_red']))

        print("--- green image ----")
        image_management(greencopy)
        image_management_add_html_green(greencopy)
        display(HTML(greencopy['html_green']))

        print("--- blue image ----")
        image_management(bluecopy)
        image_management_add_html_blue(bluecopy)
        display(HTML(bluecopy['html_blue']))
    print()
-- original image --
--- red image ----
--- green image ----
--- blue image ----
-- original image --
--- red image ----
--- green image ----
--- blue image ----

And just out of curiosity, I tried a filter that only filtered out green values. I figured it would make it look weird since the greenscale version looked the most normal.

from IPython.display import HTML, display
from pathlib import Path  # https://medium.com/@ageitgey/python-3-quick-tip-the-easy-way-to-deal-with-file-paths-on-windows-mac-and-linux-11a072b58d5f
from PIL import Image as pilImage # as pilImage is used to avoid conflicts
from io import BytesIO
import base64
import numpy as np

# prepares a series of images
def image_data(path=Path("images/"), images=None):  # path of static images is defaulted
    if images is None:  # default image
        images = [
            {'source': "VectorStock", 'label': "Awesome Smiley", 'file': "awesomesmiley.jpeg"}
        ]
    for image in images:
        # File to open
        image['filename'] = path / image['file']  # file with path
    return images

# Large image scaled to baseWidth of 320
def scale_image(img):
    baseWidth = 320
    scalePercent = (baseWidth/float(img.size[0]))
    scaleHeight = int((float(img.size[1])*float(scalePercent)))
    scale = (baseWidth, scaleHeight)
    return img.resize(scale)

# PIL image converted to base64
def image_to_base64(img, format):
    with BytesIO() as buffer:
        img.save(buffer, format)
        return base64.b64encode(buffer.getvalue()).decode()

# Set Properties of Image, Scale, and convert to Base64
def image_management(image):  # path of static images is defaulted        
    # Image open return PIL image object
    img = pilImage.open(image['filename'])
    
    # Python Image Library operations
    image['format'] = img.format
    image['mode'] = img.mode
    image['size'] = img.size
    # Scale the Image
    img = scale_image(img)
    image['pil'] = img
    image['scaled_size'] = img.size
    # Scaled HTML
    image['html'] = '<img src="data:image/png;base64,%s">' % image_to_base64(image['pil'], image['format'])
    
# Create redscale Base64 image version
def image_management_add_html_weird(image):
    # Image open return PIL image object
    img = image['pil']
    format = image['format']
    
    img_data = img.getdata()  # Reference https://www.geeksforgeeks.org/python-pil-image-getdata/
    image['data'] = np.array(img_data) # PIL image to numpy array
    image['weird_data'] = [] # key/value for data converted to the weird scale

    # 'data' is a list of RGB data, the list is traversed and hex and binary lists are calculated and formatted
    for pixel in image['data']:
        # create red scale of image
        redval = pixel[0] # preserving the red val
        blueval = pixel[2] # and preserving the blue val
        if len(pixel) > 3:
            image['weird_data'].append((redval, 0, blueval, pixel[3])) # PNG format
        else:
            image['weird_data'].append((redval, 0, blueval))
        # end for loop for pixels
        
    img.putdata(image['weird_data'])
    image['html_weird'] = '<img src="data:image/png;base64,%s">' % image_to_base64(img, format)

# Jupyter Notebook Visualization of Images
if __name__ == "__main__":
    # Use numpy to concatenate two arrays
    images = image_data()
    
    # Display meta data, scaled view, and grey scale for each image
    for image in images:
        image_management(image)
        print("-- original image --")
        display(HTML(image['html'])) 

        print("--- weird image ----")
        image_management_add_html_weird(image)
        display(HTML(image['html_weird']))
    print()
-- original image --
--- weird image ----

It actually didn't turn out that weird.

Other PIL Filters

  • There are many effects you can do as well with PIL. Blur the image or write Meta Data on screen, aka Title, Author and Image size.

Below, I put text over the smile image.

from PIL import Image, ImageDraw, ImageFont

# get an image
with Image.open("images/awesomesmiley.jpeg").convert("RGBA") as base:

    # make a blank image for the text, initialized to transparent text color
    txt = Image.new("RGBA", base.size, (255, 255, 255, 0))

    # get a drawing context
    d = ImageDraw.Draw(txt)

    # draw text, full opacity
    d.text((10, 100), "There is text on my smiley face!", fill=(255, 255, 255, 255))

    out = Image.alpha_composite(base, txt)

    display(out)

I used the default font because other fonts were giving me issues and I didn't want to have to import a .ttf file myself.