Search code examples
pythonopencvimage-processingsteganography

howcan i put a list into 2d array with known size 283*283 using python


i want to hide(invisible watermark) a string into image (283*283) using LSB (Least Significant Bit) algorithm. user gives hidden message(string) , then i put all characters' ascii code (base 2) in a list , now i want to make this list a 2d array in same size as my image then i can use '&' and '|' operators.

import cv2 as cv

#read image:

img=cv.imread('C:/Users/pc/Desktop/cameraman.jpg',0)
cv.imshow("ax bedoon ramz",img)
cv.waitKey()

#make least significant bit of each pixel 0 :

img_r=img&0b11111110
img_w=img_r.copy()

#take message and make sure it can hide in 283*283 image :

while True:
    txt=input('chi maikhay ghayem koni ? (max = 10000 character) : ')
    if len(txt)>10000:
        print('out of range characters ! ! ! ')
    else :
        break

#put characters ascii code in list :

ch_ascii_base2 = [bin(ord(i))[2:] for i in txt]

result=[]
for ch in ch_ascii_base2:
    for val in ch:
        result.append(bin(int(val))[2:])

Solution

  • There is no point in zeroing out all the LSB of all pixels, because if your secret is much smaller than the size of your image, you have modified ~50% of the remaining pixels for no reason.

    I would simply get the bitstream of the message, flatten the image and then hide your message in a slice of that array that fits the message. Then reshape it back to 2D.

    string = 'Hello world'
    
    # Getting the bits from each character with bitwise operations is better
    # than using intermediate strings with `bin` or string formats
    for byte in map(ord, string):
        bits.extend((byte >> i) & 1 for i in range(7, -1, -1))
    
    flat = img.flatten()
    flat[:len(bits)] = (flat[:len(bits)] & 0xfe) | bits
    stego = flat.reshape(img.shape)
    

    If the image is RGB, then the order of the pixels is (0, 0, R), (0, 0, G), (0, 0, B), (0, 1, R), etc. If you want to embed your secret first in, say, only the blue channel, extract that colour plane, embed as many bits as it can fit in there with the above process and then move on to another channel. It's a bit more convoluted, but not really hard.

    If you insist in converting the bitstream to a 2D array the same size as your image, just count how many pixels your image has, how many bits you have and append that many 1s or 0s to your bitstream. Then use np.reshape(). Again though, if the result is a 3D array, you have to be mindful of the final order of the bits.

    All in all, if you don't care about embedding your secret in specific planes, use the method I suggested. It's extremely short and clear and it doesn't involve any extraneous computations or modifications to your image.