In Matlab, apparently, I get different values for width and height when I use size in these two ways:
% way 1
[height, width] = size(myLoadedImage);
% way 2
height = size(myLoadedImage, 1);
width = size(myLoadedImage, 2)
Why are these two ways different?
Read the complete help for the size function. Specifically it says
[d1,d2,d3,...,dn] = size(X), for n > 1, returns the sizes of the dimensions of
the array X in the variables d1,d2,d3,...,dn, provided the number of output
arguments n equals ndims(X).
If n does not equal ndims(X), the following exceptions hold:
n < ndims(X) di equals the size of the ith dimension of X for 0<i<n, but dn
equals the product of the sizes of the remaining dimensions of X,
that is, dimensions n through ndims(X).
As shown by your comment, your image is a 3-dimensional array. So as per the manual, if you are asking for only 2 out of the 3 sizes with [h,w] = size(...), the parameter w will contain the product of the 2nd and 3rd dimension. When doing h = size(..., 1) and w = size(..., 2), you get the exact values of the first and second dimensions.
Simulating your case:
>> im = randn(512, 143, 3);
>> h = size(im, 1)
h = 512
>> w = size(im, 2)
w = 143
>> [h, w] = size(im)
h = 512
w = 429
Note that in the last case w = 143 * 3 = 429.
In addition to #BasSwinckels explanation, you can write:
[h,w,~] = size(img);
This will work for any number of dimensions (grayscale image, RGB image, or higher dimension arrays).
Related
I need to take histogram of each splited image and i want to calculate mean and variance of the splited image. here i am getting an error while i calculating the mean value..... please guide me
[h w c] = size(x);
numSplits = 3; %
sw = floor(w/numSplits); %
widths = repmat(sw, 1, numSplits-1);
widths(numSplits) = w - sum(widths);
splits = mat2cell(x, h, widths, c);
% show the splits
for ii=1:numSplits
subplot(1,numSplits,ii);
imshow(splits{ii});
g(ii)=(splits{ii});
figure, imhist(g(ii));
end
%mean
im1=g(ii);
su=mean2(im1);
mean=ceil(su);
disp('mean Value');
disp(mean)
%variance
sv=double(im1);
v = var(sv);
disp(v)
i need to get the histograms of each seperate images and i need to calculate the mean for that splitted images
I assume that x is the image you want to split and analyze and that it is the image you have linked:
First, I load the image (you have already done this, I guess, so you do not need to copy this):
x = imread('https://i.stack.imgur.com/4PAaI.png');
The following code solves your coding errors:
[h, w, c] = size(x);
numSplits = 3; %
sw = floor(w/numSplits); %
widths = repmat(sw, 1, numSplits-1);
widths(numSplits) = w - sum(widths);
splits = mat2cell(x, h, widths, c);
results = repmat(struct('mean',[], 'variance',[]),numSplits, 1);
% show and analyze the splits
for ii=1:numSplits
subplot(2,numSplits,ii);
imshow(splits{ii});
subplot(2,numSplits, ii+numSplits);
imhist(splits{ii});
results(ii).mean = mean2(splits{ii});
results(ii).variance = (std2(splits{ii})).^2;
end
The mean and variance are stored in results:
>> results(1)
ans =
struct with fields:
mean: 118.0233
variance: 1.3693e+03
>> results(2)
ans =
struct with fields:
mean: 126.1719
variance: 1.9608e+03
>> results(3)
ans =
struct with fields:
mean: 121.9004
variance: 958.3740
However, please double check that you really want to compute the stats for the combined color channels of the images and not only for, for eample, the red one.
I want to verify the convolution theorem in matlab.
Firstly, I do a 2D discrete convolution of a 2D Gaussian with
an image graymap(x, y).
Secondly, I compute the Fourier Transform of
the same 2D Gaussian and of the original image. Then perform a scalar multiplication
of these two Fourier Transforms, followed by an inverse Fourier Transform of the result.
Finally, I will calculate the MSE between the two results. However, I found the err is 800+.
This is my code:
[row, col] = size(graymap);
[row_2, col_2] = size(z);
result = zeros(row, col);
for i = 1: col
for j = 1:row
accumulation_value = 0;
for k = -4:4
for h = -4:4
if ((i+k > 0 && i+k < col + 1) && (j+h > 0 && j+h < row + 1))
value_image = double(graymap(i+k, j+h));
else
value_image = 0;
end
accumulation_value = accumulation_value + value_image * double(z(5 + k, 5 + h));
weighted_sum = weighted_sum + z(5 + k, 5 + h);
end
end
result(i,j) = (accumulation_value);
end
result_blur_1 = uint8(255*mat2gray(result));
M = size(graymap,1);
N = size(graymap,2);
resIFFT = ifft2(fft2(double(graymap), M, N) .* fft2(double(z), M, N));
result_blur_2 = uint8(255*mat2gray(resIFFT));
err = immse(result_blur_1, result_blur_2);
z is the 9*9 gaussian kernel. I don't flip it because it is symmetric.
I think my implementation of convolution is correct because the result is same as conv2(graymap, z, 'same').
Therefore, I believe there are something wrong with the second part. In fact, I am confused on how padding works. May it is the cause of the big MSE.
There are indeed problems with your implementation of the second part. The most important rule to remember when implementing convolution via fft is that you are actually calculating a circular convolution, not a linear convolution. Fortunately, there is a condition under which the two become equivalent. This condition is that the two arrays should be zero-padded to have a size equal to the sum of the sizes of each minus 1 (in all dimensions). So if you are working with an image X of size MxN, and a mask Z of size PxQ, then you should pad the two arrays with zeros to so they have at least dimensions M+P-1xN+Q-1. Any additional zeros won't hurt, so it's convenient to match a 'fft-friendly' size if possible (using nextpow2 for example). You just have to take the first M+P-1xN+Q-1 values.
Now, that would work straight forward if you just wanted the full result of the convolution. But because you want the central part of the convolution (the option 'same'), you need to select the correct indexes. The first index will be ceil(([P Q] - 1)/2) + 1, and then you take as many consecutive indexes as the image size.
Here is an example putting all together:
M = randperm(1024,1);
N = randperm(1024,1);
X = rand(M,N);
P = randperm(64,1);
Q = randperm(64,1);
Z = rand(P,Q);
% 'standard' convolution with option 'same'
C1 = conv2(X,Z,'same');
R = 2^nextpow2(M+P-1);
S = 2^nextpow2(N+Q-1);
% convolution with fft. Notice the zero-padding to R,S
C2 = real(ifft2(fft2(X,R,S) .* fft2(Z,R,S)));
n = ceil(([P Q] - 1)/2);
ind{1} = n(1) + (1:M);
ind{2} = n(2) + (1:N);
C2 = C2(ind{:});
err = immse(C1,C2)
I get errors of the order of 1e-26
I'm trying to make a kind of hsv histogram by converting the rgb values of a picture (80*120).
This is the code:
function Image_histogram = hsvHistogram(path, count_bins)
Image = double(imread(path));
Image_histogram = zeros(3 * count_bins);
[n m] = size(Image);
H_vect = zeros(n, m);
S_vect = zeros(n, m);
V_vect = zeros(n, m);
hue_vect = zeros(1, count_bins);
saturation_vect = zeros(1, count_bins);
value_vect = zeros(1, count_bins);
for line = 1 : n
for row = 1 : m
%[H_vect(line, row), S_vect(line, row), V_vect(line, row)] = rgb2hsv(Image(line, row, 1), Image(line, row, 2), Image(line, row, 3));
endfor
endfor
number = 100/count_bins;
for count = 0 : count_bins - 1
left = (number * count);
right = (number * count + number);
hue_vect(1, count + 1) = (sum(sum(H_vect(:,:) >= left & H_vect(:,:) < right)));
saturation_vect(1, count + 1) = (sum(sum(S_vect(:,:) >= left & S_vect(:,:) < right)));
value_vect(1, count + 1) = (sum(sum(V_vect(:,:) >= left & V_vect(:,:) < right)));
endfor
Image_histogram = horzcat(hue_vect, saturation_vect, value_vect);
endfunction
When i try to get the HSV matrix i always get the error : hsvHistogram: A(I,J,...): index to dimension 2 out of bounds; value 121 out of bound 120
rgb2hsv is a pixel by pixel converter. It converts R G B to H S V. It is not the built-in rgb2hsv function. The commented line seems to be the one with problems.
The problem is in the size() function.
If such image is RGB, the matrix Image will be a 3D matrix but in your size() function you just gather two outputs, which will lead to incorrect results.
You must gather all three outputs (for all three dimensions) and then eventually discard the third one (which we know it is 3). Try doing:
[n,m,~]=size(Image);
More into details, if your matrix has size n x m x q but you ask just for two outputs, like
[a,b]=size(Image);
you’ll have a=n and b=m*q.
These results are obviously incorrect because since q>1 then b>m where m is (again) the actual dimension size and you’ll experience the out-of-bounds error. In other words, the loop will run from 1 to b whereas the matrix has only dimension m (which is less than b).
As instead you must gather all three dimensions separately:
[a,b,c]=size(Image);
and (as above) eventually discard some unnecessary output arguments (thanks to the tilde ~ operator).
I am trying to create a matrix (32 x 32) with -1 on its main diagonal and 1 in its first and second superdiagonals. 0 everywhere else.
A = eye(32)* -1;
That gives me a matrix with -1 on its main diagonal, how do I proceed?
n=32;
toeplitz([-1; zeros(n-1,1)],[-1 1 1 zeros(1,n-3)])
is what you need. This will create a non-symmetric Toeplitz matrix (a band matrix), the first column of which is given by [-1; zeros(32-1,1)], the first row by [-1 1 1 zeros(1,32-3)]. You could also define a function with size n as input parameter, if necessary.
You can use spdiags to set the diagonals directly into a sparse matrix and full-it if desired.
n = 32;
Asparse = spdiags(ones(n,1)*[-1,1,1],[0,1,2],n,n);
Afull = full(Asparse);
n = 32
A = -1*eye(n); %Create 32x32 Identity
A(n+1:n+1:n^2) = 1; %Set 1st Superdiagonal to 1
A(2*n+1:n+1:n^2) = 1; %Set 2nd Superdiagonal to 1
Note that MATLAB uses column-major order for matrices. For the 1st superdiagonal, we start with the (n+1)th element and choose every (n+1)th element thereon. We do a similar operation for 2nd superdiagonal except we start from (2*n+1)th element.
Just using diag and eye:
n = 32;
z = ones(n-1,1);
A = diag(z,1)+diag(z(1:n-2),2)-eye(n);
There's also:
n = 32;
A = gallery('triw',n,1,2)-2*eye(n)
using the gallery function with the 'triw' option.
diag allows you to create a matrix passing a diagonal:
-diag(ones(n,1),0)+diag(ones(n-1,1),1)+diag(ones(n-2,1),2)
Last parameter 0 for the main diagonal, 1 and 2 for the super diagonals.
If I can suggest more esoteric code, first create a vector full of 1s, then create the identity matrix, then shift create a diagonal matrix with these 1s with the vector and shift it to the right by 1, decreasing the amount of elements in the vector, then do it again for the last superdiagonal.
n = 32;
vec = ones(n,1);
out = -eye(n) + diag(vec(1:end-1),1) + diag(vec(1:end-2),2);
N = 32;
A = -diag(ones(N,1)); % diagonal
tmp1=diag(ones(N-1,1),1); %1st supra
tmp1=diag(ones(N-2,1),2); #2nd supra
A = A+tmp1+tmp2;
using diag
Yet another approach: this uses convmtx from the Signal Processing Toolbox:
n = 32; %// matrix size
v = [-1 1 1]; %// vector with values
M = convmtx(v, n);
M = M(:,1:end-numel(v)+1);
I have a huge waveform matrix:
[w,fs] = wavread('file.wav');
length(w)
ans =
258048
I want to go through this matrix in segments (say 50) and get the maximum of these segments to compare it to another value. I tried this:
thold = max(w) * .04;
nwindows = 50;
left = 1;
right = length(w)/nwindows;
counter = 0;
for i = 1:nwindows
temp = w(left:right);
if (max(temp) > thold)
counter = counter + 1;
end
left = right;
right = right+right;
end
But MATLAB threw tons of warnings and gave me this error:
Index exceeds matrix dimensions.
Error in wlengthdur (line 17)
temp = w(left:right);
Am I close or way off course?
An alternative approach would be to use reshaped to arrange you vector in to a 2D matrix with number of row n and columns equal to ceil(length(w) / n) i.e. round up so that it is divisible as matlab matrices must be rectangular. This way you can find the max or whatever you need in one step without looping.
w = randn(47, 1);
%this needs to be a column vector, if yours isn't call w = w(:) to ensure that it is
n = 5;
%Pad w so that it's length is divisible by n
padded = [w; nan(n - mod(length(w), n), 1)];
segmented_w = reshape(padded, n, []);
max(segmented_w)