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
Related
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.
I know this looks somehow not related to code errors and development but
I want to know if someone can understand these codes of
integral image and local binary pattern, and tell me how they affect the resulting histograms.
Before the use of integral image the output histogram is normal, but after applying the integral image method I found that most of the histogram changed to zeros. To clarify things, the expected benefit from the use of an integral image is to speed up the process of lbp method. In fact, I haven't seen this before because I'm trying it for the first time. Does anybody who knows about this may help me please?
These are the codes of every method:
Integral image
function [outimg] = integral( image )
[y,x] = size(image);
outimg = zeros(y+1,x+1);
disp(y);
for a = 1:y+1
for b = 1:x+1
rx = b-1;
ry = a-1;
while ry>=1
while rx>=1
outimg(a,b) = outimg(a,b)+image(ry,rx);
rx = rx-1;
end
rx = b-1;
ry = ry-1;
end
% outimg(a,b) = outimg(a,b)-image(a,b);
end
end
% outimg(1,1) = image(1,1);
disp('end loop');
end
CS-LBP
function h = CSLBP(I)
%% this function takes patch or image as input and return Histogram of
%% CSLBP operator.
h = zeros(1,16);
[y,x] = size(I);
T = 0.1; % threshold given by authors in their paper
for i = 2:y-1
for j = 2:x-1
% keeping I(j,i) as center we compute CSLBP
% N0 - N4
a = ((I(i,j+1) - I(i, j-1) > T ) * 2^0 );
b = ((I(i+1,j+1) - I(i-1, j-1) > T ) * 2^1 );
c = ((I(i+1,j) - I(i-1, j) > T ) * 2^2 );
d = ((I(i+1,j-1) - I(i - 1, j + 1) > T ) * 2^3 );
e = a+b+c+d;
h(e+1) = h(e+1) + 1;
end
end
end
Matlab has an inbuilt function for creating integral images, integralimage(). If you don't want to use the computer vision system toolbox you can achieve the same result by calling:
IntIm = cumsum(cumsum(double(I)),2);
Possibly adding padding if needed. You should check out that the image is not saturated, they do that sometimes. Calculating the cumulative sum goes to integers way above the range of uint8 and uint16 quickly, I even had it happen with a double once!
I try to implement the GLCM method with the formula from wikipedia, but I have problems to fill my GLCM due to indices problems with matlab.
I have also used NitdepthQuantisation to reduce the number of Gray Levels, but for now I use the full 8 bit.
function [C] = GLCM(img, level, theta, delta)
% Quantisation of the input Image to desired value
imgQ = ImageQuantisation(img, level);
[m n] = size(imgQ);
% Get the number of gray levels
maxGV = max(img(:));
% Create GLCM initial Matrix
C = zeros(maxGV, maxGV);
% Positions
delta_x = ceil(delta*cos(theta));
delta_y = ceil(delta*sin(theta));
%% Find Occurences
for i = delta_x+1:m-delta_x
for j = delta_y+1:n-delta_y
if(imgQ(i, j) == imgQ(i+delta_x, j+delta_y))
C(, ) = C(, ) + 1;
end
end
end
end
The answer can be found by ensuring the inner nested double for loops have the correct indices to access the image. They were using the outer most pair of for loops for indices rather than the inner ones. The OP has commented that this has slight differences between what MATLAB gives to calculate the GLCM but it is good enough for the OP to overlook:
for o = 1:maxGV
for p = 1:maxGV
if(imgQ(i, j) == o & imgQ(i+delta_x, j+delta_y) == p)
C(o, p) = C(o, p) + 1;
end
end
end
I'm using data set with 200 data points that is used to draw B-Spline curve and I want to extract the 100 original control points from this curve to use it in one algorithm to solve one problem. The result of control points it's too small compared with the value of the data points of B-Spline curve so I don't know if I make something wrong in the following code or not I need help to know that because I must used these control points to complete my study in one algorithm
link of set of data points:
https://drive.google.com/open?id=0B_2BUqaJptbqUkRWLWdmbmpQakk
Code :
% read data set
dataset = importdata("path of data set here");
x = dataset(:,1);
y = dataset(:,2);
for i=1:200
controlpoints(i,1) = x(i);
controlpoints(i,2) = y(i);
controlpoints(i,3) = 0;
end
% Create Q with some points from originla matrix controlpoints ( I take only 103 points)
counter =1;
for i=1:200
if (i==11) || (i==20) || (i==198)
Q(counter,:) = F(i,:);
counter = counter +1;
end
if ne(mod(i,2),0)
Q(counter,:) = F(i,:);
counter = counter+1;
end
end
I used Centripetal method to find control points from curve like the following picture
Complete my code:
% 2- Create Centripetal Nodes array from Q
CP(1) = 0;
CP(103) =1;
for i=2:102
sum = 0;
for j=2:102
sum = sum + sqrt(sqrt((Q(j,1)-Q(j-1,1))^2+(Q(j,2)-Q(j-1,2))^2));
end
CP(i) = CP(i-1) + (sqrt(sqrt((Q(i,1)-Q(i-1,1))^2+(Q(i,2)-Q(i-1,2))^2))/sum);
end
p=3; % degree
% 3- Create U_K array from CP array
for i=1:103
U_K(i) = CP(i);
end
To calculate control points we must follow this equation P=Qx(R') --> R' is inverse of R matrix so we must find R matrix then fins P(control points matrix) by the above equation. The following scenario is used to find R matrix
and to calculate N in B-Spline we must use these recursive function
Complete my code :
% 5- Calculate R_i_p matrix
for a=1:100
for b=1:100
R_i_p(a,b) = NCalculate(b,p,U_K(a),U_K);
end
end
% 6- Find inverse of R_i_p matrix
R_i_p_invers = inv(R_i_p);
% 7- Find Control points ( 100 points because we have curve with 3 degree )
for i=1:100
for k=1:100
PX(i) = R_inv(i,k) * Q(k,1);
PY(i) = R_inv(i,k) * Q(k,2);
end
end
PX2 = transpose(PX);
PY2 = transpose(PY);
P = horzcat(PX2,PY2); % The final control points you can see the values is very small compared with the original data points vlaues
My Recursive Function to find the previous R matrix:
function z = NCalculate(j,k,u,U)
if (k == 1 )
if ( (u > U(j)) && (u <= U(j+1)) )
z = 1;
else
z = 0;
end
else
z = (u-U(j)/U(j+k-1)-U(j)* NCalculate(j,k-1,u,U) ) + (U(j+k)-u/U(j+k)-U(j+1) * NCalculate(j+1,k-1,u,U));
end
end
Really I need to this help so much , I tried in this problem from one week :(
Updated:
Figure 1 for the main B-spline Curve , Figure 2 for the result control points after applied reverse engineering on this curve so the value is so far and so small compared with the original data points value
Updated(2):
I made some updates on my code but the problem now in the inverse of R matrix it gives me infinite value at all time
% 2- Create Centripetal Nodes array from Q
CP(1) = 0;
CP(100) =1;
sum = 0;
for i=2:100
sum = sum + sqrt(sqrt((Q(i,1)-Q(i-1,1))^2+(Q(i,2)-Q(i-1,2))^2));
end
for i=2:99
CP(i) = CP(i-1) + (sqrt(sqrt((Q(i,1)-Q(i-1,1))^2+(Q(i,2)-Q(i-1,2))^2))/sum);
end
% 3- Create U_K array from CP array
for i=1:100
U_K(i) = CP(i);
end
p=3;
% create Knot vector
% The first elements
for i=1:p+1
U(i) = 0;
end
% The last elements
for i=100:99+p+1
U(i) = 1;
end
% The remain elements
for j=2:96
sum = 0;
for i=j:(j+p-1)
sum = sum + U_K(i);
end
U(j+p) = (1/p)* sum;
end
% 5- Calculate R_i_p matrix
for a=1:100
for b=1:100
R_i_p(a,b) = NCalculate(b,p,U_K(a),U);
end
end
R_i_p_invers = inv(R_i_p);
% 7- Find Control points ( 100 points )
for i=1:100
for k=1:100
if isinf(R_inv(i,k))
R_inv(i,k) = 0;
end
PX(i) = R_inv(i,k) * Q(k,1);
PY(i) = R_inv(i,k) * Q(k,2);
end
end
PX2 = transpose(PX);
PY2 = transpose(PY);
P = horzcat(PX2,PY2);
Note: I updated my NCalculate recursive function to give me 0 if the result is NaN (not a number )
function z = NCalculate(j,k,u,U)
if (k == 1 )
if ( (u >= U(j)) && (u < U(j+1)) )
z = 1;
else
z = 0;
end
else
z = (u-U(j)/U(j+k-1)-U(j)* NCalculate(j,k-1,u,U) ) + (U(j+k)-u/U(j+k)-U(j+1) * NCalculate(j+1,k-1,u,U));
end
if isnan(z)
z =0;
end
end
I think there are a few dubious issues in your approach:
First of all, if you try to create a b-spline curve interpolating 103 input points (and no other boundary conditions are imposed), the b-spline curve will have 103 control points regardless what degree the b-spline curve is.
The U_K array is the parameter assigned to each input point. They are not the same as the knot sequence ti used by the Cox DeBoor recursive formula. If the b-spline curve is of degree 3, you shall have (103+3+1) knot values in the knot sequence. You can create the knot values in the following way:
0) Denote the parameters as p[i], where i = 0 to (n-1), p[0]=0.0 and n is number of points.
1) Create the knot values as
knot[0] = (p[1]+p[2]+p[3])/D (where D is degree)
knot[1] = (p[2]+p[3]+p[4])/D
knot[2] = (p[3]+p[4]+p[5])/D
......
These are the interior knot values. You should notice that p[0] and p[n-1] will not be used in this step. You will have (n-D-1) interior knots.
2) Now, add p[0] to the front of the knot values (D+1) times and add p[n-1] to the end of the knot values (D+1) times and you are done. At the end, you will have (N+D+1) knots in total.
==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.