First, I read the cover image as greyscale image.
coverImage = cv2.imread(coverImagePath, 0)
Then I pass the cover image to another function to create another smaller image and that smaller image is my secret image.
def makeSecretImage(coverImage): copyImage = coverImage.copy() secretImage = cv2.resize(copyImage, (100,100)) return secretImage
After that I pass the two images to my embedding function to embed the secret image into the cover image. My intention is to embed every bit of every pixel of the secret image to the LSB of the cover image and the LSB of the cover image is selected randomly. The final output of this function is a stego image which will looks exactly same with the cover image as it only change the LSB of the pixel.
def embedding(coverImage,secretImage, password): indices = permute_indices(coverImage.shape, password) for i in range (secretImage.shape): for j in range(secretImage.shape): x,y = next(indices) #convert pixel to binary pixels_cover = format(coverImage[x][y], '08b') pixels_hide = format(secretImage[i][j], '08b') binary = list(pixels_hide) #error : keep overwriting the last bit for dataIndex in range(0,8): stegoImage = pixels_cover[:7] + binary[dataIndex] dataIndex += 1 coverImage[x][y] = int(stegoImage, 2) cv2.imwrite('StegoImage.png', coverImage)
Then the stego image is read and pass to the extracting function. Here I’m getting the last bit of the selected pixel and form back to pixel. Then those pixel values placed back to the black image. But I’m getting error here as it read extra pixels from the stego image.
def extracting(stgimg,secretImage, password): Swidth, Sheight = stgimg.shape Ewidth, Eheight = secretImage.shape newPixel =  pixelList =  # create 2 blank images OriImg = np.zeros((Swidth, Sheight, 1), np.uint8) ExtractedImg = np.zeros((Ewidth, Eheight, 1), np.uint8) indices = permute_indices(stgimg.shape, password) for x in range(Swidth): for y in range(Sheight): a, b = next(indices) stegopixel = format(stgimg[a][b], '08b') bitValue = stegopixel[-1] newPixel.append(bitValue) for i in range(0, len(newPixel),8): pixelBit = ''.join(newPixel[i:i+8]) pixelByte = int(pixelBit, 2) pixelList.append(pixelByte) img = np.array(pixelList, dtype=np.uint8).reshape(secretImage.shape) cv2.imwrite('ExtractedImage.png', ExtractedImg)
First of all, you have an error in
for dataIndex in range(0,8): stegoImage = pixels_cover[:7] + binary[dataIndex] dataIndex += 1
You hide 8 bits in the LSB of the same pixel, effectively overwriting them and keeping only the last one. You’re supposed to hide each bit in a different pixel and so you need at least 8 times more pixels in your cover image than what your secret has. With that in mind
def embedding(coverImage, secretImage, password): stegoImage = coverImage.copy() indices = permute_indices(coverImage.shape, password) for pixel in secretImage.flatten(): # no need for string "bit manipulation", straight up bitwise operations for shift in range(7, -1, -1): x, y = next(indices) bit = (pixel >> shift) & 0x01 stegoImage[x,y] = (coverImage[x,y] & 0xfe) | bit return stegoImage
def extracting(stegoImage, password): indices = permute_indices(stegoImage.shape, password) pixels =  for _ in range(secretImage.size): pixel = 0 for _ in range(8): x, y = next(indices) bit = stegoImage[x,y] & 0x01 pixel = (pixel << 1) | bit pixels.append(pixel) pixels = np.array(pixels, dtype=np.uint8).reshape(secretImage.shape) return pixels
Edit: I’ve modified the above functions to return the image arrays instead of saving them, so I can directly test it with the original input. This also assumes that
permute_indices is still the same as defined here.
password = 'password' coverImage = cv2.imread('original.png', 0) secretImage = makeSecretImage(coverImage) stegoImage = embedding(coverImage, secretImage, password) extractedImage = extracting(stegoImage, password) diff = coverImage.astype(int) - stegoImage print(diff.min(), diff.max()) # Differences should be in the [-1, 1] range print(np.all(secretImage == extractedImage)) # True