function VideoDeRaining(AVIFilename, Nun_of_frames, Alg) 
% Alg = 1->Single-image-based video rain removal, 2->Video-based rain removal for static camera, 3->Rain removal for single image  
clc
close all;
warning off;
imheight = 256;
imwidth = 256;
Patch_size = 16;
Num_of_Iterations = 100;
DictSize = 1024;
BilateralParam = 2;
w = 5;
sigma = [3 0.1] * BilateralParam;

if Alg == 3
    I = imread(AVIFilename);
    if isrgb(I)
        I = rgb2gray(I);
    end
    I = double(imresize(I, [imheight imwidth])) / 255;
    ILF = bfilter2(I, w, sigma);
    Ori_IHF = I - ILF;
    fprintf(1, 'Perform rain removal to %s...\n', AVIFilename);
    NonRainComponent = MCA_Image_Decomposition(Ori_IHF, Patch_size, Num_of_Iterations, DictSize, [], [], Alg);
    NonRainI = ILF + NonRainComponent;
    TargetName = sprintf('%s_derain.jpg', AVIFilename);
    imwrite(uint8(NonRainI*255), TargetName, 'jpg');
    fprintf(1, 'Save %s!\n', TargetName);
    
    return;
end

Ave_length = 50;
IAve = zeros(imheight, imwidth);
RainVideo = mmreader(AVIFilename);
lastFrame = read(RainVideo, inf);
numFrames = RainVideo.NumberOfFrames;
fprintf(1, 'Total number of frames in this rain video = %d.\n', numFrames);
if Alg == 1
    MovLenth = Nun_of_frames;
elseif Alg == 2
    MovLenth = Nun_of_frames - Ave_length;
end
mov(1:MovLenth) = struct('cdata', zeros(imheight, imwidth, 'uint8'), 'colormap', []);
blank = zeros(imheight, 10);
blank(:) = 1;
mov1(1:MovLenth) = struct('cdata', zeros(imheight, imwidth*2 + size(blank, 2), 'uint8'), 'colormap', []);
TextureDict = [];
CartoonDict = [];
mov_id = 1;
for k = 1 : Nun_of_frames
    I = read(RainVideo, k);
    if isrgb(I)
        I = rgb2gray(I);
    end
    I = double(imresize(I, [imheight imwidth])) / 255;
    if (Alg == 1)
        ILF = bfilter2(I, w, sigma);
        Ori_IHF = I - ILF;
        fprintf(1, 'Perform rain removal to frame %d...\n', k);
        [NonRainComponent RainComponent Texture_Dict Cartoon_Dict] = MCA_Image_Decomposition(Ori_IHF, Patch_size, Num_of_Iterations, DictSize, TextureDict, CartoonDict, Alg);
        NonRainI = ILF + NonRainComponent;
    elseif (Alg == 2)
        if (k <= Ave_length)
            IAve = IAve + I;
            if (k == Ave_length)
                ILF = IAve / Ave_length;
                %FileName = sprintf('DeRainAve_%s.jpg', AVIFilename); 
                %imwrite(uint8(ILF*255), FileName, 'jpg');
            end
        else
            Ori_IHF = I - ILF;
            fprintf(1, 'Perform rain removal to frame %d...\n', k);
            [NonRainComponent RainComponent Texture_Dict Cartoon_Dict] = MCA_Image_Decomposition(Ori_IHF, Patch_size, Num_of_Iterations, DictSize, TextureDict, CartoonDict, Alg);
            NonRainI = ILF + NonRainComponent;   
            TextureDict = Texture_Dict;
            CartoonDict = Cartoon_Dict;
        end
    end
    if (Alg == 1) || ((Alg == 2) && (k > Ave_length + 1))
        if(k <= 9)
            TargetName = sprintf('%s_000%d_derain.jpg', AVIFilename, k);
        elseif((k >= 10) && (k <= 99))
            TargetName = sprintf('%s_00%d_derain.jpg', AVIFilename, k);
        elseif((k >= 100) && (k <= 999))
            TargetName = sprintf('%s_0%d_derain.jpg', AVIFilename, k);
        elseif((k >= 1000) && (k <= 9999))
            TargetName = sprintf('%s_%d_derain.jpg', AVIFilename, k);
        end
        imwrite(uint8(NonRainI*255), TargetName, 'jpg');
        fprintf(1, 'Save %s!\n', TargetName);
        GrayNonRainI = mat2gray(NonRainI*255);
        [X, map] = gray2ind(GrayNonRainI, 256);
        mov(mov_id) = im2frame(X, map);
        
        Output = [I blank NonRainI];
        GrayNonRainI = mat2gray(Output*255);
        [X, map] = gray2ind(GrayNonRainI, 256);
        mov1(mov_id) = im2frame(X, map);
        
        mov_id = mov_id + 1;
    end
end
TargetName = sprintf('%s_derain.avi', AVIFilename);
movie2avi(mov, TargetName, 'compression', 'None');
fprintf(1, 'Save %s!\n', TargetName);
TargetName = sprintf('%s_rain_derain.avi', AVIFilename);
movie2avi(mov1, TargetName, 'compression', 'None');
fprintf(1, 'Save %s!\n', TargetName);