|
| 1 | +#include <scamp5.hpp> |
| 2 | +#include <vector> |
| 3 | +#include "MISC/MISC_FUNCS.hpp" |
| 4 | +using namespace SCAMP5_PE; |
| 5 | + |
| 6 | +vs_stopwatch frame_timer; |
| 7 | +vs_stopwatch output_timer; |
| 8 | +vs_stopwatch sum_timer; |
| 9 | + |
| 10 | +const areg_t AREG_image = A; |
| 11 | +const areg_t AREG_vertical_edges = B; |
| 12 | +const areg_t AREG_horizontal_edges = C; |
| 13 | + |
| 14 | +const dreg_t DREG_keyframe_edges = S0; |
| 15 | +const dreg_t DREG_combined_edges = S1; |
| 16 | +const dreg_t DREG_vertical_edges = S2; |
| 17 | +const dreg_t DREG_horizontal_edges = S3; |
| 18 | + |
| 19 | +void threshold_F_into_S6_for_frame_blending(areg_t reg,vs_handle display, int frame_blend_window = 16); |
| 20 | + |
| 21 | +int main() |
| 22 | +{ |
| 23 | + vs_init(); |
| 24 | + |
| 25 | + VS_GUI_DISPLAY_STYLE(style_plot,R"JSON( |
| 26 | + { |
| 27 | + "plot_palette": "plot_4", |
| 28 | + "plot_palette_groups": 4 |
| 29 | + } |
| 30 | + )JSON"); |
| 31 | + |
| 32 | + int display_size = 2; |
| 33 | + vs_handle display_00 = vs_gui_add_display("Stabilized Image",0,0,display_size); |
| 34 | + vs_handle display_01 = vs_gui_add_display("Captured Image",0,display_size,display_size); |
| 35 | + |
| 36 | + int alignment_x = 0; int alignment_y = 0; |
| 37 | + int vel_x = 0; int vel_y = 0; |
| 38 | + |
| 39 | + int use_inertia = 1; |
| 40 | + vs_gui_add_switch("use_inertia",1,&use_inertia); |
| 41 | + |
| 42 | + bool set_anchor_image = false; |
| 43 | + auto gui_btn_set_anchor_image = vs_gui_add_button("set_anchor_image"); |
| 44 | + vs_on_gui_update(gui_btn_set_anchor_image,[&](int32_t new_value) |
| 45 | + { |
| 46 | + set_anchor_image = true; |
| 47 | + }); |
| 48 | + |
| 49 | + int edge_threshold = 12; |
| 50 | + vs_gui_add_slider("edge_threshold x",0,127,edge_threshold,&edge_threshold); |
| 51 | + |
| 52 | + |
| 53 | + // Frame Loop |
| 54 | + while(1) |
| 55 | + { |
| 56 | + frame_timer.reset();//reset frame_timer |
| 57 | + |
| 58 | + vs_disable_frame_trigger(); |
| 59 | + vs_frame_loop_control(); |
| 60 | + |
| 61 | + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 62 | + //CAPTURE FRAME |
| 63 | + |
| 64 | + scamp5_kernel_begin(); |
| 65 | + //A = pixel data of latest frame, F = intermediate result |
| 66 | + get_image(A,F); |
| 67 | + scamp5_kernel_end(); |
| 68 | + |
| 69 | + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 70 | + //COMPUTE HORIZONTAL & VERTICAL EDGE IMAGES |
| 71 | + |
| 72 | + scamp5_kernel_begin(); |
| 73 | + //COPY IMAGE TO F AND SHIFT ONE "PIXEL" RIGHT |
| 74 | + bus(NEWS,AREG_image); |
| 75 | + bus(F,XW); |
| 76 | + bus(NEWS,F); |
| 77 | + bus(F,XW); |
| 78 | + |
| 79 | + //SAVE THE ABSOLUTE DIFFERENCE BETWEEN THE SHIFTED IMAGE AND ORIGINAL AS THE VERTICAL EDGES RESULT |
| 80 | + sub(F,F,AREG_image); |
| 81 | + abs(AREG_vertical_edges,F); |
| 82 | + |
| 83 | + //COPY IMAGE TO F AND SHIFT ONE "PIXEL" UP |
| 84 | + bus(NEWS,AREG_image); |
| 85 | + bus(F,XS); |
| 86 | + bus(NEWS,F); |
| 87 | + bus(F,XS); |
| 88 | + |
| 89 | + //SAVE THE ABSOLUTE DIFFERENCE BETWEEN THE SHIFTED IMAGE AND ORIGINAL AS THE HORIZONTAL EDGES RESULT |
| 90 | + sub(F,F,AREG_image); |
| 91 | + abs(AREG_horizontal_edges,F); |
| 92 | + scamp5_kernel_end(); |
| 93 | + |
| 94 | + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 95 | + //THRESHOLD AREG EDGE DATA TO BINARY |
| 96 | + |
| 97 | + scamp5_in(F,edge_threshold);//LOAD THRESHOLD INTO F |
| 98 | + |
| 99 | + scamp5_kernel_begin(); |
| 100 | + //THRESHOLD AREG_vertical_edges TO BINARY RESULT |
| 101 | + sub(E,AREG_vertical_edges,F); |
| 102 | + where(E); |
| 103 | + //IN PES WHERE AREG_vertical_edges > edge_threshold, FLAG == 1 |
| 104 | + MOV(DREG_vertical_edges,FLAG); |
| 105 | + all(); |
| 106 | + |
| 107 | + //THRESHOLD AREG_horizontal_edges TO BINARY RESULT |
| 108 | + sub(E,AREG_horizontal_edges,F); |
| 109 | + where(E); |
| 110 | + //IN PES WHERE AREG_horizontal_edges > edge_threshold, FLAG == 1 |
| 111 | + MOV(DREG_horizontal_edges,FLAG); |
| 112 | + all(); |
| 113 | + scamp5_kernel_end(); |
| 114 | + |
| 115 | + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 116 | + //COMBINE THRESHOLDED HORIZONTAL & VERTICAL EDGE RESULTS |
| 117 | + |
| 118 | + scamp5_kernel_begin(); |
| 119 | + MOV(DREG_combined_edges,DREG_vertical_edges);//COPY VERTICAL EDGE RESULT |
| 120 | + OR(DREG_combined_edges,DREG_horizontal_edges);//OR WITH HORIZONTAL EDGE RESULT |
| 121 | + scamp5_kernel_end(); |
| 122 | + |
| 123 | + |
| 124 | + int position_threshold = 48; |
| 125 | + if(abs(alignment_x) > position_threshold || abs(alignment_y) > position_threshold) |
| 126 | + { |
| 127 | + set_anchor_image = true; |
| 128 | + } |
| 129 | + if(set_anchor_image) |
| 130 | + { |
| 131 | + set_anchor_image = false; |
| 132 | + alignment_x = 0; |
| 133 | + alignment_y = 0; |
| 134 | + vel_x = 0; |
| 135 | + vel_y = 0; |
| 136 | + |
| 137 | + scamp5_kernel_begin(); |
| 138 | + MOV(DREG_keyframe_edges,DREG_combined_edges); |
| 139 | + scamp5_kernel_end(); |
| 140 | + } |
| 141 | + scamp5_kernel_begin(); |
| 142 | + REFRESH(DREG_keyframe_edges); |
| 143 | + scamp5_kernel_end(); |
| 144 | + |
| 145 | + |
| 146 | + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 147 | + //IMAGE ALIGNMENT |
| 148 | + //This code updates the "position" at which the captured image aligns with the stored key-frame |
| 149 | + |
| 150 | + if(use_inertia) |
| 151 | + { |
| 152 | + alignment_x += vel_x; |
| 153 | + alignment_y += vel_y; |
| 154 | + } |
| 155 | + |
| 156 | + //Copy the latest edge frame and shift it to the previous position determined to align with the edge key-frame |
| 157 | + scamp5_kernel_begin(); |
| 158 | + MOV(S4,S1); |
| 159 | + scamp5_kernel_end(); |
| 160 | + scamp5_shift(S4,alignment_x,alignment_y); |
| 161 | + |
| 162 | + //The directions to shift and test for better alignment (i.e. noshift,left,right,down,up) |
| 163 | + int test_shift_directions[][5] = |
| 164 | + { |
| 165 | + {0,0}, |
| 166 | + {1,0}, |
| 167 | + {-1, 0}, |
| 168 | + {0,1}, |
| 169 | + {0, -1}, |
| 170 | + }; |
| 171 | + |
| 172 | + //Array to store the global summations for each tested shift |
| 173 | + int direction_global_sums[5]; |
| 174 | + |
| 175 | + //Test each shift |
| 176 | + for (int n = 0; n < 5; n++) |
| 177 | + { |
| 178 | + int x = test_shift_directions[n][0]; |
| 179 | + int y = test_shift_directions[n][1]; |
| 180 | + |
| 181 | + //Copy the shifted edge frame & apply the test shift to it |
| 182 | + scamp5_kernel_begin(); |
| 183 | + MOV(S6,S4); |
| 184 | + scamp5_kernel_end(); |
| 185 | + scamp5_shift(S6,x,y); |
| 186 | + |
| 187 | + scamp5_in(F,127); |
| 188 | + scamp5_kernel_begin(); |
| 189 | + bus(D,F);//D = -127 |
| 190 | + |
| 191 | + AND(S5,S6,S0);//S5 == 1 where the edges of S6 & DREG_keyframe_edges overlap |
| 192 | + WHERE(S5); |
| 193 | + mov(D,F);//D = 127 in PEs where the edges of |
| 194 | + ALL(); |
| 195 | + scamp5_kernel_end(); |
| 196 | + direction_global_sums[n] = scamp5_global_sum_64(D); |
| 197 | + } |
| 198 | + |
| 199 | + if(direction_global_sums[0] > direction_global_sums[1] && |
| 200 | + direction_global_sums[0] > direction_global_sums[2] && |
| 201 | + direction_global_sums[0] > direction_global_sums[3] && |
| 202 | + direction_global_sums[0] > direction_global_sums[4]) |
| 203 | + { |
| 204 | + |
| 205 | + } |
| 206 | + else |
| 207 | + { |
| 208 | + if(direction_global_sums[1] < direction_global_sums[2]) |
| 209 | + { |
| 210 | + alignment_x--; |
| 211 | + vel_x--; |
| 212 | + } |
| 213 | + else |
| 214 | + { |
| 215 | + alignment_x++; |
| 216 | + vel_x++; |
| 217 | + } |
| 218 | + |
| 219 | + if(direction_global_sums[3] < direction_global_sums[4]) |
| 220 | + { |
| 221 | + alignment_y--; |
| 222 | + vel_y--; |
| 223 | + } |
| 224 | + else |
| 225 | + { |
| 226 | + alignment_y++; |
| 227 | + vel_y++; |
| 228 | + } |
| 229 | + } |
| 230 | + |
| 231 | + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 232 | + //OUTPUT |
| 233 | + |
| 234 | + output_timer.reset(); |
| 235 | + { |
| 236 | +// scamp5_output_image(S6,display_01); |
| 237 | + |
| 238 | + |
| 239 | + scamp5_kernel_begin(); |
| 240 | + MOV(S6,S1); |
| 241 | + scamp5_kernel_end(); |
| 242 | + scamp5_shift(S6,alignment_x+1,alignment_y); |
| 243 | + scamp5_kernel_begin(); |
| 244 | + OR(S5,DREG_keyframe_edges,S6); |
| 245 | + scamp5_kernel_end(); |
| 246 | + scamp5_output_image(S6,display_00); |
| 247 | + |
| 248 | + scamp5_output_image(S1,display_01); |
| 249 | + |
| 250 | + |
| 251 | + |
| 252 | +// scamp5_output_image(DREG_keyframe_edges,display_02); |
| 253 | + } |
| 254 | + int image_output_time_microseconds = output_timer.get_usec();//get the time taken for image output |
| 255 | + |
| 256 | + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 257 | + //OUTPUT TEXT INFO |
| 258 | + |
| 259 | + int frame_time_microseconds = frame_timer.get_usec(); //get the time taken this frame |
| 260 | + int max_possible_frame_rate = 1000000/frame_time_microseconds; //calculate the possible max FPS |
| 261 | + int image_output_time_percentage = (image_output_time_microseconds*100)/frame_time_microseconds; //calculate the % of frame time which is used for image output |
| 262 | + vs_post_text("frame time %d microseconds(%%%d image output), potential FPS ~%d \n",frame_time_microseconds,image_output_time_percentage,max_possible_frame_rate); //display this values on host |
| 263 | + } |
| 264 | + |
| 265 | + return 0; |
| 266 | +} |
| 267 | + |
0 commit comments