Error in matlab code for matrix dimension - matlab

% Image Arithmetic Operations
% Image addition is done between two similar size of image, so image resize
% function is used to make size of both image same.
% I=I1+I2
clc
close all
I1=imread('test.jpg');
I2=imread('test_1.jpg');
subplot(2,2,1);imshow(I1);title('Original image I1');
subplot(2,2,2);imshow(I2);title('Original image I2');
I=I1+I2; % Addition of two images
subplot(2,2,3);imshow(I);title('Addition of image I1+I2');
I=I1-I2; % Subtraction of two images
subplot(2,2,4);imshow(I);title('Subtraction of image I1-I2');
figure;
subplot(2,2,1);imshow(I1);title('Original image I1');
I=I1+50;
subplot(2,2,2);imshow(I);title('Bright image I');
I=I1-100;
subplot(2,2,3);imshow(I);title('Dark image I');
M=imread('key.png');
M=im2bw(M); % Converts into binary image having 0s and 1s
I=uint8(I1).*uint8(M); % Type casting before multiplication
subplot(2,2,4);imshow(I);title('Masked Image I');
%clear all;
[filename,pathname]=uigetfile({'*.bmp;*.jpg;*.gif','Choose Image File'});
myimage=imread(filename);
if(size(myimage,3)==3)
myimage=rgb2gray(myimage);
end
[Rows,Cols]=size(myimage);
newimage=zeros(Rows,Cols);
k=1;
while k<5
for i=1:Rows
for j=1:Cols
if k==1
newimage(i,j)=myimage(i,j)-100;
end
if k==2
newimage(i,j)=myimage(i,j)-50;
end
if k==3
newimage(i,j)=myimage(i,j)+50;
end
if k==4
newimage(i,j)=myimage(i,j)+50;
end
end
end
subplot(2,2,k);imshow(newimage,[]);
k=k+1;
end
% calculate mean value
[Rows,Cols]=size(myimage);
newimage=zeros(Rows,Cols);
total=0;
for i=1:Rows
for j=1:Cols
total=total+myimage(i,j);
end
end
average=total/(Rows*Cols);
I am in big trouble because this error is not resolved and i am new to matlab coding so please help me and your solution is appreciated to me in future.
I faced an error mentioned below :
??? Error using ==> times Matrix dimensions must agree.
Error in ==> DIP_3 at 23 I=uint8(I1).*uint8(M); % Type casting before
multiplication

Assuming that the three images you are working with (test.jpg, test_1.jpg and test.png) are of the same size, the problem arises when you call the im2bw function
M=im2bw(M);
The input matrix M is a 3D matrix (eg. 100x100x3) while the output matrix is only a 2D matrix (100x100).
The error is generated because you multiply matrix I1 (which is also a 3D matrix) by a 2D matrix.
I=uint8(I1).*uint8(M);
You have therefore to make the matrix M a 3D matrix.
If you want to apply the same scaling factor on matrix I1 you can do something like:
M=imread('key.png');
M0=im2bw(M); % Converts into binary image having 0s and 1s
M(:,:,2)=M0;
M(:,:,3)=M0;
Otherwise, you have to define, somehow M(:,:,2) and M(:,:,3)
Hope this helps.

Related

Wrong dimensions when normalizing an image

I am getting some error in this code section
X=imread ('Lighthouse.jpg'); %reads picture as int8 matrix
figure, imagesc(X), colormap gray, title('original picture'), % display picture
filter=[-1 0 1; -2 0 2; -1 0 1]; % builds Sobel filter matrix
filter=single(filter); %convert double to single
x=single(X); % convert int8 to single
x=x/max(max(x)); %normalisation to [0,1]
The error I get:
Error using /
Inputs must be 2-D, or at least one input must be scalar.
To compute elementwise RDIVIDE, use RDIVIDE (./) instead.
Error in sobel (line 10)
x=x/max(max(x)); %normalisation to [0,1]
Also when I am using ./ as suggested, I get new error:
Array dimensions must match for binary array op.
Error in sobel (line 10)
x=x./max(max(x)); %normalisation to [0,1]
I am doing something wrong in the normalization step.
How do I resolve this issue?
Why do you call max twice. If I run the code with
x=x/max(x(:))
I do not get an error. This runs the matrix in 1D.
Whilst Caduceus' answer is correct; it normalises over all three colours in one go. What's probably better for your case is rgb2gray, to get a single colour channel and then normalise that instead (using x/max(x(:))).
X=imread ('lighthouse.png'); %reads picture as int8 matrix
filter=[-1 0 1; -2 0 2; -1 0 1]; % builds Sobel filter matrix
filter=single(filter); %convert double to single
x = single(rgb2gray(X)); % rgb2gray gives a uint8, you want single
% x=x/max(x(:)); %normalisation to [0,1] , not needed here as x can directly be used
% for Sobel purposes as it's a grey scale image.
figure;
subplot(1,2,1)
imagesc(X)
colormap(gray)
title('original picture'), % display picture
subplot(1,2,2)
imagesc(x)
colormap(gray)
title 'Grey scale'
The reason for the first error is is that max gives a column-wise maximum, and that this is a 3D matrix. max(max()) thus gives a 1D one, instead of the desired scalar.
Then the second error occurs because max(max()) gives an array, which doesn't have the same amount of entries as the full matrix (obviously).
Basically if size(x) = [row, column channels], size(max(x)) = [row channels]
and size(max(max(x)) = [row]. Using the colon operator actually makes the entire 3D matrix a single column vector, and max(x(:)) thus gives a single value, which is the maximum across all rows, columns and channels.
When I run your code the error message says "Use RDIVIDE (./)".
implement it like this:
x=x./max(max(x));
This divides each RGB layer by its maximum. You may have to replicate the max values (I guess this depends on matlab version), use this line instead
x=x./repmat(max(max(x)),size(X,1),size(X,2),1);

2D Discrete Cosine Transform using 1D DCT

I am trying to implement the 2D Discrete Cosine Transform to an image by using
1D DCT operations. My output is incorrect if I compare it to the dct2 MATLAB function. I don't understand what went wrong in my code and where it's happening.
If someone can point out the mistake or any other advice, that would be really helpful.
Here is my code written in MATLAB
% main function
signal=rand(100);
signal_dct=myDCT(signal);
figure; imshow((signal_dct));
% function to calculate 2D DCT of an image
function res=myDCT(signal)
signal=double(signal);
l=size(signal,1);
res=zeros(l); %initialize the final result matrix
for k=1:l %calculate 1D DCT of each row of image
res(k,:)=mdct(signal(k,:));
end
for k=1:l %calculate 1D DCT of each column of image
res(:,k)=mdct(res(:,k));
end
end
%% function to calculate 1D DFT of a 1D signal
function res=mdct(signal)
l=size(signal,1);
for i=1:l
if i==1 %for signal index of 1, alpha is 1/sqrt(l)
alpha=sqrt(1/l);
else %for signal index of greater than 1
alpha=sqrt(2/l);
end
j=[1:l];
% summation calculates single entry of res by applying the
% formula of DCT on the signal
summation=sum(sum(signal(j)*cos((pi*(2*(j-1)+1)*(i-1))/(2*l))));
res(i)=alpha*summation;
end
end
You are correct in that the 2D DCT is separable. You would just apply the 1D DCT to every row first, then take the intermediate result and apply it to the columns. However, you have two fundamental mistakes. Let's go through them.
Mistake #1 - Size of DCT isn't correct
Specifically, look at this statement in your mdct function:
l=size(signal,1);
Because you are applying the DCT for each row, then each column, the above would only work if you are applying the DCT to the columns. size(signal,1) would certainly give you the length of the input vector if the input was a column. However, if your input was a row, then the output of size(signal,1) would be 1. Therefore, you should replace size(signal,1) with numel so that you are for sure going to get the total number of elements - regardless if the input is a row or column.
Also, if you want to make the code compatible to do the summation in the DCT loop, you should make sure that the input is a row vector regardless. As such, do this instead:
l = numel(signal);
signal = signal(:).';
The first line determines how many elements we have for our input signal, and the second line ensures that we have a row vector. This is done by (:) to unroll the elements into a column vector, then doing .' after to ensure we transpose the result to get a row vector.
Mistake #2 - Summation statement isn't correct
Next, you're going to have to do element-wise multiplications in your summation to get what you're looking for. You also don't need the extra sum call there. It's superfluous. Therefore, modify your summation statement to this:
summation=sum(signal.*cos((pi*(2*(j-1)+1).*(i-1))/(2*l)));
There's no need to do signal(j) because j spans the entire length of the vector, and you can just do that with signal.
Once I made these changes, and I did this on a smaller size matrix to ensure that we get the same results:
rng(123123);
signal=rand(7);
signal_dct=myDCT(signal);
signal_dct2 = dct2(signal);
The last line of code calls dct2 so that we can compare the results from your custom function and what dct2 gives us.
We get:
>> signal_dct
signal_dct =
3.7455 -0.1854 -0.1552 0.3949 0.2182 -0.3707 0.2621
-0.2747 0.1566 -0.0955 0.1415 0.3156 -0.0503 0.8581
-0.2095 0.0233 -0.2769 -0.4341 -0.1639 0.3700 -0.2282
-0.0282 0.0791 0.0517 0.4749 -0.0169 -0.4327 0.0427
-0.4047 -0.4383 0.3415 -0.1120 -0.0229 0.0310 0.3767
-0.6058 -0.0389 -0.3460 0.2732 -0.2395 -0.2961 0.1789
-0.0648 -0.3173 -0.0584 -0.3461 -0.1866 0.0301 0.2710
>> signal_dct2
signal_dct2 =
3.7455 -0.1854 -0.1552 0.3949 0.2182 -0.3707 0.2621
-0.2747 0.1566 -0.0955 0.1415 0.3156 -0.0503 0.8581
-0.2095 0.0233 -0.2769 -0.4341 -0.1639 0.3700 -0.2282
-0.0282 0.0791 0.0517 0.4749 -0.0169 -0.4327 0.0427
-0.4047 -0.4383 0.3415 -0.1120 -0.0229 0.0310 0.3767
-0.6058 -0.0389 -0.3460 0.2732 -0.2395 -0.2961 0.1789
-0.0648 -0.3173 -0.0584 -0.3461 -0.1866 0.0301 0.2710
As you can see, both results match up. Looks good to me!
Just to be sure we are consistent, this is the full code listing for both your functions, with the modifications I made:
% function to calculate 2D DCT of an image
function res=myDCT(signal)
signal=double(signal);
l=size(signal,1);
res = zeros(l);
for k=1:l %calculate 1D DCT of each row of image
res(k,:)=mdct(signal(k,:));
end
for k=1:l %calculate 1D DCT of each column of image
res(:,k)=mdct(res(:,k));
end
end
%% function to calculate 1D DFT of a 1D signal
function res=mdct(signal)
%// Change
l = numel(signal);
signal = signal(:).';
for i=1:l
if i==1 %for signal index of 1, alpha is 1/sqrt(l)
alpha=sqrt(1/l);
else %for signal index of greater than 1
alpha=sqrt(2/l);
end
j=[1:l];
% summation calculates single entry of res by applying the
% formula of DCT on the signal
%// Change
summation=sum(signal.*cos((pi*(2*(j-1)+1).*(i-1))/(2*l)));
res(i)=alpha*summation;
end
end

calculate variance within each block of an image

When I tried to calculate the variance of each of the block within an image, the same way in which I have tried to calculate mean, it throws an error like:
??? Error using ==> var at 56
First argument must be single or double.
Error in ==> #(x)var(x(:))
Error in ==> assignemt at 19
varValues = cellfun(#(x) var(x(:)),b);
Could anyone help in this regard?
The code I have written is
clc;
close all;
d=8;
a=imread('lena.jpg');
figure();
imshow(a);
b=mat2cell(a,[16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16[16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16]);
[m,n]=size(b);
[m,n]=size(a);
%calculate mean for host image
% for i=1:m
% for j=1:n
% meanValues = cellfun(#(x) mean(x(:)),b);
% end
% end
% calculate variance for host image
for i=1:m
for j=1:n
varValues = cellfun(#(x) var(x(:)),b);
end
end
You are using x(:) which is a cell. Try using [x{:}]
Your code does not run, the mat2cell-line contains two [ and none ] so I did not try it out.
Your image a is of type uint8 and therefore var is failing. Try converting the image to double either by im2double or double(a)/255.
BTW, why don't you use blockproc, nlfilt2 or similar functions?

function taking in an input image and different kernel size

I have this filtering function that takes an input image, performs convolution using a given kernel, and returns the resulting image. However, I can't seem to work it out how to make it takes different kernel sizes.For example instead of pre-defined 3x3 kernel as below in the code, it could instead take 5x5 or 7x7. and then the user could input the type of kernel/filter they want(Depending on the intended effect). I can't seem to put my head around it. i'm quite new to matlab.
function [newImg] = kernelFunc(imgB)
img=imread(imgB);
figure,imshow(img);
img2=zeros(size(img)+2);
newImg=zeros(size(img));
for rgb=1:3
for x=1:size(img,1)
for y=1:size(img,2)
img2(x+1,y+1,rgb)=img(x,y,rgb);
end
end
end
for rgb=1:3
for i= 1:size(img2,1)-2
for j=1:size(img2,2)-2
window=zeros(9,1);
inc=1;
for x=1:3
for y=1:3
window(inc)=img2(i+x-1,j+y-1,rgb);
inc=inc+1;
end
end
kernel=[1;2;1;2;4;2;1;2;1]/16;
med=window.*kernel;
disp(med);
med=sum(med);
med=floor(med);
newImg(i,j,rgb)=med;
end
end
end
newImg=uint8(newImg);
figure,imshow(newImg);
end
I have commented the code and marked the places to change <--. kernel in this example is a column vector of 3*3=9 elements. Besides changing the kernel itself, you may also need to change the amount of zero-padding around the image. E.g., for a 5x5 kernel, you would need two rows and two columns of padding instead of one. Then update the inner loop I have marked "grab each pixel" to pull an area the size of the kernel (e.g., for x=1:5 and for y=1:5 for a 5x5 kernel). The actual convolution is unchanged.
Reminder: the function is taking a uint8 (0..255-valued) RGB image. window and kernel are double, so the trunc cuts any fractional part off before putting the new pixel value in uint8 newImg.
function [newImg] = kernelFunc(imgB)
img=imread(imgB);
figure,imshow(img);
img2=zeros(size(img)+2); % one extra column on each side, and one extra
% row top and bottom. <-- May need more padding.
newImg=zeros(size(img)); % the destination
% Pad the image with zeros at the left and top (transform img->img2)
for rgb=1:3
for x=1:size(img,1) %for each row
for y=1:size(img,2) %for each column
img2(x+1,y+1,rgb)=img(x,y,rgb); % <-- adjust per kernel size
end
end
end
% Process the padded image (img2->newImg)
for rgb=1:3
for i= 1:size(img2,1)-2 % for each row
for j=1:size(img2,2)-2 % for each column
% Build a row vector of the pixels to be convolved.
window=zeros(9,1); % <-- 9=kernel size
inc=1;
for x=1:3 % <-- grab each pixel
for y=1:3 % <-- under the kernel
window(inc)=img2(i+x-1,j+y-1,rgb);
inc=inc+1;
end
end
kernel=[1;2;1;2;4;2;1;2;1]/16; % <-- the kernel itself
med=window.*kernel; % start the convolution
disp(med);
med=sum(med); % finish the convolution
med=floor(med); % fit the pixels back into uint8.
newImg(i,j,rgb)=med; % store the result
end %for each column
end %for each row
end %for each color channel
newImg=uint8(newImg);
figure,imshow(newImg);
end

Difficulty with my self built histogram in MatLab

I am trying to implement a simple function that its the same with the default hist() by MatLab.
We have two same images with different brightness and we have to convert them to grayscale and then use the default function of MatLab hist() to get the histograms (so far so good!).
Then we have to implement the function hist my_hist() , and when i am trying to count the frequency of the intensity the results are not the same.
It seems that it sums-up the frequency of 254 & 255 to 254 and 255 is zero!I dont know what the problem is, any help would be appreciated.
here is the code for the command line:
%Read the images and convert them from rgb to grayscale
i=imread('pic1.jpg');
j=rgb2gray(i);
x=imread('pic2.jpg');
y=rgb2gray(x);
%Display the two images
figure
imshow(j)
figure
imshow(y)
%Display the histogram of the two images
[a,b] = hist(j(:),0:1:255);
figure
plot(b,a)
[c,d]=hist(y(:),0:1:255);
figure
plot(d,c)
%Call of the built-in function
my_hist('pic1.jpg','pic2.jpg')
And here is the code of the self built function:
function []= my_hist( x,y)
%Read the images and convert them from rgb to grayscale
pic1=imread(x);
i=rgb2gray(pic1);
pic2=imread(y);
j=rgb2gray(pic2);
%Initialize two vectors to be the axis for histogram
plotx=0:255;
ploty=zeros(1,256);
%Take the dimensions of the first image pic1
[m,n] = size(i);
%With 2 loops we go through the matrix of the image and count how many
%pixels have the same intensity
for k=1:m
for l=1:n
num=i(k,l)+1;
ploty(num)=ploty(num)+1;
end
end
%Display the histogram for the first image pic1
figure
plot(plotx,ploty);
%Initialize two vectors to be the axis for histogram
plotx2=0:255;
ploty2=zeros(1,256);
%Take the dimensions of the second image pic2
[m2,n2] = size(j);
%With 2 loops we go through the matrix of the image and count how many
%pixels have the same intensity
for o=1:m2
for p=1:n2
num2=j(o,p)+1;
ploty2(num2)=ploty2(num2)+1;
end
end
%Display the histogram for the second image pic2
figure
plot(plotx2,ploty2);
end
And here are the images pic1 and pic2.
This is a problem due to your image being of integer type uint8 which can only range from 0-255:
>> a= uint8(255)
a =
255
>> a=a+1
a =
255
Convert your data to say type uint16 with
j = uint16(j);
y = uint16(y);
and your problem should be gone:
>> a=uint16(a)
a =
255
>> a=a+1
a =
256