Using Python to Decode Steganography Images (example images at Wikipedia)

百般思念 提交于 2019-12-25 05:34:08

问题


At Wikipedia's Steganography Article there is an example image given with hidden image data.

  • Original Image of trees found here
  • Decrypted image data of a cat found here

Wikipedia notes:

Image of a tree with a steganographically hidden image. The hidden image is revealed by removing all but the two least significant bits of each color component and a subsequent normalization. The hidden image is shown (here).

QUESTION: I'm confused about "subsequent normalisation"; assuming working Python 2.x code based on PIL module, how does normalisation factor into the retrieval?


回答1:


The subsequent normalization is linear interpolation of each color component.

Say, the the red color component of pixel 1,1 is 234.

The binary representation of 234 is

In [1]: bin(234)
Out[1]: '0b11101010'

We can remove everything but the two least significant bits with some bitwise operation:

In [2]: bin(234 & 0b11)
Out[2]: '0b10'

The range of a 8-bit image is 8-bits or 256 possible shades. But the range of our color value is just 2-bits or 4 possible shades.

The normalization part is doing linear interpolation to stretch the 2-bit value to fill 8-bit space:

In [3]: (234 & 0b11) * (256/4)
Out[2]: 128

Do this is done on each color component and the cat would appear.




回答2:


Normalization is the process of changing a range of values into another range of values.

You have the range [0,3] because of the binary values of 00, 01, 10 and 11. The reason why you want to normalize this to [0,255] is to cover the whole range of pixel intensities. If you were to just save an image from an array with values in the range [0,3], it would appear black because all of these values are very close to 0 and very far away from 255.

The wikipedia page on image normalization gives you the general formula for this. It also shows an example of converting the range [50,180] (call this range A) to [0,255] (range B).

First, we shift A so it starts from zero. Effectively, you subtract the lowest value (50) so that [50,180] becomes [0,130] (call this C). The maximum distance for C is 130-0 = 130 and for B it is 255-0 = 255. So you'll need to multiply all values of C by 255/130. Since the lowest value in C is 0, so it will be for C * 255/130. But if B doesn't start from 0, you simply add the necessary offset to account for this.

In case words are confusing, here's a visualisation of converting [2,5] to [-4,4].

In your cases, the normalization is from [0,3] to [0,255]. Since both ranges start from 0, you don't need any offsets, just a simple multiplication by 255/3. This result converts {0,1,2,3} to {0,85,170,255}.

A bit of caution here, 255/3 is conveniently an integer number. But if you were normalizing, say [0,7], the most accurate conversion would require the float scaling factor 255/7. Whether you keep that as a float or round it to an integer is outside the scope of this answer.

The simplest code to achieve this would be

import Image
import numpy as np

# The array will be of type `np.uint8`. For integer computations that exceed
# this range, use `np.asarray(Image.open(...), dtype=int)`.
stego = np.asarray(Image.open('Steganography_original.png'))
extracted = stego & 0b00000011
extracted *= (255 / 3)

# Compare result with the one from wikipedia
wiki_extracted = np.asarray(Image.open('Steganography_recovered.png').convert('RGB'))
if np.all(wiki_extracted == extracted):
    print 'All pixels match'


来源:https://stackoverflow.com/questions/28121436/using-python-to-decode-steganography-images-example-images-at-wikipedia

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!