Matlab : create my own dct2 - matlab

==Question solved==
This code will get you the dct2 output.
I am working to make improvement on my own codes
Thank you.
%Get the size of the input image
[m, n] = size(image);
output = zeros(m,n);
for u = 0:m-1
for v = 0:n-1
if u==0
a=sqrt(1/8);
else
a=sqrt(2/8);
end
if v==0
b=sqrt(1/8);
else
b=sqrt(2/8);
end
temp = 0;
for x = 0:m-1
for y = 0:n-1
temp = (cos((((2*x)+1)*pi*u)/(2*m))*cos((((2*y)+1)*pi*v)/(2*n)));
end
end
output(u+1,v+1) = a*b*temp;
end
end

There are two problems with your code if you are trying to compare it to the Matlab function dct2. For the record, you can open and analyze the files to understand what Matlab is doing.
In both case you are not following the formula:
a and b need to be a function of n:
if u==0
a=sqrt(1/n);
else
a=sqrt(2/n);
end
if v==0
b=sqrt(1/n);
else
b=sqrt(2/n);
end
You need to multiply your temp term by the image values (which you are not doing):
temp = temp+(image(x+1,y+1))*(cos((((2*x)+1)*pi*u)/(2*m))*cos((((2*y)+1)*pi*v)/(2*n)));
I haven't addressed the performance problem, and you really should look into that on your own.

Related

Optimization of column shifting of large matrices (Circshift, etc.)

I am currently looking for the most efficient way to shift and rearrange large matrices. Essentially, I have data with some parabolic shift that needs to be corrected in order to shift the "signal" to a linear event.
I have currently tried the following solutions and tried timing them. Is there any other method that may prove to be more efficient?
DATA = ones(100000,501);
DATA(10000,251) = 100;
for i=1:250
DATA(10000+i^2-1000:10000+i^2+1000,251-i) = 100;
DATA(10000+i^2-1000:10000+i^2+1000,251+i) = 100;
end
k = abs(-250:1:250).^2;
d = size(DATA,1);
figure(99)
imagesc(DATA)
t_INDEX = timeit(#()fun_INDEX(DATA,k))
t_SNIPPET = timeit(#()fun_SNIPPET(DATA,k))
t_CIRCSHIFT = timeit(#()fun_CIRCSHIFT(DATA,k))
t_INDEX_clean = timeit(#()fun_INDEX_clean(DATA,k))
t_SPARSE = timeit(#()fun_SPARSE(DATA,k))
t_BSXFUN = timeit(#()fun_BSXFUN(DATA,k))
function fun_INDEX(DATA,k)
DATA_1 = zeros(size(DATA));
for i=1:size(DATA,2)
DATA_1(:,i) = DATA([k(i)+1:end 1:k(i)],i);
end
figure(1)
imagesc(DATA_1)
end
function fun_SNIPPET(DATA,k)
kmax = max(k);
DATA_2 = zeros(size(DATA,1)-kmax,size(DATA,2));
for i=1:size(DATA,2)
DATA_2(:,i) = DATA(k(i)+1:end-kmax+k(i),i);
end
figure(2)
imagesc(DATA_2)
end
function fun_CIRCSHIFT(DATA,k)
DATA_3 = zeros(size(DATA));
for i=1:size(DATA,2)
DATA_3(:,i) = circshift(DATA(:,i),-k(i),1);
end
figure(3)
imagesc(DATA_3)
end
function fun_INDEX_clean(DATA,k)
[m, n] = size(DATA);
k = size(DATA,1)-k;
DATA_4 = zeros(m, n);
for i = (1 : n)
DATA_4(:, i) = [DATA((m - k(i) + 1 : m), i); DATA((1 : m - k(i) ), i)];
end
figure(4)
imagesc(DATA_4)
end
function fun_SPARSE(DATA,k)
[m,n] = size(DATA);
k = -k;
S = full(sparse(mod(k,m)+1,1:n,1,m,n));
DATA_5 = ifft(fft(DATA).*fft(S),'symmetric');
figure(5)
imagesc(DATA_5)
end
function fun_BSXFUN(DATA,k)
DATA = DATA';
k = -k;
[m,n] = size(DATA);
idx0 = mod(bsxfun(#plus,n-k(:),1:n)-1,n);
DATA_6 = DATA(bsxfun(#plus,(idx0*m),(1:m)'));
figure(6)
imagesc(DATA_6)
end
Is there any way to decrease computation time for this kind of problem?
Thanks in advance for any tips!
One option would be to use MATLAB's GPU functions, if your workstation has a GPU. Depending on if the entire data fits on the GPU at once, it will start to outperform CPU circshift at 1000 X 1000 matrix size.
The implementation only requires you to copy your data to the GPU with a single statement, and then operate circshift on the newly created you array.
A small discussion on its performance can be found here: https://www.mathworks.com/matlabcentral/answers/274619-circshift-slower-on-gpu . Especially, the last post describes a much faster GPU implementation if you actually don't need to circularly shift, but can get away with zero passing on one side, which might be relevant.

Convesion vector Index exceeds array bounds - matlab

I build some program in Matlab for "Histograma matching".
When I'm trying to implement the function "conVector" I get the error
"Index exceeds array bounds." anyone can help me with this error?
Here is my full code. Thank you!
function [newImage] = histShape (srcimg,destimg)
%find the histogram of the image
src = imgHist(srcimg);
dest = imgHist(destimg);
sna = normalizationHist(src);
dna = normalizationHist(dest);
conVector(sna,dna);
end
function [Hist] = imgHist (img)
[Rows,Cols] = size(img);
Hist = zeros(1,256);
for i=1:Rows
for j=1:Cols
Hist(img(i,j)+1)=Hist(img(i,j)+1)+1;
end
end
end
function [Ahist] = normalizationHist (hist)
[Rows,Cols] = size(hist);
Ahist = hist;
for i=2:256
Ahist(i)=Ahist(i-1)+hist(i);
end
Ahist = Ahist/(Rows*Cols);
end
function [cv] = conVector(SNA,DNA)
cv=zeros(1,257);
s = 1;
d = 1;
while s<=256
if DNA(d)<SNA(s)
d = d+1;
else
cv(s)=d;
s = s+1;
end
end
end
If all values in DNA(d:end) are smaller then the value in SNA(s) than the loop keep adding 1 to d but not to s, and finally goes out of bound because it conditioned only by s.
I guess you should either take the s = s+1 out of the inner condition, so it will be executed on every iteration, or add a condition on d to the loop, or convert it to a for loop.

parfor doesn't consider information about vectors which are used in it

This is a part of my code in Matlab. I tried to make it parallel but there is an error:
The variable gax in a parfor cannot be classified.
I know why the error occurs. because I should tell Matlab that v is an incresing vector which doesn't contain repeated elements. Could anyone help me to use this information to parallelize the code?
v=[1,3,6,8];
ggx=5.*ones(15,14);
gax=ones(15,14);
for m=v
if m > 1
parfor j=1:m-1
gax(j,m-1) = ggx(j,m-1);
end
end
if m<nn
parfor jo=m+1:15
gax(jo,m) = ggx(jo,m);
end
end
end
Optimizing a code should be closely related to its purpose, especially when you use parfor. The code you wrote in the question can be written in a much more efficient way, and definitely, do not need to be parallelized.
However, I understand that you tried to simplify the problem, just to get the idea of how to slice your variables, so here is a fixed version the can run with parfor. But this is surely not the way to write this code:
v = [1,3,6,8];
ggx = 5.*ones(15,14);
gax = ones(15,14);
nn = 5;
for m = v
if m > 1
temp_end = m-1;
temp = ggx(:,temp_end);
parfor ja = 1:temp_end
gax(ja,temp_end) = temp(ja);
end
end
if m < nn
temp = ggx(:,m);
parfor jo = m+1:15
gax(jo,m) = temp(jo);
end
end
end
A vectorized implementation will look like this:
v = [1,3,6,8];
ggx = 5.*ones(15,14);
gax = ones(15,14);
nn = 5;
m1 = v>1; % first condition with logical indexing
temp = v(m1)-1; % get the values from v
r = ones(1,sum(temp)); % generate a vector of indicies
r(cumsum(temp)) = -temp+1; % place the reseting locations
r = cumsum(r); % calculate the indecies
r(cumsum(temp)) = temp; % place the ending points
c = repelem(temp,temp); % create an indecies vector for the columns
inds1 = sub2ind(size(gax),r,c); % convert the indecies to linear
mnn = v<nn; % second condition with logical indexing
temp = v(mnn)+1; % get the values from v
r_max = size(gax,1); % get the height of gax
r_count = r_max-temp+1; % calculate no. of rows per value in v
r = ones(1,sum(r_count)); % generate a vector of indicies
r([1 r_count(1:end-1)+1]) = temp; % set the t indicies
r(cumsum(r_count)+1) = -(r_count-temp)+1; % place the reseting locations
r = cumsum(r(1:end-1)); % calculate the indecies
c = repelem(temp-1,r_count); % create an indecies vector for the columns
inds2 = sub2ind(size(gax),r,c); % convert the indecies to linear
gax([inds1 inds2]) = ggx([inds1 inds2]); % assgin the relevant values
This is indeed quite complicated, and not always necessary. A good thing to remember, though, is that nested for loop are much slower than a single loop, so in some cases (depend on the size of the output), this will may be the fastest solution:
for m = v
if m > 1
gax(1:m-1,m-1) = ggx(1:m-1,m-1);
end
if m<nn
gax(m+1:15,m) = ggx(m+1:15,m);
end
end

DCT of an image

I work on a function in Matlab that calculates the DCT (discrete cosine transform) of an image. I don't know what is not working in my code,which is used in image compression.please help me.
Any ideas please.
clc;close all;clear all;
image=('cameraman.tif');
[h w] = size(image);
image = double(image) - 128;
b=8;
block = zeros(b,b);
image_t=zeros(size(image));
for k=1:b:h
for l=1:b:w
image_t(k:k+b-1,l:l+b-1)= image(k:k+b-1,l:l+b-1);
for u=1:b
for v=1:b
if u == 0
Cu = 1/sqrt(2);
else
Cu = 1;
end
if v == 0
Cv = 1/sqrt(2);
else
Cv = 1;
end
Res_sum=0;
for x=1:b;
for y=1:b
Res_sum = Res_sum + ((image_t(x,y))*cos(((2*x)+1)*u*pi/(2*b))*cos(((2*y)+1)*v*pi/(2*b)));
end
end
dct= (1/4)*Cu*Cv*Res_sum;
block(u,v) = dct;
end
end
image_comp(k:k+b-1,l:l+b-1)=block(u,v);
end
end
end
I assume you implement the following formula for the DCT:
with
And I guess you need to divide the image into blocks of 8x8 and do the DCT on each of these blocks.
Please comment your code! It helps you and others understand it much better!
You can never reach the part inside if u == 0 or if v == 0, as you go through u and v in for loops which run through 1:b. The underlying problem is that MATLAB starts indexing at 1, while the frequencies in the DCT start at 0. My hint: Use u and v as frequency as in the formula, not like index, i.e. for u=0:b-1 and use u+1 when indexing.
The same for x and y.
image_t should only contain the current block (i thus renamed it to current_block) and not the whole image. That's current_block = image(k:k+b-1,l:l+b-1);
In the line dct= (1/4)*Cu*Cv*Res_sum;, it should not be 1/4 but rather 1/sqrt(2*N) where N is your block size (you call it b), thus 1/sqrt(2*b). For a block size of 8, as in your example, this is of course 1/4.
image is the name of a MATLAB function. It is advisable not to use it as a function name. Consider changing it e.g. to input_image.
I am not sure why you subtract 128 from the input image, please overthink why you are doing that.
That leads to the code below. I don't know if that solves all your problem, but you should be much closer to that now ;-)
PS: Consider vectorization of the code for improved performance.
function image_comp = dctII(input_image, b)
[h, w] = size(input_image);
input_image = double(input_image);
block_dct = zeros(b);
% Loop through all blocks
for k=1:b:h
for l=1:b:w
% Save true image of block
current_block = input_image(k:k+b-1,l:l+b-1);
% Loop through all cos frequencies (u,v)
for u=0:b-1
for v=0:b-1
if u == 0
Cu = 1/sqrt(2);
else
Cu = 1;
end
if v == 0
Cv = 1/sqrt(2);
else
Cv = 1;
end
Res_sum = 0;
% Loop through all pixel values
for x=0:b-1
for y=0:b-1
Res_sum = Res_sum + ((current_block(x+1,y+1))*cos(((2*x)+1)*u*pi/(2*b))*cos(((2*y)+1)*v*pi/(2*b)));
end
end
% Calculate DCT value at frequency (u,v)
dct = 1/sqrt(2*b) * Cu * Cv * Res_sum;
block_dct(u+1,v+1) = dct;
end
end
image_comp(k:k+b-1,l:l+b-1) = block_dct(u+1,v+1);
end
end
end % of function

matlab parcial equation with 2 intervals

Here is the code I have so far :
function [u]=example222(xrange,trange,uinit,u0bound,uLbound);
n = length(xrange);
m = length(trange);
u = zeros(n,m); %%%
Dx = (xrange(n)-xrange(1))/(n-1);
Dt = (trange(m)-trange(1))/(m-1);
u(:,1)=uinit';
u(1,:)=u0bound;
u(n,:)=uLbound;
gegu=0.08;
alpha=0;
koefa=(-Dt*gegu/(2*Dx));
koefb=(alpha*Dt/(Dx)^2);
u
% first time step
for i = 2:n-1
u(i,2) = u(i,1)+2*koefa*(u(i+1,1)-u(i-1,1))+(koefb/2)*(u(i-1,1)-2*u(i,1)+u(i+1,1))
end;
% subsequent time steps
for j = 2:m-1
for i = 2:n-1
u(i,j+1)=u(i,j-1)+koefa*(u(i+1,j)-u(i-1,j))+koefb*(u(i-1,j)-2*u(i,j)+u(i+1,j))
end;
end;
______________________________________
x = (0:0.1:1);
t = (0:0.8:8) ;
u0=zeros;uL=zeros;
uinit=1-(10*x-1).^2;
[u]=example222(x,t,uinit,u0,uL);
surf(x,t,u,'EdgeColor','black')
Next thing I need to do is to implement an interval for uinit=1-(10*x-1).^2
IF x-0.08*t < 0.2. then => uinit=1-(10*x-1).^2;
else uinit=0;
Can someone help me with that please. I was trying to do it with if clauses and loops and couldn't make it work. Help is greatly appreciated.
There are many ways to define a piecewise function my usual method is as follows:
uinit = zeros(size(x));
I = x<(0.08*t+0.2); %// Find the indices where x<(0.08*t+0.2)
uinit(I) = 1-(10*x(I)-1).^2;
This case is easier than what you may often have since you want all the other values of uinit to be zero. If you had another function in the other region (say x^2) you could also do:
uinit(1-I) = x(1-I).^2;
The operation 1-I gives 0 where I==1 and 1 where I==0, therefore your get the complement of I.