Add LSB of image pixel into LSB of pixels of video frames

Viewed 20

I am working on a code to hide an image inside a video. For the same, I have broken down the video into its frames and extracted the RGB values of pixels of each frame. I have also written a code in python that extracts RGB values of the image. Now, I want to embed the image inside the video. For this I want to use LSB approach according to which the LSB of video frame pixels are replaced by LSB of image pixels. The RGB pixel values are in binary form (8-bit) and the last three bits are to be replaced. I am not getting any insight into how to proceed. Also, I need to use a method by which I can decrypt the video once encrypted.

Python code that deals with video

import numpy as np
import cv2 as cv
from numpy import binary_repr
from PIL import Image

vidcap = cv.VideoCapture("video.mp4")
if not vidcap.isOpened():
    print("Cannot open")
    exit()

while True:
# Capture frame-by-frame
ret, frame = vidcap.read()
 # -------------------------------------------------------------> step 2 - split
# if frame is read correctly, ret is True
if not ret:
    print("Can't receive frame (stream end?). Exiting ...")
    break
# Our operations on the frame come here
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)

# Display the resulting frame
cv.imshow('frame', gray)
width, height, d= frame.shape
print("reshaped...")
row=int(width*height)
newframe = frame.reshape(row,3) #2D mein change kiya
newframe_list=newframe.tolist()
# print(type(newframe_list))
all_pixels=[] #empty list
# print(newframe_list)
for i in newframe_list:
    all_pixels.extend(i)

    for i in all_pixels:
        x=np.binary_repr(all_pixels[i], width=8)
        vidpix=x[5:]
        print(x)

print("image pixels")
#kiwi wali image ke pixels iterate kr rhe
def img_pix():
    img = Image.open("kiwi.jpg")
    pixels = img.load()  # this is not a list, nor is it list()'able
    w, h = img.size
    all_img_pixels = []
    for m in range(w):
        for n in range(h):
            cpixel = pixels[m, n]
            all_img_pixels.append(cpixel)

    for m in range(w):
        for n in range(3):
            z = np.binary_repr(all_img_pixels[m][n], width=8)
            imgpix = z[6:]
            print(z)


img_pix()
 if cv.waitKey(1) == ord('q'):
        break

# When everything done, release the capture

vidcap.release()
cv.destroyAllWindows()

code dealing with image

import numpy as np
import cv2 as cv
from PIL import Image
from numpy import binary_repr

def img_pix():
    img = Image.open("kiwi.jpg")
    pixels = img.load() # this is not a list, nor is it list()'able
    width, height = img.size
    all_img_pixels = []
    for m in range(width):
        for n in range(height):
            cpixel = pixels[m, n]
            all_img_pixels.append(cpixel)



    for m in range(width):
        for n in range(3):
            z=np.binary_repr(all_img_pixels[m][n], width=8)
            imgpix=z[5:]
            print(imgpix)

img_pix()
1 Answers

Word of caution

If you want to embed a secret in the LSBs of video frames, you need to save those video frames in a lossless format, or else the pixels of those frames will be slightly modified, thus destroying your secret. This is the same issue you'd have if you were to embed a secret in an image and then save it to jpeg.


First things first, do not load the pixels of a secret image. Just load the bytestream of the image itself. A compressed jpeg file may be, for example, 100 kB, or ~100k bytes in total. The same image, which could be 1000x1000, would have 1 million pixels (x3 for the RGB of each pixel). This would require 30x more the capacity to hide.

You haven't "extracted" the secret image and video pixels. You've merely printed them to the console. But if you do collect them in relevant lists/arrays, then you can iterate as many video frame pixels as necessary until you've embedded all your secret bits. An example where you embed a bit triplet in each RGB pixel of each video frame is shown below:

def load_secret(fname):
    with open(fname, 'rb') as f:
        data = f.read()
    return data

secret_bytes = load_secret("kiwi.jpg")
bits = []
# As it's assumed you'll be embedding 3 bits in each pixel,
# we'll split each byte in three triplets.
for byte in secret_bytes:
    for k in range(6, -1, -3):
        bits.append((byte >> k) & 0x07)

# Now start reading your video frames and count how many
# triplets you have embedded so far.
index = 0
while True:
    ret, frame = vidcap.read()
    if index < len(bits):
        # Assuming you want to embed in each RGB pixels,
        # you can embed up to `width x height x 3` triplets.
        size = np.prod(frame.shape)
        bit_groups = np.array(bits[index:index+size], dtype=np.uint8)
        # Flatten the frame for quick embedding
        frame_flat = frame.flatten()
        # Embed as many bit groups as necessary
        frame_flat[:len(bit_groups)] = (frame_flat[:len(bit_groups)] & 0b11111000) | bit_groups
        # Reshape it back
        new_frame = np.reshape(frame_flat, frame.shape)
        index += size
    else:
        new_frame = frame
    # You can now write `new_frame` to a new video.

Extracting the secret is then a process of iterating over all pixels from each video frame extracting the 3 LSBs and stitching three triplets into a byte.

bits = []
while True:
    ret, frame = vidcap.read()
    flat_frame = frame.flatten()
    bits.extend(flat_frame & 0x07)
    # You need to decide how many triplets is enough to extract

bytestream = b''
for i in range(0, len(bits), 3):
    bytestream += bytes([(bits[i] << 6) | (bits[i+1] << 3) | bits[i+2]])
# `bytestream` should now be equal to `secret_bytes`
with open('extracted_kiwi.jpg', 'wb') as f:
    f.write(bytestream)
Related