embedding a character in an image - matlab

So here is what I was trying to do. I'm absolutely new to matlab. It has only been a day or so that I've used it and here is a little something that my teacher had asked me to do. Embed statements or group of strings within an image using the LSB Algorithm. The string is to be read from a file.
As of now, I've not used any file operations. I'm trying this using one character and I don't know whats wrong. The algo seems simple but my output i.e, both the cover and the steg pixels show the same value. :(
cover=imread('D:\l.jpg');
steg=cover;
l=1;
LSB=0;
height = size (cover, 1);
width = size (cover, 2);
message = 'J' ;
mdec = uint8(message);
mbin = dec2bin(mdec, 8);
mbins= mbin(:);
len=length(mbins);
for i = 1:height
for j = 1:width
if(l<=len)
LSB = mod(cover(i,j), 2);
if(mbins(l)==LSB)
steg(i,j) = cover(i,j);
else if (mbins(l)~=LSB && LSB==1 && mbins(l)==0)
steg(i,j) = cover(i,j)-1;
else if (mbins(l)~=LSB && LSB==0 && mbins(l)==1)
steg(i,j) = cover(i,j)+1;
end
end
end
l=l+1;
end
end
end
imwrite(steg,'D:\hidden.jpg');
%imshow(steg)
cover(1, 1:8)
steg(1, 1:8)

Oh, nested loops... that's not the way to go.
You want to replace the least significant bits of the first l pixels with the binary ascii representation of your input string.
First thing that went wrong - converting char to binary:
Converting a character to its binary representation should be done using bitget
>> bitget( uint8('J'), 1:8 )
0 1 0 1 0 0 1 0
Gives back 1-by-8 binary array, while using dec2bin:
>> dec2bin( uint8('J'), 8 )
01001010
Gives back 1-by-8 string: the actual numeric values of this array are
>> uint8(dec2bin( uint8('J'), 8 ))
48 49 48 48 49 48 49 48
Can you appreciate the difference between the two methods?
If you insist on using dec2bin, consider
>> dec2bin( uint8('J'), 8 ) - '0'
0 1 0 0 1 0 1 0
Second point - nested loops:
Matlab favors vector/matrix vectorized operations rather than loops.
Here's a nice way of doing it without loops, assuming cover is a gray scale image (that is it has a single color channel rather than 3) of type uint8.
NoLsb = bitshift( bitshift( cover, -1 ), 1 ); %// use shift operation to set lsb to zero
lsb = cover - NoLsb; %// get the lsb values of ALL pixels
lsb( 1:l ) = mbins; %// set lsb of first l pixels to bits of message
steg = NoLsb + lsb; %// this is it!

Related

How to use bitset function in MATLAB to modify multiple bits simultaneously

>> a = 255
a =
255
>> bitset(a,1,0)
ans =
254
here the first bit is set to 0 so we get 11111110 equivalent to 254
>> bitset(a,[1,2],0)
ans =
254 253
here the 1st bit and 2nd bit are being set to 0 seperately. Hence we get
11111110 equivalent to 254
11111101 equivalent to 253
how to get 11111100 equivalent to 252?
Apply bitset twice:
bitset(bitset(a, 1, 0), 2, 0)
The order of application should not matter.
Alternatively, you can use the fact that bitset is an equivalent to applying the correct sequence of bitand, bitor and bitcmp operations.
Since you are interested in turning off multiple bits, you can do
bitand(bitset(a, 1, 0), bitset(a, 2, 0))
Here's a one-liner:
a = 255;
bits = [1,2];
bitand(a,bitcmp(sum(2.^(bits-1)),'uint32'))
Taken apart:
b = sum(2.^(bits-1))
computes the integer with the given bits set. Note that bits must not contain duplicate elements. Use unique to enforce this: bits = unique(bits).
c = bitcmp(b,'uint32')
computes the 32-bit complement of the above. ANDing with the complement resets the given bits.
bitand(a,c)
computes the binary AND of the input number and the integer with the given bits turned off.
Setting bits is easier:
a = 112;
bits = [1,2];
bitor(a,sum(2.^(bits-1)))
Maybe most explicit, easiest to understand, you can convert to a string representing binary and then do the operations there, then convert back.
a = 255
bin_a = flip(dec2bin(a)) % flip to make bigendian
bin_a([1, 2]) = '0'
a = bin2dec(flip(bin_a))
Here is a little recursive function based on the answer from #Mad Physicist that will allow zeroing of any number of bits in data . Thanks for the original info. The recursion is probably dead obvious to most people but it might help somebody out.
function y = zero_nbits(x, n)
y = bitset(x, n, 0)
if n > 1
y = zero_nbits(y, n-1);
end
end

How to assign a big stream bit into one column vector

I have a large bit stream. (e.g. 10110001010101000.....001 size thousands or millions)
I want to assign this bit stream into a one column vector x.
x = zeros(n,1);
I have tried to use some mod or rem operations, there will have some problems.
I guess it caused by the integer size.
I want to ask is there any good method to solve this problem?
Thanks for reading.
Assuming, for example:
x = '10100101010101010100';
You could turn it into a logical column vector this way:
x = (x == '1')';
You can also use a simple subtraction trick with the ascii value of 0 -
x-'0'
Sample run -
>> x =
00101011001
>> x-'0'
ans =
0 0 1 0 1 0 1 1 0 0 1
Then, transpose the matrix to get a column vector - [x-'0']'.
Consider addressing the problem earlier in the processing, at load time. Each '0'/'1' character is stored as a byte, so load bytes (unsigned chars or uchar) which contain the character codes, then convert the character codes to the right 0/1 values:
fid = fopen('binchars.txt','r');
digits = fread(fid,'uchar') - 48
fclose(fid);

Histogram Equalization method without use of histeq

I am new to Matlab and am trying to implement code to perform the same function as histeq without actual use of the function. In my code the image colour I get changes drastically when it should not change that much. The average intensity in the image (ranging between 0 and 255) is 105.3196. The image is of an open source pollen particle.
Any help would be much appreciated. The sooner the better! Please could any help be simplified as my Matlab understanding is limited. Thanks.
clc;
clear all;
close all;
pollenJpg = imread ('pollen.jpg', 'jpg');
greyscalePollen = rgb2gray (pollenJpg);
histEqPollen = histeq(greyscalePollen);
averagePollen = mean2 (greyscalePollen)
sizeGreyScalePollen = size(greyscalePollen);
rowsGreyScalePollen = sizeGreyScalePollen(1,1);
columnsGreyScalePollen = sizeGreyScalePollen(1,2);
for i = (1:rowsGreyScalePollen)
for j = (1:columnsGreyScalePollen)
if (greyscalePollen(i,j) > averagePollen)
greyscalePollen(i,j) = greyscalePollen(i,j) + (0.1 * averagePollen);
if (greyscalePollen(i,j) > 255)
greyscalePollen(i,j) = 255;
end
elseif (greyscalePollen(i,j) < averagePollen)
greyscalePollen(i,j) = greyscalePollen(i,j) - (0.1 * averagePollen);
if (greyscalePollen(i,j) > 0)
greyscalePollen(i,j) = 0;
end
end
end
end
figure;
imshow (pollenJpg);
title ('Original Image');
figure;
imshow (greyscalePollen);
title ('Attempted Histogram Equalization of Image');
figure;
imshow (histEqPollen);
title ('True Histogram Equalization of Image');
To implement the equalisation algorithm described on the Wikipedia page, follow these these steps:
Decide on a binSize to group greyscale values. (This is a tweakable, the larger the bin, the less accurate the result from the ideal case, but I think it can cause problems if chosen too small on real images).
Then, calculate the probability of a pixel being a shade of grey:
pixelCount = imageWidth * imageHeight
histogram = all zero
for each pixel in image at coordinates i, j
histogram[floor(pixel / 255 / 10) + 1] += 1 / pixelCount // 1-based arrays, not 0-based
// Note a technicality here: you may need to
// write special code to handle pixels of 255,
// because they will fall in their own bin. Or instead use rounding with an offset.
The histogram in this calculation is scaled (divided by the pixel count) so that the values make sense as probabilities. You can of course factor the division out of the for loop.
Now you need to calculate the accumulative sum of this:
histogramSum = all zero // length of histogramSum must be one bigger than histogram
for i == 1 .. length(histogram)
histogramSum[i + 1] = histogramSum[i] + histogram[i]
Now you have to invert this function and this is the tricky part. The best is to not calculate an explicit inverse, but calculate it on the spot, and apply it on the image. The basic idea is to search for the pixel value in the histogramSum (find the closest index below), and then do a linear interpolation between the index and the next index.
foreach pixel in image at coordinates i, j
hIndex = findIndex(pixel, histogramSum) // You have to write findIndex, it should be simple
equilisationFactor = (pixel - histogramSum[hIndex])/(histogramSum[hIndex + 1] - histogramSum[hIndex]) * binSize
// This above is the linear interpolation step.
// Notice the technicality that you need to handle:
// histogramSum[hIndex + 1] may be out of bounds
equalisedImage[i, j] = pixel * equilisationFactor
Edit: without drilling into the maths, I can't be 100% sure, but I think that division by 0 errors are possible. These can occur if one bin is empty, so consecutive sums are equal. So you need special code to handle this case too. The best you can do is take the value for the factor as halfway between hIndex, hIndex + n, where n is the highest value for which histogramSum[hIndex + n] == histogramSum[hIndex].
And that should be it, once you have dealt with all the technicalities.
The above algorithm is slow (especially in the findIndex step). You may be able to optimize this with a special lookup datastructure. But only do that when it's working, and only if necessary.
One more thing about your Matlab code: the rows and columns are inverted. Because of the symmetry in the algorithm, the result is the same, but it can cause puzzling bugs in other algorithms, and be very confusing if you examine pixel values during debugging. In the pseudocode above I used them the same as you, though.
Relatively few (5) lines of code can do this. I used a low contrast file called 'pollen.jpg' that I found at http://commons.wikimedia.org/wiki/File%3ALepismium_lorentzianum_pollen.jpg
I read it in using your code, run all the above, then do the following:
% find out the index of pixels sorted by intensity:
[gv gi] = sort(greyscalePollen(:));
% create a table of "approximately equal" intensity values:
N = numel(gv);
newVals = repmat(0:255, [ceil(N/256) 1]);
% perform lookup:
% the pixels in sorted order need new values from "equal bins" table:
newImg = zeros(size(greyscalePollen));
newImg(gi) = newVals(1:N);
% if the size of the image doesn't divide into 256, the last bin will have
% slightly fewer pixels in it than the others
When I run this algorithm, and then create a composite of the four images (original, your attempt, my attempt, and histeq), you get the following:
I think it's convincing. The images are not exactly identical - I believe that is because the matlab histeq routine ignores all pixels with value 0. Since it is fully vectorized it is also pretty fast (although not nearly as fast as histeq by about a factor 15 on my image.
EDIT: a bit of explanation might be in order. The repmat command I use to create the newVals matrix creates a matrix that looks like this:
0 1 2 3 4 ... 255
0 1 2 3 4 ... 255
0 1 2 3 4 ... 255
...
0 1 2 3 4 ... 255
Since matlab stores matrices in "first index first" order, if you read this matrix with a single index (as I do in the line newVals(1:N)), you access first all the zeros, then all the ones, etc:
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 ...
So - when I know the indices of the pixels in the order of their intensity (as returned by the second argument of the sort command, which I called gi), then I can easily assign the value 0 to the first N/256 pixels, the value 1 to the next N/256 etc, with the command I used:
newImg(gi) = newVals(1:N);
I hope this makes the code a little easier to understand.

Convert logical to string

I need to convert logical vector to string .. so i can take each 8 bits of the logical vectors and convert it to it's equevilant of char ..
A=0 1 1 1 0 1 1 0 1 1 0 0 0 0 1 ;
A is of type logical
i need to convert it to a string , so A will equal 'va'
You can use char to convert a number to a character.
To convert each 8 elements of A into a number, there are a few methods:
% using definition of binary
n = sum(A(1:8).*2.^[7:-1:0])
% using 'base2dec'
n = base2dec(sprintf('%i',A(1:8)),2)
Then use char(n) to get the character out.
To apply this to every 8 elements of A you could use a loop or something like arrayfun.
arrayfun( #(i) char(base2dec(sprintf('%i',A(i:(i+7))),2)),
1:8:length(A) )
Note The A you gave in your original question has only 15 elements so you can't really group every 8 (need 16) - you will need to write some code to deal with what to do in this case.
Helpful docs:
base2dec
arrayfun
char
In addition to #mathematical.coffee answer, instead of SPRINTF you can simply add 48 (which is code for character '0') to A to get the string:
Astr = char(A + 48);
or
Astr = char(A + int8('0'));
You can also use BIN2DEC instead of BASE2DEC.
So you can use it in ARRAYFUN as
arrayfun( #(i) char(bin2dec(char(A(i:(i+7))+48))),1:7:length(A) )

Faster version of dec2bin function for converting many elements?

I am reading a bitmap file and converting each of the RGB values ranging from 0 to 255 to binary.
So a 240 by 320 bitmap will have 230400 RGB values to convert. The original dec2bin function was too slow, so I wrote my own as I know my value will always be between 0 to 255.
But going through 230400 values will still take approx. 6sec on my machine, and a single colour bitmap will take about 2.3sec.
Is there anyway to speed things up to be under 1sec or even better 0.5sec, as every msec counts for my application?
Here is my code:
function s = dec2bin_2(input)
if input == 255
s = [1;1;1;1;1;1;1;1];
return;
end
s = [0;0;0;0;0;0;0;0];
if input == 0
return;
end
if input >= 128
input = input - 128;
s(1) = 1;
if input == 0
return;
end
end
if input >= 64
input = input - 64;
s(2) = 1;
if input == 0
return;
end
end
if input >= 32
input = input - 32;
s(3) = 1;
if input == 0
return;
end
end
if input >= 16
input = input - 16;
s(4) = 1;
if input == 0
return;
end
end
if input >= 8
input = input - 8;
s(5) = 1;
if input == 0
return;
end
end
if input >= 4
input = input - 4;
s(6) = 1;
if input == 0
return;
end
end
if input >= 2
input = input - 2;
s(7) = 1;
if input == 0
return;
else
s(8) = 1;
end
end
end
I was thinking if I'm not able to do it in MATLAB then maybe I'll do the conversion in C++. Is this advisable?
Thanks.
An even faster way is to use lookup tables. Since you know all the values are intensities between 0 and 255, you construct the binary equivalent of each to speed up the process.
% build table (computed once) [using gnovice option#1]
lookupTable = cell2mat(arrayfun(#(i)bitget([0:255]',9-i),1:8,'UniformOutput',0));
% random' image
I = randi(256, [240 320])-1;
% decimal to binary conversion
binI = lookupTable(I(:)+1,:);
On my machine, it took on average 0.0036329 seconds (only the conversion). Note the lookup table has almost no space overhead:
>> whos lookupTable
Name Size Bytes Class Attributes
lookupTable 256x8 2048 uint8
Option #1: Loop over each pixel and use BITGET
You can loop over each pixel (or RGB value) in your image and use BITGET to get a vector of zeroes and ones. Here's an example of how to use BITGET:
>> bitget(uint8(127),8:-1:1) % Get bits 8 through 1 for a uint8 value
ans =
0 1 1 1 1 1 1 1
Option #2: Vectorized solution with BITGET
It's possible to create a vectorized solution where you loop over each bit instead of each pixel, performing a BITGET operation on the entire image matrix each time through the loop. The following is one such implementation:
function B = get_bits(A,N)
% Gets the N lowest bits from each element of A
B = zeros([size(A) 0]);
nDims = ndims(A)+1;
for iBit = N:-1:1
B = cat(nDims,B,bitget(A,iBit));
end
end
If the matrix A is 2-D (n-by-m) or 3-D (n-by-m-by-p), the matrix B will be one dimension larger. The extra dimension will be of size N with the highest bit in index 1. You can either index into this dimension to get a bit value or reshape B to a more easily visualized form. Here's an example of the usage:
>> A = uint8([126 128; 127 129]); % A 2-by-2 matrix of uint8 values
>> B = get_bits(A,8); % B is a 2-by-2-by-8 matrix
>> B(:,:,1) % Get bit 8 for each value in A
ans =
0 1
0 1
>> reshape(B,4,8) % Reshape B into a 4-by-8 matrix
ans =
0 1 1 1 1 1 1 0
0 1 1 1 1 1 1 1
1 0 0 0 0 0 0 0
1 0 0 0 0 0 0 1
Can't you use bitand to get the bits directly ?
s(0) = 256 bitand input
s(1) = 128 bitand input
s(2) = 64 bitand input
etc...
This kind of problem (perform a per-element operation on a large array, because Matlab's built-in code is too slow) sometimes calls for a solution in Java, since Matlab runs on a JRE and converting/passing array arguments is usually a fairly fast operation.
gnovice's solution sounds like it works for you, but if you run into a situation you can't solve in pure Matlab, and you're proficient in Java, consider writing a custom JAR file. It's pretty easy. (well, a whole lot easier than trying to interface C++ to Matlab!)