Disclaimer: This was part of a homework assignment, however, it has been passed in already. I'm simply looking for the correct solution for future know-how.
The goal with this program was to use the Python OpenCV library to implement image -> image steganography (Embedding/Extracting images inside other images). This is done with two images of equal size using the least significant bit(LSB) method.
The program allows the user to choose the number of bits used for embedding, so with 1 bit used the embedded image is nearly undetectable to the human eye, and with 7 you can clearly make out the hidden image.
I've correctly implemented the embedding just fine, by taking the most significant bits(MSB) of each RGB byte from the secret image, and setting them in the LSB places of the cover image.
My problem is extracting the secret image after it has been embedded. After the code runs, the image that I'm left with seems to be only the blue representation of it. I'm not sure where I went wrong, but I have a feeling it has something to do with my bit manipulation techniques, or use of the OpenCV library. Any help is greatly appreciated, thanks in advance!
Code for extracting:
import cv2
import numpy
def extract(img1, bitsUsed):
print "Extracting..."
# Import image & get dimensions
img = cv2.imread(img1)
h = img.shape[0]
w = img.shape[1]
# Create new image to extract secret image
# Same dimensions, and rgb channel
secretImg = numpy.zeros((h,w,3), numpy.uint8)
x, y = 0, 0
# Loop thru each pixel
while x < w:
while y < h:
# Grab the LSB (based on bitsUsed from embedding)
lsb_B = img.item(y,x,0) & bitsUsed
lsb_G = img.item(y,x,1) & bitsUsed
lsb_R = img.item(y,x,2) & bitsUsed
# Place those bits into MSB positions on new img
secretImg.itemset((y,x,0), lsb_B << (8 - bitsUsed))
secretImg.itemset((y,x,0), lsb_G << (8 - bitsUsed))
secretImg.itemset((y,x,0), lsb_R << (8 - bitsUsed))
y += 1
y = 0
x += 1
cv2.imwrite("extractedImg.png", secretImg)
njuffa is correct. In the extraction, when you have embedded only 1 bit, you want to AND with 0b00000001 (1), for 2 bits with 0b00000011 (3), for 3 bits with 0b00000111 (7), etc. Generally, for k
embedded bits, you want the mask 2**k - 1
.
Moreover, cv2.imread()
will generate a numpy array of the pixels. Instead of looping through each pixel, you can vectorise your computations. All in all, this is what your code could look like.
import cv2
def embed(cover_file, secret_file, k):
cover = cv2.imread(cover_file)
secret = cv2.imread(secret_file)
mask = 256 - 2**k
stego = (cover & mask) | (secret >> (8 - k))
cv2.imwrite('stego.png', stego)
def extract(stego_file, k):
stego = cv2.imread(stego_file)
mask = 2**k - 1
output = (stego & mask) << (8 - k)
cv2.imwrite('extracted.png', output)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With