Assignment 2: Image Processing And Steganography

Part 2: Image Decoding (15 Points)

Chris Tralie

Due Wednesday 9/28

Background: RGB Images And Steganography

A color image is actually an array of pixels with 3 dimensions: a row, a column, and a "color channel"; that is, each color pixel has 3 numbers associated to it: red, green, and blue (as explained in the last assignment). As with grayscale images, each red/green/blue channel is 8-bits and ranges from 0 to 255.

I've created a wrapper around the stb image library which exposes the pixels as a 3D array. You can access this by using the SimpleCanvas class that I created. For example, below is a code snippet that loads in the image of the penguin provided with your code, puts a 100x100 square at the center of the image, and writes a new version of it to the file penguinredsquare.png:

If you run this code, it will create the following image penguinredsquare.png

This example has pretty much everything you need for this assignment, but I've also provided the programs grayscale.cpp and noise.cpp, which show how to convert an image to grayscale an add noise to it, respectively. For example, making the project and running

creates this image

and

creates the following image (for those interested, 0.5 is the signal to noise ratio)

You should study these examples to the extent that you understand how they're loading images, changing them, and then writing them to a folder, as specified by command line arguments.

Least Significant Bit Information Hiding

The main idea behind the program will be making can be illustrated by the following example. Look at the two pictures below.

Ordinary image

Hidden message

The picture on the right contains 12 paragraphs of text on the Ursinus 150 strategic plan. Can you see the difference? No? Well great, that's the point!

So how do we do this? The idea is beautifully simple, and is best understood with an example. Consider the following 3-pixel image

[254, 119, 50] [2, 141, 254] [91, 159, 64]

We're going to extract a binary signal by looking at the least significant bit (the 1's place in binary) of each color channel in each pixel from left to right from red, to green, to blue, and put them together into one binary string. In other words, for a particular pixel and a particular color channel, we'll extract a 0 if it's an even number and a 1 if it's an odd number. Let's look at the first 8 bits in the above image. We have

2540
1191
500
20
1411
2540
911
1591

All together, this is the binary string 01001011, which is the character 'K' in ASCII. What if we wanted to change it to some other character though? Perhaps the character 'z', which is 0x7A hex, or 01111010 in binary. Then we can just tweak the 1's place of the pixel values as follows, where I've bolded the ones that have changed:

2540
1191
511
31
1411
2540
911
1580

Here's what these updated values look like

[254, 119, 51] [3, 141, 254] [91, 158, 64]

If you were just looking at it and comparing it to what we started with, you would never notice the difference! So we have freedom to tweak the least significant bit of every color channel of every pixel at will to encode text, and this is exactly what you will be doing in this assignment!. In a 500x500 image, for example, this means we can store 250,000 bits. Since each ASCII character is 8 bits, this is 31,250 characters total, or roughly about 6000 words (so you can put all of your CIE essays into a single image!)

Programming Task (15 Points)

As your first task, create a file decode.cpp which decodes the text hidden in an image. Your program should take one command line argument, which is a path to the image you want to decode. You should read the least significant bits of the image from red, green, blue channel row by row from top to bottom, and then assemble them into characters which you print out (every 8 bits you should print a character). Continue until you encounter the null terminator \0. Below are a few examples:

Example 1: tiny_encoded.png

Here's a good example of a very small 4x4 image that you can test as you're getting started. If you run the following

you should get the bits 001100010011011100110100001000010000101000000000. If we group them up into ASCII char variables, we see this is the character string "174!\n"

00110001'1'
00110111'7'
00110100'4'
00100001'!'
00001010'\n'
00000000'\0'

Example 2: Mona Lisa

If you run

you'll get some "fun facts" about people trying to destroy the Mona Lisa

Example 3: Ursinus Birthday

If you run

you'll get some information on the Ursinus 150 strategic plan

Example 4: Penguin

If you run

you'll get a Robert Frost Poem