Skip to content

CaoAssignments/cse8a-wi26-pa7

Repository files navigation

CSE 8A Winter 2026 PA7

Due Date: Sunday, March 8, 2026, 11:59 PM PST

Provided Files

CSE8AImage.py, steganography.py, M_M.bmp, CookieMonster.bmp

File(s) to Submit

steganography.py (details on how to submit your file can be found below)

Part 1. Implementation (100 points)

In this PA, we will try to hide a message image within a context image. Then we will also implement a function to recover that message image from a combined image.

CSE8AImage.py provides image loading/saving and some other supports. Do not change anything in it.

steganography.py contains starter code for this PA. Complete the functions with #TODO comments by following the instructions below.


Part 1.1 Background: Binary Representation

Every pixel in a digital image is made up of three color values: Red, Green, and Blue (RGB). Each value is an integer from 0 to 255, which can be represented as an 8-bit binary number. For example:

Decimal Binary
255 11111111
200 11001000
63 00111111
0 00000000

The most significant bits are the leftmost bits (they contribute the most to the value), and the least significant bits are the rightmost bits (they contribute the least).

The key idea behind steganography is that small changes to the least significant bits of a pixel are nearly invisible to the human eye. We can exploit this by hiding data in those bits.


Part 1.2 Function Specifications

Implement the following functions in steganography.py. Each function has a #TODO comment marking where you should write your code.

def get_least_significant2(num)

This function takes in an integer and returns the two least significant bits (rightmost two) as an integer.

  • You can assume num will always be an integer between 0 and 255 inclusive.
  • For example:
    • get_least_significant2(255) should return 3 (since the rightmost two bits of 11111111 are 11, which is 3)
    • get_least_significant2(253) should return 1 (since the rightmost two bits of 11111101 are 01, which is 1)

def get_most_significant2(num)

This function takes in an integer and returns the two most significant bits (leftmost two) as an integer.

  • You can assume num will always be an integer between 0 and 255 inclusive.
  • For example:
    • get_most_significant2(200) should return 3 (since the leftmost two bits of 11001000 are 11, which is 3)
    • get_most_significant2(150) should return 2 (since the leftmost two bits of 10010110 are 10, which is 2)

def embed_digits2(context_val, message_val)

This function takes in two integers and returns the result of replacing the two least significant bits (rightmost two) of context_val with the value of message_val.

  • You can assume context_val will always be an integer between 0 and 255 inclusive (an 8-bit integer) and message_val will always be an integer between 0 and 3 inclusive (a 2-bit integer).

  • For example:

    • embed_digits2(255, 0) should return 252 — the two rightmost bits of 11111111 are replaced with 00, giving 11111100 = 252
    • embed_digits2(0, 3) should return 3 — the two rightmost bits of 00000000 are replaced with 11, giving 00000011 = 3
  • Hint: One approach is to first "clear" the two least significant bits of context_val (set them to 0) and then add message_val. A quick way to clear two bits is to shift right by 2 and then shift left by 2. For example:

    • 00111111 shift right 2 → 00001111
    • 00001111 shift left 2 → 00111100 (the two rightmost bits are now 0)

def hide_secret_message_2bits(context_img, message_img)

This function takes in two 2D arrays of tuples and returns a new image with message_img hidden in the least significant 2 bits of context_img.

  • You need to hide the most significant 2 bits of each RGB value in message_img into the least significant 2 bits of the corresponding RGB values in context_img.
  • You can assume message_img is always the same size as context_img.
  • This function must make a copy of context_img and return that modified copy. It must not modify the original context_img.
  • Hint: Make use of functions that you already implemented.

def recover_secret_message_2bits(img_with_message)

Given an image (a 2D array of tuples), this function returns a 2D array of tuples that is the hidden message image recovered from img_with_message.

  • You can assume the message is hidden in the least significant 2 bits of the image.
  • Your function should go through the entire img_with_message image. The returned image should have the same size as img_with_message.
  • This function must not modify the input img_with_message image.
  • Hint: Make use of functions that you already implemented.

Part 1.3 Hide and Recover

After implementing all the functions above, use them to hide the CookieMonster.bmp image inside the M_M.bmp image.

In terminal, do the following:

  1. Load M_M.bmp as the context image and CookieMonster.bmp as the message image using load_img.
  2. Call hide_secret_message_2bits to produce the combined image.
  3. Save the result to a file called M_MWithMessage.bmp using save_img.
  4. Call recover_secret_message_2bits on the combined image.
  5. Save the recovered image to a file called recMessage.bmp.

When finished, two additional files — M_MWithMessage.bmp and recMessage.bmp — should be created in your working directory.

For your reference, the created images should look like below:

M_MWithMessage.bmp

M_MWithMessage

recMessage.bmp

recMessage


Part 2. Submission

Once you are confident that your program is correct, submit steganography.py to Gradescope.

The file name must be exactly steganography.py to pass the autograder.

If you get any test cases wrong, you may have feedback that tells you:

  • The function being tested
  • The input values used
  • The expected output vs. your actual output

Use this feedback to debug and fix your code. You may submit multiple times. Your latest submission will be graded.

For this PA, we have test cases across all five functions. There are 100 total points: 85 points come from public tests you can see, and 15 points are from hidden tests which will only be revealed after the deadline. Make sure your implementation handles all edge cases to maximize your score.


Grading

  • Correctness (100 points)

    You will earn points based on the autograder tests that your code passes. If the autograder is not able to run your code (e.g., your file has a syntax error or does not match the specifications in this writeup), you may not earn credit. Your latest submission will be graded.

About

CSE 8A Winter 2026 - PA7

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages