What does a function n-mod(a,m) such as 8-mod(330,8) do on MATLAB? - matlab

I really can't figure out what it does.
More specifically, I am working on image compression on Matlab and I am provided a code that looks like this:
X=imread('image1.jpg');
s=size(X); % image1.jpg has size 330 x 220
offset1 = mod(8-mod(s(1),8),8);
offset2 = mod(8-mod(s(2),8),8);
if offset1 ~= 0 || offset2 ~= 0
X(s(1)+offset1, s(2)+offset2, 3) = 0;
end
figure(1)
image(X);
axis image
axis off
Trying to figure out what that if statement does, but I have no clue what that offset1 and offset2 is referring to.

They're trying to determine whether the image size is a multiple of 8. JPEG images are always multiples of 8 in size internally because they are made from 8x8 DCT blocks. The header can specify a smaller size, in which case only the specified upper-leftmost portion is visible, and the right and bottom are trimmed.
The part 8 - mod(s(1), 8) is computing how many more bytes it would take to get to the next multiple of 8 in the X size. The outer mod(..., 8) just folds the case of "8 more bytes" back into "0 more bytes".

Related

PSNR of image in matlab

I am confused with the Peak signal-to-noise ratio (PSNR) between original image and encrypted image. As i know, the higher PSNR value means the better image quality. I tried to test and calculate the PSNR value. I used LSB technique on the text steganography.
I tried embed 100 character into an image. It results with 69.9696 dB.
I tried embed 5 character into an image. It results with 68 dB.
Now, what I think in my mind is:
Should more character embed into image, produce less PSNR value, or less character embed into image, produce high PSNR value?
More character embed, means more manipulation on the pixel. So, PSNR value become lesser?
Anyone can tell me or correct me with my mistake?
------Attached Coding------
Str = 'after this, I tried calculate the PSNR value with original image and stego image. 100 character which is read from file is embedded into image, higher PSNR value. 5 character, less PSNR value.';%many character
%Str = 'a'; %one character
Str=uint8(Str); %converting to 8 bit numbers for proper calculation
fprintf('%d ', Str);
fprintf('\n');
stringLength = length(Str);
x=imread('lena.bmp'); %reading the image file
x=uint8(x); %conversion to 8 bit
[x_row,x_col]=size(x);
numPixelsInImage = numel(x);
bitsPerLetter = 7; % For ASCII, this is 7.
numPixelsNeededForString = stringLength * bitsPerLetter;
binaryAsciiString = dec2bin(Str)'
whos binaryAsciiString
binaryAsciiString = binaryAsciiString(:)'
stegoImage = x;
stegoImage(1:numPixelsInImage) = bitset(stegoImage(1:numPixelsInImage), 1, 0);
oneIndexes = find(binaryAsciiString == '1');
stegoImage(oneIndexes) = bitset(stegoImage(oneIndexes), 1, 1);
imwrite(uint8(stegoImage),'stego123.bmp')
fprintf('\nPSNR: %9.7f dB\n\n', psnr(x,stegoImage));
After this, I tried calculate the PSNR value with original image and stego image. 100 character which is read from file is embedded into image, higher PSNR value. 5 character, less PSNR value.
That's why I get confused.
---HERE is my PSNR code---
function [PSNR,mse]=psnr(X,Y)
% function [PSNR,mse]=psnr(X,Y)
% Peak signal to noise ratio of the difference between images and the
%mean square error
% If the second input Y is missing then the PSNR and MSE of X itself
% becomes the output (as if Y=0).
if nargin<2, D=X;
else
if any(size(X)~=size(Y)), error('The input size is not equal to each other!'); end
D=X-Y;
end
mse=sum(D(:).*D(:))/prod(size(X));
PSNR=10*log10(255^2/mse);
I just call the function of PSNR and print the PSNR value of original image and stego image.
The many character I embed, I get 51.1687256 dB.
The one character I embed, I get 51.1578686 dB.
Can tell me why?
There is an error in your pnsr function. Both inputs are uint8, which restricts all values in the 0-255 range. This can be a problem for D=X-Y.
>> uint8(0) - uint8(1)
0
>> double(0) - double(1)
-1
Changing to D = double(X) - double(Y) will give you the correct values for the long and 1-letter strings, 51.1576 dB and 51.1578 dB respectively.
However, your algorithm is suboptimal. You set the LSB of every pixel to 0 before embedding your bits. You effectively modify up to 262144 pixels while your message is much shorter. This brings down the PSNR by a lot and explains why the value is so similar for messages of both 7 and 1536 bits long. Instead, you should modify only the minimum number of pixels required for embedding your message by using numPixelsNeededForString. Or more compactly,
cover = imread('lena512.png');
Str = 'after this, I tried calculate the PSNR value with original image and stego image. 100 character which is read from file is embedded into image, higher PSNR value. 5 character, less PSNR value.';
%Str = Str(1:1);
bits = dec2bin(Str, 7)';
bits = bits(:);
stego = cover;
stego(1:numel(bits)) = bitset(stego(1:numel(bits)), 1, str2num(bits)');
psnr(cover, stego)
Doing so will give you a PSNR of 73.9530 dB for the long string and 95.3265 dB for the 1-letter string.

integers can only be combined with integers of same class or scalar doubles error

I do not know what this error means or how to fix it. I am trying to perform an image rotation in a separate space of coordinates. When defining the reference space of the matrix to be at zero, I am getting the error that integers can only be comibined with integers of the same class or scalar doubles. the line is
WZcentered = WZ - [x0;yo]*ones(1,Ncols);
WZ is classified as a 400x299x3 unit 8, in the workspace. It is an image. x0 and y0 are set to 0 when the function is called. How can I fix this issue/what exactly is happening here?
Also, when I do the same thing yet make WZ to be equal to double(WZ) I get the error that 'matrix dimensions must agree.' I am not sure what the double function does however. Here is the whole code.
function [out_flag, WZout, x_final, y_final] = adopted_moveWZ(WZ, x0, y0);
%Initial Test of plot
[Nrows,Ncols]=size(WZ);
if Nrows ~= 2
if Ncols ==2
WZ=transpose(WZ); %take transpose
[Nrows,Ncols]=size(WZ); %reset the number of rows and columns
else
fprintf('ERROR: Input file should have 2-vectors for the input points.\n');
end
end
plot(WZ(1,:),WZ(2,:),'.')
title('These are the original points in the image');
pause(2.0)
%WZorig = WZ;
%centering
WZcentered = WZ - ([x0;y0] * ones(1,Ncols));
FigScale=400;
axis([-FigScale 2*FigScale -FigScale 2*FigScale])
disp('Hit any key to start the animation');
pause;
SceneCenter = zeros(Nrows,Ncols);
WZnew = WZcentered;
for ii=0:20
%rotate
R = [cos(pi/ii) -sin(pi/ii) 0; sin(pi/ii) cos(pi/ii) 0; 0 0 1];
WZnew = R * WZnew;
plot(WZnew(1,:),WZnew(2,:),'.')
%place WZnew at a different place in the scene
SceneCenter = (ii*[30;40])*ones(1,Ncols);
plot(SceneCenter(1,:) + WZnew(1,:), SceneCenter(2,:) + WZnew(2,:),'.')
axis([-FigScale 2*FigScale -FigScale 2*FigScale])
pause(1.0);
end
%Set final values for output at end of program
x_final = SceneCenter(1,1);
y_final = SceneCenter(2,1);
PPout = PPnew + SceneCenter;
This happens due to WZ and ([x0;y0] * ones(1,Ncols)) being of different data types. You might think MATLAB is loosely typed, and hence should do the right thing when you have a floating point type operated with an integer type, but this rule breaks every once in a while. A simpler example to demonstrate this is here:
X = uint8(magic(5))
Y = zeros(5)
X - Y
This breaks with the same error that you are reporting. One way to fix this is to force cast one of the operands to the other, typically up-casted to make sure the math works. When you do this, both the numbers you are working on are floating point (double precision), and so they are represented in the same byte formatting sequence in memory. This way, the '-' sign is valid, in the same way that you can say 3 apples + 4 apples = 7 apples, but 3 oranges (uint8) + 4 apples (double) = ?. The double(X) makes it clear that you really mean to use double precision arithmetic, and hence fixes the error. This is how it looks now:
double(X) - Y
After having identified this, the new error is 'matrix dimensions do not match'. This means exactly what it says. WZ is a 400x299x3 matrix, and the right hand side matrix is 2xnCols. Now can you subtract a 2D matrix from a 3D matrix of different sizes meaningfully?
Depending on what your code is really intending to do, you can pad the RHS matrix, or find out other ways to make the sizes equal.
All of this is why MATLAB includes routines to do image rotation, namely http://www.mathworks.com/help/images/ref/imrotate.html . This is part of the Image Processing Toolbox, though.

Matlab edge expansion vectorization

I have the following matlab code in a project of mine. image_working at this point is a logical image, the result of edge detection. The below loop expands each white point to be essentially a cross with width width (this is so a later call to imfill() will find more closed regions. The four if statements check that each point is within the original bounds.
[edge_row, edge_col] = find(image_working);
for width = 1:width_edge_widen
for i = 1:length(edge_row)
if (edge_row(i) + width <= m)
image_working(edge_row(i) + width, edge_col(i)) = 1;
end
if (edge_row(i) - width >= 1)
image_working(edge_row(i) - width, edge_col(i)) = 1;
end
if (edge_col(i) + width <= n)
image_working(edge_row(i), edge_col(i) + width) = 1;
end
if (edge_col(i) - width >= 1)
image_working(edge_row(i), edge_col(i) - width) = 1;
end
end
end
I suspect there's a good way to vectorize it and avoid the top-level loop, but I'm at a loss as to how to go about it. Simply indexing (like image_working(edge_row, edge_col)) doesn't work, since this will give give a rectangular region rather than the individual points. Linear indexing (calling inds = find(image_working)) is undesirable because it's difficult to do both vertical and horizontal shifts, although there may well be a vectorizable transform on the indices that I haven't thought of. Any advice?
First, a "vectorized" solution will not neseserally be the fastest here, this depends in how sparse your binary image is. Second, here are a few solutions that will be faster than your code:
First create a random binary image
im0=rand(2000)>0.999; % this means sparsity (density) ~ 1e-3
Solution 1 - for loop (for a cross of width 1, but you can change it as needed):
im=im0;
sd=size(im);
width=1;
[x y]=find(im((1+width):sd(1)-(width+1), (1+width):sd(2)-(width+1)));
x=x+width; y=y+width;
for n=1:numel(y)
im(x(n)-width:x(n)+width,y(n))=1;
im(x(n),y(n)-width:y(n)+width)=1;
end
Solution 2 - vectorized and one line (for a cross of width 1):
im=conv2(single(im0),[0 1 0; 1 1 1; 0 1 0],'same')>0;
Solution 3 - vectorized logical indexing (for a cross of width 1)
im =( im0(2:end-1,2:end-1) | im0(1:end-2,2:end-1) |...
im0(2:end-1,1:end-2) | im0(3:end ,2:end-1) |...
im0(2:end-1,3:end));
im =[zeros(1,size(im,2)); im; zeros(1,size(im,2))];
im= [zeros(size(im0,1),1) im zeros(size(im,1),1)];
You'll see that for sparse images the for loop will be faster than the other methods.
Solution 1: Elapsed time is 0.028668 seconds.
Solution 2: Elapsed time is 0.041758 seconds.
Solution 3: Elapsed time is 0.120594 seconds.
For less sparse images say (~1%) you can use the vectorized solution (Solution 2), as the for loop will very quickly become less efficient but I would check performance on your data before deciding.
Bonus edit, for fun I vectorized the cross filter in solution 2 to have arbitrary width as follows:
f=#(width) circshift(vander([1 zeros(1,2*width)]),[width -width]);
so im=conv2(single(im0),f(1),'same')>0; is equivalent to what is written in Solution 2, but now you can use any f(width_size) you want.

crop an image according to what is different between 2 images

I have different images and I would like to crop them and keep only what is different between both. Here is the code I have so far.
video = VideoReader('frames.avi', 'Tag', 'my reader object');
frameFirst = read(video,1);
frameSecond = read(video, video.NumberOfFrames-1 );
imshowpair (frameSecond,frameFirst);
pause();
Well, it's tough to give you a good answer without much more detail. I think I understand what you're trying to do, and this might get you moving in the right direction. This code iterates through each pixel of the image (each pixel contains a 1x3 vector of RGB data ranging from 0 to 1), by row and column. If the difference in any of the elements of the 1x3 RGB vector exceeds some threshold (in this case, set to 0.1), we make that whole pixel black (set it to [0 0 0]). Else, we lust make it whatever the last frame was. To filter out all but those pixels that are identical, set the thresh value to 0. It goes like this:
thresh = 0.1
for ii = 1:size(frameFirst, 1)
for jj = 1:size(frameFirst, 2)
pixDiff = frameFirst{ii, jj} - frameSecond{ii, jj}
if (pixDiff(1) > thresh || pixDiff(2) > thresh || pixDiff(3) > thresh)
outputFrame = frameSecond{ii, jj};
else
outputFrame = [0 0 0];
end
end
end
I hope this does what you're looking for. Good luck!
Edit 1: Ok, I understand what you are looking for now. You need to have the indices of the bottom-right and top-left. If you already have those, just do this: frameOut = frameIn(xStart:xStop, yStart, yStop. If you need to find those points, that's harder. Let me know and I'll help you work it out.

Selecting objects overlapping a pixel in matlab

I'm implementing some sort of flood fill algorithm in Matlab that, given a starting pixel in a binary image, will output a binary image containing only the pixels that can be directly connected to it.
Basically, let
foo =
1 1 1
1 0 0
1 0 1
calling flood_fill(foo,1,1) would yield
1 1 1
1 0 0
1 0 0
Now, I'm pretty new to Matlab. I initially implemented flood_fill in a recursive style, but the pass-by-value behaviour of Matlab made working with large images very inefficient. To fix this, I reimplemented flood_fill like this
function [outImage] = flood_fill(inImage,start_x,start_y)
width = size(inImage,2);
height = size(inImage,1);
outImage = zeros(height,width);
points = [];
points = [points; [start_x start_y]];
while size(points,1)>0
point = points(1,:);
points = points(2:end,:);
y=point(2);
x=point(1);
outImage(y,x)=1;
if (y>1 && (outImage(y-1,x)==0) && (inImage(y-1,x)==1))
points = [points; [x y-1]];
end
if (y<height && (outImage(y+1,x)==0) && (inImage(y+1,x)==1))
points = [points; [x y+1]];
end
if (x>1 && (outImage(y,x-1)==0) && (inImage(y,x-1)==1))
points = [points; [x-1 y]];
end
if (x<width && (outImage(y,x+1)==0) && (inImage(y,x+1)==1))
points = [points; [x+1 y]];
end
end
end
Now, this works on small matrices/images but takes forever on large images as well. I suspect the reason why is the large amount of array resizes going on. Normally (in C++ for example), I'd use an unordered linked list and use it as a stack (remove from and insert at the head) to avoid costly array resizes.
Is there an equivalent to such a data structure in Matlab? If not, what's a Matlab idiom I could use? Perhaps a built-in function?
The function that you search for called bwselect:
foo=[1 1 1; 1 0 0; 1 0 1]
b=bwselect(foo,1, 1)
Note that you can define also fourth input n (like that: bwselect(foo,1,1,n)), that can have a value of 4 to specify 4-connected region, or 8 to specify 8-connected region.
Adiel answered your second question "Perhaps a built-in function?". As for the first part:
I'm not familiar with linked lists in MATLAB. However, you can speed up your function significantly by initializing the size of the points-matrix and don't change the size after that. Pre-initialization should always be done in MATLAB. If the function won't work with matrices of fixed size, I would always recommend you to try to rewrite the function.
For your specific case:
function [outImage] = flood_fill(inImage,start_x,start_y)
width = size(inImage,2);
height = size(inImage,1);
outImage = zeros(height,width);
points = zeros(nnz(inImage),2); % I take it this is the maximum size
points(1,:) = [start_x start_y];
k = 1; % Increment row number in points
while size(points,1)>0
k = k + 1;
y=points(k, 2);
x=points(k, 1);
I understand it you have programming skills in general, so I believe you should be able to adapt the remaining code to the new format. (I don't have time to go through it and rewrite it). I'm quite sure it will run much faster!