Index out of bounds because of numel MATLAB - matlab

I am trying to create bit scales images. I am getting an error with this code. What is wrong?
clc
clear all
a=imread('image.tif');%read file
[row col]=size(a);%row of image and column of image
b=zeros(row,col,8);%3D 0 matrix
for k=1:8%position of bit
for i=1:row%for every row
for j=1:col%for every column
bits = de2bi(a(i,j));
b(i,j,k)=bits(k);
end%endFor
end%endFor
end%endFor
for k=1:8
subplot(3,3,k);
imshow(b(:,:,k));
title(strcat(num2str(k),'. bit'));
end%endFor
ERROR:
??? Attempted to access bits(2); index out of bounds because numel(bits)=1.
Error in ==> soru1 at 13
b(i,j,k)=bits(k);

At this line of code:
bits = de2bi(a(i,j));
You are calling de2bi on the value of the pixel at "i,j". Presuming that the image you are opening is of type uint8, the value of a(i,j) can be anywhere between 0 and 255. If these values are 0 or 1, the output of de2bi as you call it is just "0" or "1" - that is, it only has one element in it, and you cannot access the second, non-existent element.
To correct this, you need to force the size of the output of de2bi to be the size you require, which can be done using a second input, like this:
bits = de2bi(a(i,j),8)
In fact the loop isn't required since de2bi, like most MATLAB functions, can handle vectors or matrices as input, not just single numbers:
a=imread('image.tif');
b=de2bi(a);
b = reshape(de2bi,[size(a),8]);

Related

Convolution Kernel using a user defined function. How to deal with negative pixel values?

I've declared a function that will be used to calculate the convolution of an image using an arbitrary 3x3 kernel. I also created a script that will prompt the user to select both an image as well as enter the convolution kernel of their choice. However, I do not know how to go about dealing with negative pixel values that will arise for various kernels. How would I implement a condition into my script that will deal with these negative values?
This is my function:
function y = convul(x,m,H,W)
y=zeros(H,W);
for i=2:(H-1)
for j=2:(W-1)
Z1=(x(i-1,j-1))*(m(1,1));
Z2=(x(i-1,j))*(m(1,2));
Z3=(x(i-1,j+1))*(m(1,3));
Z4=(x(i,j-1))*(m(2,1));
Z5=(x(i,j))*(m(2,2));
Z6=(x(i,j+1))*(m(2,3));
Z7=(x(i+1,j-1))*(m(3,1));
Z8=(x(i+1,j))*(m(3,2));
Z9=(x(i+1,j+1))*(m(3,3));
y(i,j)=Z1+Z2+Z3+Z4+Z5+Z6+Z7+Z8+Z9;
end
end
And this is the script that I've written that prompts the user to enter an image and select a kernel of their choice:
[file,path]=uigetfile('*.bmp');
x = imread(fullfile(path,file));
x_info=imfinfo(fullfile(path,file));
W=x_info.Width;
H=x_info.Height;
L=x_info.NumColormapEntries;
prompt='Enter a convulation kernel m: ';
m=input(prompt)/9;
y=convul(x,m,H,W);
imshow(y,[0,(L-1)]);
I've tried to use the absolute value of the convolution, as well as attempting to locate negatives in the output image, but nothing worked.
This is the original image:
This is the image I get when I use the kernel [-1 -1 -1;-1 9 -1; -1 -1 -1]:
I don't know what I'm doing wrong.
MATLAB is rather unique in how it handles operations between different data types. If x is uint8 (as it likely is in this case), and m is double (as it likely is in this case), then this operation:
Z1=(x(i-1,j-1))*(m(1,1));
returns a uint8 value, not a double. Arithmetic in MATLAB always takes the type of the non-double argument. (And you cannot do arithmetic between two different types unless one of them is double.)
MATLAB does integer arithmetic with saturation. That means that uint8(5) * -1 gives 0, not -5, because uint8 cannot represent a negative value.
So all your Z1..Z9 are uint8 values, negative results have been set to 0. Now you add all of these, again with saturation, leading to a value of at most 255. This value is assigned to the output (a double). So it looks like you are doing your computations correctly and outputting a double array, but you are still clamping your result in an odd way.
A Correct implementation would cast each of the values of x to double before multiplying by a potentially negative number. For example:
for i = 2:H-1
for j = 2:W-1
s = 0;
s = s + double(x(i-1,j-1))*m(1,1);
s = s + double(x(i-1,j))*m(1,2);
s = s + double(x(i-1,j+1))*m(1,3);
s = s + double(x(i,j-1))*m(2,1);
s = s + double(x(i,j))*m(2,2);
s = s + double(x(i,j+1))*m(2,3);
s = s + double(x(i+1,j-1))*m(3,1);
s = s + double(x(i+1,j))*m(3,2);
s = s + double(x(i+1,j+1))*m(3,3);
y(i,j) = s;
end
end
(Note that I removed your use of 9 different variables, I think this is cleaner, and I also removed a lot of your unnecessary brackets!)
A simpler implementation would be:
for i = 2:H-1
for j = 2:W-1
s = double(x(i-1:i+1,j-1:j+1)) .* m;
y(i,j) = sum(s(:));
end
end

Subscripted assignment dimension mismatch in MCMV code

The below code gives me a error:
Subscripted assignment dimension mismatch.
Error in ==> lookmcvmt at 18
M(:,:,j,i) = mcmvOUT2((k+1):(k+Nz), i:Nt:Nr);
Please help to solve.
load MCMVout1xzy
mcmvOUT2 = MCMVout1xzy;
whos
[Nr2 Nr] = size(mcmvOUT2);
Ny = 51;
Nx = 51;
Nz = 41;
Nt = 10;
M = zeros(Nz,Nx,Ny,Nt);
for j=1:Ny
for i=1:Nt
k = Nz*(j-1);
M(:,:,j,i) = mcmvOUT2((k+1):(k+Nz), i:Nt:Nr);
end
end
The error 'subscripted assignment dimension mismatch' means you are trying to assign a block of values into a space that is the wrong size.
This entity
mcmvOUT2((k+1):(k+Nz), i:Nt:Nr);
represents a matrix of values in 2 dimensions. Its size is defined by the two ranges specified by (k+1):(k+Nz) and i:Nt:Nr - you can check its size by typing
size(mcmvOUT2((k+1):(k+Nz), i:Nt:Nr))
The space you are trying to fit it into has to be exactly the same dimensions. The size of the range specified by
M(:,:,j,i)
is defined by the Nz and Nx arguments to the zeros call with which you preallocated the array.
We can't test this because the MCMVout1xzy file containing your data is not given, but you will be able to solve this yourself by using the size command and making sure all your dimensions match.
Because matlab uses column-wise indexing, and a lot of us are used to the row-wise paradigm of cartesian coordinate systems, getting the order of your indexes right can be confusing - this is the root of a lot of these kinds of error (for me anyway).
Things to check: your dimensions Nz etc. are correct and the order of your Nz etc. variables in the zeros call is correct.

Matlab Bug -- Matrix Elements Keep Maxing Out

There's a peculiar bug in my code that I can't seem to figure out. For context, I is an image, a matrix, consisting of scaled values from 0 to 255. GetSpatAvg is a function that is not included here. The problem I'm facing is that the elements in ngtdm always max out at 255. When this function finishes, I get the matrix ngtdm back consisting of many many values that are 255. The code is below exactly as it shows on my computer.
function ngtdm = getNGTDM(I,d)
[rowI, colI] = size(I);
ngtdm = zeros(256, 1);
for r=1+d:rowI-d
for c=1+d:colI-d
term = I(r,c)-getSpatAvg(r,c);
ngtdm(I(r,c)+1)=ngtdm(I(r,c)+1)+term;
end
end
end
I isolated a specific value in I, 254, in the code below.
function ngtdm = getNGTDM(I,d)
[rowI, colI] = size(I);
ngtdm = zeros(256, 1);
for r=1+d:rowI-d
for c=1+d:colI-d
if(I(r,c)==254)
term = I(r,c)-getSpatAvg(r,c);
disp(term);
ngtdm(I(r,c)+1)=ngtdm(I(r,c)+1)+term;
end
end
end
end
The variable 'term', in this instance was always 222. There were 369 instances of 222. Therefore the value at ngtdm(255) (254+1=255) should be larger than 255, yet the element still maxed out at 255. When I replace term with 222 as shown below:
ngtdm(I(r,c)+1)=ngtdm(I(r,c)+1)+222;
I get the correct value, a number larger than 255.
I can't seem to figure out why my element is always maxing out at 255. Could it be something to do with the fact that the values of I are scaled between 0 and 255. I'm pretty positive that getSpatAvg is not the issue because the correct value is being returned.
Thank You
It's not a bug - it sounds like you are using a uint8 datatype. If you convert to a datatype with more bits - e.g. uint16, uint32, single, double, etc - you will not run into this problem. I guess you are working with images, as images read using imread are read in as uint8 by default to save memory. Quickest fix: use I=double(I); either at the start of your function, or on the variable I before you put it into the functions.

What's the concise expression for the following Matlab code

img is an image of a single color channel.
img_temp is defined as follows:
img_temp = zeros(size(img,1), size(img,2), N);
where N is an integer. Therefore, each entry of img_temp contains N values.
What's the concise way of expressing the following operation in Matlab?
for x=1:size(img,1)
for y=1:size(img,2)
img(x,y,1) = find(img_temp(x,y,:)==max(img_temp(x,y,:)));
end
end
I want to find the index of the largest value in the array img_temp(x,y,:) and store it in the corresponding place in img, namely, img(x,y,1)
The max function can operate along any dimension and return an index along with the max value. In your case, you only care about the index and want it stored in img(:,:,1), so try this:
[~, img(:,:,1)] = max(img_temp, [], 3);

bitxor operation in MATLAB

I am trying to understand why the original image is not coming with this code. The resulting image receive is yellowish in color, instead of being similar to the image Img_new.
Img=imread(‘lena_color.tif’);
Img_new=rgb2gray(img);
Send=zeroes(size(Img_new);
Receive= zeroes(size(Img_new);
Mask= rand(size(Img_new);
for i=1 :256
for j=1:256
Send(i,j)=xor( Img_new(i,j),mask(i,j));
End
End
image(send);
imshow(send);
for i=1 :256
for j=1:256
receive(i,j)=xor( send(i,j),mask(i,j));
End
End
image(receive);
imshow(receive);
What am I doing wrong?
There are several problems in your code.
MATLAB is case sensitive so end and End is not the same. Same goes for receive, and send.
MATLAB has a lot of matrix-based operations so please use for loops as a last resort since most of these operations can be executed by MATLAB's optimized routines for matrices.
MATLAB's xor returns the logical xor so when it sees two values (or matrices of values) it doesn't matter if it's 234 xor 123 or 12 xor 23 since it is equivalent to 1 xor 1 and 1 xor 1. You're looking for bitxor which does the bitwise xor on each element of the matrix and I've used it in my code below. This is the only way you can retrieve the information with the pixel == xor(xor(pixel,key),key) operation (assuming that's what you want to do).
rand returns a real value from 0 - 1 ; therefore, to do a successful bitwise xor, you need numbers from 0 - 255. Hence, in my code, you'll see that mask has random values from 0-255.
Note: I've used peppers.png since it's available in MATLAB. Replace it with lena_color.tif.
%%# Load and convert the image to gray
img = imread('peppers.png');
img_new = rgb2gray(img);
%%# Get the mask matrix
mask = uint8(rand(size(img_new))*256);
%%# Get the send and receive matrix
send = bitxor(img_new,mask);
receive = bitxor(send,mask);
%%# Check and display
figure;imshow(send,[0 255]);
figure;imshow(receive,[0 255]);
Update:
%%# Get mask and img somehow (imread, etc.)
img = double(img);
mask_rgb = double(repmat(mask,[1 1 3]));
bitxor(img,mask);
If instead, you choose to make everything uint8 instead of double, then I urge you to check if you are losing data anywhere. img is uint8 so there is no loss, but if any of the values of mask is greater than 255 then making it double will lead to a loss in data.