I have a figure like x axis Bit Error Rate and y axis Data Rate. And I want to find minimum Bit Error Rate and maximum Data rate in this figure. Namely I want to do thing that in this figure there are 18 points and I want to find optimal result but I cannot it ?
I believe what you are asking is to find the optimal ratio between BitErrorRate and DataRate, in that case you need to calculate the ratio of BitErrorRate per DataRate and then find the min or max of that depending on whether you are looking for fewer or more BitErrorRate per DataRate. Assuming the BitErrorRate and BitRate are saved in arrays you could use code like this:
% Give some random numbers to illustrate functionality
BitErrorRate = [2 7 3 5 8 1];
DataRate = [1 3 4 2 6 5];
% Find the ratio of BitErrorRate per DataRate
ErrorRatio = BitErrorRate ./ BitRate;
% Optimal ratio with minimal errors per data rate and corresponding index
[MinError, MinIndex] = min(ErrorRatio);
% Print results in console
disp(['Optimal error rate ratio is ' num2str(ErrorRatio(MinIndex)) ...
' BitErrorRate per DataRate with a Bit Error Rate of ' ...
num2str(BitErrorRate(MinIndex)) ' and a Bit Rate of ' ...
num2str(BitRate(MinIndex)) '.']);
% Sort in ascending manner according to top row, below this is DataRate
SortedForDataRate = sortrows([DataRate;BitErrorRate;ErrorRatio]')';
fig = figure(1);
subplot(3,1,1)
plot(SortedForDataRate(1,:))
title('BitErrorRate')
subplot(3,1,2)
plot(SortedForDataRate(2,:))
title('DataRate')
subplot(3,1,3)
plot(SortedForDataRate(3,:))
title('ErrorRatio')
Related
I would like to calculate the median of each pixel in a set of images or "video". However, when MATLAB starts calculating this, it takes a very long time and finishes randomly with an index error. Why?
This is the code:
V = VideoReader('hall_monitor.avi');
info = get(V);
M = info.Width;
N = info.Height;
nb_frames_bk = 5;
v_pixel = zeros([nb_frames_bk 3]);
IB=zeros([M N 3],'double');
for i=1:M
for j=1:N
for k=1:nb_frames_bk
frm=read(V,k);
v_pixel(k,:)=frm(i,j,:);
end
IB(i,j,:)=median(v_pixel(:,:));
end
end
IB=uint8(IB);
imshow(IB);
This code can benefit from a lot of refactoring. For one thing, you are re-reading frames when you can just read them once, store them and use them after you're done.
Secondly, iterating over all pixels to compute your median is going to be very slow. From what it looks like in your code, for each spatial position over the first nb_frames_bk frames, you collect all of the RGB values within these frames and calculate the median RGB value.
Also as a minor note, you are getting a dimension exceeds error because you defined the output matrix wrong. You defined it as M x N with M being the width and N being the height. This needs to be swapped. Remember that matrices are defined as height first, width second. However, this is unnecessary with what I'm going to suggest for implementing this properly.
Instead of reading the frames one at a time, specify a range of frames. This way, you will get a 4D matrix where the first three dimensions references an image, with the fourth dimension representing the frame number. You can then take the median in the fourth dimension to find the median RGB value over all frames.
In other words, simply do this:
V = VideoReader('hall_monitor.avi');
nb_frames_bk = 5;
frms = read(V, [1 nb_frames_bk]);
IB = median(frms, 4);
imshow(IB);
This is much better, to the point and guaranteed to be faster. You also don't need to obtain the width and height of each frame as it is no longer needed as we are no longer looping over each pixel.
I have a three dimensional cell that holds images (i.e. images = cell(10,4,5)) and each cell block holds images of different sizes. The sizes are not too important in terms of what I’m trying to achieve. I would like to know if there is an efficient way to compute the sharpness of each of these cell blocks (total cell blocks = 10*4*5 = 200). I need to compute the sharpness of each block using the following function:
If it matters:
40 cell blocks contain images of size 240 X 320
40 cell blocks contain images of size 120 X 160
40 cell blocks contain images of size 60 X 80
40 cell blocks contain images of size 30 X 40
40 cell blocks contain images of size 15 X 20
which totals to 200 cells.
%% Sharpness Estimation From Image Gradients
% Estimate sharpness using the gradient magnitude.
% sum of all gradient norms / number of pixels give us the sharpness
% metric.
function [sharpness]=get_sharpness(G)
[Gx, Gy]=gradient(double(G));
S=sqrt(Gx.*Gx+Gy.*Gy);
sharpness=sum(sum(S))./(480*640);
Currently I am doing the following:
for i = 1 : 10
for j = 1 : 4
for k = 1 : 5
sharpness = get_sharpness(images{i,j,k});
end
end
end
The sharpness function isn’t anything fancy. I just have a lot of data hence it takes a long time to compute everything.
Currently I am using a nested for loop that iterates through each cell block. Hope someone can help me find a better solution.
(P.S. This is my first time asking a question hence if anything is unclear please ask further questions. THANK YOU)
I'm trying to create a mozaic image in Matlab. The database consists of mostly RGB images but also some gray scale images.
I need to calculate the histograms - like in the example of the Wikipedia article about color histograms - for the RGB images and thought about using the bitshift operator in Matlab to combine the R,G and B channels.
nbins = 4;
nbits = 8;
index = bitshift(bitshift(image(:,:,1), log2(nbins)-nbits), 2*log2(nbins)) + ...
+ bitshift(bitshift(image(:,:,2), log2(nbins)-nbits), log2(nbins)) + ...
+ bitshift(image(:,:,3), log2(nbins)-nbits) + 1;
index is now a matrix of the same size as image with the index to the corresponding bin for the pixel value.
How can I sum the occurences of all unique values in this matrix to get the histogram of the RGB image?
Is there a better approach than bitshift to calculate the histogram of an RGB image?
Calculating Indices
The bitshift operator seems OK to do. Me what I would personally do is create a lookup relationship that relates RGB value to bin value. You first have to figure out how many bins in each dimension that you want. For example, let's say we wanted 8 bins in each channel. This means that we would have a total of 512 bins all together. Assuming we have 8 bits per channel, you would produce a relationship that creates an index like so:
% // Figure out where to split our bins
accessRed = floor(256 / NUM_RED_BINS);
accessGreen = floor(256 / NUM_GREEN_BINS);
accessBlue = floor(256 / NUM_BLUE_BINS);
%// Figures out where to index the histogram
redChan = floor(red / accessRed);
greenChan = floor(green / accessGreen);
blueChan = floor(blue / accessBlue);
%// Find single index
out = 1 + redChan + (NUM_RED_BINS)*greenChan + (NUM_RED_BINS*NUM_GREEN_BINS)*blueChan;
This assumes we have split our channels into red, green and blue. We also offset our indices by 1 as MATLAB indexes arrays starting at 1. This makes more sense to me, but the bitshift operator looks more efficient.
Onto your histogram question
Now, supposing you have the indices stored in index, you can use the accumarray function that will help you do that. accumarray takes in a set of locations in your array, as well as "weights" for each location. accumarray will find the corresponding locations as well as the weights and aggregate them together. In your case, you can use sum. accumarray isn't just limited to sum. You can use any operation that provides a 1-to-1 relationship. As an example, suppose we had the following variables:
index =
1
2
3
4
5
1
1
2
2
3
3
weights =
1
1
1
2
2
2
3
3
3
4
4
What accumarray will do is for each value of weights, take a look at the corresponding value in index, and accumulate this value into its corresponding slot.
As such, by doing this you would get (make sure that index and weights are column vectors):
out = accumarray(index, weights);
out =
6
7
9
2
2
If you take a look, all indices that have a value of 1, any values in weights that share the same index of 1 get summed into the first slot of out. We have three values: 1, 2 and 3. Similarly, with the index 2 we have values of 1, 3 and 3, which give us 7.
Now, to apply this to your application, given your code, your indices look like they start at 1. To calculate the histogram of your image, all we have to do is set all of the weights to 1 and use accumarray to accumulate the entries. Therefore:
%// Make sure these are column vectors
index = index(:);
weights = ones(numel(index), 1);
%// Calculate histogram
h = accumarray(index, weights);
%// You can also do:
%// h = accumarray(index, 1); - This is a special case if every value
%// in weights is the same number
accumarray's behaviour by default invokes sum. This should hopefully give you what you need. Also, should there be any indices that are missing values, (for example, suppose the index of 2 is missing from your index matrix), accumarray will conveniently place a zero in this location when you aggregate. Makes sense right?
Good luck!
In Matlab I've got a 3D matrix (over 100 frames 512x512). My goal is to find some representative points through the whole hyper-matrix. To do so I've implemented the traditional (and not very efficient) method: I subdivide the large matrix into smaller sub-matrices and then I look for the pixel with the highest value. After doing that I change those relative coordinates of that very pixel in the sub-matrix to global coordinates referenced to the large matrix.
Now, I'm redesigning the algorithm. I've seen that in order to analyze a large matrix block-by-block (that's actually what I'm doing with my old algorithm) the BLOCKPROC function is very efficient. I've read the documentation but I don't know how the "fun" function should be implemented to extract that the pixel with the highest value of each block. Thank you in advance.
*I'm trying to get the coordinates of those maximum pixels referenced to the global matrix, I really don't care about their value.
First define a function to find the location of the maximum of a (sub)matrix:
function loc = max_location(M);
[~, ii] = max(M(:));
[r c] = ind2sub(size(M),ii);
loc = [r c];
Then use
blockproc(im, blocksize, #(x) x.location+max_location(x.data)-1)
where im is your image (2D array) and blocksize is a 1x2 vector specifying block size. Within blockproc, the data field is the submatrix (which you pass to max_location), and the location field contains the coordinates of the top-left corner of the submatrix (which you add to the result of max_location, minus 1).
Example:
>> blocksize = [3 3];
>> im = [ 0.3724 0.0527 0.4177 0.6981 0.0326 0.4607
0.1981 0.7379 0.9831 0.6665 0.5612 0.9816
0.4897 0.2691 0.3015 0.1781 0.8819 0.1564
0.3395 0.4228 0.7011 0.1280 0.6692 0.8555
0.9516 0.5479 0.6663 0.9991 0.1904 0.6448
0.9203 0.9427 0.5391 0.1711 0.3689 0.3763 ];
>> blockproc(im, blocksize, #(x) x.location+max_location(x.data)-1)
ans =
2 3 2 6
5 1 5 4
meaning your block maxima are located at coordinates (2,3), (5,1), (2,6) and (5,4)
Another possiblity is to use im2col for each frame. If I is your frame (512,512):
% rearranges 512 x 512 image into 4096 x 64
% each column of I2 represents a 64 x 64 block
n = 64;
I2 = im2col(I,[n,n],'distinct');
% find max in each block
% ~ to ignore that output
[~,y] = max(I2);
% convert those values to overall indices
ind = sub2ind(size(I2),y, 1:n);
% create new matrix
I3 = zeros(size(I2));
I3(ind)=1;
I3 = col2im(I3,[n,n],size(I),'distinct');
I3 should now be an image the same size of input I but with all zeros except for the locations of the maximum points in each sub-matrix.
the tricky part with the function handle "fun" is that it refers to the subblocks which are a struct, this is an object with one or more fields and one or more values assigend to each of the fields.
The values of your subblocks are stored in a field called "data" so the function call
#(x)max(x)
is not enough, in this case the correct version of that is
#(x)max(x.data)
A 2D example of what you are looking for would look like this:
a=magic(4);
b=blockproc(a,[2,2],#(x) find(x.data==max(max(x.data)))); %linear indexes
outputs
a =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
b =
1 3
4 2
b are the linear indexes of each subblock, so that's the values 16, 13, 14, 15 in a.
Hope that helps!
I want to know the frequency of data. I had a little bit idea that it can be done using FFT, but I am not sure how to do it. Once I passed the entire data to FFT, then it is giving me 2 peaks, but how can I get the frequency?
Thanks a lot in advance.
Here's what you're probably looking for:
When you talk about computing the frequency of a signal, you probably aren't so interested in the component sine waves. This is what the FFT gives you. For example, if you sum sin(2*pi*10x)+sin(2*pi*15x)+sin(2*pi*20x)+sin(2*pi*25x), you probably want to detect the "frequency" as 5 (take a look at the graph of this function). However, the FFT of this signal will detect the magnitude of 0 for the frequency 5.
What you are probably more interested in is the periodicity of the signal. That is, the interval at which the signal becomes most like itself. So most likely what you want is the autocorrelation. Look it up. This will essentially give you a measure of how self-similar the signal is to itself after being shifted over by a certain amount. So if you find a peak in the autocorrelation, that would indicate that the signal matches up well with itself when shifted over that amount. There's a lot of cool math behind it, look it up if you are interested, but if you just want it to work, just do this:
Window the signal, using a smooth window (a cosine will do. The window should be at least twice as large as the largest period you want to detect. 3 times as large will give better results). (see http://zone.ni.com/devzone/cda/tut/p/id/4844 if you are confused).
Take the FFT (however, make sure the FFT size is twice as big as the window, with the second half being padded with zeroes. If the FFT size is only the size of the window, you will effectively be taking the circular autocorrelation, which is not what you want. see https://en.wikipedia.org/wiki/Discrete_Fourier_transform#Circular_convolution_theorem_and_cross-correlation_theorem )
Replace all coefficients of the FFT with their square value (real^2+imag^2). This is effectively taking the autocorrelation.
Take the iFFT
Find the largest peak in the iFFT. This is the strongest periodicity of the waveform. You can actually be a little more clever in which peak you pick, but for most purposes this should be enough. To find the frequency, you just take f=1/T.
Suppose x[n] = cos(2*pi*f0*n/fs) where f0 is the frequency of your sinusoid in Hertz, n=0:N-1, and fs is the sampling rate of x in samples per second.
Let X = fft(x). Both x and X have length N. Suppose X has two peaks at n0 and N-n0.
Then the sinusoid frequency is f0 = fs*n0/N Hertz.
Example: fs = 8000 samples per second, N = 16000 samples. Therefore, x lasts two seconds long.
Suppose X = fft(x) has peaks at 2000 and 14000 (=16000-2000). Therefore, f0 = 8000*2000/16000 = 1000 Hz.
If you have a signal with one frequency (for instance:
y = sin(2 pi f t)
With:
y time signal
f the central frequency
t time
Then you'll get two peaks, one at a frequency corresponding to f, and one at a frequency corresponding to -f.
So, to get to a frequency, can discard the negative frequency part. It is located after the positive frequency part. Furthermore, the first element in the array is a dc-offset, so the frequency is 0. (Beware that this offset is usually much more than 0, so the other frequency components might get dwarved by it.)
In code: (I've written it in python, but it should be equally simple in c#):
import numpy as np
from pylab import *
x = np.random.rand(100) # create 100 random numbers of which we want the fourier transform
x = x - mean(x) # make sure the average is zero, so we don't get a huge DC offset.
dt = 0.1 #[s] 1/the sampling rate
fftx = np.fft.fft(x) # the frequency transformed part
# now discard anything that we do not need..
fftx = fftx[range(int(len(fftx)/2))]
# now create the frequency axis: it runs from 0 to the sampling rate /2
freq_fftx = np.linspace(0,2/dt,len(fftx))
# and plot a power spectrum
plot(freq_fftx,abs(fftx)**2)
show()
Now the frequency is located at the largest peak.
If you are looking at the magnitude results from an FFT of the type most common used, then a strong sinusoidal frequency component of real data will show up in two places, once in the bottom half, plus its complex conjugate mirror image in the top half. Those two peaks both represent the same spectral peak and same frequency (for strictly real data). If the FFT result bin numbers start at 0 (zero), then the frequency of the sinusoidal component represented by the bin in the bottom half of the FFT result is most likely.
Frequency_of_Peak = Data_Sample_Rate * Bin_number_of_Peak / Length_of_FFT ;
Make sure to work out your proper units within the above equation (to get units of cycles per second, per fortnight, per kiloparsec, etc.)
Note that unless the wavelength of the data is an exact integer submultiple of the FFT length, the actual peak will be between bins, thus distributing energy among multiple nearby FFT result bins. So you may have to interpolate to better estimate the frequency peak. Common interpolation methods to find a more precise frequency estimate are 3-point parabolic and Sinc convolution (which is nearly the same as using a zero-padded longer FFT).
Assuming you use a discrete Fourier transform to look at frequencies, then you have to be careful about how to interpret the normalized frequencies back into physical ones (i.e. Hz).
According to the FFTW tutorial on how to calculate the power spectrum of a signal:
#include <rfftw.h>
...
{
fftw_real in[N], out[N], power_spectrum[N/2+1];
rfftw_plan p;
int k;
...
p = rfftw_create_plan(N, FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE);
...
rfftw_one(p, in, out);
power_spectrum[0] = out[0]*out[0]; /* DC component */
for (k = 1; k < (N+1)/2; ++k) /* (k < N/2 rounded up) */
power_spectrum[k] = out[k]*out[k] + out[N-k]*out[N-k];
if (N % 2 == 0) /* N is even */
power_spectrum[N/2] = out[N/2]*out[N/2]; /* Nyquist freq. */
...
rfftw_destroy_plan(p);
}
Note it handles data lengths that are not even. Note particularly if the data length is given, FFTW will give you a "bin" corresponding to the Nyquist frequency (sample rate divided by 2). Otherwise, you don't get it (i.e. the last bin is just below Nyquist).
A MATLAB example is similar, but they are choosing the length of 1000 (an even number) for the example:
N = length(x);
xdft = fft(x);
xdft = xdft(1:N/2+1);
psdx = (1/(Fs*N)).*abs(xdft).^2;
psdx(2:end-1) = 2*psdx(2:end-1);
freq = 0:Fs/length(x):Fs/2;
In general, it can be implementation (of the DFT) dependent. You should create a test pure sine wave at a known frequency and then make sure the calculation gives the same number.
Frequency = speed/wavelength.
Wavelength is the distance between the two peaks.