Decomposing Embedded Images - Loren On The Art of MATLAB

Download as pdf or txt
Download as pdf or txt
You are on page 1of 12

Decomposing Embedded Images | Loren on the Art of MATLAB

Search: Blogs

Page 1

File Exchange

Answers

Newsgroup

Link Exchange

Blogs

Trendy

Cody

Contest

MathWorks.com

Loren on the Art of MATLAB


February 24th, 2009

Decomposing Embedded Images


Today Id like to introduce a guest blogger, Jiro, who is an application engineer here at The MathWorks. Some of you may know him as one of the bloggers for the File Exchange Pick of the Week.

Contents
Setup Show Images Image Decomposition Decomposing the Second Image How It Works Embed Function & Decode Function Cleanup Comments? I recently presented to a group of freshman engineering students at Virginia Commonwealth University. I wanted to show something that was fun, eye-catching, and relatively easy to explain. So I created this image-related demo. I am not an expert in image processing, but I certainly had a lot of fun working on this example. For anyone interested in hardcore image processing, I would suggest also taking a look at Steve's Image Processing blog. This example demonstrates how to embed an image into another image and how to decompose the images. The embedded image is created by storing two 8-bit RGB image as 16-bit RGB image. The primary image is stored in the most significant byte, while the secondary image is stored in the least significant byte. (See the section titled "Embed Function & Decode Function" of this post for the code). With this method, the secondary image can be concealed inside the primary image, without any loss of information. This post focuses on the decomposition part of the demo. This demo uses functions from the Image Processing Toolbox.

Setup
curImshowBorder = iptgetpref('ImshowBorder'); iptsetpref('ImshowBorder', 'tight');

Show Images
Here are two images that look the same. But are they?? peppers_BlueHills.png

http://blogs.mathworks.com/loren/2009/02/24/decomposing-embedded-images/

8/29/2012 11:26:27 AM

Decomposing Embedded Images | Loren on the Art of MATLAB


peppers_BlueHills.png

Page 2

peppers_trees.png

Would you believe me if I say these were very different images? Perhaps you'll believe MATLAB:

isequal(imread('peppers_BlueHills.png'), imread('peppers_trees.png')) ans = 0 In fact, they have completely different images embedded in them. You just can't tell with the naked eye.

Image Decomposition
Let's try to decompose the image and see what's hidden inside. These are 16-bit RGB images. See the "Embed Function & Decode Function" section of this report to see the function that I used for creating these images.

imData = imread('peppers_BlueHills.png'); whos imData Name imData Size 384x512x3 Bytes 1179648 Class uint16 Attributes

http://blogs.mathworks.com/loren/2009/02/24/decomposing-embedded-images/

8/29/2012 11:26:27 AM

Decomposing Embedded Images | Loren on the Art of MATLAB


Name imData Size 384x512x3 Bytes 1179648 Class uint16 Attributes

Page 3

The image contains two 8-bit images. The primary image is stored in the most significant byte and the secondary image is stored in the least significant byte. Convert RGB 3-D Array to a Vector We'll be using TYPECAST to convert the data type, and the function requires a vector.

pixelVals = imData(:); pixelVals(1:10) ans = 16097 16352 16862 16348 16346 16344 16087 16854 16082 15822 Convert UINT16 to UINT8 Next, convert the data type from UINT16 to UINT8. In doing so, we'll use TYPECAST (instead of CAST) to preserve the data.

pixelValsConv = typecast(pixelVals, 'uint8'); whos pixelVals* Name pixelVals pixelValsConv Size 589824x1 1179648x1 Bytes 1179648 1179648 Class uint16 uint8 Attributes

Notice that pixelValsConv has twice as many elements. This is because there are two 8-bit values to a 16-bit value. Separate Two Images We'll reshape them to separate out the least and the most significant bytes.

pixelValsConv = reshape(pixelValsConv, 2, [])'; pixelValsConv(1:10, :) ans = 225 224 222 220 218 216 215 214 210 206

62 63 65 63 63 63 62 65 62 61

On a system with "little-endian" architecture, the first column is the least significant byte and the second column is the most significant column. (first pixel) 62*256 + 225 = 16097

On a "big-endian" architecture system, the order is switched.

[cmp,maxsize,endian] = computer if strcmp(endian, 'L') imOrder = [2 1]; else imOrder = [1 2]; d

http://blogs.mathworks.com/loren/2009/02/24/decomposing-embedded-images/

8/29/2012 11:26:27 AM

Decomposing Embedded Images | Loren on the Art of MATLAB

Page 4

[cmp,maxsize,endian] = computer if strcmp(endian, 'L') imOrder = [2 1]; else imOrder = [1 2]; end cmp = PCWIN maxsize = 2.1475e+009 endian = L We'll take each column and reshape them as the primary and secondary images.

imDataPrimary = reshape(pixelValsConv(:, imOrder(1)), size(imData)); imDataSecondary = reshape(pixelValsConv(:, imOrder(2)), size(imData)); We can see that we end up with two images, both of which are now UINT8 images.

whos imData* Name imData imData2Primary imData2Secondary imDataPrimary imDataSecondary Size 384x512x3 384x512x3 384x512x3 384x512x3 384x512x3 Bytes Class Attributes

1179648 uint16 589824 uint8 589824 uint8 589824 uint8 589824 uint8

Show Primary and Secondary Images

figure;imshow(imDataPrimary); figure;imshow(imDataSecondary);

http://blogs.mathworks.com/loren/2009/02/24/decomposing-embedded-images/

8/29/2012 11:26:27 AM

Decomposing Embedded Images | Loren on the Art of MATLAB

Page 5

Decomposing the Second Image


We'll do the same thing for the second image we read in. Let's see what's embedded in that one. We'll use decodeImage.m which is a function with the above algorithm.

[imData2Primary, imData2Secondary] = decodeImage('peppers_trees.png'); figure; imshow(imData2Primary); figure; imshow(imData2Secondary);

http://blogs.mathworks.com/loren/2009/02/24/decomposing-embedded-images/

8/29/2012 11:26:27 AM

Decomposing Embedded Images | Loren on the Art of MATLAB

Page 6

How It Works
So, how does this work? Why is the secondary image unrecognizable by the naked eye? That's because the secondary image is stored in the least significant byte. To understand this, let's take a look at a single row of pixels in one of the RGB planes. We'll look at row 150 of the red plane.

pixelRow16 = imData(150, :, 1);

% row 150, red plane

We covert this vector to UINT8 using TYPECAST :

pixelRow8 = typecast(pixelRow16, 'uint8'); pixelRow8 = reshape(pixelRow8, 2, []); pixelRow8(:, 1:10) ans = 64 67

60 70

61 71

61 70

57 70

60 72

61 74

61 69

61 63

61 63

On a little-endian architecture system, the first row is the secondary image, and the second row is the primary image. Next, we'll create a UINT16 vector with only the primary image.

% set the secondary image vector to ZERO pixelRow8Main = [zeros(1, size(pixelRow8, 2), 'uint8'); pixelRow8(2, :)]; pixelRow16Main = typecast(pixelRow8Main(:)', 'uint16'); Now let's compare the values of the total image vector with those of the primary image vector

http://blogs.mathworks.com/loren/2009/02/24/decomposing-embedded-images/

8/29/2012 11:26:27 AM

Decomposing Embedded Images | Loren on the Art of MATLAB


Now, let's compare the values of the total image vector with those of the primary image vector.

Page 7

figure; ax1 = axes;hold on; plot(pixelRow16); plot(pixelRow16Main, 'r'); xlabel('Pixel Count'); ylabel('Pixel Value (UINT16)'); legend('Total Image', 'Primary Image', 'Location', 'NorthWest'); rectX = 160; rectY = 15000; rectW = 30; rectH = 3500; rectangle('Position', [rectX, rectY, rectW, rectH]); dar = get(ax1, 'DataAspectRatio'); dar = dar(2)/dar(1); w = .3; h = w*(rectH/rectW)/dar; ax2 = axes(... 'Units', 'Normalized', ... 'Position', [.6 .2 w h], ... 'Box', 'on', ... 'LineWidth', 2, ... 'XTick', [], ... 'Ytick', [], ... 'Color', [.95 .95 .95]);hold on; xlabel('Magnified Region'); plot(pixelRow16); plot(pixelRow16Main, 'r'); xlim([rectX, rectX+rectW]); ylim([rectY, rectY+rectH]);

As this figure shows, the primary image represents the majority of the information. The information for the secondary image is much smaller relative to the primary image. But if we look at the data for the secondary image by itself, you see that we have the full 8-bit information.

figure; plot(pixelRow8(1, :), 'g'); ylim([0 300]); legend('Secondary Image', 'Location', 'NorthWest'); title('Secondary Image'); xlabel('Pixel Count'); ylabel('Pixel Value (UINT8)');

http://blogs.mathworks.com/loren/2009/02/24/decomposing-embedded-images/

8/29/2012 11:26:27 AM

Decomposing Embedded Images | Loren on the Art of MATLAB

Page 8

The following animations show how the secondary image data becomes more apparent as we subtract out the primary image data. Animations created using ANYMATE. 2-D Animation

3-D Animation

http://blogs.mathworks.com/loren/2009/02/24/decomposing-embedded-images/

8/29/2012 11:26:27 AM

Decomposing Embedded Images | Loren on the Art of MATLAB

Page 9

Embed Function & Decode Function


These are the actual functions for creating and decoding embedded images. embedImage.m

help embedImage EMBEDIMAGE Embed an image into another image EMBEDIMAGE(PRIMARYIMAGE, IMAGETOEMBED) embeds the image file IMAGETOEMBED into the image file PRIMARYIMAGE. Both PRIMARYIMAGE and IMAGETOEMBED must be valid file names. The image files must be 8-bit images. The output image file will be a 16-bit PNG image, named PRIMARYIMAGE_IMAGETOEMBED.png. The primary image data will be stored in the most significant byte and the embedded image data will be stored in the least significant byte. Example: embedImage('trees.tif', 'football.jpg'); See also DECODEIMAGE. Jiro Doke Jan 24, 2009.

decodeImage.m

help decodeImage DECODEIMAGE Decode embedded image. DECODEIMAGE(IMAGEFILE) decodes embedded image file IMAGEFILE. IMAGEFILE must be a valid file name. It will display a figure with 3 axes. The top axis is the original image. The bottom left is the primary image, and the bottom right is the embedded hidden image. [PRIMARY, HIDDEN] = DECODEIMAGE(IMAGEFILE) returns the primary image and the hidden image data as RGB data. This function only works on images created by embedImage.m. Example: % create embedded image embedImage('trees.tif', 'football.jpg'); decodeImage('trees_football.png');

http://blogs.mathworks.com/loren/2009/02/24/decomposing-embedded-images/

8/29/2012 11:26:27 AM

Decomposing Embedded Images | Loren on the Art of MATLAB


DECODEIMAGE Decode embedded image. DECODEIMAGE(IMAGEFILE) decodes embedded image file IMAGEFILE. IMAGEFILE must be a valid file name. It will display a figure with 3 axes. The top axis is the original image. The bottom left is the primary image, and the bottom right is the embedded hidden image. [PRIMARY, HIDDEN] = DECODEIMAGE(IMAGEFILE) returns the primary image and the hidden image data as RGB data. This function only works on images created by embedImage.m. Example: % create embedded image embedImage('trees.tif', 'football.jpg'); decodeImage('trees_football.png'); See also EMBEDIMAGE. Jiro Doke Jan 24, 2009.

Page 10

Cleanup
iptsetpref('ImshowBorder', curImshowBorder);

Comments?
I hope you liked this example. Images make nice examples because they are visual. Let me know if you have other fun, pedagogical examples that involve graphics. Put them on the File Exchange, and I'll be sure to take a look at it as a potential Pick of the Week!

Get the MATLAB code


Published with MATLAB 7.7

By Loren Shure

15:06 UTC | Posted in Image Processing | Permalink | 13 Comments You can follow any responses to this entry through the RSS 2.0 feed. Both comments and pings are currently closed.

13 Responses to Decomposing Embedded Images


1. George Kapodistrias replied on March 2nd, 2009 at 18:22 UTC : Hi Loren, Great blog. Thanks, gk. 2. adam replied on March 7th, 2009 at 07:58 UTC : one of the coolest posts in a while. i cant wait to really go through it in detail. 3. Seth Popinchalk replied on March 7th, 2009 at 13:17 UTC : Jiro great example! This reminds me of Steves post on the MATLAB default image. Do you ever use this technique to hide information? 4. Jiro replied on March 13th, 2009 at 01:20 UTC : Glad you guys enjoyed it. Seth, I actually didnt know about Steves post and the default images. I knew about the little boy, but I had no idea all of these other images existed. Thats really cool! 5. Gavin replied on April 17th, 2009 at 21:16 UTC : Does this only work with 2 images or can it be applied to multiple layers of image? Could for instance a 16bit tiff contain several hundred layers of 8bit images? 6. Loren replied on April 19th, 2009 at 17:32 UTC :

http://blogs.mathworks.com/loren/2009/02/24/decomposing-embedded-images/

8/29/2012 11:26:27 AM

Decomposing Embedded Images | Loren on the Art of MATLAB


6. Loren replied on April 19th, 2009 at 17:32 UTC : GavinYou can pack more than 2 images into 64 bits, but youd have to know how they are packed together. See this post on Steves blog for how 17 images are part of MATLABs default image. Loren 7. OysterEngineer replied on November 12th, 2009 at 03:31 UTC : This is a very complex topic for a layman like me. But, Im happy to see it & Im learning a bit. A couple basic questions: Up in near the top of the Image Decomposition section you do a whos on imData. How do you tell from the returned data that the image contains two 8-bit images? I dont see anything in the returned data that would even hint about this. How does the recast operation on pixelValsConv automatically put the least & most significant bytes in the appropriate columns? Isnt the output of the recast operation just the 1st half of the input vector in the 1st column of the output & the 2nd half in the 2nd column? Finally, this post pointed out a major shortcoming of the FRP for the cast function: It doesnt have any text to warn users that the data may be changed. 8. Jiro replied on November 12th, 2009 at 20:02 UTC : @OysterEngineer Thanks for your comments. Im no expert in image processing, so it was certainly a learning and fun experience for me. 1. Youre right. Just from the information provided by WHOS, you cant tell that it contains two 8-bit images. It says the datatype is uint16, so Im just telling you that I have stored two 8-bit data into 16-bits. 2. (Im not entirely sure what you mean by recast. I used TYPECAST and RESHAPE in my code.) TYPECAST puts the data starting from the least significant byte to the most significant byte (or vice versa, depending on the endiannes). When I passed a vector into TYPECAST, it did the conversion for each element (and returned a vector), so I had to RESHAPE it to put the different bytes into different columns. 3. Good point about the lack of warning in CAST. I will submit a enhancement request for this. 9. OysterEngineer replied on November 12th, 2009 at 22:16 UTC : My typo, I should have said reshape rather than recast. I guess the question really is, how do you know that the 1st half of the vector is the one level of byte while the 2nd half is the other level of byte? I understand how reshape splits the input vector to make an array. What I dont understand is how you can count on typecast putting the pairs of bytes in each half of the output vector. The FRP for typecast is disturbingly vague on this detail. In reading the last paragraph of the Description in the FRP for typecast, I would conclude that the bytes in the output would be, in this case, in adjacent pairs of bytes, one per row & not separated into halves of the output, shaped into a vector. 10. Jiro replied on November 13th, 2009 at 14:01 UTC : @OysterEngineer, I suppose youre right that the FRP for TYPECAST does not explicitly explain how the output is formatted if the input is a vector. The example 2 in the FRP describes the behavior. Perhaps this behavior should be explicitly mentioned in the description section. Ill pass this along. Thanks. 11. Alan Hester replied on February 8th, 2010 at 07:04 UTC : can you put infomation in the interlaced images that the subconscious will pick up on and remember that can later be accessed by the conscious mind following some kind of a trigger? Would like to know. Please advise! 12. Huckfish replied on February 12th, 2010 at 00:15 UTC : I am interested in taking a puzzle grid and then analyzing the cells so that I know where the empty space is and then coloring the empty space. Suggestions? 13. Loren replied on February 12th, 2010 at 12:26 UTC : HuckfishYou may want to check out Image Processing Toolbox; look at the demos by following the demos link There

Page 11

http://blogs.mathworks.com/loren/2009/02/24/decomposing-embedded-images/

8/29/2012 11:26:27 AM

Decomposing Embedded Images | Loren on the Art of MATLAB


You may want to check out Image Processing Toolbox; look at the demos by following the demos link. There should be several good ideas there for you to try. Loren These postings are the author's and don't necessarily represent the opinions of MathWorks.
Problems? Suggestions? Contact us at [email protected] 1994-2012 The MathWorks, Inc. Patents Trademarks Privacy Policy Preventing Piracy Terms of Use

Page 12

http://blogs.mathworks.com/loren/2009/02/24/decomposing-embedded-images/

8/29/2012 11:26:27 AM

You might also like