Reputation: 33
I am trying to make an image steganography script in python 3.7.2 using the image library in PIL. My script to hide one image inside another is not working properly, once the generated file, hidden.png is extracted again it is outputting either full black images or images with less contrast and different colors depending on the amount of bits selected. (My extract script is tested and working.) I normally pick 4 bits but it still isn't working properly at 7.
Here is my code for the hiding script:
def hide(medium, secret_image, lsb):
medimage = Image.open(medium).convert(mode="RGB") #open the medum
secretimage = Image.open(secret_image).convert(mode="RGB") #open the secret image
medimage = medimage.resize(secretimage.size) #resize the medium to be same size as secret
acrossrow = 0 #start at first row
downcol = 0 #start at first column
secret = secretimage.load() #load pixels from secretimage
med = medimage.load()
while acrossrow < secretimage.height:
downcol = 0 #stay first column until reach bottom row
while downcol < secretimage.width:
r, g, b, = secret[acrossrow,downcol] #r,g,b = the rgb of secret image pixel
r = (r >> 8 - lsb) #shift amount of significant bits wanted to the end for hiding
g = (g >> 8 - lsb)
b = (b >> 8 - lsb)
r1, g1, b1 = med[acrossrow,downcol] #more rgb values for medium
r1 = r1 & (0b11111111 << lsb) #remove the last n amount of bits for replacing
g1 = g1 & (0b11111111 << lsb)
b1 = b1 & (0b11111111 << lsb)
r1 = r1 | r #compare medium with secret, combining all 1s
g1 = g1 | g
b1 = b1 | g
med[acrossrow,downcol] = (r1, g1, b1) #send new rgb values to medium
downcol = downcol + 1 #go to next column
acrossrow = acrossrow + 1 #go to next row
medimage.save('hidden.png') #save modified image to new file
medimage.show() #open and display new image
FYI: medium = the path of the medium, secret_image = path to the secret and lsb is the amount of bits i want to hide from the secret image into the medium.
I have gone over my code and am unable to see the problem, if someone could help me out that would be great. Thanks!
EDIT: Here is a link to the full script if you want to test it or build on it. Here is the link to my test hidden.png That one uses 2 lsb Here is the link to the medium. Here is the link to the secret image. For the linked medium and secret image, I am using 4 lsb.
Upvotes: 1
Views: 687
Reputation: 33
I have been over my code and have gotten it working by changing my extract script from my original hide code to:
def hide(medium, secret_image, lsb):
medimage = Image.open(medium).convert(mode="RGB")
secretimage = Image.open(secret_image).convert(mode="RGB")
medimage = medimage.resize(secretimage.size)
acrossrow = 0
downcol = 0
secret = secretimage.load()
med = medimage.load()
result = Image.new("RGB", medimage.size)
r_pixels = result.load()
while acrossrow < secretimage.height:
downcol = 0
while downcol < secretimage.width:
m_r, m_g, m_b = med[acrossrow, downcol]
s_r, s_g, s_b = secret[acrossrow, downcol]
r = (m_r >> lsb << lsb) | (s_r >> (8 - lsb))
g = (m_g >> lsb << lsb) | (s_g >> (8 - lsb))
b = (m_b >> lsb << lsb) | (s_b >> (8 - lsb))
r_pixels[acrossrow, downcol] = r, g, b
downcol = downcol + 1
acrossrow = acrossrow + 1
result.save('testhid.png')
result.show()
result.close()
medimage.close()
secretimage.close()
It now works perfectly on the image posted by @martineau with the yellow brain in both. The link to my updated code is here. If anyone could explain why this works and my original code didn't work, that would be great! Thanks!
Upvotes: 1
Reputation: 123541
Well, after examining the images you added and running my own tests, as far as I can tell your code is functioning correctly. For my own test I applied your hide()
function the brain.png
file using sat.png
as the "medium" image and examined the resulting hidden.png
file your extract()
function in the linked code generates from it (using an lsb
value of 4
).
Yes, the colors in the result differ a bit from the original, but that's to be expected because the hiding process being used effectively reduces the 24 bits-per-pixel of the original (3 x 8) to 12 (3 * 4), so things like contrast will understandably suffer as a result.
Below are the original (left) and extracted versions of the image being shown side-by-side in my image editor showing these differences:
I think the problem may be simply because you don't fully understanding how this particular steganographic technique works.
Upvotes: 0