问题
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