-----------------------------------------------------------------------
-- An example of Actor Prolog program.                               --
-- (c) 2014 IRE RAS Alexei A. Morozov                                --
-----------------------------------------------------------------------
import .. from "morozov/Java2D";
import .. from "morozov/Vision";
-----------------------------------------------------------------------
class 'Main' (specialized 'Alpha'):
--
constant:
--
data_directory          = "data";
target_directory        = "Fight_RunAway1";
--
-- Warning: This matrix corresponds to the CAVIAR data set,
-- clips from INRIA (1st Set) only!
--
inverse_transformation_matrix   = [
                [0.3945,0.0468,0.0168],
                [0.0996,-0.1625,0.0056],
                [-34.0116,28.5636,1.0000]];
--
sampling_rate           = 25.0;
--
stage_one               = (('ImagePreprocessor',
                                data_directory,
                                target_directory,
                                sampling_rate,
                                low_level_analyzer,
                                stage_two));
stage_two               = (('ImageAnalyser',
                                low_level_analyzer,
                                sampling_rate));
--
internal:
--
low_level_analyzer      = ('ImageSubtractor',
                                extract_blobs= 'yes',
                                track_blobs= 'yes',
                                minimal_training_interval= 7,
                                maximal_training_interval= -1,
                                use_grayscale_colors= 'yes',
                                apply_gaussian_filtering_to_background= 'yes',
                                background_gaussian_filter_radius= 1,
                                apply_median_filtering_to_background= 'yes',
                                background_median_filter_threshold= 3,
                                background_standard_deviation_factor= 1.2,
                                horizontal_blob_border= 3,
                                vertical_blob_border= 3,
                                minimal_blob_intersection_area= 1,
                                minimal_blob_size= 10,
                                minimal_track_duration= 5,
                                maximal_blob_invisibility_interval= 3,
                                maximal_track_retention_interval= 4500,
                                inverse_transformation_matrix,
                                sampling_rate,
                                apply_median_filtering_to_velocity= 'yes',
                                velocity_median_filter_halfwidth= 3,
                                refuse_slow_tracks= 'yes',
                                fuzzy_velocity_threshold= 0.3,
                                fuzzy_distance_threshold= 40.0,
                                fuzzy_threshold_border= 0.50,
                                synthesized_image_transparency= 64,
                                make_rectangular_blobs_in_synthesized_image= 'no');
--
[
]
-----------------------------------------------------------------------
class 'ImagePreprocessor' (specialized 'Timer'):
--
constant:
--
        data_directory;
        target_directory;
        sampling_rate;
--
        low_level_analyzer;
        stage_two;
--
internal:
--
        subtractor      = ('SynchronizedImageSubtractor',
                                image_subtractor= low_level_analyzer);
--
        text            = ('Text');
        image           = ('BufferedImage');
        state           = ('ProgramState');
--
[
goal:-!,
        Time0== ?milliseconds(),
        state ? set_beginning_time(Time0),
        set_period(1/sampling_rate,0),
        activate.
--
tick:-
        T2== ?milliseconds(),
        state ? get_beginning_time(T1),
        Delta== (T2 - T1) / 1000.0 * sampling_rate,
        N== ?convert_to_integer(?round(Delta)),!,
        load_figure(N,T2).
--
load_figure(N2,_):-
        state ? get_current_frame(N1),
        N1 == N2,!.
load_figure(N,_):-
        state ? set_current_frame(N),
        ShortFileName== text?format("%03d",N) + ".jpg",
        ImageToBeLoaded==
                "jar:" + data_directory + "/" +
                target_directory + "_jpg" + "/JPEGS/" +
                target_directory +
                ShortFileName,
        image ? does_exist(ImageToBeLoaded),!,
        image ? load(ImageToBeLoaded),
        subtractor ? subtract(N,image),
        stage_two [<<] draw_scene().
load_figure(_,T2):-
        state ? set_beginning_time(T2),
        subtractor ? reset_results.
]
-----------------------------------------------------------------------
class 'ImageAnalyser' (specialized 'Alpha'):
--
constant:
--
        sampling_rate;
--
        low_level_analyzer;
--
internal:
--
        subtractor      = ('SynchronizedImageSubtractor',
                                image_subtractor= low_level_analyzer);
--
constant:
--
        walking_speed_threshold_value           = 0.5;
        walking_speed_threshold_halfwidth       = 0.5;
        running_speed_threshold_value           = 1.0;
        running_speed_threshold_halfwidth       = 0.5;
        movement_duration_threshold_value       = 0.75;
        movement_duration_threshold_halfwidth   = 0.5;
--
        velocity_bound_1                        = 0.5;
        velocity_bound_2                        = 0.75;
        velocity_bound_3                        = 1.0;
        velocity_bound_4                        = 1.25;
        velocity_bound_5                        = 1.5;
        velocity_bound_6                        = 2.0;
        velocity_bound_7                        = 2.5;
        velocity_bound_8                        = 3.0;
--
        velocity_color_1                        = 'Violet';
        velocity_color_2                        = 'Magenta';
        velocity_color_3                        = 'Cyan';
        velocity_color_4                        = 'Emerald';
        velocity_color_5                        = 'Lime';
        velocity_color_6                        = 'Yellow';
        velocity_color_7                        = 'Orange';
        velocity_color_8                        = 'Pink';
        velocity_color_9                        = 'Red';
--
        maximal_depth_of_search                 = 15;
--
        circle_radius                           = 0.005;
--
internal:
--
        graphic_window  = ('Canvas2D',
                                y= 0,
                                height= 22.3);
        prompt_window   = ('Report',
                                y= 22.3,
                                height= 2.7,
                                font_size= 14,
                                font_style= 'bold');
        text            = ('Text');
        image           = ('BufferedImage');
        timer           = ('Timer');
--
[
goal:-!,
        timer ? set_priority('MIN_PRIORITY'),
        graphic_window ? show,
        prompt_window ? write(
                "The project is supported by RFBR, Russia, "
                "RFBR-DST 13-07-92694, "
                "and Govt. of India, DST-RFBR P-159.\n",
                "The data are coming from the EC Funded CAVIAR "
                "project / IST 2001 37540 "
                "(http://homepages.inf.ed.ac.uk/rbf/CAVIAR/).").
--
draw_scene:-
        subtractor ? commit,
        subtractor ? get_recent_frame_number(FrameN),
        graphic_window ? suspend_redrawing,
        graphic_window ? clear,
        draw_target_image,
        draw_target_objects(FrameN),
        report_time(FrameN),
        graphic_window ? draw_now.
--
draw_target_image:-
        subtractor ? get_recent_image(image),
        graphic_window ? draw_image(image,0,0,1,1).
--
draw_target_objects(FrameN):-
        subtractor ? get_connected_graphs(Graphs),
        image ? get_size(IW,IH),
        -- draw_legend,
        draw_graphs(IW,IH,Graphs,1,'method_two',FrameN).
--
draw_graphs(IW,IH,[Graph|Rest],N,AnalysisMethod,FrameN):-
        do_analyse_graph(AnalysisMethod),
        is_a_kind_of_a_lam(
                AnalysisMethod,Graph,1,Graph,_,_,_,_,_,_),!,
        draw_graph(IW,IH,Graph,Graph,'yes',AnalysisMethod,N,FrameN),
        graphic_window ? set_font({size:48,weight:'WEIGHT_BOLD'}),
        graphic_window ? set_pen({color:'Red'}),
        graphic_window ? set_text_alignment('CENTER','CENTER'),
        graphic_window ? draw_text(0.5,0.5,"Attention!"),
        draw_graphs(IW,IH,Rest,N+1,AnalysisMethod,FrameN).
draw_graphs(IW,IH,[Graph|Rest],N,AnalysisMethod,FrameN):-!,
        draw_graph(IW,IH,Graph,Graph,'no',AnalysisMethod,N,FrameN),
        draw_graphs(IW,IH,Rest,N+1,AnalysisMethod,FrameN).
draw_graphs(_,_,_,_,_,_).
--
do_analyse_graph('off'):-!,
        fail.
do_analyse_graph(_).
--
is_a_kind_of_a_lam(
                'method_one',
                [Edge|_],EN,Graph,
                WalkingPerson,N1,Edge,EN,RunningPerson,N3):-
        Edge == {inputs:Origins,outputs:Branches|_},
        Branches == [_,_|_],
        contains_a_walking_person(
                Origins,Graph,[],WalkingPerson,_,_,0,N1,0),
        contains_a_running_person(
                Branches,Graph,[],RunningPerson,_,_,0,N3,0),!.
is_a_kind_of_a_lam(
                'method_two',
                [ForkEdge|_],EN,Graph,
                JoiningEdge,N1,ForkEdge,EN,RunningPerson,N3):-
        ForkEdge == {inputs:Origins,outputs:Branches|_},
        Branches == [_,_|_],
        contains_a_running_person(
                Branches,Graph,[],RunningPerson,_,_,0,N3,0),
        is_a_meeting(
                Origins,Graph,[],ForkEdge,EN,JoiningEdge,N1,0),!.
is_a_kind_of_a_lam(
                AnalysisMethod,
                [_|Rest],EN,Graph,
                Person1,N1,CommonEdge,N2,Person2,N3):-
        is_a_kind_of_a_lam(
                AnalysisMethod,
                Rest,EN+1,Graph,
                Person1,N1,CommonEdge,N2,Person2,N3).
--
contains_a_running_person([N1|_],Graph,Stack,Person,M1,M2,_,N2,D):-
        is_not_element(N1,Stack),
        get_edge(N1,Graph,Edge),
        is_a_running_person(
                Edge,Graph,[N1|Stack],Person,M1,M2,N1,N2,D),!.
contains_a_running_person([_|Rest],Graph,Stack,Person,M1,M2,N1,N2,D):-
        D <= maximal_depth_of_search,
        contains_a_running_person(
                Rest,Graph,Stack,Person,M1,M2,N1,N2,D+1).
--
is_a_running_person(Edge,_,_,Edge,M1,M2,N,N,_):-
        Edge == {
                mean_velocity:Velocity,
                frame1:Beginning,
                frame2:End|_},
        M1== ?fuzzy_metrics(
                Velocity,
                running_speed_threshold_value,
                running_speed_threshold_halfwidth),
        Duration== (End - Beginning) / sampling_rate,
        M2== ?fuzzy_metrics(
                Duration,
                movement_duration_threshold_value,
                movement_duration_threshold_halfwidth),
        M1 * M2 >= 0.5,!.
is_a_running_person(Edge,Graph,Stack,Person,M1,M2,N1,N2,D):-
        Edge == {outputs:Branches|_},
        D <= maximal_depth_of_search,
        contains_a_running_person(
                Branches,Graph,Stack,Person,M1,M2,N1,N2,D+1).
--
contains_a_walking_person([N1|_],Graph,Stack,Person,M1,M2,_,N2,D):-
        is_not_element(N1,Stack),
        get_edge(N1,Graph,Edge),
        is_a_walking_person(
                Edge,Graph,[N1|Stack],Person,M1,M2,N1,N2,D),!.
contains_a_walking_person([_|Rest],Graph,Stack,Person,M1,M2,N1,N2,D):-
        D <= maximal_depth_of_search,
        contains_a_walking_person(
                Rest,Graph,Stack,Person,M1,M2,N1,N2,D+1).
--
is_a_walking_person(Edge,_,_,Edge,M1,M2,N,N,_):-
        Edge == {
                mean_velocity:Velocity,
                frame1:Beginning,
                frame2:End|_},
        M1== 1 - ?fuzzy_metrics(
                Velocity,
                walking_speed_threshold_value,
                walking_speed_threshold_halfwidth),
        Duration== (End - Beginning) / sampling_rate,
        M2== ?fuzzy_metrics(
                Duration,
                movement_duration_threshold_value,
                movement_duration_threshold_halfwidth),
        M1 * M2 >= 0.5,!.
is_a_walking_person(Edge,Graph,Stack,Person,M1,M2,N1,N2,D):-
        Edge == {inputs:Origins|_},
        D <= maximal_depth_of_search,
        contains_a_walking_person(
                Origins,Graph,Stack,Person,M1,M2,N1,N2,D+1).
--
is_a_meeting(Origins,_,_,JoiningEdge,N0,JoiningEdge,N0,_):-
        Origins == [_,_|_],!.
is_a_meeting([N1|_],Graph,Stack,_,_,JoiningEdge,N2,D):-
        D <= maximal_depth_of_search,
        is_not_element(N1,Stack),
        get_edge(N1,Graph,Edge),
        Edge == {inputs:Origins|_},
        is_a_meeting(
                Origins,Graph,[N1|Stack],Edge,N1,JoiningEdge,N2,D+1).
--
is_not_element(N1,[N2|Rest]):-
        N1 <> N2,
        is_not_element(N1,Rest).
is_not_element(_,[]).
--
fuzzy_metrics(X,Threshold,Halfwidth) = 1.0 :-
        X >= Threshold + Halfwidth,!.
fuzzy_metrics(X,Threshold,Halfwidth) = 0.0 :-
        X <= Threshold - Halfwidth,!.
fuzzy_metrics(X,Threshold,Halfwidth) = Value :-
        Value== (X-Threshold+Halfwidth) * (1 / (2*Halfwidth)).
--
draw_graph(IW,IH,[Edge|Rest],Graph,IsALam,AnalyseGraph,N,FrameN):-!,
        draw_edge(IW,IH,Edge,Graph,IsALam,AnalyseGraph,N,FrameN),
        draw_graph(IW,IH,Rest,Graph,IsALam,AnalyseGraph,N,FrameN).
draw_graph(_,_,_,_,_,_,_,_).
--
draw_edge(      IW,IH,
                {       x1:X1a,y1:Y1a,x2:X2a,y2:Y2a,
                        inputs:Origins,
                        outputs:Branches,
                        coordinates:TrackOfBlobs,
                        mean_velocity:Velocity|_},
                Graph,IsALam,AnalyseGraphs,N,FrameN):-
        X1r== X1a / IW,
        Y1r== Y1a / IH,
        X2r== X2a / IW,
        Y2r== Y2a / IH,
        graphic_window ? set_pen({color:'Blue',lineWidth:1}),
        draw_origins(X1a,Y1a,IW,IH,Origins,Graph),
        draw_track_of_blobs(IW,IH,TrackOfBlobs,IsALam,Velocity),
        draw_rectangle(IsALam,Branches,TrackOfBlobs,IW,IH,FrameN),
        graphic_window ? set_brush('on'),
        graphic_window ? set_pen({color:'Green',lineWidth:1}),
        -- graphic_window ? draw_line(X1r,Y1r,X2r,Y2r),
        draw_circle(X1r,Y1r),
        draw_circle(X2r,Y2r),
        draw_graph_identifier(AnalyseGraphs,X1r,Y1r,X2r,Y2r,N),
        fail.
draw_edge(_,_,_,_,_,_,_,_).
--
draw_circle(X0,Y0):-
        X1== X0 - circle_radius,
        Y1== Y0 - circle_radius,
        Width== circle_radius * 2,
        Height== circle_radius * 2,
        graphic_window ? draw_ellipse(X1,Y1,Width,Height).
--
draw_graph_identifier('off',X1,Y1,X2,Y2,Id):-!,
        Text== text?format("%d",Id),
        graphic_window ? set_font({size:18}),
        graphic_window ? set_text_alignment('CENTER','CENTER'),
        graphic_window ? draw_text((X1+X2)/2,(Y1+Y2)/2,Text).
draw_graph_identifier(_,_,_,_,_,_).
--
draw_origins(Sx,Sy,IW,IH,[Origin|Rest],Graph):-!,
        draw_origin(Sx,Sy,IW,IH,Origin,Graph),
        draw_origins(Sx,Sy,IW,IH,Rest,Graph).
draw_origins(_,_,_,_,_,_).
--
draw_origin(SxA,SyA,IW,IH,N,Graph):-
        get_edge(N,Graph,Edge),
        Edge == {x2:Nx2a,y2:Ny2a|_},!,
        draw_origin_arrow(SxA,SyA,Nx2a,Ny2a,IW,IH).
draw_origin(_,_,_,_,_,_).
--
draw_origin_arrow(X,Y,X,Y,_,_):-!.
draw_origin_arrow(SxA,SyA,Nx2a,Ny2a,IW,IH):-
        SxR== SxA / IW,
        SyR== SyA / IH,
        Nx2r== Nx2a / IW,
        Ny2r== Ny2a / IH,
        graphic_window ? draw_line(SxR,SyR,Nx2r,Ny2r).
--
get_edge(1,[Edge|_],Edge):-!.
get_edge(N,[_|Rest],Edge):-
        N > 0,
        get_edge(N-1,Rest,Edge).
--
draw_track_of_blobs(IW,IH,[Blob|Rest],IsALam,Velocity):-
        Blob== {x:Xa,y:Ya|_},!,
        Xr== Xa / IW,
        Yr== Ya / IH,
        draw_track_of_blobs(IW,IH,Xr,Yr,Rest,IsALam,Velocity).
draw_track_of_blobs(_,_,_,_,_).
--
draw_track_of_blobs(IW,IH,X1,Y1,[Blob|Rest],IsALam,_/*Velocity*/):-
        Blob== {x:Xa,y:Ya,velocity:Velocity|_},!,
        X2== Xa / IW,
        Y2== Ya / IH,
        select_line_color(IsALam,Velocity,Color,LW),
        graphic_window ? set_pen({color:Color,lineWidth:LW}),
        graphic_window ? draw_line(X1,Y1,X2,Y2),
        draw_track_of_blobs(IW,IH,X2,Y2,Rest,IsALam,Velocity).
draw_track_of_blobs(_,_,_,_,_,_,_).
--
select_line_color('yes',_,'Red',5):-!.
select_line_color(_,_,'Cyan',2):-!.
select_line_color(_,Velocity,Color,2):-
        select_line_color(Velocity,Color).
--
select_line_color(Velocity,velocity_color_1):-
        Velocity <= velocity_bound_1,!.
select_line_color(Velocity,velocity_color_2):-
        Velocity > velocity_bound_1,
        Velocity <= velocity_bound_2,!.
select_line_color(Velocity,velocity_color_3):-
        Velocity > velocity_bound_2,
        Velocity <= velocity_bound_3,!.
select_line_color(Velocity,velocity_color_4):-
        Velocity > velocity_bound_3,
        Velocity <= velocity_bound_4,!.
select_line_color(Velocity,velocity_color_5):-
        Velocity > velocity_bound_4,
        Velocity <= velocity_bound_5,!.
select_line_color(Velocity,velocity_color_6):-
        Velocity > velocity_bound_5,
        Velocity <= velocity_bound_6,!.
select_line_color(Velocity,velocity_color_7):-
        Velocity > velocity_bound_6,
        Velocity <= velocity_bound_7,!.
select_line_color(Velocity,velocity_color_8):-
        Velocity > velocity_bound_7,
        Velocity <= velocity_bound_8,!.
select_line_color(_,velocity_color_9).
--
draw_rectangle('yes',[],Track,IW,IH,FrameN):-!,
        draw_colored_rectangle(Track,IW,IH,FrameN,'Yellow',3).
-- draw_rectangle('no',[],Track,IW,IH,FrameN):-!,
--      draw_colored_rectangle(Track,IW,IH,FrameN,'Cyan',1).
draw_rectangle(_,_,_,_,_,_).
--
draw_colored_rectangle([Blob],IW,IH,FrameN,Color,LW):-
        Blob == {frame:FrameN,x:X0,y:Y0,width:W1,height:H1|_},!,
        graphic_window ? set_brush('off'),
        graphic_window ? set_pen({color:Color,lineWidth:LW}),
        X2== (X0 - W1 / 2) / IW,
        Y2== (Y0 - H1 / 2) / IH,
        W2== W1 / IW,
        H2== H1 / IH,
        graphic_window ? draw_rectangle(X2,Y2,W2,H2).
draw_colored_rectangle([_|Rest],IW,IH,FrameN,Color,LW):-!,
        draw_colored_rectangle(Rest,IW,IH,FrameN,Color,LW).
draw_colored_rectangle(_,_,_,_,_,_).
--
draw_legend:-
        graphic_window ? set_brush('off'),
        graphic_window ? set_font({size:12,weight:'WEIGHT_BOLD'}),
        graphic_window ? set_text_alignment('LEFT','CENTER'),
        X0r== 0.82,
        Y0r== 0.05,
        X1r== X0r + 0.02,
        Y1r== Y0r + 0.03,
        Y2r== Y1r + 0.03,
        Y3r== Y2r + 0.03,
        Y4r== Y3r + 0.03,
        Y5r== Y4r + 0.03,
        Y6r== Y5r + 0.03,
        Y7r== Y6r + 0.03,
        Y8r== Y7r + 0.03,
        Y9r== Y8r + 0.03,
        T1== text?format("Velocity <= %1.2f",velocity_bound_1),
        T2== text?format("Velocity > %1.2f",velocity_bound_1),
        T3== text?format("Velocity > %1.2f",velocity_bound_2),
        T4== text?format("Velocity > %1.2f",velocity_bound_3),
        T5== text?format("Velocity > %1.2f",velocity_bound_4),
        T6== text?format("Velocity > %1.2f",velocity_bound_5),
        T7== text?format("Velocity > %1.2f",velocity_bound_6),
        T8== text?format("Velocity > %1.2f",velocity_bound_7),
        T9== text?format("Velocity > %1.2f",velocity_bound_8),
        graphic_window ? set_pen({color:velocity_color_1}),
        graphic_window ? draw_text(X1r,Y1r,T1),
        graphic_window ? set_pen({color:velocity_color_2}),
        graphic_window ? draw_text(X1r,Y2r,T2),
        graphic_window ? set_pen({color:velocity_color_3}),
        graphic_window ? draw_text(X1r,Y3r,T3),
        graphic_window ? set_pen({color:velocity_color_4}),
        graphic_window ? draw_text(X1r,Y4r,T4),
        graphic_window ? set_pen({color:velocity_color_5}),
        graphic_window ? draw_text(X1r,Y5r,T5),
        graphic_window ? set_pen({color:velocity_color_6}),
        graphic_window ? draw_text(X1r,Y6r,T6),
        graphic_window ? set_pen({color:velocity_color_7}),
        graphic_window ? draw_text(X1r,Y7r,T7),
        graphic_window ? set_pen({color:velocity_color_8}),
        graphic_window ? draw_text(X1r,Y8r,T8),
        graphic_window ? set_pen({color:velocity_color_9}),
        graphic_window ? draw_text(X1r,Y9r,T9),
        graphic_window ? set_pen({color:'Green',lineWidth:1}),
        Wr== 0.17,
        Hr== Y9r - Y0r + 0.025,
        graphic_window ? draw_rectangle(X0r,Y0r,Wr,Hr).
--
report_time(_):-
        graphic_window ? set_brush('Green'),
        graphic_window ? set_font({size:18}),
        graphic_window ? set_text_alignment('LEFT','TOP'),
        fail.
report_time(FrameN):-
        FrameN >= 0,!,
        graphic_window ? draw_text(
                0.02, 0.02,
                text?format(
                        "Time: %3.2f [sec]; Frame: %s",
                        FrameN/sampling_rate,FrameN)).
report_time(_):-
        graphic_window ? draw_text(
                0.02, 0.02,
                "Training... Please wait a minute...").
]
-----------------------------------------------------------------------
class 'ProgramState' (specialized 'Database'):
[
CLAUSES:
--
get_beginning_time(T):-
        Item== ?match(beginning_time(_)),
        Item == beginning_time(T),!.
--
set_beginning_time(T):-
        retract_all(beginning_time(_)),
        append(beginning_time(T)).
--
get_current_frame(N):-
        Item== ?match(current_frame(_)),
        Item == current_frame(N),!.
--
set_current_frame(N):-
        retract_all(current_frame(_)),
        append(current_frame(N)).
]
-----------------------------------------------------------------------