def extract_hidden_pixels(image, width_visible, height_visible, pixel_count): """ Extracts a sequence of bits representing a sequence of binary values of all pixels of the hidden image. The information representing a hidden image is stored in the 4 least significant bits of a subset of pixels of the visible image. Args: image: An RGB image to recover a hidden image from width_visible: Width of the visible image height_visible: Height of the visible image pixel_count: Number of pixels in the hidden image Returns: A binary string representing pixel values of the hidden image """ hidden_image_pixels = '' idx = 0 for col in range(width_visible): for row in range(height_visible): if row == 0 and col == 0: continue r, g, b = image[col, row] r_binary, g_binary, b_binary = rgb_to_binary(r, g, b) hidden_image_pixels += r_binary[4:8] + g_binary[4:8] + b_binary[4:8] if idx >= pixel_count * 2: return hidden_image_pixels return hidden_image_pixels
def decode(image): """ Loads the image to recover a hidden image from, retrieves the information about the size of the hidden image stored in the top left pixel of the visible image, extracts the hidden binary pixel values from the image and reconstructs the hidden image. Args: image: An RGB image to recover a hidden image from Returns: A recovered image, which was hidden in the binary representation of the visible image """ image_copy = image.load() width_visible, height_visible = image.size r, g, b = image_copy[0, 0] r_binary, g_binary, b_binary = rgb_to_binary(r, g, b) w_h_binary = r_binary + g_binary + b_binary width_hidden = int(w_h_binary[0:12], 2) height_hidden = int(w_h_binary[12:24], 2) pixel_count = width_hidden * height_hidden hidden_image_pixels = extract_hidden_pixels(image_copy, width_visible, height_visible, pixel_count) decoded_image = reconstruct_image(hidden_image_pixels, width_hidden, height_hidden) return decoded_image
def change_binary_values(self, img_visible, hidden_image_pixels, width_visible, height_visible, width_hidden, height_hidden): idx = 0 for col in range(width_visible): for row in range(height_visible): if row == 0 and col == 0: width_hidden_binary = add_leading_zeros( bin(width_hidden)[2:], 12) height_hidden_binary = add_leading_zeros( bin(height_hidden)[2:], 12) w_h_binary = width_hidden_binary + height_hidden_binary img_visible[col, row] = (int(w_h_binary[0:8], 2), int(w_h_binary[8:16], 2), int(w_h_binary[16:24], 2)) continue r, g, b = img_visible[col, row] r_binary, g_binary, b_binary = rgb_to_binary(r, g, b) r_binary = r_binary[0:4] + hidden_image_pixels[idx:idx + 4] g_binary = g_binary[0:4] + hidden_image_pixels[idx + 4:idx + 8] b_binary = b_binary[0:4] + hidden_image_pixels[idx + 8:idx + 12] idx += 12 img_visible[col, row] = (int(r_binary, 2), int(g_binary, 2), int(b_binary, 2)) if idx >= len(hidden_image_pixels): return img_visible # can never be reached, but let's return the image anyway return img_visible
def get_binary_pixel_values(self, img, width, height): hidden_image_pixels = '' for col in range(width): for row in range(height): pixel = img[col, row] r = pixel[0] g = pixel[1] b = pixel[2] r_binary, g_binary, b_binary = rgb_to_binary(r, g, b) hidden_image_pixels += r_binary + g_binary + b_binary return hidden_image_pixels
def change_binary_values(img_visible, hidden_image_pixels, width_visible, height_visible, width_hidden, height_hidden): """ Replaces the 4 least significant bits of a subset of pixels in an image with bits representing a sequence of binary values of RGB channels of all pixels of the image to be concealed. The first pixel in the top left corner is used to store the width and height of the image to be hidden, which is necessary for recovery of the hidden image. Args: img_visible: An RGB image to be used for hiding another image hidden_image_pixels: Binary string representing all pixel values of the image to be hidden width_visible: Width of the image to be used for hiding another image height_visible: Height of the image to be used for hiding another image width_hidden: Width of the image to be hidden height_hidden: Height of the image to be hidden Returns: An RGB image which is a copy of img_visible where the 4 least significant bits of a subset of pixels are replaced with bits representing the hidden image. """ idx = 0 for col in range(width_visible): for row in range(height_visible): if row == 0 and col == 0: width_hidden_binary = add_leading_zeros( bin(width_hidden)[2:], 12) height_hidden_binary = add_leading_zeros( bin(height_hidden)[2:], 12) w_h_binary = width_hidden_binary + height_hidden_binary img_visible[col, row] = (int(w_h_binary[0:8], 2), int(w_h_binary[8:16], 2), int(w_h_binary[16:24], 2)) continue r, g, b = img_visible[col, row] r_binary, g_binary, b_binary = rgb_to_binary(r, g, b) r_binary = r_binary[0:4] + hidden_image_pixels[idx:idx + 4] g_binary = g_binary[0:4] + hidden_image_pixels[idx + 4:idx + 8] b_binary = b_binary[0:4] + hidden_image_pixels[idx + 8:idx + 12] idx += 12 img_visible[col, row] = (int(r_binary, 2), int(g_binary, 2), int(b_binary, 2)) if idx >= len(hidden_image_pixels): return img_visible # can never be reached, but let's return the image anyway return img_visible
def get_binary_pixel_values(img, width, height): """ Retrieves a string of concatenated binary representations of RGB channel values of all pixels in an image. Args: img: An RGB image width: Width of the image height: Height of the image Returns: A string with concatenated binary numbers representing the RGB channel values of all pixels in the image where each binary number representing one channel value is 8 bits long, padded with leading zeros when necessary. Therefore, each pixel in the image is represented by 24 bit long binary sequence. """ hidden_image_pixels = '' for col in range(width): for row in range(height): pixel = img[col, row] r = pixel[0] g = pixel[1] b = pixel[2] r_binary, g_binary, b_binary = rgb_to_binary(r, g, b) hidden_image_pixels += r_binary + g_binary + b_binary return hidden_image_pixels