Skip to content

Commit e668b79

Browse files
committed
Added background subtraction example
1 parent 4eb20f6 commit e668b79

File tree

2 files changed

+250
-1
lines changed

2 files changed

+250
-1
lines changed
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
#include <scamp5.hpp>
2+
#include "MISC/MISC_FUNCS.hpp"
3+
using namespace SCAMP5_PE;
4+
5+
vs_stopwatch frame_timer;
6+
vs_stopwatch output_timer;
7+
vs_stopwatch areg_quantization_refresh_timer;
8+
9+
const areg_t AREG_captured_image = A;
10+
const areg_t AREG_stored_background = B;
11+
const areg_t AREG_background_update_mask = C;
12+
const dreg_t DREG_detected_motion = S0;
13+
14+
int main()
15+
{
16+
vs_init();
17+
18+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
19+
//SETUP IMAGE DISPLAYS
20+
21+
int disp_size = 2;
22+
auto display_00 = vs_gui_add_display("Captured Image",0,0,disp_size);
23+
auto display_01 = vs_gui_add_display("Stored Background",0,disp_size,disp_size);
24+
auto display_02 = vs_gui_add_display("Background Subtraction Result",0,disp_size*2,disp_size);
25+
auto display_10 = vs_gui_add_display("Background Update Mask",disp_size,0,disp_size);
26+
auto display_11 = vs_gui_add_display("Motion",disp_size,disp_size,disp_size);
27+
28+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
29+
//SETUP GUI ELEMENTS & CONTROLLABLE VARIABLES
30+
31+
int quantization_levels = 16;
32+
vs_gui_add_slider("quantization_levels",2,32,quantization_levels,&quantization_levels);
33+
34+
//Each frame the background update mask is steadily increased in value according to the following variables
35+
//The stored background is updated wherever this mask is high in value
36+
int bg_mask_increase_value = 10;//value added to mask
37+
vs_gui_add_slider("bg_mask_inc_value",0,127,bg_mask_increase_value,&bg_mask_increase_value);
38+
int bg_mask_increase_interval = 250;//time in ms between each addition
39+
vs_gui_add_slider("bg_mask_inc_interval",0,1000,bg_mask_increase_interval,&bg_mask_increase_interval);
40+
vs_stopwatch bg_mask_update_timer;
41+
42+
//Threshold used to detect motion, using frame differencing (i.e. abs(current_frame-previous_frame)
43+
//The background update mask is reset wherever motion is detected, stopping the background from being updated in those PEs
44+
int motion_threshold = 16;
45+
vs_gui_add_slider("motion_threshold",0,127,motion_threshold,&motion_threshold);
46+
47+
int motion_expansion = 5;
48+
vs_gui_add_slider("motion_expansion",0,20,motion_expansion,&motion_expansion);
49+
50+
//The threshold used to detect differences between the stored background and the current frame
51+
int background_sub_threshold = 32;
52+
vs_gui_add_slider("background_sub_threshold",0,127,background_sub_threshold,&background_sub_threshold);
53+
54+
auto gui_btn_store_images = vs_gui_add_button("Set Background");
55+
vs_on_gui_update(gui_btn_store_images,[&](int32_t new_value)
56+
{
57+
scamp5_in(AREG_background_update_mask,127); //Reset Background Mask
58+
});
59+
60+
int output_binary_result = 1;
61+
vs_gui_add_switch("binary_result",output_binary_result == 1,&output_binary_result);
62+
63+
//Reset background update mask
64+
scamp5_in(AREG_background_update_mask,127);
65+
66+
//CONTINOUS FRAME LOOP
67+
while(true)
68+
{
69+
frame_timer.reset();//reset frame_timer
70+
71+
vs_disable_frame_trigger();
72+
vs_frame_loop_control();
73+
74+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
75+
//CAPTURE FRAME
76+
77+
scamp5_kernel_begin();
78+
mov(E, AREG_captured_image);//store a copy previous frame
79+
get_image(AREG_captured_image, F); //get new frame
80+
scamp5_kernel_end();
81+
82+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
83+
//DETECT MOTION BY FRAME DIFFERENCING
84+
85+
scamp5_in(D,motion_threshold);
86+
scamp5_kernel_begin();
87+
//Compute absolute difference between latest frame and previous frame
88+
sub(F,AREG_captured_image,E);// E = difference between latest and previous frame
89+
abs(E,F);// F == absolute difference between current and last frame
90+
91+
//Detect PEs where "motion" occurred due to absolute difference between current and last frame being above threshold
92+
sub(E,E,D);
93+
where(E);
94+
MOV(DREG_detected_motion,FLAG);//Store mask of PEs where there was "motion"
95+
all();
96+
scamp5_kernel_end();
97+
98+
//Expand motion mask to ensure background is not updated in any PEs even near where motion is occuring
99+
scamp5_kernel_begin();
100+
SET(RN,RS,RE,RW);
101+
scamp5_kernel_end();
102+
for(int n = 0 ; n < motion_expansion; n++)
103+
{
104+
scamp5_kernel_begin();
105+
DNEWS0(S6,DREG_detected_motion);//S6 will contain 1s at locations that S0 will expand into this step
106+
OR(DREG_detected_motion,S6);//Combine expanded locations with S0 itself
107+
scamp5_kernel_end();
108+
}
109+
110+
111+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
112+
//UPDATE BACKGROUND MASK
113+
114+
//Where motion occurred reset background update mask to minimum value
115+
scamp5_in(D,-127);
116+
scamp5_kernel_begin();
117+
WHERE(DREG_detected_motion);
118+
mov(AREG_background_update_mask,D);
119+
all();
120+
scamp5_kernel_end();
121+
122+
//If sufficient time has passed, increase the value of mask
123+
if(bg_mask_update_timer.get_usec() >= bg_mask_increase_interval*1000)
124+
{
125+
//Reset Counter
126+
bg_mask_update_timer.reset();
127+
128+
//Update Background Update Mask
129+
scamp5_in(F,bg_mask_increase_value);
130+
scamp5_kernel_begin();
131+
add(AREG_background_update_mask,AREG_background_update_mask,F);
132+
scamp5_kernel_end();
133+
}
134+
135+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
136+
//UPDATE BACKGROUND, BUT ONLY WHERE BACKGROUND UPDATE MASK IS HIGH VALUE
137+
138+
int background_update_mask_threshold = 100;
139+
scamp5_in(F,background_update_mask_threshold);//Threshold at which to perform background update
140+
scamp5_kernel_begin();
141+
sub(E,AREG_background_update_mask,F);
142+
where(E);//Where Background Update Mask > Threshold
143+
mov(AREG_stored_background,AREG_captured_image);//Update Background
144+
all();
145+
scamp5_kernel_end();
146+
147+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
148+
//REFRESH QUANTIZED AREG STORAGE, SNAPS EACH PE'S STORED VALUE TO THE NEAREST QUANTIZED VALUE TO PREVENT VALUE DECAY/DRIFT
149+
150+
areg_quantization_refresh_timer.reset();
151+
{
152+
scamp5_kernel_begin();
153+
SET(S6);//Use the S6 DREG to track which PEs have been snapped to a quantization level
154+
scamp5_kernel_end();
155+
156+
int quantization_interval = 256/(quantization_levels-1);
157+
int current_value = -127;//Value of the current quantization level
158+
int decision_value = current_value + quantization_interval/2;//Value to compare with data to determine if it should snap downwards to current quantization level
159+
160+
//Iterate through each value of quantization, from lowest to highest
161+
for(int n = 0 ; n < quantization_levels-1 ;n++)
162+
{
163+
scamp5_in(F,decision_value);
164+
scamp5_in(E,current_value);
165+
166+
scamp5_kernel_begin();
167+
sub(F,F,AREG_stored_background);
168+
where(F);//Compare stored data with decision value, FLAG == 1 in PEs with data below the decision value
169+
170+
AND(S5,S6,FLAG);//Get PEs whose is below the decision value, AND has not been snapped yet, these PEs will be snapped to a value now
171+
NOT(S6,FLAG);//Update S6, copy the FLAG over now before the next WHERE instruction, all PEs where FLAG = 1 will have had their data snapped to a value
172+
173+
WHERE(S5);
174+
mov(AREG_stored_background,E);//Snap the data of these PEs to the current quantization value
175+
all();
176+
scamp5_kernel_end();
177+
178+
//update current and decision values
179+
current_value += quantization_interval;
180+
decision_value = current_value + quantization_interval/2;
181+
}
182+
183+
//snap all remaining PEs that have not been quantized to the max quantization value
184+
scamp5_in(E,127);
185+
scamp5_kernel_begin();
186+
WHERE(S6);
187+
mov(AREG_stored_background,E);
188+
all();
189+
scamp5_kernel_end();
190+
}
191+
int time_spent_on_areg_quantization_refresh = areg_quantization_refresh_timer.get_usec();
192+
193+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
194+
//COMPUTE BACKGROUND SUBTRACTION MASK
195+
196+
scamp5_in(F,background_sub_threshold);
197+
scamp5_kernel_begin();
198+
//Compute absolute difference between background and current frame
199+
sub(D,AREG_captured_image,AREG_stored_background);
200+
abs(E,D);
201+
202+
//Find where absolute difference is above threshold, and copy the current frames data into these PEs
203+
sub(E,E,F);
204+
where(E);
205+
MOV(S5,FLAG);//Store binary background subtraction mask/result
206+
all();
207+
scamp5_kernel_end();
208+
209+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
210+
//OUTPUT IMAGES
211+
212+
output_timer.reset();
213+
214+
//display current captured frame and thresholded image
215+
output_4bit_image_via_DNEWS(AREG_captured_image,display_00);
216+
output_4bit_image_via_DNEWS(AREG_stored_background,display_01);
217+
output_4bit_image_via_DNEWS(AREG_background_update_mask,display_10);
218+
scamp5_output_image(DREG_detected_motion,display_11);
219+
if(output_binary_result)
220+
{
221+
scamp5_output_image(S5,display_02);
222+
}
223+
else
224+
{
225+
//Generate analogue background subtraction image using the binary background subtraction mask
226+
scamp5_in(E,-127);
227+
scamp5_kernel_begin();
228+
WHERE(S5);
229+
mov(E,AREG_captured_image);
230+
ALL();
231+
scamp5_kernel_end();
232+
output_4bit_image_via_DNEWS(E,display_02);
233+
}
234+
235+
int output_time_microseconds = output_timer.get_usec();//get the time taken for image output
236+
237+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
238+
//OUTPUT TEXT INFO
239+
240+
int frame_time_microseconds = frame_timer.get_usec(); //get the time taken this frame
241+
int max_possible_frame_rate = 1000000/frame_time_microseconds; //calculate the possible max FPS
242+
int image_output_time_percentage = (output_time_microseconds*100)/frame_time_microseconds; //calculate the % of frame time which is used for image output
243+
vs_post_text("time_spent_on_areg_quantization_refresh %d\n",time_spent_on_areg_quantization_refresh);
244+
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
245+
}
246+
return 0;
247+
}
248+

scamp5_main.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
//#include "EXAMPLES/EX04_IMAGE_THRESHOLDING.hpp"
2525
//#include "EXAMPLES/EX05_AREG_NEWS.hpp"
2626
//#include "EXAMPLES/EX06_SIMPLE_EDGE_DETECTION.hpp"
27-
#include "EXAMPLES/EX07_DNEWS.hpp"
27+
//#include "EXAMPLES/EX07_DNEWS.hpp"
2828
//#include "EXAMPLES/EX08_DREG_SHIFTING.hpp"
2929
//#include "EXAMPLES/EX09_DREG_EXPAND_AND_ERODE.hpp"
3030
//#include "EXAMPLES/EX10_HALF_SCALING.hpp"
31+
#include "EXAMPLES/EX_BACKGROUND_SUBTRACTION.hpp"

0 commit comments

Comments
 (0)