Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenCV extracting image using LSB method

Tags:

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)
like image 554
P Gilson Avatar asked Oct 29 '16 16:10

P Gilson


1 Answers

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)
like image 103
Reti43 Avatar answered Sep 23 '22 16:09

Reti43