├── .gitattributes ├── Baseline ├── Makefile ├── README.md ├── csim.tcl ├── haar.cpp ├── haar.h ├── haar_dataEWC_with_partitioning.h ├── haar_dataRcc_with_partitioning.h ├── haar_mapping.h ├── image.cpp ├── image.h ├── image0_320_240.h ├── main.cpp └── sqrt.h ├── LICENSE ├── Makefile ├── Parallel_and_Pipelined ├── Makefile ├── README.md ├── csim.tcl ├── haar.cpp ├── haar.h ├── haar_dataEWC_with_partitioning.h ├── haar_dataRcc_with_partitioning.h ├── haar_mapping.h ├── image.cpp ├── image.h ├── image0_320_240.h ├── main.cpp └── sqrt.h ├── Pipelined ├── Makefile ├── README.md ├── csim.tcl ├── haar.cpp ├── haar.h ├── haar_dataEWC_with_partitioning.h ├── haar_dataRcc_with_partitioning.h ├── haar_mapping.h ├── image.cpp ├── image.h ├── image0_320_240.h ├── main.cpp └── sqrt.h ├── README.md ├── csim.tcl ├── gen_dataset ├── gen_image.cpp ├── image0_320_240.h ├── image0_320_240.pgm ├── image1_320_240.h ├── image1_320_240.pgm ├── image2_320_240.h ├── image2_320_240.pgm ├── image3_320_240.h ├── image3_320_240.pgm ├── image4_320_240.h └── image4_320_240.pgm ├── haar.cpp ├── haar.h ├── haar_dataEWC_with_partitioning.h ├── haar_dataRcc_with_partitioning.h ├── haar_mapping.h ├── image.cpp ├── image.h ├── image0_320_240.h ├── main.cpp └── sqrt.h /.gitattributes: -------------------------------------------------------------------------------- 1 | **/*.h linguist-language=C++ 2 | -------------------------------------------------------------------------------- /Baseline/Makefile: -------------------------------------------------------------------------------- 1 | APPSOURCES = image.cpp main.cpp haar.cpp 2 | EXECUTABLE = face.elf 3 | 4 | PLATFORM = zc706 5 | SDSFLAGS = -sds-pf ${PLATFORM} \ 6 | -sds-hw detectFaces haar.cpp -clkid 3 -sds-end \ 7 | -poll-mode 1 8 | 9 | 10 | CC = sds++ ${SDSFLAGS} 11 | 12 | CFLAGS = -Wall -O3 -c 13 | CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)" 14 | LFLAGS = -O3 15 | 16 | OBJECTS := $(APPSOURCES:.cpp=.o) 17 | DEPS := $(OBJECTS:.o=.d) 18 | 19 | .PHONY: all 20 | 21 | all: ${EXECUTABLE} 22 | 23 | ${EXECUTABLE}: ${OBJECTS} 24 | ${CC} ${LFLAGS} ${OBJECTS} -o $@ >> sdsoc.log 25 | 26 | %.o: %.cpp 27 | ${CC} ${CFLAGS} $< -o $@ > sdsoc.log 28 | 29 | clean: 30 | ${RM} ${EXECUTABLE} ${OBJECTS} *.d 31 | 32 | csim: 33 | vivado_hls csim.tcl 34 | sw: 35 | g++ -O3 ${APPSOURCES} 36 | 37 | ultraclean: clean 38 | ${RM} ${EXECUTABLE}.bit 39 | ${RM} -rf _sds sd_card hls.prj 40 | ${RM} sdsoc.log vivado_hls.log 41 | -------------------------------------------------------------------------------- /Baseline/README.md: -------------------------------------------------------------------------------- 1 | Publications 2 | ------------------------------------------------------------------------ 3 | 4 | If you use this benchmark in your research, please cite our [FPGA'17 5 | paper][4]: 6 | 7 | ``` 8 | @inproceedings{lockhart-pymtl-micro2014, 9 | title = {Accelerating Face Detection on Programmable SoC Using 10 | C-Based Synthesis}, 11 | author = {Nitish Srivastava and Steve Dai and Rajit Manohar and 12 | Zhiru Zhang}, 13 | booktitle = {25\textsuperscript{th} ACM/SIGDA International 14 | Symposium on Field-Programmable Gate Arrays}, 15 | month = {Feb}, 16 | year = {2017}, 17 | doi = {10.1145/3020078.3021753}, 18 | } 19 | ``` 20 | 21 | [4]: http://dx.doi.org/10.1145/3020078.3021753 22 | 23 | 24 | facedetect-fpga is an open-source implementation of Viola-Jones face 25 | detection algorithm suitable for C-based synthesis. It was introduced 26 | at FPGA-25 in February, 2017. 27 | 28 | Tutorial 29 | ------------------------------------------------------------------------ 30 | 31 | ### C-simulation 32 | 33 | The face detection benchmark has been written in C. The current version 34 | also supports C simulation so that functionality of the algorithm can be 35 | tested without going through the painful process of bitstream generation. 36 | 37 | To do the C-simulation of the design enter the following command in the 38 | main directory: 39 | 40 | % make csim 41 | 42 | This will create a hls.prj directory containing all the logs for the C 43 | simulation. The output of the face-detection can be seen in the directory 44 | hls.prj/solution/csim/build/Output.pgm Make sure that all the faces have 45 | been detected and marked using rectangles. 46 | 47 | One should always do C-simulation before synthesizing the design as it 48 | is fast and detects the trivial syntactic/algorithmic errors. 49 | 50 | ### Bitstream generation 51 | 52 | To synthesize the design for FPGA type the following command in the main 53 | directory: 54 | 55 | % make 56 | 57 | This will produce two folders: 58 | 59 | ./_sds 60 | ./sd_card 61 | 62 | The \_sds folder will have all the reports generated by SDSoC and 63 | Vivado-HLS. The sd\_card folder will have the bitstream and the 64 | associated files which will be used to port face-detection accelerator 65 | onto the FPGA. 66 | 67 | The timing and utilization reports generated by Vivado-HLS can be found 68 | in the following directory: 69 | 70 | _sds/vhls/haar/solution/syn/report 71 | 72 | The log generated by Vivado-HLS can be found as: 73 | 74 | _sds/vhls/vivado_hls.log 75 | 76 | The area, utilzation and timing reports generated by SDSoC can be found 77 | in the following directory: 78 | 79 | _sds/reports 80 | 81 | ### Porting Face-detection accelerator onto the FPGA 82 | 83 | To port the face-detection accelerator onto the FPGA copy all the files 84 | in the sd\_card folder into the SD-card of the FPGA. After that you can 85 | reboot the FPGA board and connect it to your computer using UART. Go to 86 | the mnt folder and run face.elf binary 87 | 88 | $ cd /mnt 89 | $ ./face.elf 90 | 91 | This will print the co-ordinates of all the rectangles detected on the 92 | screen and will also give the time taken to detect the faces. Wait for a 93 | while ( 4-5 seconds ) and remove the SD-card and insert it in your 94 | computer. You will see an Output.pgm file with rectangles drawn around 95 | all the faces. The wait time of 4-5 seconds is to make sure that this 96 | image is written properly. 97 | 98 | ### Adding a new image 99 | 100 | The face-detection algorithm can only process the images when each pixel 101 | in the image is represented as a 8-bit number. The gen\_dataset folder 102 | has the files to generate the hex images using the images in pgm format. 103 | To add a new 320 X 240 image (pgm format) copy it to the folder 104 | gen\_dataset. Edit the input and the output file names in the main 105 | function in gen\_dataset/gen\_image.cpp and compile and run it: 106 | 107 | % cd gen_dataset 108 | % cp /path/to/image/test-image.pgm . 109 | 110 | Edit main() function in gen_image.cpp/ 111 | 112 | % g++ gen_image.cpp 113 | % ./a.out 114 | 115 | This will produce the .h file for the image with the image pixels in the 116 | hex format. Copy this .h file to the main directory: 117 | 118 | % cp test-image.h ../. 119 | 120 | And then edit the main.cpp file to have this line instead: 121 | 122 | #include "image0_320_240.h" 123 | 124 | Now you have added a new image. Do the C-simulation as described above. 125 | Make sure the C-simulation is working and producing the right results. 126 | Generate the bitstream and run it on the FPGA. 127 | 128 | 129 | ### Stages of Optimizations 130 | 131 | The source code for different stages of optimizations mentioned in our 132 | paper is also added to the repository so that users can get a feel of 133 | the effects of each and every optimzation. There are 3 extra folders 134 | which are added to the repo: 135 | 136 | Baseline : This folder has the baseline implementation which replaces 137 | all the non synthesizable constructs. 138 | 139 | Pipelined : This folder has the code when all the classifiers are 140 | pipelined. 141 | 142 | Parallel\_and\_Pipeline : This folder has the code when the classifiers 143 | in the first 3 stages are in parallel and the ones in the other 22 144 | stages are in pipeline. 145 | 146 | The main folder has the code which combines all these optimizations. 147 | 148 | 149 | License 150 | ------------------------------------------------------------------------ 151 | 152 | face-detection benchmark is offered under the terms of the Open Source 153 | Initiative BSD 3-Clause License. More information about this license can 154 | be found here: 155 | 156 | - http://choosealicense.com/licenses/bsd-3-clause 157 | - http://opensource.org/licenses/BSD-3-Clause 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /Baseline/csim.tcl: -------------------------------------------------------------------------------- 1 | #============================================================================= 2 | # run.tcl 3 | #============================================================================= 4 | # @brief: A Tcl script for C simulation of the face-detection design 5 | 6 | # Open/reset the project 7 | open_project hls.prj -reset 8 | 9 | # Top function of the design is "detectFaces" 10 | set_top detectFaces 11 | 12 | # Add design and testbench files 13 | add_files haar.cpp 14 | 15 | add_files -tb main.cpp 16 | add_files -tb image.cpp 17 | 18 | open_solution solution 19 | 20 | # Use Zynq device 21 | # zc-706 22 | set_part xc7z045ffg900-2 23 | 24 | config_rtl -reset state 25 | 26 | # Simulate the C++ design 27 | csim_design 28 | 29 | # Co-simulate the design 30 | # cosim_design 31 | 32 | exit 33 | -------------------------------------------------------------------------------- /Baseline/haar.cpp: -------------------------------------------------------------------------------- 1 | #include "haar.h" 2 | #include "sqrt.h" 3 | 4 | #define TOTAL_NODES 2913 5 | #define TOTAL_STAGES 25 6 | #define TOTAL_COORDINATES TOTAL_NODES*12 7 | #define TOTAL_WEIGHTS TOTAL_NODES*3 8 | 9 | #define WINDOW_SIZE 25 10 | #define SQ_SIZE 2 11 | #define PYRAMID_HEIGHT 12 12 | 13 | /****************************************************************************************/ 14 | /* DECLARATION OF FUNCTIONS 15 | ****************************************************************************************/ 16 | void integralImages( int height, int width, unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH], int Sum[IMAGE_HEIGHT][IMAGE_WIDTH], int Sqsum[IMAGE_HEIGHT][IMAGE_WIDTH]); 17 | 18 | void imageScaler ( int src_height, 19 | int src_width, 20 | unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH], 21 | int dest_height, 22 | int dest_width, 23 | unsigned char IMG1_data[IMAGE_HEIGHT][IMAGE_WIDTH] 24 | ); 25 | 26 | void processImage ( float factor, 27 | int sum_row, 28 | int sum_col, 29 | int *AllCandidates_x, 30 | int *AllCandidates_y, 31 | int *AllCandidates_w, 32 | int *AllCandidates_h, 33 | int *AllCandidates_size, 34 | unsigned char IMG1_data[IMAGE_HEIGHT][IMAGE_WIDTH], 35 | MySize winSize 36 | ); 37 | 38 | 39 | int cascadeClassifier ( int SUM1_data[IMAGE_HEIGHT][IMAGE_WIDTH], 40 | int SQSUM1_data[IMAGE_HEIGHT][IMAGE_WIDTH], 41 | MyPoint pt 42 | ); 43 | 44 | int weakClassifier ( int stddev, 45 | ap_uint<25> coord[12], 46 | int haar_counter, 47 | int w_id 48 | ); 49 | 50 | void groupRectangles ( MyRect *rectList, 51 | int *rectList_size, 52 | int groupThreshold, 53 | float eps 54 | ); 55 | 56 | unsigned int int_sqrt ( unsigned int value 57 | ); 58 | 59 | inline int myRound ( float value ) 60 | { 61 | return (int)(value + (value >= 0 ? 0.5 : -0.5)); 62 | } 63 | 64 | //======================================================================================== 65 | // TOP LEVEL MODULE OR DUT (DEVICE UNDER TEST) 66 | //======================================================================================== 67 | 68 | void detectFaces 69 | 70 | ( 71 | unsigned char inData[IMAGE_WIDTH], // input port 72 | int result_x[RESULT_SIZE], // Output ports 73 | int result_y[RESULT_SIZE], 74 | int result_w[RESULT_SIZE], 75 | int result_h[RESULT_SIZE], 76 | int *result_size 77 | ) 78 | 79 | { 80 | static unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH]; 81 | int i, j; 82 | 83 | int result_x_Scale[RESULT_SIZE]; 84 | int result_y_Scale[RESULT_SIZE]; 85 | int result_w_Scale[RESULT_SIZE]; 86 | int result_h_Scale[RESULT_SIZE]; 87 | int res_size_Scale = 0; 88 | int *result_size_Scale = &res_size_Scale; 89 | 90 | /* Here we save the 320 X 240 image into the BRAMS. The CPU makes 240 calls to this hardware function haar 91 | * first 239 calls just load the BRAMs with the image and last 240th call does the actual face detection 92 | * This is a hacky way because SDSoC does not allow to send 320X240 image at once. In future sdsalloc can be 93 | * used allocate the memory directly into the FPGA. */ 94 | 95 | static int counter = 0; 96 | if ( counter < IMAGE_HEIGHT){ 97 | for( j = 0; j < IMAGE_WIDTH; j++){ 98 | Data[counter][j] = inData[j]; 99 | } 100 | counter++; 101 | if ( counter < IMAGE_HEIGHT ){ 102 | for ( i = 0; i < RESULT_SIZE; i++){ 103 | result_x[i] = 0; 104 | result_y[i] = 0; 105 | result_w[i] = 0; 106 | result_h[i] = 0; 107 | } 108 | *result_size = 0; 109 | return ; // return to the CPU to get next line in gthe image 110 | } 111 | } 112 | 113 | *result_size = 0; 114 | 115 | float scaleFactor = 1.2; 116 | unsigned char IMG1_data[IMAGE_HEIGHT][IMAGE_WIDTH]; 117 | 118 | float factor; 119 | int height,width; 120 | 121 | MySize winSize0; 122 | winSize0.width = 24; 123 | winSize0.height= 24; 124 | 125 | factor = scaleFactor; 126 | 127 | // Loop for image pyramid formation 128 | 129 | L1: 130 | while ( IMAGE_WIDTH/factor > WINDOW_SIZE && IMAGE_HEIGHT/factor > WINDOW_SIZE ) 131 | { 132 | 133 | /* size of the window scaled up */ 134 | MySize winSize = { myRound(winSize0.width*factor), myRound(winSize0.height*factor) }; 135 | 136 | /* size of the image scaled down */ 137 | MySize sz = { (IMAGE_WIDTH/factor), (IMAGE_HEIGHT/factor) }; 138 | 139 | height = sz.height; 140 | width = sz.width; 141 | 142 | imageScaler ( IMAGE_HEIGHT, 143 | IMAGE_WIDTH, 144 | Data, 145 | height, 146 | width, 147 | IMG1_data 148 | ); 149 | 150 | 151 | processImage ( factor, 152 | height, 153 | width, 154 | result_x_Scale, 155 | result_y_Scale, 156 | result_w_Scale, 157 | result_h_Scale, 158 | result_size_Scale, 159 | IMG1_data, 160 | winSize 161 | ); 162 | factor *= scaleFactor; 163 | } 164 | 165 | for ( i = 0; i < RESULT_SIZE; i++){ 166 | result_x[i] = result_x_Scale[i]; 167 | result_y[i] = result_y_Scale[i]; 168 | result_w[i] = result_w_Scale[i]; 169 | result_h[i] = result_h_Scale[i]; 170 | } 171 | *result_size = *result_size_Scale; 172 | } 173 | 174 | void processImage 175 | 176 | ( float factor, 177 | int sum_row, 178 | int sum_col, 179 | int *AllCandidates_x, 180 | int *AllCandidates_y, 181 | int *AllCandidates_w, 182 | int *AllCandidates_h, 183 | int *AllCandidates_size, 184 | unsigned char IMG1_data[IMAGE_HEIGHT][IMAGE_WIDTH], 185 | MySize winSize 186 | ) 187 | { 188 | #pragma HLS inline off 189 | MyPoint p; 190 | int result; 191 | int step; 192 | 193 | int u,v; 194 | int x,y,i,j,k; 195 | 196 | int SUM1_data[IMAGE_HEIGHT][IMAGE_WIDTH], SQSUM1_data[IMAGE_HEIGHT][IMAGE_WIDTH]; 197 | 198 | integralImages( sum_row, sum_col ,IMG1_data, SUM1_data, SQSUM1_data ); 199 | 200 | Pixely: for( y = 0; y < sum_row - WINDOW_SIZE + 1; y++ ){ 201 | Pixelx: for ( x = 0; x < sum_col - WINDOW_SIZE + 1; x++ ){ 202 | 203 | p.x = x; 204 | p.y = y; 205 | 206 | result = cascadeClassifier ( SUM1_data, 207 | SQSUM1_data, 208 | p 209 | ); 210 | 211 | if ( result > 0 ) { 212 | MyRect r = {myRound(p.x*factor), myRound(p.y*factor), winSize.width, winSize.height}; 213 | AllCandidates_x[*AllCandidates_size]=r.x; 214 | AllCandidates_y[*AllCandidates_size]=r.y; 215 | AllCandidates_w[*AllCandidates_size]=r.width; 216 | AllCandidates_h[*AllCandidates_size]=r.height; 217 | *AllCandidates_size=*AllCandidates_size+1; 218 | } 219 | } 220 | } 221 | } 222 | 223 | int cascadeClassifier 224 | 225 | ( int SUM1_data[IMAGE_HEIGHT][IMAGE_WIDTH], 226 | int SQSUM1_data[IMAGE_HEIGHT][IMAGE_WIDTH], 227 | MyPoint pt 228 | ) 229 | 230 | { 231 | #pragma HLS INLINE 232 | 233 | int i, j, k; 234 | 235 | int mean; 236 | int stddev = 0; 237 | int haar_counter = 0; 238 | int w_index = 0; 239 | int r_index = 0; 240 | int stage_sum=0; 241 | 242 | #include "haar_dataRcc_with_partitioning.h" 243 | 244 | static ap_uint<25> coord[12]; 245 | #pragma HLS array_partition variable=coord complete dim=0 246 | 247 | 248 | MyRect equRect; 249 | 250 | equRect.x = equRect.y = 0; 251 | equRect.width = WINDOW_SIZE; 252 | equRect.height = WINDOW_SIZE; 253 | 254 | stddev = SQSUM1_data[pt.y][pt.x] 255 | - SQSUM1_data[pt.y][pt.x+WINDOW_SIZE-1] 256 | - SQSUM1_data[pt.y+WINDOW_SIZE-1][pt.x] 257 | + SQSUM1_data[pt.y+WINDOW_SIZE-1][pt.x+WINDOW_SIZE-1]; 258 | 259 | mean = SUM1_data[pt.y][pt.x] 260 | - SUM1_data[pt.y][pt.x+WINDOW_SIZE-1] 261 | - SUM1_data[pt.y+WINDOW_SIZE-1][pt.x] 262 | + SUM1_data[pt.y+WINDOW_SIZE-1][pt.x+WINDOW_SIZE-1]; 263 | 264 | stddev = (stddev*(WINDOW_SIZE-1)*(WINDOW_SIZE-1)); 265 | stddev = stddev - mean*mean; 266 | 267 | if( stddev > 0 ) 268 | { 269 | stddev = int_sqrt(stddev); 270 | } 271 | else{ 272 | stddev = 1; 273 | } 274 | 275 | MyRect tr0,tr1,tr2; 276 | 277 | int r_id; 278 | int w_id; 279 | int s; 280 | 281 | Stages: for ( i = 0; i < 25; i++ ) { 282 | Filters: for ( j = 0; j < stages_array[i] ; j++ ){ 283 | 284 | if ( j == 0 ) { 285 | stage_sum = 0; s=0; 286 | } 287 | 288 | r_id = r_index; 289 | w_id = w_index; 290 | 291 | tr0.x = pt.x + rectangles_array0[haar_counter]; 292 | tr0.width = rectangles_array2[haar_counter]; 293 | tr0.y = pt.y + rectangles_array1[haar_counter]; 294 | tr0.height = rectangles_array3[haar_counter]; 295 | 296 | tr1.x = pt.x + rectangles_array4[haar_counter]; 297 | tr1.width = rectangles_array6[haar_counter]; 298 | tr1.y = pt.y + rectangles_array5[haar_counter]; 299 | tr1.height = rectangles_array7[haar_counter]; 300 | 301 | tr2.x = rectangles_array8[haar_counter]; 302 | tr2.width = rectangles_array10[haar_counter]; 303 | tr2.y = rectangles_array9[haar_counter]; 304 | tr2.height = rectangles_array11[haar_counter]; 305 | 306 | coord[0] = SUM1_data[tr0.y][tr0.x]; 307 | coord[1] = SUM1_data[tr0.y][tr0.x+tr0.width]; 308 | coord[2] = SUM1_data[tr0.y+tr0.height][tr0.x]; 309 | coord[3] = SUM1_data[tr0.y+tr0.height][tr0.x+tr0.width]; 310 | 311 | coord[4] = SUM1_data[tr1.y][tr1.x]; 312 | coord[5] = SUM1_data[tr1.y][tr1.x+tr1.width]; 313 | coord[6] = SUM1_data[tr1.y+tr1.height][tr1.x]; 314 | coord[7] = SUM1_data[tr1.y+tr1.height][tr1.x+tr1.width]; 315 | 316 | if (!(tr2.x ==0 && tr2.width==0 && tr2.y==0 && tr2.height==0 ) && tr2.width!=0 && tr2.height!=0) 317 | { 318 | coord[8] = SUM1_data[pt.y + tr2.y][pt.x + tr2.x]; 319 | coord[9] = SUM1_data[pt.y + tr2.y][pt.x + tr2.x+tr2.width]; 320 | coord[10] = SUM1_data[pt.y + tr2.y+tr2.height][pt.x + tr2.x]; 321 | coord[11] = SUM1_data[pt.y + tr2.y+tr2.height][pt.x + tr2.x+tr2.width]; 322 | } 323 | else 324 | { 325 | coord[8] = 0; 326 | coord[9] = 0; 327 | coord[10] = 0; 328 | coord[11] = 0; 329 | } 330 | 331 | s = weakClassifier ( stddev, 332 | coord, 333 | haar_counter, 334 | w_id 335 | ); 336 | 337 | stage_sum = stage_sum + s; 338 | haar_counter = haar_counter+1; 339 | w_index = w_index+3; 340 | r_index = r_index+12; 341 | } /* end of j loop */ 342 | 343 | if( stage_sum < 0.4*stages_thresh_array[i] ){ 344 | return -i; 345 | } 346 | } /* end of i loop */ 347 | 348 | return 1; 349 | } 350 | 351 | int weakClassifier 352 | ( 353 | int stddev, 354 | ap_uint<25> coord[12], 355 | int haar_counter, 356 | int w_id 357 | ) 358 | { 359 | #include "haar_dataEWC_with_partitioning.h" 360 | #pragma HLS INLINE 361 | int t = tree_thresh_array[haar_counter] * stddev; 362 | 363 | int sum0 =0; 364 | int sum1 =0; 365 | int sum2 =0; 366 | int final_sum =0; 367 | int return_value; 368 | 369 | sum0 = (coord[0] - coord[1] - coord[2] + coord[3]) * weights_array0[haar_counter];//[w_id] area of 1st filter block (rectangle) multiplied by its weigh 370 | sum1 = (coord[4] - coord[5] - coord[6] + coord[7]) * weights_array1[haar_counter];//[w_id+1]; 371 | sum2 = (coord[8] - coord[9] - coord[10] + coord[11]) * weights_array2[haar_counter];//[w_id+2]; 372 | final_sum = sum0+sum1+sum2; 373 | 374 | if(final_sum >= t) 375 | { 376 | return_value = alpha2_array[haar_counter]; 377 | } 378 | else 379 | { 380 | return_value = alpha1_array[haar_counter]; 381 | } 382 | 383 | return return_value ; 384 | 385 | } 386 | 387 | void integralImages( int height, int width, unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH], int Sum[IMAGE_HEIGHT][IMAGE_WIDTH], int Sqsum[IMAGE_HEIGHT][IMAGE_WIDTH]) 388 | { 389 | int x, y, s, sq, t, tq; 390 | unsigned char it; 391 | 392 | for( y = 0; y < height; y++) 393 | { 394 | s = 0; 395 | sq = 0; 396 | /* loop over the number of columns */ 397 | for( x = 0; x < width; x ++) 398 | { 399 | it = Data[y][x]; 400 | /* sum of the current row (integer)*/ 401 | s += it; 402 | sq += it*it; 403 | 404 | t = s; 405 | tq = sq; 406 | if (y != 0) 407 | { 408 | t += Sum[(y-1)][x]; 409 | tq += Sqsum[(y-1)][x]; 410 | } 411 | Sum[y][x]=t; 412 | Sqsum[y][x]=tq; 413 | } 414 | } 415 | } 416 | 417 | 418 | /*********************************************************** 419 | * This function downsample an image using nearest neighbor 420 | * It is used to build the image pyramid 421 | **********************************************************/ 422 | void imageScaler 423 | ( 424 | int src_height, 425 | int src_width, 426 | unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH], 427 | int dest_height, 428 | int dest_width, 429 | unsigned char IMG1_data[IMAGE_HEIGHT][IMAGE_WIDTH] 430 | ) 431 | { 432 | int y; 433 | int j; 434 | int x; 435 | int i; 436 | unsigned char* t; 437 | unsigned char* p; 438 | int w1 = src_width; 439 | int h1 = src_height; 440 | int w2 = dest_width; 441 | int h2 = dest_height; 442 | 443 | int rat = 0; 444 | 445 | int x_ratio = (int)((w1<<16)/w2) +1; 446 | int y_ratio = (int)((h1<<16)/h2) +1; 447 | 448 | 449 | nearestNeighborL1: 450 | for ( i = 0 ; i < IMAGE_HEIGHT ; i++ ) 451 | { 452 | nearestNeighborL1_1: 453 | for (j=0;j < IMAGE_WIDTH ;j++) 454 | { 455 | #pragma HLS pipeline 456 | if ( j < w2 && i < h2 ) 457 | { 458 | IMG1_data[i][j] = Data[(i*y_ratio)>>16][(j*x_ratio)>>16]; 459 | } 460 | } 461 | } 462 | } 463 | 464 | unsigned int int_sqrt 465 | ( 466 | unsigned int value 467 | ) 468 | { 469 | int i; 470 | unsigned int a = 0, b = 0, c = 0; 471 | 472 | 473 | 474 | for ( i = 0 ; i < (32 >> 1) ; i++ ) 475 | { 476 | #pragma HLS unroll 477 | c<<= 2; 478 | #define UPPERBITS(value) (value>>30) 479 | c += UPPERBITS(value); 480 | #undef UPPERBITS 481 | value <<= 2; 482 | a <<= 1; 483 | b = (a<<1) | 1; 484 | if ( c >= b ) 485 | { 486 | c -= b; 487 | a++; 488 | } 489 | } 490 | return a; 491 | } 492 | 493 | 494 | int max 495 | ( 496 | int a, 497 | int b 498 | ) 499 | { 500 | if ( a > b ) 501 | return a; 502 | else 503 | return b; 504 | } 505 | 506 | int min 507 | ( 508 | int a, 509 | int b 510 | ) 511 | { 512 | if ( a < b ) 513 | return a; 514 | else 515 | return b; 516 | } 517 | 518 | -------------------------------------------------------------------------------- /Baseline/haar.h: -------------------------------------------------------------------------------- 1 | #ifndef __HAAR_H__ 2 | #define __HAAR_H__ 3 | 4 | #include "ap_int.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "ap_int.h" 11 | 12 | const int ROWS = 25; 13 | const int COLS = 25; 14 | 15 | const int NUM_BANKS = 12; 16 | const int SIZE = 2913; 17 | 18 | typedef ap_uint<18> uint18_t; 19 | typedef ap_uint<10> uint10_t; 20 | typedef ap_uint<1> bit; 21 | typedef ap_uint<5> uint5_t; 22 | 23 | 24 | #ifndef __PARAMETERS__ 25 | #define __PARAMETERS__ 26 | 27 | #define IMAGE_HEIGHT 240 28 | #define IMAGE_WIDTH 320 29 | #define IMAGE_MAXGREY 255 30 | #define IMAGE_SIZE ( IMAGE_HEIGHT * IMAGE_WIDTH ) 31 | 32 | #define RESULT_SIZE 100 33 | 34 | #define TOTAL_NODES 2913 35 | #define TOTAL_STAGES 25 36 | #define TOTAL_COORDINATES TOTAL_NODES*12 37 | #define TOTAL_WEIGHTS TOTAL_NODES*3 38 | 39 | #define WINDOW_SIZE 25 40 | #define SQ_SIZE 2 41 | #define PYRAMID_HEIGHT 12 42 | 43 | #define OUTPUT_FILENAME "Output.pgm" 44 | #define INPUT_IMAGE "image0_320_240.h" 45 | 46 | 47 | #endif 48 | 49 | 50 | typedef ap_uint<13> int_I; 51 | typedef ap_uint<21> int_SI; 52 | typedef ap_uint<18> int_II; 53 | typedef ap_uint<26> int_SII; 54 | 55 | #ifdef __cplusplus 56 | extern "C" { 57 | #endif 58 | 59 | typedef struct MyPoint 60 | { 61 | int x; 62 | int y; 63 | } 64 | MyPoint; 65 | 66 | typedef struct 67 | { 68 | int width; 69 | int height; 70 | } 71 | MySize; 72 | 73 | typedef struct 74 | { 75 | int x; 76 | int y; 77 | int width; 78 | int height; 79 | } 80 | MyRect; 81 | 82 | typedef struct 83 | { 84 | int width; 85 | int height; 86 | int maxgrey; 87 | int flag; 88 | } 89 | MyInputImage; 90 | 91 | void detectFaces( unsigned char Data[IMAGE_WIDTH], 92 | int _result_x[RESULT_SIZE], 93 | int _result_y[RESULT_SIZE], 94 | int _result_w[RESULT_SIZE], 95 | int _result_h[RESULT_SIZE], 96 | int *result_size); 97 | 98 | #ifdef __cplusplus 99 | } 100 | #endif 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /Baseline/haar_mapping.h: -------------------------------------------------------------------------------- 1 | 2 | static int bank_mapping[ROWS * COLS] = 3 | {8, 13, 20, 14, 21, 12, 10, 1, 15, 2, 14, 17, 16, 20, 9, 6, 19, 14, 1, 0, 2, 18, 11, 5, 4, 15, 16, 13, 2, 0, 15, 24, 21, 25, 4, 14, 27, 23, 7, 12, 10, 3, 6, 18, 20, 11, 9, 4, 2, 16, 23, 25, 0, 5, 12, 6, 3, 15, 4, 13, 19, 12, 18, 20, 25, 1, 14, 17, 16, 19, 26, 22, 1, 21, 2, 12, 12, 17, 25, 3, 19, 21, 7, 16, 24, 22, 25, 13, 23, 26, 20, 27, 22, 7, 5, 5, 3, 2, 27, 14, 0, 5, 11, 10, 17, 4, 12, 27, 21, 3, 25, 20, 19, 24, 23, 26, 24, 19, 13, 9, 15, 16, 6, 15, 22, 17, 20, 26, 4, 24, 25, 13, 0, 22, 23, 7, 11, 11, 6, 5, 12, 3, 26, 22, 18, 18, 10, 9, 1, 1, 9, 9, 14, 1, 20, 3, 11, 11, 24, 7, 17, 0, 4, 9, 1, 12, 22, 13, 2, 15, 19, 5, 21, 10, 10, 13, 27, 6, 14, 4, 5, 20, 24, 11, 11, 9, 19, 2, 2, 23, 21, 1, 15, 0, 21, 7, 18, 18, 9, 18, 20, 3, 27, 17, 6, 23, 19, 17, 1, 12, 11, 22, 7, 2, 23, 6, 25, 15, 4, 16, 0, 11, 5, 19, 21, 22, 4, 24, 6, 1, 20, 6, 10, 2, 16, 11, 23, 7, 7, 0, 1, 15, 9, 17, 17, 12, 12, 13, 14, 3, 6, 1, 16, 0, 25, 19, 1, 20, 7, 14, 2, 2, 9, 3, 17, 16, 21, 5, 10, 7, 14, 15, 26, 23, 15, 5, 24, 2, 27, 10, 1, 16, 16, 7, 0, 15, 9, 6, 19, 19, 14, 11, 18, 3, 20, 20, 20, 23, 25, 17, 16, 18, 9, 2, 22, 22, 15, 6, 6, 0, 7, 5, 5, 16, 2, 9, 12, 18, 21, 13, 25, 14, 3, 17, 11, 19, 19, 15, 7, 2, 18, 18, 18, 5, 13, 13, 14, 14, 21, 20, 9, 10, 16, 9, 11, 19, 4, 12, 26, 23, 18, 22, 22, 11, 23, 7, 2, 19, 9, 9, 21, 14, 0, 18, 4, 5, 6, 17, 15, 4, 26, 13, 19, 20, 10, 2, 2, 11, 16, 26, 24, 18, 14, 3, 1, 0, 10, 13, 4, 16, 5, 6, 21, 14, 3, 13, 0, 5, 11, 20, 17, 17, 25, 15, 24, 10, 4, 22, 3, 5, 5, 6, 12, 12, 13, 3, 14, 11, 11, 25, 10, 7, 20, 22, 6, 4, 5, 7, 3, 9, 26, 22, 23, 18, 15, 6, 20, 21, 25, 10, 4, 17, 13, 5, 12, 3, 25, 0, 0, 0, 1, 0, 2, 4, 11, 25, 17, 23, 4, 3, 24, 26, 20, 5, 12, 7, 0, 27, 6, 18, 24, 10, 22, 14, 15, 21, 15, 23, 1, 3, 17, 9, 27, 16, 18, 26, 4, 19, 10, 9, 12, 25, 0, 24, 24, 22, 16, 6, 23, 2, 25, 13, 14, 24, 15, 21, 1, 9, 19, 10, 4, 11, 23, 26, 24, 22, 16, 1, 20, 2, 9, 19, 18, 7, 11, 9, 10, 1, 17, 2, 12, 0, 3, 20, 12, 12, 2, 5, 15, 6, 11, 26, 1, 19, 13, 14, 27, 7, 13, 22, 26, 2, 4, 22, 1, 6, 27, 7, 22, 11, 12, 18, 0, 15, 3, 13, 24, 2, 15, 27, 7, 5, 9, 1, 21, 3, 1, 9, 16, 17, 24, 19, 16, 26, 11, 20, 12, 18, 22, 17, 25, 9, 27, 7, 4, 16, 15, 2, 3, 5, 14, 21, 24, 13, 13, 23, 7, 26, 5, 6, 20, 3, 10, 11, 22, 2, 23, 24, 12, 17, 27, 1, 25, 18, 18}; 4 | 5 | static int offset_mapping[ROWS * COLS] = 6 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 2, 1, 2, 0, 1, 0, 1, 3, 0, 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 3, 2, 1, 1, 2, 1, 2, 2, 1, 3, 3, 2, 1, 3, 2, 3, 2, 2, 4, 1, 3, 2, 0, 0, 3, 2, 4, 4, 5, 2, 3, 2, 3, 3, 1, 4, 1, 1, 4, 3, 2, 1, 4, 1, 2, 2, 2, 3, 3, 5, 2, 5, 3, 4, 2, 2, 3, 4, 6, 3, 4, 4, 5, 5, 4, 2, 3, 2, 3, 5, 4, 2, 4, 5, 3, 5, 3, 4, 6, 3, 5, 4, 6, 5, 4, 4, 4, 3, 3, 4, 4, 5, 7, 5, 4, 5, 3, 4, 3, 3, 4, 5, 4, 5, 6, 6, 7, 6, 5, 6, 5, 4, 5, 5, 6, 6, 7, 8, 6, 6, 6, 6, 6, 6, 5, 4, 5, 7, 4, 5, 7, 7, 7, 8, 6, 7, 8, 7, 7, 7, 8, 5, 6, 8, 7, 6, 7, 5, 5, 6, 8, 7, 9, 7, 5, 6, 6, 6, 8, 7, 9, 9, 9, 7, 6, 9, 7, 7, 7, 8, 8, 6, 7, 10, 8, 9, 8, 8, 9, 7, 8, 10, 10, 9, 6, 10, 7, 11, 8, 7, 8, 8, 11, 9, 9, 8, 9, 10, 11, 8, 8, 8, 10, 12, 8, 9, 8, 10, 13, 11, 9, 9, 11, 12, 10, 9, 10, 9, 9, 9, 7, 10, 10, 10, 5, 9, 11, 10, 8, 13, 6, 8, 14, 10, 11, 11, 10, 12, 11, 11, 11, 12, 11, 12, 8, 10, 12, 13, 14, 10, 9, 11, 12, 9, 12, 14, 9, 10, 13, 12, 13, 11, 12, 11, 12, 13, 15, 13, 12, 10, 10, 9, 10, 12, 11, 12, 13, 13, 14, 14, 13, 16, 11, 12, 13, 13, 10, 11, 13, 14, 11, 15, 14, 9, 14, 15, 14, 15, 10, 13, 6, 11, 14, 11, 12, 15, 12, 14, 17, 16, 16, 17, 12, 15, 12, 15, 11, 14, 14, 13, 15, 12, 7, 12, 17, 16, 10, 18, 19, 16, 15, 8, 9, 16, 16, 12, 15, 13, 11, 13, 13, 16, 15, 15, 13, 17, 13, 14, 14, 16, 17, 17, 14, 15, 11, 16, 10, 12, 14, 13, 14, 17, 18, 16, 14, 15, 15, 15, 18, 18, 19, 12, 13, 15, 18, 14, 17, 15, 19, 16, 16, 18, 9, 15, 13, 17, 17, 18, 19, 14, 13, 14, 16, 16, 16, 20, 16, 17, 14, 15, 16, 17, 16, 18, 20, 17, 20, 15, 17, 14, 18, 18, 11, 10, 20, 21, 17, 17, 19, 7, 19, 18, 12, 15, 16, 19, 18, 15, 19, 15, 17, 19, 18, 19, 8, 17, 19, 11, 19, 18, 16, 20, 18, 16, 20, 13, 14, 17, 18, 20, 16, 21, 17, 17, 20, 15, 20, 16, 18, 21, 19, 17, 20, 21, 17, 12, 16, 18, 19, 19, 21, 22, 22, 20, 20, 18, 22, 23, 18, 20, 19, 23, 19, 21, 20, 22, 20, 21, 24, 22, 21, 21, 23, 13, 21, 21, 18, 21, 9, 19, 19, 19, 14, 25, 21, 20, 22, 22, 10, 20, 21, 24, 22, 21, 22, 22, 21, 20, 17, 26, 23, 11, 21, 23, 24, 23, 17, 22, 24, 25, 20, 20, 18, 22, 21, 15, 25, 23, 23, 22, 22, 21, 18, 26, 12, 22, 22, 22, 24, 27, 23, 24, 22, 18, 19, 21, 22, 18, 23, 16, 25, 23, 24, 24, 19, 26, 23, 28, 19, 20, 24, 22, 13, 25, 19, 23, 24}; 7 | -------------------------------------------------------------------------------- /Baseline/image.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "image.h" 5 | 6 | #define MYDEBUG 7 | 8 | char* strrev(char* str) 9 | { 10 | char *p1, *p2; 11 | if (!str || !*str) 12 | return str; 13 | for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2) 14 | { 15 | *p1 ^= *p2; 16 | *p2 ^= *p1; 17 | *p1 ^= *p2; 18 | } 19 | return str; 20 | } 21 | 22 | void itochar(int x, char* szBuffer, int radix) 23 | { 24 | int i = 0, n, xx; 25 | n = x; 26 | while (n > 0) 27 | { 28 | xx = n%radix; 29 | n = n/radix; 30 | szBuffer[i++] = '0' + xx; 31 | } 32 | szBuffer[i] = '\0'; 33 | strrev(szBuffer); 34 | } 35 | 36 | /* Writes a Pgm file using the hex image */ 37 | int writePgm(char *fileName, unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH] ) 38 | { 39 | char parameters_str[5]; 40 | int i; 41 | const char *format = "P5"; 42 | FILE *fp = fopen(fileName, "w"); 43 | 44 | if (!fp){ 45 | printf("Unable to open file %s\n", fileName); 46 | return -1; 47 | } 48 | 49 | fputs(format, fp); 50 | fputc('\n', fp); 51 | 52 | itochar(IMAGE_WIDTH, parameters_str, 10); 53 | fputs(parameters_str, fp); 54 | parameters_str[0] = 0; 55 | fputc(' ', fp); 56 | 57 | itochar(IMAGE_HEIGHT, parameters_str, 10); 58 | fputs(parameters_str, fp); 59 | parameters_str[0] = 0; 60 | fputc('\n', fp); 61 | 62 | itochar(IMAGE_MAXGREY, parameters_str, 10); 63 | fputs(parameters_str, fp); 64 | fputc('\n', fp); 65 | 66 | for (i = 0; i < IMAGE_HEIGHT; i++) 67 | for (int j = 0; j < IMAGE_WIDTH ; j++) 68 | fputc(Data[i][j], fp); 69 | 70 | fclose(fp); 71 | return 0; 72 | } 73 | 74 | /* draw white bounding boxes around detected faces */ 75 | void drawRectangle(unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH], MyRect r) 76 | { 77 | int i; 78 | int col = IMAGE_WIDTH; 79 | 80 | for (i = 0; i < r.width; i++) 81 | Data[r.y][r.x + i] = 255; 82 | for (i = 0; i < r.height; i++) 83 | Data[r.y+i][r.x + r.width] = 255; 84 | for (i = 0; i < r.width; i++) 85 | Data[r.y + r.height][r.x + r.width - i] = 255; 86 | for (i = 0; i < r.height; i++) 87 | Data[r.y + r.height - i][r.x] = 255; 88 | } 89 | -------------------------------------------------------------------------------- /Baseline/image.h: -------------------------------------------------------------------------------- 1 | #ifndef __IMAGE_H__ 2 | #define __IMAGE_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "haar.h" 8 | 9 | #ifndef __PARAMETERS__ 10 | #define __PARAMETERS__ 11 | 12 | #define TOTAL_NODES 2913 13 | #define TOTAL_STAGES 25 14 | #define TOTAL_COORDINATES TOTAL_NODES*12 15 | #define TOTAL_WEIGHTS TOTAL_NODES*3 16 | #define IMAGE_HEIGHT 240 17 | #define IMAGE_WIDTH 320 18 | 19 | 20 | #endif 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | void drawRectangle ( unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH], 27 | MyRect r); 28 | 29 | int writePgm(char *fileName, unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH] ); 30 | 31 | #ifdef __cplusplus 32 | } 33 | #endif 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /Baseline/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "haar.h" 5 | #include "image.h" 6 | 7 | using namespace std; 8 | 9 | int main ( int argc, char *argv[] ) 10 | { 11 | 12 | int flag; 13 | int in_flag , in_width , in_height , in_maxgrey; 14 | int ret_val=1; 15 | 16 | printf ("-- entering main function --\r\n"); 17 | printf ("-- loading image --\r\n"); 18 | 19 | // 320 X 240 Input image in hex format 20 | #include INPUT_IMAGE 21 | 22 | double duration; 23 | 24 | // Arguments to be passed to DUT 25 | MyRect result[RESULT_SIZE]; 26 | int result_x[RESULT_SIZE]; 27 | int result_y[RESULT_SIZE]; 28 | int result_w[RESULT_SIZE]; 29 | int result_h[RESULT_SIZE]; 30 | 31 | int res_size=0; 32 | int *result_size = &res_size; 33 | int i; 34 | 35 | // As the SDSoC generated data motion network does not support sending 320 X 240 images at once 36 | // We needed to send all the 240 rows using 240 iterations. The last invokation of detectFaces() does the actual face detection 37 | 38 | for ( i = 0; i < IMAGE_HEIGHT-1; i+=1 ){ 39 | detectFaces ( Data[i], result_x, result_y, result_w, result_h, result_size); 40 | } 41 | 42 | printf ("-- detecting faces --\r\n"); 43 | 44 | std::clock_t start = std::clock(); 45 | detectFaces ( Data[IMAGE_HEIGHT-1], result_x, result_y, result_w, result_h, result_size); 46 | duration = ( std::clock() - start ) / (double) CLOCKS_PER_SEC; 47 | 48 | printf("\nresult_size = %d", *result_size); 49 | 50 | for (int j = 0; j < RESULT_SIZE; j++){ 51 | result[j].x = result_x[j]; 52 | result[j].y = result_y[j]; 53 | result[j].width = result_w[j]; 54 | result[j].height = result_h[j]; 55 | } 56 | 57 | for( int i=0 ; i < *result_size ; i++ ) 58 | printf("\n [Test Bench (main) ] detected rects: %d %d %d %d",result[i].x,result[i].y,result[i].width,result[i].height); 59 | 60 | if ( *result_size > 0 ) ret_val = 0; 61 | 62 | printf("\n-- saving output image [Start] --\r\n"); 63 | 64 | // Draw the rectangles onto the images and save the outputs. 65 | for(i = 0; i < *result_size ; i++ ) 66 | { 67 | MyRect r = result[i]; 68 | drawRectangle(Data, r); 69 | } 70 | 71 | flag = writePgm((char *)(OUTPUT_FILENAME),Data); 72 | printf("\n-- saving output image [Done] --\r\n"); 73 | printf("DURATION: %2f", duration); 74 | 75 | return ret_val; 76 | 77 | } 78 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-2017, Cornell University 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the copyright holder nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | APPSOURCES = image.cpp main.cpp haar.cpp 2 | EXECUTABLE = face.elf 3 | 4 | PLATFORM = zc706 5 | SDSFLAGS = -sds-pf ${PLATFORM} \ 6 | -sds-hw detectFaces haar.cpp -clkid 3 -sds-end \ 7 | -poll-mode 1 8 | 9 | 10 | CC = sds++ ${SDSFLAGS} 11 | 12 | CFLAGS = -Wall -O3 -c 13 | CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)" 14 | LFLAGS = -O3 15 | 16 | OBJECTS := $(APPSOURCES:.cpp=.o) 17 | DEPS := $(OBJECTS:.o=.d) 18 | 19 | .PHONY: all 20 | 21 | all: ${EXECUTABLE} 22 | 23 | ${EXECUTABLE}: ${OBJECTS} 24 | ${CC} ${LFLAGS} ${OBJECTS} -o $@ >> sdsoc.log 25 | 26 | %.o: %.cpp 27 | ${CC} ${CFLAGS} $< -o $@ > sdsoc.log 28 | 29 | clean: 30 | ${RM} ${EXECUTABLE} ${OBJECTS} *.d 31 | 32 | csim: 33 | vivado_hls csim.tcl 34 | sw: 35 | g++ -O3 ${APPSOURCES} 36 | 37 | ultraclean: clean 38 | ${RM} ${EXECUTABLE}.bit 39 | ${RM} -rf _sds sd_card hls.prj 40 | ${RM} sdsoc.log vivado_hls.log 41 | -------------------------------------------------------------------------------- /Parallel_and_Pipelined/Makefile: -------------------------------------------------------------------------------- 1 | APPSOURCES = image.cpp main.cpp haar.cpp 2 | EXECUTABLE = face.elf 3 | 4 | PLATFORM = zc706 5 | SDSFLAGS = -sds-pf ${PLATFORM} \ 6 | -sds-hw detectFaces haar.cpp -clkid 3 -sds-end \ 7 | -poll-mode 1 8 | 9 | 10 | CC = sds++ ${SDSFLAGS} 11 | 12 | CFLAGS = -Wall -O3 -c 13 | CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)" 14 | LFLAGS = -O3 15 | 16 | OBJECTS := $(APPSOURCES:.cpp=.o) 17 | DEPS := $(OBJECTS:.o=.d) 18 | 19 | .PHONY: all 20 | 21 | all: ${EXECUTABLE} 22 | 23 | ${EXECUTABLE}: ${OBJECTS} 24 | ${CC} ${LFLAGS} ${OBJECTS} -o $@ >> sdsoc.log 25 | 26 | %.o: %.cpp 27 | ${CC} ${CFLAGS} $< -o $@ > sdsoc.log 28 | 29 | clean: 30 | ${RM} ${EXECUTABLE} ${OBJECTS} *.d 31 | 32 | csim: 33 | vivado_hls csim.tcl 34 | sw: 35 | g++ -O3 ${APPSOURCES} 36 | 37 | ultraclean: clean 38 | ${RM} ${EXECUTABLE}.bit 39 | ${RM} -rf _sds sd_card hls.prj 40 | ${RM} sdsoc.log vivado_hls.log 41 | -------------------------------------------------------------------------------- /Parallel_and_Pipelined/README.md: -------------------------------------------------------------------------------- 1 | Publications 2 | ------------------------------------------------------------------------ 3 | 4 | If you use this benchmark in your research, please cite our [FPGA'17 5 | paper][4]: 6 | 7 | ``` 8 | @inproceedings{lockhart-pymtl-micro2014, 9 | title = {Accelerating Face Detection on Programmable SoC Using 10 | C-Based Synthesis}, 11 | author = {Nitish Srivastava and Steve Dai and Rajit Manohar and 12 | Zhiru Zhang}, 13 | booktitle = {25\textsuperscript{th} ACM/SIGDA International 14 | Symposium on Field-Programmable Gate Arrays}, 15 | month = {Feb}, 16 | year = {2017}, 17 | doi = {10.1145/3020078.3021753}, 18 | } 19 | ``` 20 | 21 | [4]: http://dx.doi.org/10.1145/3020078.3021753 22 | 23 | 24 | facedetect-fpga is an open-source implementation of Viola-Jones face 25 | detection algorithm suitable for C-based synthesis. It was introduced 26 | at FPGA-25 in February, 2017. 27 | 28 | Tutorial 29 | ------------------------------------------------------------------------ 30 | 31 | ### C-simulation 32 | 33 | The face detection benchmark has been written in C. The current version 34 | also supports C simulation so that functionality of the algorithm can be 35 | tested without going through the painful process of bitstream generation. 36 | 37 | To do the C-simulation of the design enter the following command in the 38 | main directory: 39 | 40 | % make csim 41 | 42 | This will create a hls.prj directory containing all the logs for the C 43 | simulation. The output of the face-detection can be seen in the directory 44 | hls.prj/solution/csim/build/Output.pgm Make sure that all the faces have 45 | been detected and marked using rectangles. 46 | 47 | One should always do C-simulation before synthesizing the design as it 48 | is fast and detects the trivial syntactic/algorithmic errors. 49 | 50 | ### Bitstream generation 51 | 52 | To synthesize the design for FPGA type the following command in the main 53 | directory: 54 | 55 | % make 56 | 57 | This will produce two folders: 58 | 59 | ./_sds 60 | ./sd_card 61 | 62 | The \_sds folder will have all the reports generated by SDSoC and 63 | Vivado-HLS. The sd\_card folder will have the bitstream and the 64 | associated files which will be used to port face-detection accelerator 65 | onto the FPGA. 66 | 67 | The timing and utilization reports generated by Vivado-HLS can be found 68 | in the following directory: 69 | 70 | _sds/vhls/haar/solution/syn/report 71 | 72 | The log generated by Vivado-HLS can be found as: 73 | 74 | _sds/vhls/vivado_hls.log 75 | 76 | The area, utilzation and timing reports generated by SDSoC can be found 77 | in the following directory: 78 | 79 | _sds/reports 80 | 81 | ### Porting Face-detection accelerator onto the FPGA 82 | 83 | To port the face-detection accelerator onto the FPGA copy all the files 84 | in the sd\_card folder into the SD-card of the FPGA. After that you can 85 | reboot the FPGA board and connect it to your computer using UART. Go to 86 | the mnt folder and run face.elf binary 87 | 88 | $ cd /mnt 89 | $ ./face.elf 90 | 91 | This will print the co-ordinates of all the rectangles detected on the 92 | screen and will also give the time taken to detect the faces. Wait for a 93 | while ( 4-5 seconds ) and remove the SD-card and insert it in your 94 | computer. You will see an Output.pgm file with rectangles drawn around 95 | all the faces. The wait time of 4-5 seconds is to make sure that this 96 | image is written properly. 97 | 98 | ### Adding a new image 99 | 100 | The face-detection algorithm can only process the images when each pixel 101 | in the image is represented as a 8-bit number. The gen\_dataset folder 102 | has the files to generate the hex images using the images in pgm format. 103 | To add a new 320 X 240 image (pgm format) copy it to the folder 104 | gen\_dataset. Edit the input and the output file names in the main 105 | function in gen\_dataset/gen\_image.cpp and compile and run it: 106 | 107 | % cd gen_dataset 108 | % cp /path/to/image/test-image.pgm . 109 | 110 | Edit main() function in gen_image.cpp/ 111 | 112 | % g++ gen_image.cpp 113 | % ./a.out 114 | 115 | This will produce the .h file for the image with the image pixels in the 116 | hex format. Copy this .h file to the main directory: 117 | 118 | % cp test-image.h ../. 119 | 120 | And then edit the main.cpp file to have this line instead: 121 | 122 | #include "image0_320_240.h" 123 | 124 | Now you have added a new image. Do the C-simulation as described above. 125 | Make sure the C-simulation is working and producing the right results. 126 | Generate the bitstream and run it on the FPGA. 127 | 128 | 129 | ### Stages of Optimizations 130 | 131 | The source code for different stages of optimizations mentioned in our 132 | paper is also added to the repository so that users can get a feel of 133 | the effects of each and every optimzation. There are 3 extra folders 134 | which are added to the repo: 135 | 136 | Baseline : This folder has the baseline implementation which replaces 137 | all the non synthesizable constructs. 138 | 139 | Pipelined : This folder has the code when all the classifiers are 140 | pipelined. 141 | 142 | Parallel\_and\_Pipeline : This folder has the code when the classifiers 143 | in the first 3 stages are in parallel and the ones in the other 22 144 | stages are in pipeline. 145 | 146 | The main folder has the code which combines all these optimizations. 147 | 148 | 149 | License 150 | ------------------------------------------------------------------------ 151 | 152 | face-detection benchmark is offered under the terms of the Open Source 153 | Initiative BSD 3-Clause License. More information about this license can 154 | be found here: 155 | 156 | - http://choosealicense.com/licenses/bsd-3-clause 157 | - http://opensource.org/licenses/BSD-3-Clause 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /Parallel_and_Pipelined/csim.tcl: -------------------------------------------------------------------------------- 1 | #============================================================================= 2 | # run.tcl 3 | #============================================================================= 4 | # @brief: A Tcl script for C simulation of the face-detection design 5 | 6 | # Open/reset the project 7 | open_project hls.prj -reset 8 | 9 | # Top function of the design is "haar" 10 | set_top detectFaces 11 | 12 | # Add design and testbench files 13 | add_files haar.cpp 14 | 15 | add_files -tb main.cpp 16 | add_files -tb image.cpp 17 | 18 | open_solution solution 19 | 20 | # Use Zynq device 21 | # zc-706 22 | set_part xc7z045ffg900-2 23 | 24 | config_rtl -reset state 25 | 26 | # Simulate the C++ design 27 | csim_design 28 | 29 | # Co-simulate the design 30 | # cosim_design 31 | 32 | exit 33 | -------------------------------------------------------------------------------- /Parallel_and_Pipelined/haar.h: -------------------------------------------------------------------------------- 1 | #ifndef __HAAR_H__ 2 | #define __HAAR_H__ 3 | 4 | #include "ap_int.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "ap_int.h" 11 | 12 | const int ROWS = 25; 13 | const int COLS = 25; 14 | 15 | const int NUM_BANKS = 12; 16 | const int SIZE = 2913; 17 | 18 | typedef ap_uint<18> uint18_t; 19 | typedef ap_uint<10> uint10_t; 20 | typedef ap_uint<1> bit; 21 | typedef ap_uint<5> uint5_t; 22 | 23 | 24 | #ifndef __PARAMETERS__ 25 | #define __PARAMETERS__ 26 | 27 | #define IMAGE_HEIGHT 240 28 | #define IMAGE_WIDTH 320 29 | #define IMAGE_MAXGREY 255 30 | #define IMAGE_SIZE ( IMAGE_HEIGHT * IMAGE_WIDTH ) 31 | 32 | #define RESULT_SIZE 100 33 | 34 | #define TOTAL_NODES 2913 35 | #define TOTAL_STAGES 25 36 | #define TOTAL_COORDINATES TOTAL_NODES*12 37 | #define TOTAL_WEIGHTS TOTAL_NODES*3 38 | 39 | #define WINDOW_SIZE 25 40 | #define SQ_SIZE 2 41 | #define PYRAMID_HEIGHT 12 42 | 43 | #define OUTPUT_FILENAME "Output.pgm" 44 | #define INPUT_IMAGE "image0_320_240.h" 45 | 46 | 47 | #endif 48 | 49 | 50 | typedef ap_uint<13> int_I; 51 | typedef ap_uint<21> int_SI; 52 | typedef ap_uint<18> int_II; 53 | typedef ap_uint<26> int_SII; 54 | 55 | #ifdef __cplusplus 56 | extern "C" { 57 | #endif 58 | 59 | typedef struct MyPoint 60 | { 61 | int x; 62 | int y; 63 | } 64 | MyPoint; 65 | 66 | typedef struct 67 | { 68 | int width; 69 | int height; 70 | } 71 | MySize; 72 | 73 | typedef struct 74 | { 75 | int x; 76 | int y; 77 | int width; 78 | int height; 79 | } 80 | MyRect; 81 | 82 | typedef struct 83 | { 84 | int width; 85 | int height; 86 | int maxgrey; 87 | int flag; 88 | } 89 | MyInputImage; 90 | 91 | void detectFaces( unsigned char Data[IMAGE_WIDTH], 92 | int _result_x[RESULT_SIZE], 93 | int _result_y[RESULT_SIZE], 94 | int _result_w[RESULT_SIZE], 95 | int _result_h[RESULT_SIZE], 96 | int *result_size); 97 | 98 | #ifdef __cplusplus 99 | } 100 | #endif 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /Parallel_and_Pipelined/haar_mapping.h: -------------------------------------------------------------------------------- 1 | 2 | static int bank_mapping[ROWS * COLS] = 3 | {8, 13, 20, 14, 21, 12, 10, 1, 15, 2, 14, 17, 16, 20, 9, 6, 19, 14, 1, 0, 2, 18, 11, 5, 4, 15, 16, 13, 2, 0, 15, 24, 21, 25, 4, 14, 27, 23, 7, 12, 10, 3, 6, 18, 20, 11, 9, 4, 2, 16, 23, 25, 0, 5, 12, 6, 3, 15, 4, 13, 19, 12, 18, 20, 25, 1, 14, 17, 16, 19, 26, 22, 1, 21, 2, 12, 12, 17, 25, 3, 19, 21, 7, 16, 24, 22, 25, 13, 23, 26, 20, 27, 22, 7, 5, 5, 3, 2, 27, 14, 0, 5, 11, 10, 17, 4, 12, 27, 21, 3, 25, 20, 19, 24, 23, 26, 24, 19, 13, 9, 15, 16, 6, 15, 22, 17, 20, 26, 4, 24, 25, 13, 0, 22, 23, 7, 11, 11, 6, 5, 12, 3, 26, 22, 18, 18, 10, 9, 1, 1, 9, 9, 14, 1, 20, 3, 11, 11, 24, 7, 17, 0, 4, 9, 1, 12, 22, 13, 2, 15, 19, 5, 21, 10, 10, 13, 27, 6, 14, 4, 5, 20, 24, 11, 11, 9, 19, 2, 2, 23, 21, 1, 15, 0, 21, 7, 18, 18, 9, 18, 20, 3, 27, 17, 6, 23, 19, 17, 1, 12, 11, 22, 7, 2, 23, 6, 25, 15, 4, 16, 0, 11, 5, 19, 21, 22, 4, 24, 6, 1, 20, 6, 10, 2, 16, 11, 23, 7, 7, 0, 1, 15, 9, 17, 17, 12, 12, 13, 14, 3, 6, 1, 16, 0, 25, 19, 1, 20, 7, 14, 2, 2, 9, 3, 17, 16, 21, 5, 10, 7, 14, 15, 26, 23, 15, 5, 24, 2, 27, 10, 1, 16, 16, 7, 0, 15, 9, 6, 19, 19, 14, 11, 18, 3, 20, 20, 20, 23, 25, 17, 16, 18, 9, 2, 22, 22, 15, 6, 6, 0, 7, 5, 5, 16, 2, 9, 12, 18, 21, 13, 25, 14, 3, 17, 11, 19, 19, 15, 7, 2, 18, 18, 18, 5, 13, 13, 14, 14, 21, 20, 9, 10, 16, 9, 11, 19, 4, 12, 26, 23, 18, 22, 22, 11, 23, 7, 2, 19, 9, 9, 21, 14, 0, 18, 4, 5, 6, 17, 15, 4, 26, 13, 19, 20, 10, 2, 2, 11, 16, 26, 24, 18, 14, 3, 1, 0, 10, 13, 4, 16, 5, 6, 21, 14, 3, 13, 0, 5, 11, 20, 17, 17, 25, 15, 24, 10, 4, 22, 3, 5, 5, 6, 12, 12, 13, 3, 14, 11, 11, 25, 10, 7, 20, 22, 6, 4, 5, 7, 3, 9, 26, 22, 23, 18, 15, 6, 20, 21, 25, 10, 4, 17, 13, 5, 12, 3, 25, 0, 0, 0, 1, 0, 2, 4, 11, 25, 17, 23, 4, 3, 24, 26, 20, 5, 12, 7, 0, 27, 6, 18, 24, 10, 22, 14, 15, 21, 15, 23, 1, 3, 17, 9, 27, 16, 18, 26, 4, 19, 10, 9, 12, 25, 0, 24, 24, 22, 16, 6, 23, 2, 25, 13, 14, 24, 15, 21, 1, 9, 19, 10, 4, 11, 23, 26, 24, 22, 16, 1, 20, 2, 9, 19, 18, 7, 11, 9, 10, 1, 17, 2, 12, 0, 3, 20, 12, 12, 2, 5, 15, 6, 11, 26, 1, 19, 13, 14, 27, 7, 13, 22, 26, 2, 4, 22, 1, 6, 27, 7, 22, 11, 12, 18, 0, 15, 3, 13, 24, 2, 15, 27, 7, 5, 9, 1, 21, 3, 1, 9, 16, 17, 24, 19, 16, 26, 11, 20, 12, 18, 22, 17, 25, 9, 27, 7, 4, 16, 15, 2, 3, 5, 14, 21, 24, 13, 13, 23, 7, 26, 5, 6, 20, 3, 10, 11, 22, 2, 23, 24, 12, 17, 27, 1, 25, 18, 18}; 4 | 5 | static int offset_mapping[ROWS * COLS] = 6 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 2, 1, 2, 0, 1, 0, 1, 3, 0, 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 3, 2, 1, 1, 2, 1, 2, 2, 1, 3, 3, 2, 1, 3, 2, 3, 2, 2, 4, 1, 3, 2, 0, 0, 3, 2, 4, 4, 5, 2, 3, 2, 3, 3, 1, 4, 1, 1, 4, 3, 2, 1, 4, 1, 2, 2, 2, 3, 3, 5, 2, 5, 3, 4, 2, 2, 3, 4, 6, 3, 4, 4, 5, 5, 4, 2, 3, 2, 3, 5, 4, 2, 4, 5, 3, 5, 3, 4, 6, 3, 5, 4, 6, 5, 4, 4, 4, 3, 3, 4, 4, 5, 7, 5, 4, 5, 3, 4, 3, 3, 4, 5, 4, 5, 6, 6, 7, 6, 5, 6, 5, 4, 5, 5, 6, 6, 7, 8, 6, 6, 6, 6, 6, 6, 5, 4, 5, 7, 4, 5, 7, 7, 7, 8, 6, 7, 8, 7, 7, 7, 8, 5, 6, 8, 7, 6, 7, 5, 5, 6, 8, 7, 9, 7, 5, 6, 6, 6, 8, 7, 9, 9, 9, 7, 6, 9, 7, 7, 7, 8, 8, 6, 7, 10, 8, 9, 8, 8, 9, 7, 8, 10, 10, 9, 6, 10, 7, 11, 8, 7, 8, 8, 11, 9, 9, 8, 9, 10, 11, 8, 8, 8, 10, 12, 8, 9, 8, 10, 13, 11, 9, 9, 11, 12, 10, 9, 10, 9, 9, 9, 7, 10, 10, 10, 5, 9, 11, 10, 8, 13, 6, 8, 14, 10, 11, 11, 10, 12, 11, 11, 11, 12, 11, 12, 8, 10, 12, 13, 14, 10, 9, 11, 12, 9, 12, 14, 9, 10, 13, 12, 13, 11, 12, 11, 12, 13, 15, 13, 12, 10, 10, 9, 10, 12, 11, 12, 13, 13, 14, 14, 13, 16, 11, 12, 13, 13, 10, 11, 13, 14, 11, 15, 14, 9, 14, 15, 14, 15, 10, 13, 6, 11, 14, 11, 12, 15, 12, 14, 17, 16, 16, 17, 12, 15, 12, 15, 11, 14, 14, 13, 15, 12, 7, 12, 17, 16, 10, 18, 19, 16, 15, 8, 9, 16, 16, 12, 15, 13, 11, 13, 13, 16, 15, 15, 13, 17, 13, 14, 14, 16, 17, 17, 14, 15, 11, 16, 10, 12, 14, 13, 14, 17, 18, 16, 14, 15, 15, 15, 18, 18, 19, 12, 13, 15, 18, 14, 17, 15, 19, 16, 16, 18, 9, 15, 13, 17, 17, 18, 19, 14, 13, 14, 16, 16, 16, 20, 16, 17, 14, 15, 16, 17, 16, 18, 20, 17, 20, 15, 17, 14, 18, 18, 11, 10, 20, 21, 17, 17, 19, 7, 19, 18, 12, 15, 16, 19, 18, 15, 19, 15, 17, 19, 18, 19, 8, 17, 19, 11, 19, 18, 16, 20, 18, 16, 20, 13, 14, 17, 18, 20, 16, 21, 17, 17, 20, 15, 20, 16, 18, 21, 19, 17, 20, 21, 17, 12, 16, 18, 19, 19, 21, 22, 22, 20, 20, 18, 22, 23, 18, 20, 19, 23, 19, 21, 20, 22, 20, 21, 24, 22, 21, 21, 23, 13, 21, 21, 18, 21, 9, 19, 19, 19, 14, 25, 21, 20, 22, 22, 10, 20, 21, 24, 22, 21, 22, 22, 21, 20, 17, 26, 23, 11, 21, 23, 24, 23, 17, 22, 24, 25, 20, 20, 18, 22, 21, 15, 25, 23, 23, 22, 22, 21, 18, 26, 12, 22, 22, 22, 24, 27, 23, 24, 22, 18, 19, 21, 22, 18, 23, 16, 25, 23, 24, 24, 19, 26, 23, 28, 19, 20, 24, 22, 13, 25, 19, 23, 24}; 7 | -------------------------------------------------------------------------------- /Parallel_and_Pipelined/image.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "image.h" 5 | 6 | #define MYDEBUG 7 | 8 | char* strrev(char* str) 9 | { 10 | char *p1, *p2; 11 | if (!str || !*str) 12 | return str; 13 | for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2) 14 | { 15 | *p1 ^= *p2; 16 | *p2 ^= *p1; 17 | *p1 ^= *p2; 18 | } 19 | return str; 20 | } 21 | 22 | void itochar(int x, char* szBuffer, int radix) 23 | { 24 | int i = 0, n, xx; 25 | n = x; 26 | while (n > 0) 27 | { 28 | xx = n%radix; 29 | n = n/radix; 30 | szBuffer[i++] = '0' + xx; 31 | } 32 | szBuffer[i] = '\0'; 33 | strrev(szBuffer); 34 | } 35 | 36 | /* Writes a Pgm file using the hex image */ 37 | int writePgm(char *fileName, unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH] ) 38 | { 39 | char parameters_str[5]; 40 | int i; 41 | const char *format = "P5"; 42 | FILE *fp = fopen(fileName, "w"); 43 | 44 | if (!fp){ 45 | printf("Unable to open file %s\n", fileName); 46 | return -1; 47 | } 48 | 49 | fputs(format, fp); 50 | fputc('\n', fp); 51 | 52 | itochar(IMAGE_WIDTH, parameters_str, 10); 53 | fputs(parameters_str, fp); 54 | parameters_str[0] = 0; 55 | fputc(' ', fp); 56 | 57 | itochar(IMAGE_HEIGHT, parameters_str, 10); 58 | fputs(parameters_str, fp); 59 | parameters_str[0] = 0; 60 | fputc('\n', fp); 61 | 62 | itochar(IMAGE_MAXGREY, parameters_str, 10); 63 | fputs(parameters_str, fp); 64 | fputc('\n', fp); 65 | 66 | for (i = 0; i < IMAGE_HEIGHT; i++) 67 | for (int j = 0; j < IMAGE_WIDTH ; j++) 68 | fputc(Data[i][j], fp); 69 | 70 | fclose(fp); 71 | return 0; 72 | } 73 | 74 | /* draw white bounding boxes around detected faces */ 75 | void drawRectangle(unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH], MyRect r) 76 | { 77 | int i; 78 | int col = IMAGE_WIDTH; 79 | 80 | for (i = 0; i < r.width; i++) 81 | Data[r.y][r.x + i] = 255; 82 | for (i = 0; i < r.height; i++) 83 | Data[r.y+i][r.x + r.width] = 255; 84 | for (i = 0; i < r.width; i++) 85 | Data[r.y + r.height][r.x + r.width - i] = 255; 86 | for (i = 0; i < r.height; i++) 87 | Data[r.y + r.height - i][r.x] = 255; 88 | } 89 | -------------------------------------------------------------------------------- /Parallel_and_Pipelined/image.h: -------------------------------------------------------------------------------- 1 | #ifndef __IMAGE_H__ 2 | #define __IMAGE_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "haar.h" 8 | 9 | #ifndef __PARAMETERS__ 10 | #define __PARAMETERS__ 11 | 12 | #define TOTAL_NODES 2913 13 | #define TOTAL_STAGES 25 14 | #define TOTAL_COORDINATES TOTAL_NODES*12 15 | #define TOTAL_WEIGHTS TOTAL_NODES*3 16 | #define IMAGE_HEIGHT 240 17 | #define IMAGE_WIDTH 320 18 | 19 | 20 | #endif 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | void drawRectangle ( unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH], 27 | MyRect r); 28 | 29 | int writePgm(char *fileName, unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH] ); 30 | 31 | #ifdef __cplusplus 32 | } 33 | #endif 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /Parallel_and_Pipelined/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "haar.h" 5 | #include "image.h" 6 | 7 | using namespace std; 8 | 9 | int main ( int argc, char *argv[] ) 10 | { 11 | 12 | int flag; 13 | int in_flag , in_width , in_height , in_maxgrey; 14 | int ret_val=1; 15 | 16 | printf ("-- entering main function --\r\n"); 17 | printf ("-- loading image --\r\n"); 18 | 19 | // 320 X 240 Input image in hex format 20 | #include INPUT_IMAGE 21 | 22 | double duration; 23 | 24 | // Arguments to be passed to DUT 25 | MyRect result[RESULT_SIZE]; 26 | int result_x[RESULT_SIZE]; 27 | int result_y[RESULT_SIZE]; 28 | int result_w[RESULT_SIZE]; 29 | int result_h[RESULT_SIZE]; 30 | 31 | int res_size=0; 32 | int *result_size = &res_size; 33 | int i; 34 | 35 | // As the SDSoC generated data motion network does not support sending 320 X 240 images at once 36 | // We needed to send all the 240 rows using 240 iterations. The last invokation of detectFaces() does the actual face detection 37 | 38 | for ( i = 0; i < IMAGE_HEIGHT-1; i+=1 ){ 39 | detectFaces ( Data[i], result_x, result_y, result_w, result_h, result_size); 40 | } 41 | 42 | printf ("-- detecting faces --\r\n"); 43 | 44 | std::clock_t start = std::clock(); 45 | detectFaces ( Data[IMAGE_HEIGHT-1], result_x, result_y, result_w, result_h, result_size); 46 | duration = ( std::clock() - start ) / (double) CLOCKS_PER_SEC; 47 | 48 | printf("\nresult_size = %d", *result_size); 49 | 50 | for (int j = 0; j < RESULT_SIZE; j++){ 51 | result[j].x = result_x[j]; 52 | result[j].y = result_y[j]; 53 | result[j].width = result_w[j]; 54 | result[j].height = result_h[j]; 55 | } 56 | 57 | for( int i=0 ; i < *result_size ; i++ ) 58 | printf("\n [Test Bench (main) ] detected rects: %d %d %d %d",result[i].x,result[i].y,result[i].width,result[i].height); 59 | 60 | if ( *result_size > 0 ) ret_val = 0; 61 | 62 | printf("\n-- saving output image [Start] --\r\n"); 63 | 64 | // Draw the rectangles onto the images and save the outputs. 65 | for(i = 0; i < *result_size ; i++ ) 66 | { 67 | MyRect r = result[i]; 68 | drawRectangle(Data, r); 69 | } 70 | 71 | flag = writePgm((char *)(OUTPUT_FILENAME),Data); 72 | printf("\n-- saving output image [Done] --\r\n"); 73 | printf("DURATION: %2f", duration); 74 | 75 | return ret_val; 76 | 77 | } 78 | -------------------------------------------------------------------------------- /Pipelined/Makefile: -------------------------------------------------------------------------------- 1 | APPSOURCES = image.cpp main.cpp haar.cpp 2 | EXECUTABLE = face.elf 3 | 4 | PLATFORM = zc706 5 | SDSFLAGS = -sds-pf ${PLATFORM} \ 6 | -sds-hw detectFaces haar.cpp -clkid 3 -sds-end \ 7 | -poll-mode 1 8 | 9 | 10 | CC = sds++ ${SDSFLAGS} 11 | 12 | CFLAGS = -Wall -O3 -c 13 | CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)" 14 | LFLAGS = -O3 15 | 16 | OBJECTS := $(APPSOURCES:.cpp=.o) 17 | DEPS := $(OBJECTS:.o=.d) 18 | 19 | .PHONY: all 20 | 21 | all: ${EXECUTABLE} 22 | 23 | ${EXECUTABLE}: ${OBJECTS} 24 | ${CC} ${LFLAGS} ${OBJECTS} -o $@ >> sdsoc.log 25 | 26 | %.o: %.cpp 27 | ${CC} ${CFLAGS} $< -o $@ > sdsoc.log 28 | 29 | clean: 30 | ${RM} ${EXECUTABLE} ${OBJECTS} *.d 31 | 32 | csim: 33 | vivado_hls csim.tcl 34 | sw: 35 | g++ -O3 ${APPSOURCES} 36 | 37 | ultraclean: clean 38 | ${RM} ${EXECUTABLE}.bit 39 | ${RM} -rf _sds sd_card hls.prj 40 | ${RM} sdsoc.log vivado_hls.log 41 | -------------------------------------------------------------------------------- /Pipelined/README.md: -------------------------------------------------------------------------------- 1 | Publications 2 | ------------------------------------------------------------------------ 3 | 4 | If you use this benchmark in your research, please cite our [FPGA'17 5 | paper][4]: 6 | 7 | ``` 8 | @inproceedings{lockhart-pymtl-micro2014, 9 | title = {Accelerating Face Detection on Programmable SoC Using 10 | C-Based Synthesis}, 11 | author = {Nitish Srivastava and Steve Dai and Rajit Manohar and 12 | Zhiru Zhang}, 13 | booktitle = {25\textsuperscript{th} ACM/SIGDA International 14 | Symposium on Field-Programmable Gate Arrays}, 15 | month = {Feb}, 16 | year = {2017}, 17 | doi = {10.1145/3020078.3021753}, 18 | } 19 | ``` 20 | 21 | [4]: http://dx.doi.org/10.1145/3020078.3021753 22 | 23 | 24 | facedetect-fpga is an open-source implementation of Viola-Jones face 25 | detection algorithm suitable for C-based synthesis. It was introduced 26 | at FPGA-25 in February, 2017. 27 | 28 | Tutorial 29 | ------------------------------------------------------------------------ 30 | 31 | ### C-simulation 32 | 33 | The face detection benchmark has been written in C. The current version 34 | also supports C simulation so that functionality of the algorithm can be 35 | tested without going through the painful process of bitstream generation. 36 | 37 | To do the C-simulation of the design enter the following command in the 38 | main directory: 39 | 40 | % make csim 41 | 42 | This will create a hls.prj directory containing all the logs for the C 43 | simulation. The output of the face-detection can be seen in the directory 44 | hls.prj/solution/csim/build/Output.pgm Make sure that all the faces have 45 | been detected and marked using rectangles. 46 | 47 | One should always do C-simulation before synthesizing the design as it 48 | is fast and detects the trivial syntactic/algorithmic errors. 49 | 50 | ### Bitstream generation 51 | 52 | To synthesize the design for FPGA type the following command in the main 53 | directory: 54 | 55 | % make 56 | 57 | This will produce two folders: 58 | 59 | ./_sds 60 | ./sd_card 61 | 62 | The \_sds folder will have all the reports generated by SDSoC and 63 | Vivado-HLS. The sd\_card folder will have the bitstream and the 64 | associated files which will be used to port face-detection accelerator 65 | onto the FPGA. 66 | 67 | The timing and utilization reports generated by Vivado-HLS can be found 68 | in the following directory: 69 | 70 | _sds/vhls/haar/solution/syn/report 71 | 72 | The log generated by Vivado-HLS can be found as: 73 | 74 | _sds/vhls/vivado_hls.log 75 | 76 | The area, utilzation and timing reports generated by SDSoC can be found 77 | in the following directory: 78 | 79 | _sds/reports 80 | 81 | ### Porting Face-detection accelerator onto the FPGA 82 | 83 | To port the face-detection accelerator onto the FPGA copy all the files 84 | in the sd\_card folder into the SD-card of the FPGA. After that you can 85 | reboot the FPGA board and connect it to your computer using UART. Go to 86 | the mnt folder and run face.elf binary 87 | 88 | $ cd /mnt 89 | $ ./face.elf 90 | 91 | This will print the co-ordinates of all the rectangles detected on the 92 | screen and will also give the time taken to detect the faces. Wait for a 93 | while ( 4-5 seconds ) and remove the SD-card and insert it in your 94 | computer. You will see an Output.pgm file with rectangles drawn around 95 | all the faces. The wait time of 4-5 seconds is to make sure that this 96 | image is written properly. 97 | 98 | ### Adding a new image 99 | 100 | The face-detection algorithm can only process the images when each pixel 101 | in the image is represented as a 8-bit number. The gen\_dataset folder 102 | has the files to generate the hex images using the images in pgm format. 103 | To add a new 320 X 240 image (pgm format) copy it to the folder 104 | gen\_dataset. Edit the input and the output file names in the main 105 | function in gen\_dataset/gen\_image.cpp and compile and run it: 106 | 107 | % cd gen_dataset 108 | % cp /path/to/image/test-image.pgm . 109 | 110 | Edit main() function in gen_image.cpp/ 111 | 112 | % g++ gen_image.cpp 113 | % ./a.out 114 | 115 | This will produce the .h file for the image with the image pixels in the 116 | hex format. Copy this .h file to the main directory: 117 | 118 | % cp test-image.h ../. 119 | 120 | And then edit the main.cpp file to have this line instead: 121 | 122 | #include "image0_320_240.h" 123 | 124 | Now you have added a new image. Do the C-simulation as described above. 125 | Make sure the C-simulation is working and producing the right results. 126 | Generate the bitstream and run it on the FPGA. 127 | 128 | 129 | ### Stages of Optimizations 130 | 131 | The source code for different stages of optimizations mentioned in our 132 | paper is also added to the repository so that users can get a feel of 133 | the effects of each and every optimzation. There are 3 extra folders 134 | which are added to the repo: 135 | 136 | Baseline : This folder has the baseline implementation which replaces 137 | all the non synthesizable constructs. 138 | 139 | Pipelined : This folder has the code when all the classifiers are 140 | pipelined. 141 | 142 | Parallel\_and\_Pipeline : This folder has the code when the classifiers 143 | in the first 3 stages are in parallel and the ones in the other 22 144 | stages are in pipeline. 145 | 146 | The main folder has the code which combines all these optimizations. 147 | 148 | 149 | License 150 | ------------------------------------------------------------------------ 151 | 152 | face-detection benchmark is offered under the terms of the Open Source 153 | Initiative BSD 3-Clause License. More information about this license can 154 | be found here: 155 | 156 | - http://choosealicense.com/licenses/bsd-3-clause 157 | - http://opensource.org/licenses/BSD-3-Clause 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /Pipelined/csim.tcl: -------------------------------------------------------------------------------- 1 | #============================================================================= 2 | # run.tcl 3 | #============================================================================= 4 | # @brief: A Tcl script for C simulation of the face-detection design 5 | 6 | # Open/reset the project 7 | open_project hls.prj -reset 8 | 9 | # Top function of the design is "haar" 10 | set_top detectFaces 11 | 12 | # Add design and testbench files 13 | add_files haar.cpp 14 | 15 | add_files -tb main.cpp 16 | add_files -tb image.cpp 17 | 18 | open_solution solution 19 | 20 | # Use Zynq device 21 | # zc-706 22 | set_part xc7z045ffg900-2 23 | 24 | config_rtl -reset state 25 | 26 | # Simulate the C++ design 27 | csim_design 28 | 29 | # Co-simulate the design 30 | # cosim_design 31 | 32 | exit 33 | -------------------------------------------------------------------------------- /Pipelined/haar.cpp: -------------------------------------------------------------------------------- 1 | /* THIS FILE CONTAINS THE C-CODE FOR HARDWARE BLOCKS. AS THERE WERE SOME ISSUES IN PUTTING 2 | * HARDWARE FUNCTIONS IN DIFFERENT FILES, WE HAVE INCLUDED EVERYTHING IN ONE FILE. \ 3 | */ 4 | 5 | #include "haar.h" 6 | #include "sqrt.h" 7 | 8 | //====================================================== 9 | // Memory BANKING 10 | //===================================================== 11 | 12 | #include "haar_mapping.h" 13 | 14 | inline uint5_t get_bank( uint10_t addr ) 15 | { 16 | return bank_mapping[addr]; 17 | } 18 | 19 | inline uint5_t get_offset( uint10_t addr ) 20 | { 21 | return offset_mapping[addr]; 22 | } 23 | 24 | inline uint18_t get_data0 ( int offset, uint18_t aa[ROWS*COLS]) 25 | { 26 | uint18_t a; 27 | switch (offset) 28 | { 29 | case 0:a = aa[19]; break; 30 | case 1:a = aa[29]; break; 31 | case 2:a = aa[52]; break; 32 | case 3:a = aa[100]; break; 33 | case 4:a = aa[132]; break; 34 | case 5:a = aa[161]; break; 35 | case 6:a = aa[193]; break; 36 | case 7:a = aa[220]; break; 37 | case 8:a = aa[239]; break; 38 | case 9:a = aa[253]; break; 39 | case 10:a = aa[284]; break; 40 | case 11:a = aa[309]; break; 41 | case 12:a = aa[362]; break; 42 | case 13:a = aa[385]; break; 43 | case 14:a = aa[396]; break; 44 | case 15:a = aa[447]; break; 45 | case 16:a = aa[448]; break; 46 | case 17:a = aa[449]; break; 47 | case 18:a = aa[451]; break; 48 | case 19:a = aa[466]; break; 49 | case 20:a = aa[492]; break; 50 | case 21:a = aa[531]; break; 51 | case 22:a = aa[562]; break; 52 | default: a = 0; break; 53 | }; 54 | 55 | return a; 56 | } 57 | 58 | inline uint18_t get_data1 ( int offset, uint18_t aa[ROWS*COLS]) 59 | { 60 | uint18_t a; 61 | switch (offset) 62 | { 63 | case 0:a = aa[7]; break; 64 | case 1:a = aa[18]; break; 65 | case 2:a = aa[65]; break; 66 | case 3:a = aa[72]; break; 67 | case 4:a = aa[148]; break; 68 | case 5:a = aa[149]; break; 69 | case 6:a = aa[153]; break; 70 | case 7:a = aa[164]; break; 71 | case 8:a = aa[191]; break; 72 | case 9:a = aa[208]; break; 73 | case 10:a = aa[229]; break; 74 | case 11:a = aa[240]; break; 75 | case 12:a = aa[251]; break; 76 | case 13:a = aa[256]; break; 77 | case 14:a = aa[280]; break; 78 | case 15:a = aa[384]; break; 79 | case 16:a = aa[450]; break; 80 | case 17:a = aa[478]; break; 81 | case 18:a = aa[506]; break; 82 | case 19:a = aa[517]; break; 83 | case 20:a = aa[527]; break; 84 | case 21:a = aa[542]; break; 85 | case 22:a = aa[554]; break; 86 | case 23:a = aa[573]; break; 87 | case 24:a = aa[576]; break; 88 | case 25:a = aa[621]; break; 89 | default: a = 0; break; 90 | }; 91 | return a; 92 | } 93 | 94 | inline uint18_t get_data2 ( int offset, uint18_t aa[ROWS*COLS]) 95 | { 96 | uint18_t a; 97 | switch (offset) 98 | { 99 | case 0:a = aa[9]; break; 100 | case 1:a = aa[20]; break; 101 | case 2:a = aa[28]; break; 102 | case 3:a = aa[48]; break; 103 | case 4:a = aa[74]; break; 104 | case 5:a = aa[97]; break; 105 | case 6:a = aa[168]; break; 106 | case 7:a = aa[187]; break; 107 | case 8:a = aa[188]; break; 108 | case 9:a = aa[213]; break; 109 | case 10:a = aa[233]; break; 110 | case 11:a = aa[260]; break; 111 | case 12:a = aa[261]; break; 112 | case 13:a = aa[277]; break; 113 | case 14:a = aa[303]; break; 114 | case 15:a = aa[314]; break; 115 | case 16:a = aa[329]; break; 116 | case 17:a = aa[356]; break; 117 | case 18:a = aa[375]; break; 118 | case 19:a = aa[376]; break; 119 | case 20:a = aa[452]; break; 120 | case 21:a = aa[499]; break; 121 | case 22:a = aa[519]; break; 122 | case 23:a = aa[529]; break; 123 | case 24:a = aa[536]; break; 124 | case 25:a = aa[551]; break; 125 | case 26:a = aa[567]; break; 126 | case 27:a = aa[597]; break; 127 | case 28:a = aa[615]; break; 128 | default: a = 0; break; 129 | }; 130 | return a; 131 | } 132 | 133 | inline uint18_t get_data3 ( int offset, uint18_t aa[ROWS*COLS]) 134 | { 135 | uint18_t a; 136 | switch (offset) 137 | { 138 | case 0:a = aa[41]; break; 139 | case 1:a = aa[56]; break; 140 | case 2:a = aa[79]; break; 141 | case 3:a = aa[96]; break; 142 | case 4:a = aa[109]; break; 143 | case 5:a = aa[141]; break; 144 | case 6:a = aa[155]; break; 145 | case 7:a = aa[201]; break; 146 | case 8:a = aa[249]; break; 147 | case 9:a = aa[263]; break; 148 | case 10:a = aa[293]; break; 149 | case 11:a = aa[322]; break; 150 | case 12:a = aa[383]; break; 151 | case 13:a = aa[394]; break; 152 | case 14:a = aa[408]; break; 153 | case 15:a = aa[415]; break; 154 | case 16:a = aa[428]; break; 155 | case 17:a = aa[445]; break; 156 | case 18:a = aa[459]; break; 157 | case 19:a = aa[479]; break; 158 | case 20:a = aa[532]; break; 159 | case 21:a = aa[564]; break; 160 | case 22:a = aa[575]; break; 161 | case 23:a = aa[598]; break; 162 | case 24:a = aa[611]; break; 163 | default: a = 0; break; 164 | }; 165 | return a; 166 | } 167 | 168 | inline uint18_t get_data4 ( int offset, uint18_t aa[ROWS*COLS]) 169 | { 170 | uint18_t a; 171 | 172 | switch (offset) 173 | { 174 | case 0:a = aa[24]; break; 175 | case 1:a = aa[34]; break; 176 | case 2:a = aa[47]; break; 177 | case 3:a = aa[58]; break; 178 | case 4:a = aa[105]; break; 179 | case 5:a = aa[128]; break; 180 | case 6:a = aa[162]; break; 181 | case 7:a = aa[179]; break; 182 | case 8:a = aa[218]; break; 183 | case 9:a = aa[226]; break; 184 | case 10:a = aa[346]; break; 185 | case 11:a = aa[364]; break; 186 | case 12:a = aa[369]; break; 187 | case 13:a = aa[388]; break; 188 | case 14:a = aa[406]; break; 189 | case 15:a = aa[425]; break; 190 | case 16:a = aa[440]; break; 191 | case 17:a = aa[453]; break; 192 | case 18:a = aa[458]; break; 193 | case 19:a = aa[486]; break; 194 | case 20:a = aa[510]; break; 195 | case 21:a = aa[552]; break; 196 | case 22:a = aa[594]; break; 197 | default: a = 0; break; 198 | }; return a; 199 | } 200 | 201 | inline uint18_t get_data5 ( int offset, uint18_t aa[ROWS*COLS]) 202 | { 203 | uint18_t a; 204 | 205 | switch (offset) 206 | { 207 | case 0:a = aa[23]; break; 208 | case 1:a = aa[53]; break; 209 | case 2:a = aa[94]; break; 210 | case 3:a = aa[95]; break; 211 | case 4:a = aa[101]; break; 212 | case 5:a = aa[139]; break; 213 | case 6:a = aa[171]; break; 214 | case 7:a = aa[180]; break; 215 | case 8:a = aa[222]; break; 216 | case 9:a = aa[267]; break; 217 | case 10:a = aa[275]; break; 218 | case 11:a = aa[311]; break; 219 | case 12:a = aa[312]; break; 220 | case 13:a = aa[333]; break; 221 | case 14:a = aa[365]; break; 222 | case 15:a = aa[390]; break; 223 | case 16:a = aa[397]; break; 224 | case 17:a = aa[409]; break; 225 | case 18:a = aa[410]; break; 226 | case 19:a = aa[426]; break; 227 | case 20:a = aa[443]; break; 228 | case 21:a = aa[463]; break; 229 | case 22:a = aa[537]; break; 230 | case 23:a = aa[571]; break; 231 | case 24:a = aa[599]; break; 232 | case 25:a = aa[608]; break; 233 | default: a = 0; break; 234 | }; return a; 235 | } 236 | 237 | inline uint18_t get_data6 ( int offset, uint18_t aa[ROWS*COLS]) 238 | { 239 | uint18_t a; 240 | switch (offset) 241 | { 242 | case 0:a = aa[15]; break; 243 | case 1:a = aa[42]; break; 244 | case 2:a = aa[55]; break; 245 | case 3:a = aa[122]; break; 246 | case 4:a = aa[138]; break; 247 | case 5:a = aa[177]; break; 248 | case 6:a = aa[204]; break; 249 | case 7:a = aa[215]; break; 250 | case 8:a = aa[228]; break; 251 | case 9:a = aa[231]; break; 252 | case 10:a = aa[250]; break; 253 | case 11:a = aa[287]; break; 254 | case 12:a = aa[307]; break; 255 | case 13:a = aa[308]; break; 256 | case 14:a = aa[366]; break; 257 | case 15:a = aa[391]; break; 258 | case 16:a = aa[411]; break; 259 | case 17:a = aa[424]; break; 260 | case 18:a = aa[435]; break; 261 | case 19:a = aa[468]; break; 262 | case 20:a = aa[497]; break; 263 | case 21:a = aa[539]; break; 264 | case 22:a = aa[555]; break; 265 | case 23:a = aa[609]; break; 266 | default: a = 0; break; 267 | }; return a; 268 | } 269 | 270 | inline uint18_t get_data7 ( int offset, uint18_t aa[ROWS*COLS]) 271 | { 272 | uint18_t a; 273 | 274 | switch (offset) 275 | { 276 | case 0:a = aa[38]; break; 277 | case 1:a = aa[82]; break; 278 | case 2:a = aa[93]; break; 279 | case 3:a = aa[135]; break; 280 | case 4:a = aa[159]; break; 281 | case 5:a = aa[195]; break; 282 | case 6:a = aa[212]; break; 283 | case 7:a = aa[237]; break; 284 | case 8:a = aa[238]; break; 285 | case 9:a = aa[258]; break; 286 | case 10:a = aa[269]; break; 287 | case 11:a = aa[283]; break; 288 | case 12:a = aa[310]; break; 289 | case 13:a = aa[328]; break; 290 | case 14:a = aa[355]; break; 291 | case 15:a = aa[421]; break; 292 | case 16:a = aa[427]; break; 293 | case 17:a = aa[465]; break; 294 | case 18:a = aa[523]; break; 295 | case 19:a = aa[547]; break; 296 | case 20:a = aa[557]; break; 297 | case 21:a = aa[570]; break; 298 | case 22:a = aa[593]; break; 299 | case 23:a = aa[606]; break; 300 | default: a = 0; break; 301 | }; return a; 302 | } 303 | 304 | inline uint18_t get_data8 ( int offset, uint18_t aa[ROWS*COLS]) 305 | { 306 | uint18_t a; 307 | 308 | switch (offset) 309 | { 310 | case 0:a = aa[0]; break; 311 | default: a = 0; break; 312 | }; return a; 313 | } 314 | 315 | inline uint18_t get_data9 ( int offset, uint18_t aa[ROWS*COLS]) 316 | { 317 | uint18_t a; 318 | 319 | switch (offset) 320 | { 321 | case 0:a = aa[14]; break; 322 | case 1:a = aa[46]; break; 323 | case 2:a = aa[119]; break; 324 | case 3:a = aa[147]; break; 325 | case 4:a = aa[150]; break; 326 | case 5:a = aa[151]; break; 327 | case 6:a = aa[163]; break; 328 | case 7:a = aa[185]; break; 329 | case 8:a = aa[198]; break; 330 | case 9:a = aa[242]; break; 331 | case 10:a = aa[262]; break; 332 | case 11:a = aa[286]; break; 333 | case 12:a = aa[302]; break; 334 | case 13:a = aa[315]; break; 335 | case 14:a = aa[340]; break; 336 | case 15:a = aa[343]; break; 337 | case 16:a = aa[358]; break; 338 | case 17:a = aa[359]; break; 339 | case 18:a = aa[429]; break; 340 | case 19:a = aa[481]; break; 341 | case 20:a = aa[489]; break; 342 | case 21:a = aa[507]; break; 343 | case 22:a = aa[520]; break; 344 | case 23:a = aa[525]; break; 345 | case 24:a = aa[572]; break; 346 | case 25:a = aa[577]; break; 347 | case 26:a = aa[591]; break; 348 | default: a = 0; break; 349 | }; return a; 350 | } 351 | 352 | inline uint18_t get_data10 ( int offset, uint18_t aa[ROWS*COLS]) 353 | { 354 | uint18_t a; 355 | 356 | switch (offset) 357 | { 358 | case 0:a = aa[6]; break; 359 | case 1:a = aa[40]; break; 360 | case 2:a = aa[103]; break; 361 | case 3:a = aa[146]; break; 362 | case 4:a = aa[173]; break; 363 | case 5:a = aa[174]; break; 364 | case 6:a = aa[232]; break; 365 | case 7:a = aa[268]; break; 366 | case 8:a = aa[279]; break; 367 | case 9:a = aa[341]; break; 368 | case 10:a = aa[374]; break; 369 | case 11:a = aa[386]; break; 370 | case 12:a = aa[405]; break; 371 | case 13:a = aa[420]; break; 372 | case 14:a = aa[439]; break; 373 | case 15:a = aa[471]; break; 374 | case 16:a = aa[488]; break; 375 | case 17:a = aa[509]; break; 376 | case 18:a = aa[526]; break; 377 | case 19:a = aa[612]; break; 378 | default: a = 0; break; 379 | }; return a; 380 | } 381 | 382 | inline uint18_t get_data11 ( int offset, uint18_t aa[ROWS*COLS]) 383 | { 384 | uint18_t a; 385 | 386 | switch (offset) 387 | { 388 | case 0:a = aa[22]; break; 389 | case 1:a = aa[45]; break; 390 | case 2:a = aa[102]; break; 391 | case 3:a = aa[136]; break; 392 | case 4:a = aa[137]; break; 393 | case 5:a = aa[156]; break; 394 | case 6:a = aa[157]; break; 395 | case 7:a = aa[183]; break; 396 | case 8:a = aa[184]; break; 397 | case 9:a = aa[210]; break; 398 | case 10:a = aa[221]; break; 399 | case 11:a = aa[235]; break; 400 | case 12:a = aa[291]; break; 401 | case 13:a = aa[324]; break; 402 | case 14:a = aa[344]; break; 403 | case 15:a = aa[353]; break; 404 | case 16:a = aa[377]; break; 405 | case 17:a = aa[398]; break; 406 | case 18:a = aa[417]; break; 407 | case 19:a = aa[418]; break; 408 | case 20:a = aa[454]; break; 409 | case 21:a = aa[511]; break; 410 | case 22:a = aa[524]; break; 411 | case 23:a = aa[540]; break; 412 | case 24:a = aa[559]; break; 413 | case 25:a = aa[584]; break; 414 | case 26:a = aa[613]; break; 415 | default: a = 0; break; 416 | }; return a; 417 | } 418 | 419 | inline uint18_t get_data12 ( int offset, uint18_t aa[ROWS*COLS]) 420 | { 421 | uint18_t a; 422 | 423 | switch (offset) 424 | { 425 | case 0:a = aa[5]; break; 426 | case 1:a = aa[39]; break; 427 | case 2:a = aa[54]; break; 428 | case 3:a = aa[61]; break; 429 | case 4:a = aa[75]; break; 430 | case 5:a = aa[76]; break; 431 | case 6:a = aa[106]; break; 432 | case 7:a = aa[140]; break; 433 | case 8:a = aa[165]; break; 434 | case 9:a = aa[209]; break; 435 | case 10:a = aa[245]; break; 436 | case 11:a = aa[246]; break; 437 | case 12:a = aa[316]; break; 438 | case 13:a = aa[347]; break; 439 | case 14:a = aa[412]; break; 440 | case 15:a = aa[413]; break; 441 | case 16:a = aa[444]; break; 442 | case 17:a = aa[464]; break; 443 | case 18:a = aa[490]; break; 444 | case 19:a = aa[530]; break; 445 | case 20:a = aa[534]; break; 446 | case 21:a = aa[535]; break; 447 | case 22:a = aa[560]; break; 448 | case 23:a = aa[586]; break; 449 | case 24:a = aa[618]; break; 450 | default: a = 0; break; 451 | }; return a; 452 | } 453 | 454 | inline uint18_t get_data13 ( int offset, uint18_t aa[ROWS*COLS]) 455 | { 456 | uint18_t a; 457 | 458 | switch (offset) 459 | { 460 | case 0:a = aa[1]; break; 461 | case 1:a = aa[27]; break; 462 | case 2:a = aa[59]; break; 463 | case 3:a = aa[87]; break; 464 | case 4:a = aa[118]; break; 465 | case 5:a = aa[131]; break; 466 | case 6:a = aa[167]; break; 467 | case 7:a = aa[175]; break; 468 | case 8:a = aa[247]; break; 469 | case 9:a = aa[319]; break; 470 | case 10:a = aa[334]; break; 471 | case 11:a = aa[335]; break; 472 | case 12:a = aa[371]; break; 473 | case 13:a = aa[387]; break; 474 | case 14:a = aa[395]; break; 475 | case 15:a = aa[414]; break; 476 | case 16:a = aa[442]; break; 477 | case 17:a = aa[501]; break; 478 | case 18:a = aa[544]; break; 479 | case 19:a = aa[548]; break; 480 | case 20:a = aa[565]; break; 481 | case 21:a = aa[603]; break; 482 | case 22:a = aa[604]; break; 483 | default: a = 0; break; 484 | }; return a; 485 | } 486 | 487 | inline uint18_t get_data14 ( int offset, uint18_t aa[ROWS*COLS]) 488 | { 489 | uint18_t a; 490 | 491 | switch (offset) 492 | { 493 | case 0:a = aa[3]; break; 494 | case 1:a = aa[10]; break; 495 | case 2:a = aa[17]; break; 496 | case 3:a = aa[35]; break; 497 | case 4:a = aa[66]; break; 498 | case 5:a = aa[99]; break; 499 | case 6:a = aa[152]; break; 500 | case 7:a = aa[178]; break; 501 | case 8:a = aa[248]; break; 502 | case 9:a = aa[259]; break; 503 | case 10:a = aa[270]; break; 504 | case 11:a = aa[290]; break; 505 | case 12:a = aa[321]; break; 506 | case 13:a = aa[336]; break; 507 | case 14:a = aa[337]; break; 508 | case 15:a = aa[361]; break; 509 | case 16:a = aa[382]; break; 510 | case 17:a = aa[393]; break; 511 | case 18:a = aa[416]; break; 512 | case 19:a = aa[473]; break; 513 | case 20:a = aa[502]; break; 514 | case 21:a = aa[545]; break; 515 | case 22:a = aa[600]; break; 516 | default: a = 0; break; 517 | }; return a; 518 | } 519 | 520 | inline uint18_t get_data15 ( int offset, uint18_t aa[ROWS*COLS]) 521 | { 522 | uint18_t a; 523 | 524 | switch (offset) 525 | { 526 | case 0:a = aa[8]; break; 527 | case 1:a = aa[25]; break; 528 | case 2:a = aa[30]; break; 529 | case 3:a = aa[57]; break; 530 | case 4:a = aa[120]; break; 531 | case 5:a = aa[123]; break; 532 | case 6:a = aa[169]; break; 533 | case 7:a = aa[192]; break; 534 | case 8:a = aa[217]; break; 535 | case 9:a = aa[241]; break; 536 | case 10:a = aa[271]; break; 537 | case 11:a = aa[274]; break; 538 | case 12:a = aa[285]; break; 539 | case 13:a = aa[306]; break; 540 | case 14:a = aa[327]; break; 541 | case 15:a = aa[368]; break; 542 | case 16:a = aa[403]; break; 543 | case 17:a = aa[434]; break; 544 | case 18:a = aa[474]; break; 545 | case 19:a = aa[476]; break; 546 | case 20:a = aa[504]; break; 547 | case 21:a = aa[538]; break; 548 | case 22:a = aa[563]; break; 549 | case 23:a = aa[568]; break; 550 | case 24:a = aa[596]; break; 551 | default: a = 0; break; 552 | }; return a; 553 | } 554 | 555 | inline uint18_t get_data16 ( int offset, uint18_t aa[ROWS*COLS]) 556 | { 557 | uint18_t a; 558 | 559 | switch (offset) 560 | { 561 | case 0:a = aa[12]; break; 562 | case 1:a = aa[26]; break; 563 | case 2:a = aa[49]; break; 564 | case 3:a = aa[68]; break; 565 | case 4:a = aa[83]; break; 566 | case 5:a = aa[121]; break; 567 | case 6:a = aa[219]; break; 568 | case 7:a = aa[234]; break; 569 | case 8:a = aa[252]; break; 570 | case 9:a = aa[265]; break; 571 | case 10:a = aa[281]; break; 572 | case 11:a = aa[282]; break; 573 | case 12:a = aa[300]; break; 574 | case 13:a = aa[313]; break; 575 | case 14:a = aa[342]; break; 576 | case 15:a = aa[378]; break; 577 | case 16:a = aa[389]; break; 578 | case 17:a = aa[483]; break; 579 | case 18:a = aa[496]; break; 580 | case 19:a = aa[516]; break; 581 | case 20:a = aa[578]; break; 582 | case 21:a = aa[582]; break; 583 | case 22:a = aa[595]; break; 584 | default: a = 0; break; 585 | }; return a; 586 | } 587 | 588 | inline uint18_t get_data17 ( int offset, uint18_t aa[ROWS*COLS]) 589 | { 590 | uint18_t a; 591 | 592 | switch (offset) 593 | { 594 | case 0:a = aa[11]; break; 595 | case 1:a = aa[67]; break; 596 | case 2:a = aa[77]; break; 597 | case 3:a = aa[104]; break; 598 | case 4:a = aa[125]; break; 599 | case 5:a = aa[160]; break; 600 | case 6:a = aa[203]; break; 601 | case 7:a = aa[207]; break; 602 | case 8:a = aa[243]; break; 603 | case 9:a = aa[244]; break; 604 | case 10:a = aa[264]; break; 605 | case 11:a = aa[299]; break; 606 | case 12:a = aa[323]; break; 607 | case 13:a = aa[367]; break; 608 | case 14:a = aa[400]; break; 609 | case 15:a = aa[401]; break; 610 | case 16:a = aa[441]; break; 611 | case 17:a = aa[456]; break; 612 | case 18:a = aa[480]; break; 613 | case 19:a = aa[528]; break; 614 | case 20:a = aa[579]; break; 615 | case 21:a = aa[589]; break; 616 | case 22:a = aa[619]; break; 617 | default: a = 0; break; 618 | }; return a; 619 | 620 | } 621 | 622 | 623 | inline uint18_t get_data18 ( int offset, uint18_t aa[ROWS*COLS]) 624 | { 625 | uint18_t a; 626 | switch (offset) 627 | { 628 | case 0:a = aa[21]; break; 629 | case 1:a = aa[43]; break; 630 | case 2:a = aa[62]; break; 631 | case 3:a = aa[144]; break; 632 | case 4:a = aa[145]; break; 633 | case 5:a = aa[196]; break; 634 | case 6:a = aa[197]; break; 635 | case 7:a = aa[199]; break; 636 | case 8:a = aa[292]; break; 637 | case 9:a = aa[301]; break; 638 | case 10:a = aa[317]; break; 639 | case 11:a = aa[330]; break; 640 | case 12:a = aa[331]; break; 641 | case 13:a = aa[332]; break; 642 | case 14:a = aa[350]; break; 643 | case 15:a = aa[363]; break; 644 | case 16:a = aa[381]; break; 645 | case 17:a = aa[433]; break; 646 | case 18:a = aa[469]; break; 647 | case 19:a = aa[484]; break; 648 | case 20:a = aa[522]; break; 649 | case 21:a = aa[561]; break; 650 | case 22:a = aa[587]; break; 651 | case 23:a = aa[623]; break; 652 | case 24:a = aa[624]; break; 653 | default: a = 0; break; 654 | }; return a; 655 | } 656 | 657 | inline uint18_t get_data19 ( int offset, uint18_t aa[ROWS*COLS]) 658 | { 659 | uint18_t a; 660 | 661 | switch (offset) 662 | { 663 | case 0:a = aa[16]; break; 664 | case 1:a = aa[60]; break; 665 | case 2:a = aa[69]; break; 666 | case 3:a = aa[80]; break; 667 | case 4:a = aa[112]; break; 668 | case 5:a = aa[117]; break; 669 | case 6:a = aa[170]; break; 670 | case 7:a = aa[186]; break; 671 | case 8:a = aa[206]; break; 672 | case 9:a = aa[223]; break; 673 | case 10:a = aa[255]; break; 674 | case 11:a = aa[288]; break; 675 | case 12:a = aa[289]; break; 676 | case 13:a = aa[325]; break; 677 | case 14:a = aa[326]; break; 678 | case 15:a = aa[345]; break; 679 | case 16:a = aa[357]; break; 680 | case 17:a = aa[372]; break; 681 | case 18:a = aa[487]; break; 682 | case 19:a = aa[508]; break; 683 | case 20:a = aa[521]; break; 684 | case 21:a = aa[543]; break; 685 | case 22:a = aa[581]; break; 686 | default: a = 0; break; 687 | }; return a; 688 | } 689 | 690 | inline uint18_t get_data20 ( int offset, uint18_t aa[ROWS*COLS]) 691 | { 692 | uint18_t a; 693 | 694 | switch (offset) 695 | { 696 | case 0:a = aa[2]; break; 697 | case 1:a = aa[13]; break; 698 | case 2:a = aa[44]; break; 699 | case 3:a = aa[63]; break; 700 | case 4:a = aa[90]; break; 701 | case 5:a = aa[111]; break; 702 | case 6:a = aa[126]; break; 703 | case 7:a = aa[154]; break; 704 | case 8:a = aa[181]; break; 705 | case 9:a = aa[200]; break; 706 | case 10:a = aa[230]; break; 707 | case 11:a = aa[257]; break; 708 | case 12:a = aa[294]; break; 709 | case 13:a = aa[295]; break; 710 | case 14:a = aa[296]; break; 711 | case 15:a = aa[339]; break; 712 | case 16:a = aa[373]; break; 713 | case 17:a = aa[399]; break; 714 | case 18:a = aa[422]; break; 715 | case 19:a = aa[436]; break; 716 | case 20:a = aa[462]; break; 717 | case 21:a = aa[518]; break; 718 | case 22:a = aa[533]; break; 719 | case 23:a = aa[585]; break; 720 | case 24:a = aa[610]; break; 721 | default: a = 0; break; 722 | }; return a; 723 | } 724 | 725 | inline uint18_t get_data21 ( int offset, uint18_t aa[ROWS*COLS]) 726 | { 727 | uint18_t a; 728 | 729 | switch (offset) 730 | { 731 | case 0:a = aa[4]; break; 732 | case 1:a = aa[32]; break; 733 | case 2:a = aa[73]; break; 734 | case 3:a = aa[81]; break; 735 | case 4:a = aa[108]; break; 736 | case 5:a = aa[172]; break; 737 | case 6:a = aa[190]; break; 738 | case 7:a = aa[194]; break; 739 | case 8:a = aa[224]; break; 740 | case 9:a = aa[266]; break; 741 | case 10:a = aa[318]; break; 742 | case 11:a = aa[338]; break; 743 | case 12:a = aa[360]; break; 744 | case 13:a = aa[392]; break; 745 | case 14:a = aa[437]; break; 746 | case 15:a = aa[475]; break; 747 | case 16:a = aa[505]; break; 748 | case 17:a = aa[574]; break; 749 | case 18:a = aa[601]; break; 750 | default: a = 0; break; 751 | }; return a; 752 | } 753 | 754 | inline uint18_t get_data22 ( int offset, uint18_t aa[ROWS*COLS]) 755 | { 756 | uint18_t a; 757 | 758 | switch (offset) 759 | { 760 | case 0:a = aa[71]; break; 761 | case 1:a = aa[85]; break; 762 | case 2:a = aa[92]; break; 763 | case 3:a = aa[124]; break; 764 | case 4:a = aa[133]; break; 765 | case 5:a = aa[143]; break; 766 | case 6:a = aa[166]; break; 767 | case 7:a = aa[211]; break; 768 | case 8:a = aa[225]; break; 769 | case 9:a = aa[304]; break; 770 | case 10:a = aa[305]; break; 771 | case 11:a = aa[351]; break; 772 | case 12:a = aa[352]; break; 773 | case 13:a = aa[407]; break; 774 | case 14:a = aa[423]; break; 775 | case 15:a = aa[431]; break; 776 | case 16:a = aa[472]; break; 777 | case 17:a = aa[495]; break; 778 | case 18:a = aa[515]; break; 779 | case 19:a = aa[549]; break; 780 | case 20:a = aa[553]; break; 781 | case 21:a = aa[558]; break; 782 | case 22:a = aa[588]; break; 783 | case 23:a = aa[614]; break; 784 | default: a = 0; break; 785 | }; return a; 786 | } 787 | 788 | inline uint18_t get_data23 ( int offset, uint18_t aa[ROWS*COLS]) 789 | { 790 | uint18_t a; 791 | 792 | switch (offset) 793 | { 794 | case 0:a = aa[37]; break; 795 | case 1:a = aa[50]; break; 796 | case 2:a = aa[88]; break; 797 | case 3:a = aa[114]; break; 798 | case 4:a = aa[134]; break; 799 | case 5:a = aa[189]; break; 800 | case 6:a = aa[205]; break; 801 | case 7:a = aa[214]; break; 802 | case 8:a = aa[236]; break; 803 | case 9:a = aa[273]; break; 804 | case 10:a = aa[297]; break; 805 | case 11:a = aa[349]; break; 806 | case 12:a = aa[354]; break; 807 | case 13:a = aa[432]; break; 808 | case 14:a = aa[457]; break; 809 | case 15:a = aa[477]; break; 810 | case 16:a = aa[498]; break; 811 | case 17:a = aa[512]; break; 812 | case 18:a = aa[605]; break; 813 | case 19:a = aa[616]; break; 814 | default: a = 0; break; 815 | }; return a; 816 | } 817 | 818 | inline uint18_t get_data24 ( int offset, uint18_t aa[ROWS*COLS]) 819 | { 820 | uint18_t a; 821 | 822 | switch (offset) 823 | { 824 | case 0:a = aa[31]; break; 825 | case 1:a = aa[84]; break; 826 | case 2:a = aa[113]; break; 827 | case 3:a = aa[116]; break; 828 | case 4:a = aa[129]; break; 829 | case 5:a = aa[158]; break; 830 | case 6:a = aa[182]; break; 831 | case 7:a = aa[227]; break; 832 | case 8:a = aa[276]; break; 833 | case 9:a = aa[380]; break; 834 | case 10:a = aa[404]; break; 835 | case 11:a = aa[460]; break; 836 | case 12:a = aa[470]; break; 837 | case 13:a = aa[493]; break; 838 | case 14:a = aa[494]; break; 839 | case 15:a = aa[503]; break; 840 | case 16:a = aa[514]; break; 841 | case 17:a = aa[566]; break; 842 | case 18:a = aa[580]; break; 843 | case 19:a = aa[602]; break; 844 | case 20:a = aa[617]; break; 845 | default: a = 0; break; 846 | }; return a; 847 | } 848 | 849 | inline uint18_t get_data25 ( int offset, uint18_t aa[ROWS*COLS]) 850 | { 851 | uint18_t a; 852 | 853 | switch (offset) 854 | { 855 | case 0:a = aa[33]; break; 856 | case 1:a = aa[51]; break; 857 | case 2:a = aa[64]; break; 858 | case 3:a = aa[78]; break; 859 | case 4:a = aa[86]; break; 860 | case 5:a = aa[110]; break; 861 | case 6:a = aa[130]; break; 862 | case 7:a = aa[216]; break; 863 | case 8:a = aa[254]; break; 864 | case 9:a = aa[298]; break; 865 | case 10:a = aa[320]; break; 866 | case 11:a = aa[402]; break; 867 | case 12:a = aa[419]; break; 868 | case 13:a = aa[438]; break; 869 | case 14:a = aa[446]; break; 870 | case 15:a = aa[455]; break; 871 | case 16:a = aa[491]; break; 872 | case 17:a = aa[500]; break; 873 | case 18:a = aa[590]; break; 874 | case 19:a = aa[622]; break; 875 | default: a = 0; break; 876 | }; return a; 877 | } 878 | 879 | inline uint18_t get_data26 ( int offset, uint18_t aa[ROWS*COLS]) 880 | { 881 | uint18_t a; 882 | 883 | switch (offset) 884 | { 885 | case 0:a = aa[70]; break; 886 | case 1:a = aa[89]; break; 887 | case 2:a = aa[115]; break; 888 | case 3:a = aa[127]; break; 889 | case 4:a = aa[142]; break; 890 | case 5:a = aa[272]; break; 891 | case 6:a = aa[348]; break; 892 | case 7:a = aa[370]; break; 893 | case 8:a = aa[379]; break; 894 | case 9:a = aa[430]; break; 895 | case 10:a = aa[461]; break; 896 | case 11:a = aa[485]; break; 897 | case 12:a = aa[513]; break; 898 | case 13:a = aa[541]; break; 899 | case 14:a = aa[550]; break; 900 | case 15:a = aa[583]; break; 901 | case 16:a = aa[607]; break; 902 | default: a = 0; break; 903 | }; return a; 904 | } 905 | 906 | inline uint18_t get_data27 ( int offset, uint18_t aa[ROWS*COLS]) 907 | { 908 | uint18_t a; 909 | 910 | switch (offset) 911 | { 912 | case 0:a = aa[36]; break; 913 | case 1:a = aa[91]; break; 914 | case 2:a = aa[98]; break; 915 | case 3:a = aa[107]; break; 916 | case 4:a = aa[176]; break; 917 | case 5:a = aa[202]; break; 918 | case 6:a = aa[278]; break; 919 | case 7:a = aa[467]; break; 920 | case 8:a = aa[482]; break; 921 | case 9:a = aa[546]; break; 922 | case 10:a = aa[556]; break; 923 | case 11:a = aa[569]; break; 924 | case 12:a = aa[592]; break; 925 | case 13:a = aa[620]; break; 926 | default: a = 0; break; 927 | }; return a; 928 | } 929 | 930 | //inline void get_all_data( uint18_t output[12], uint10_t addr_list[12], bit enable_list[12], uint18_t aa[ROWS*COLS]) 931 | inline void get_all_data( uint18_t output[12], uint10_t addr_list[12], uint18_t aa[ROWS*COLS]) 932 | { 933 | 934 | #pragma HLS inline 935 | #pragma HLS interface ap_stable port=aa 936 | 937 | 938 | uint5_t bank[12]; 939 | #pragma HLS array_partition variable=bank complete dim=0 940 | uint5_t offset[12]; 941 | #pragma HLS array_partition variable=offset complete dim=0 942 | uint5_t offset_for_banks[28]; 943 | #pragma HLS array_partition variable=offset_for_banks complete dim=0 944 | uint18_t data_from_banks[28]; 945 | #pragma HLS array_partition variable=data_from_banks complete dim=0 946 | 947 | COMPUTE_BANK_AND_OFFSET: 948 | for (int i = 0; i < 12; i ++ ) 949 | { 950 | #pragma HLS unroll 951 | bank[i] = get_bank(addr_list[i]); 952 | offset[i] = get_offset(addr_list[i]); 953 | } 954 | 955 | ASSIGN_OFFSET_FOR_BANKS: 956 | for (int i = 0; i < 28; i ++ ) 957 | { 958 | #pragma HLS unroll 959 | offset_for_banks[i] = (bank[ 0] == i) ? offset[ 0] : 960 | (bank[ 1] == i) ? offset[ 1] : 961 | (bank[ 2] == i) ? offset[ 2] : 962 | (bank[ 3] == i) ? offset[ 3] : 963 | (bank[ 4] == i) ? offset[ 4] : 964 | (bank[ 5] == i) ? offset[ 5] : 965 | (bank[ 6] == i) ? offset[ 6] : 966 | (bank[ 7] == i) ? offset[ 7] : 967 | (bank[ 8] == i) ? offset[ 8] : 968 | (bank[ 9] == i) ? offset[ 9] : 969 | (bank[10] == i) ? offset[10] : 970 | (bank[11] == i) ? offset[11] : 971 | uint5_t("0",10); 972 | 973 | } 974 | 975 | READ_ALL_BANKS: 976 | data_from_banks[ 0] = get_data0 (offset_for_banks[ 0], aa); 977 | data_from_banks[ 1] = get_data1 (offset_for_banks[ 1], aa); 978 | data_from_banks[ 2] = get_data2 (offset_for_banks[ 2], aa); 979 | data_from_banks[ 3] = get_data3 (offset_for_banks[ 3], aa); 980 | data_from_banks[ 4] = get_data4 (offset_for_banks[ 4], aa); 981 | data_from_banks[ 5] = get_data5 (offset_for_banks[ 5], aa); 982 | data_from_banks[ 6] = get_data6 (offset_for_banks[ 6], aa); 983 | data_from_banks[ 7] = get_data7 (offset_for_banks[ 7], aa); 984 | data_from_banks[ 8] = get_data8 (offset_for_banks[ 8], aa); 985 | data_from_banks[ 9] = get_data9 (offset_for_banks[ 9], aa); 986 | data_from_banks[10] = get_data10(offset_for_banks[10], aa); 987 | data_from_banks[11] = get_data11(offset_for_banks[11], aa); 988 | data_from_banks[12] = get_data12(offset_for_banks[12], aa); 989 | data_from_banks[13] = get_data13(offset_for_banks[13], aa); 990 | data_from_banks[14] = get_data14(offset_for_banks[14], aa); 991 | data_from_banks[15] = get_data15(offset_for_banks[15], aa); 992 | data_from_banks[16] = get_data16(offset_for_banks[16], aa); 993 | data_from_banks[17] = get_data17(offset_for_banks[17], aa); 994 | data_from_banks[18] = get_data18(offset_for_banks[18], aa); 995 | data_from_banks[19] = get_data19(offset_for_banks[19], aa); 996 | data_from_banks[20] = get_data20(offset_for_banks[20], aa); 997 | data_from_banks[21] = get_data21(offset_for_banks[21], aa); 998 | data_from_banks[22] = get_data22(offset_for_banks[22], aa); 999 | data_from_banks[23] = get_data23(offset_for_banks[23], aa); 1000 | data_from_banks[24] = get_data24(offset_for_banks[24], aa); 1001 | data_from_banks[25] = get_data25(offset_for_banks[25], aa); 1002 | data_from_banks[26] = get_data26(offset_for_banks[26], aa); 1003 | data_from_banks[27] = get_data27(offset_for_banks[27], aa); 1004 | 1005 | CHOOSE_DATA: 1006 | for (int i = 0; i < 12; i ++ ) 1007 | { 1008 | #pragma HLS unroll 1009 | //output[i] = enable_list[i] ? data_from_banks[bank[i]] : uint18_t("0",10); 1010 | output[i] = data_from_banks[bank[i]]; 1011 | } 1012 | 1013 | } 1014 | 1015 | uint18_t use_data(uint18_t values[12], bit enable_list[12]) 1016 | { 1017 | #pragma HLS inline off 1018 | uint18_t sum = 0; 1019 | for (int i = 0; i < 12; i ++ ) 1020 | { 1021 | if(enable_list[i]) 1022 | sum += values[i]; 1023 | } 1024 | return sum; 1025 | } 1026 | 1027 | 1028 | /****************************************************************************************/ 1029 | /* FUNCTION DECLARATIONS 1030 | ****************************************************************************************/ 1031 | void imageScaler ( int src_height, 1032 | int src_width, 1033 | unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH], 1034 | int dest_height, 1035 | int dest_width, 1036 | unsigned char IMG1_data[IMAGE_HEIGHT][IMAGE_WIDTH] 1037 | ); 1038 | 1039 | void processImage ( float _factor, 1040 | int sum_row, 1041 | int sum_col, 1042 | int *AllCandidates_x, 1043 | int *AllCandidates_y, 1044 | int *AllCandidates_w, 1045 | int *AllCandidates_h, 1046 | int *AllCandidates_size, 1047 | unsigned char IMG1_data[IMAGE_HEIGHT][IMAGE_WIDTH], 1048 | MySize winSize 1049 | ); 1050 | 1051 | int cascadeClassifier ( MyPoint pt, 1052 | int_II II[WINDOW_SIZE][WINDOW_SIZE], 1053 | int_SII SII[SQ_SIZE][SQ_SIZE] 1054 | ); 1055 | 1056 | int weakClassifier ( int stddev, 1057 | uint18_t coord[12], 1058 | int haar_counter, 1059 | int w_id 1060 | ); 1061 | 1062 | void groupRectangles ( MyRect *rectList, 1063 | int *rectList_size, 1064 | int groupThreshold, 1065 | float eps 1066 | ); 1067 | 1068 | unsigned int int_sqrt ( ap_uint<32> value 1069 | ); 1070 | 1071 | inline int myRound ( float value ) 1072 | { 1073 | return (int)(value + (value >= 0 ? 0.5 : -0.5)); 1074 | } 1075 | 1076 | //======================================================================================== 1077 | // TOP LEVEL MODULE OR DUT (DEVICE UNDER TEST) 1078 | //======================================================================================== 1079 | 1080 | void detectFaces 1081 | 1082 | ( 1083 | unsigned char inData[IMAGE_WIDTH], 1084 | int result_x[RESULT_SIZE], 1085 | int result_y[RESULT_SIZE], 1086 | int result_w[RESULT_SIZE], 1087 | int result_h[RESULT_SIZE], 1088 | int *result_size 1089 | ) 1090 | 1091 | { 1092 | static unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH]; 1093 | int i, j; 1094 | 1095 | int result_x_Scale[RESULT_SIZE]; 1096 | int result_y_Scale[RESULT_SIZE]; 1097 | int result_w_Scale[RESULT_SIZE]; 1098 | int result_h_Scale[RESULT_SIZE]; 1099 | int res_size_Scale = 0; 1100 | int *result_size_Scale = &res_size_Scale; 1101 | 1102 | static int counter = 0; 1103 | if ( counter < IMAGE_HEIGHT){ 1104 | for( j = 0; j < IMAGE_WIDTH; j++){ 1105 | Data[counter][j] = inData[j]; 1106 | } 1107 | counter++; 1108 | if ( counter < IMAGE_HEIGHT ){ 1109 | for ( i = 0; i < RESULT_SIZE; i++){ 1110 | result_x[i] = 0; 1111 | result_y[i] = 0; 1112 | result_w[i] = 0; 1113 | result_h[i] = 0; 1114 | } 1115 | *result_size = 0; 1116 | return ; 1117 | } 1118 | } 1119 | 1120 | *result_size = 0; 1121 | 1122 | float scaleFactor = 1.2; 1123 | 1124 | unsigned char IMG1_data[IMAGE_HEIGHT][IMAGE_WIDTH]; 1125 | 1126 | int height, width; 1127 | float factor; 1128 | 1129 | MySize winSize0; 1130 | winSize0.width = 24; 1131 | winSize0.height= 24; 1132 | 1133 | factor = scaleFactor ; 1134 | 1135 | L1: 1136 | while ( IMAGE_WIDTH/factor > WINDOW_SIZE && IMAGE_HEIGHT/factor > WINDOW_SIZE ) 1137 | { 1138 | 1139 | /* size of the image scaled up */ 1140 | MySize winSize = { myRound(winSize0.width*factor), myRound(winSize0.height*factor) }; 1141 | /* size of the image scaled down (from bigger to smaller) */ 1142 | MySize sz = { ( IMAGE_WIDTH/factor ), ( IMAGE_HEIGHT/factor ) }; 1143 | 1144 | height = sz.height; 1145 | width = sz.width; 1146 | 1147 | imageScaler ( IMAGE_HEIGHT, 1148 | IMAGE_WIDTH, 1149 | Data, 1150 | height, 1151 | width, 1152 | IMG1_data 1153 | ); 1154 | 1155 | 1156 | processImage ( factor, 1157 | height, 1158 | width, 1159 | result_x_Scale, 1160 | result_y_Scale, 1161 | result_w_Scale, 1162 | result_h_Scale, 1163 | result_size_Scale, 1164 | IMG1_data, 1165 | winSize 1166 | ); 1167 | factor *= scaleFactor; 1168 | } /* end of the factor loop, finish all scales in pyramid*/ 1169 | 1170 | for ( i = 0; i < RESULT_SIZE; i++){ 1171 | result_x[i] = result_x_Scale[i]; 1172 | result_y[i] = result_y_Scale[i]; 1173 | result_w[i] = result_w_Scale[i]; 1174 | result_h[i] = result_h_Scale[i]; 1175 | } 1176 | *result_size = *result_size_Scale; 1177 | } 1178 | 1179 | void processImage 1180 | 1181 | ( float factor, 1182 | int sum_row, 1183 | int sum_col, 1184 | int *AllCandidates_x, 1185 | int *AllCandidates_y, 1186 | int *AllCandidates_w, 1187 | int *AllCandidates_h, 1188 | int *AllCandidates_size, 1189 | unsigned char IMG1_data[IMAGE_HEIGHT][IMAGE_WIDTH], 1190 | MySize winSize 1191 | ) 1192 | { 1193 | #pragma HLS inline off 1194 | MyPoint p; 1195 | int result; 1196 | int step; 1197 | 1198 | int u,v; 1199 | int x,y,i,j,k; 1200 | 1201 | /** Image Line buffer ( 24 BRAMs ) */ 1202 | unsigned char L[WINDOW_SIZE-1][IMAGE_WIDTH]; 1203 | #pragma HLS array_partition variable=L complete dim=1 1204 | 1205 | /** Image Window buffer ( 1250 registers )*/ 1206 | static int_I I[WINDOW_SIZE][2*WINDOW_SIZE]; 1207 | #pragma HLS array_partition variable=I complete dim=0 1208 | 1209 | /** Integral Image Window buffer ( 625 registers )*/ 1210 | static int_II II[WINDOW_SIZE][WINDOW_SIZE]; 1211 | #pragma HLS array_partition variable=II complete dim=0 1212 | 1213 | /** Square Image Window buffer ( 1250 registers ) **/ 1214 | static int_SI SI[WINDOW_SIZE][2*WINDOW_SIZE]; 1215 | #pragma HLS array_partition variable=SI complete dim=0 1216 | 1217 | /** Square Integral Image Window buffer ( 625 registers )*/ 1218 | static int_SII SII[SQ_SIZE][SQ_SIZE]; 1219 | #pragma HLS array_partition variable=SII complete dim=0 1220 | 1221 | 1222 | Initialize0u : 1223 | for ( u = 0; u < WINDOW_SIZE; u++ ){ 1224 | #pragma HLS unroll 1225 | Initailize0v: 1226 | for ( v = 0; v < WINDOW_SIZE; v++ ){ 1227 | #pragma HLS unroll 1228 | II[u][v] = 0; 1229 | } 1230 | } 1231 | 1232 | SII[0][0] = 0; 1233 | SII[0][1] = 0; 1234 | SII[1][0] = 0; 1235 | SII[1][1] = 0; 1236 | 1237 | 1238 | Initialize1i: 1239 | for ( i = 0; i < WINDOW_SIZE ; i++ ){ 1240 | #pragma HLS unroll 1241 | Initialize1j: 1242 | for ( j = 0; j < 2*WINDOW_SIZE; j++ ){ 1243 | #pragma HLS unroll 1244 | I[i][j] = 0; 1245 | SI[i][j] = 0; 1246 | } 1247 | } 1248 | 1249 | 1250 | Initialize2y : 1251 | for ( y = 0; y < WINDOW_SIZE-1; y++ ){ 1252 | #pragma HLS unroll 1253 | Initialize2x : 1254 | for ( x = 0; x < IMAGE_WIDTH ; x++){//IMAGE_WIDTH; x++ ){ 1255 | L[y][x] = 0; 1256 | } 1257 | } 1258 | 1259 | 1260 | int element_counter = 0; 1261 | int x_index = 0; 1262 | int y_index = 0; 1263 | int ii, jj; 1264 | 1265 | /** Loop over each point in the Image ( scaled ) **/ 1266 | Pixely: for( y = 0; y < sum_row; y++ ){ 1267 | Pixelx : for ( x = 0; x < sum_col; x++ ){ 1268 | 1269 | /* Updates for Integral Image Window Buffer (I) */ 1270 | SetIIu: for ( u = 0; u < WINDOW_SIZE; u++){ 1271 | #pragma HLS unroll 1272 | SetIIj: for ( v = 0; v < WINDOW_SIZE; v++ ){ 1273 | #pragma HLS unroll 1274 | II[u][v] = II[u][v] + ( I[u][v+1] - I[u][0] ); 1275 | } 1276 | } 1277 | 1278 | /* Updates for Square Image Window Buffer (SI) */ 1279 | SII[0][0] = SII[0][0] + ( SI[0][1] - SI[0][0] ); 1280 | SII[0][1] = SII[0][1] + ( SI[0][WINDOW_SIZE] - SI[0][0] ); 1281 | SII[1][0] = SII[1][0] + ( SI[WINDOW_SIZE-1][1] - SI[WINDOW_SIZE-1][0] ); 1282 | SII[1][1] = SII[1][1] + ( SI[WINDOW_SIZE-1][WINDOW_SIZE] - SI[WINDOW_SIZE-1][0] ); 1283 | 1284 | /* Updates for Image Window Buffer (I) and Square Image Window Bufer (SI) */ 1285 | SetIj: for( j = 0; j < 2*WINDOW_SIZE-1; j++){ 1286 | #pragma HLS unroll 1287 | SetIi: for( i = 0; i < WINDOW_SIZE; i++ ){ 1288 | #pragma HLS unroll 1289 | if( i+j != 2*WINDOW_SIZE-1 ){ 1290 | I[i][j] = I[i][j+1]; 1291 | SI[i][j] = SI[i][j+1]; 1292 | } 1293 | else if ( i > 0 ){ 1294 | I[i][j] = I[i][j+1] + I[i-1][j+1]; 1295 | SI[i][j] = SI[i][j+1] + SI[i-1][j+1]; 1296 | } 1297 | } 1298 | } 1299 | /** Last column of the I[][] matrix **/ 1300 | Ilast: for( i = 0; i < WINDOW_SIZE-1; i++ ){ 1301 | #pragma HLS unroll 1302 | I[i][2*WINDOW_SIZE-1] = L[i][x]; 1303 | SI[i][2*WINDOW_SIZE-1] = L[i][x]*L[i][x]; 1304 | } 1305 | I[WINDOW_SIZE-1][2*WINDOW_SIZE-1] = IMG1_data[y][x]; 1306 | SI[WINDOW_SIZE-1][2*WINDOW_SIZE-1] = IMG1_data[y][x]*IMG1_data[y][x]; 1307 | 1308 | /** Updates for Image Line Buffer (L) **/ 1309 | LineBuf: for( k = 0; k < WINDOW_SIZE-2; k++ ){ 1310 | #pragma HLS unroll 1311 | L[k][x] = L[k+1][x]; 1312 | } 1313 | L[WINDOW_SIZE-2][x] = IMG1_data[y][x]; 1314 | 1315 | /* Pass the Integral Image Window buffer through Cascaded Classifier. Only pass 1316 | * when the integral image window buffer has flushed out the initial garbage data */ 1317 | if ( element_counter >= ( ( (WINDOW_SIZE-1)*sum_col + WINDOW_SIZE ) + WINDOW_SIZE -1 ) ) { 1318 | 1319 | /* Sliding Window should not go beyond the boundary */ 1320 | if ( x_index < ( sum_col - (WINDOW_SIZE-1) ) && y_index < ( sum_row - (WINDOW_SIZE-1) ) ){ 1321 | p.x = x_index; 1322 | p.y = y_index; 1323 | 1324 | result = cascadeClassifier ( p, 1325 | II, 1326 | SII 1327 | ); 1328 | 1329 | if ( result > 0 ) 1330 | { 1331 | MyRect r = {myRound(p.x*factor), myRound(p.y*factor), winSize.width, winSize.height}; 1332 | AllCandidates_x[*AllCandidates_size]=r.x; 1333 | AllCandidates_y[*AllCandidates_size]=r.y; 1334 | AllCandidates_w[*AllCandidates_size]=r.width; 1335 | AllCandidates_h[*AllCandidates_size]=r.height; 1336 | *AllCandidates_size=*AllCandidates_size+1; 1337 | } 1338 | }// inner if 1339 | if ( x_index < sum_col-1 ) 1340 | x_index = x_index + 1; 1341 | else{ 1342 | x_index = 0; 1343 | y_index = y_index + 1; 1344 | } 1345 | } // outer if 1346 | element_counter +=1; 1347 | } 1348 | } 1349 | 1350 | } 1351 | 1352 | int cascadeClassifier 1353 | ( 1354 | MyPoint pt, 1355 | int_II II[WINDOW_SIZE][WINDOW_SIZE], 1356 | int_SII SII[SQ_SIZE][SQ_SIZE] 1357 | ) 1358 | 1359 | { 1360 | #pragma HLS INLINE 1361 | 1362 | int i, j, k; 1363 | 1364 | int mean; 1365 | int stddev = 0; 1366 | int haar_counter = 0; 1367 | int w_index = 0; 1368 | int r_index = 0; 1369 | int stage_sum=0; 1370 | 1371 | /* The rectangle co-ordinagte values for all the classifiers */ 1372 | #include "haar_dataRcc_with_partitioning.h" 1373 | 1374 | static uint18_t coord[12]; 1375 | #pragma HLS array_partition variable=coord complete dim=0 1376 | 1377 | /* Banking */ 1378 | 1379 | /* 12 (x,y,w,h) values corresponding to 3 rectangles that need to be read */ 1380 | uint18_t values[12]; 1381 | #pragma HLS array_partition variable=values complete dim=0 1382 | 1383 | /* location/address of those 12 values in the 25 X 25 window */ 1384 | uint10_t addr_list[12]; 1385 | #pragma HLS array_partition variable=addr_list complete dim=0 1386 | 1387 | /* among the 12 values which of them are needed to be read from the 25 X 25 window */ 1388 | bit enable_list[12] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; 1389 | #pragma HLS array_partition variable=enable_list complete dim=0 1390 | 1391 | uint18_t _II[WINDOW_SIZE*WINDOW_SIZE]; 1392 | #pragma HLS array_partition variable=_II complete dim=0 1393 | 1394 | COPY_LOOP1: for (int i = 0; i < WINDOW_SIZE; i ++ ){ 1395 | #pragma HLS unroll 1396 | COPY_LOOP2: for (int j = 0; j < WINDOW_SIZE; j ++ ){ 1397 | #pragma HLS unroll 1398 | _II[i*25+j] = II[i][j]; 1399 | } 1400 | } 1401 | 1402 | stddev = SII[0][0] 1403 | - SII[0][SQ_SIZE- 1] 1404 | - SII[SQ_SIZE-1][0] 1405 | + SII[SQ_SIZE-1][SQ_SIZE-1]; 1406 | 1407 | mean = II[0][0] 1408 | - II[0][WINDOW_SIZE - 1] 1409 | - II[WINDOW_SIZE - 1][0] 1410 | + II[WINDOW_SIZE - 1][WINDOW_SIZE - 1]; 1411 | 1412 | stddev = (stddev*(WINDOW_SIZE-1)*(WINDOW_SIZE-1)); 1413 | stddev = stddev - mean*mean; 1414 | 1415 | if( stddev > 0 ) 1416 | stddev = int_sqrt(stddev); 1417 | else 1418 | stddev = 1; 1419 | 1420 | MyRect tr0,tr1,tr2; 1421 | 1422 | int r_id; 1423 | int w_id; 1424 | int s; 1425 | 1426 | 1427 | /******************************************/ 1428 | // ALL 25 STAGES 1429 | /*****************************************/ 1430 | 1431 | Stages: for ( i = 0; i < 25; i++ ){ 1432 | Filters: for ( j = 0; j < stages_array[i] ; j++ ){ 1433 | 1434 | #pragma HLS pipeline 1435 | if ( j == 0 ) { 1436 | stage_sum = 0; s=0; 1437 | } 1438 | 1439 | r_id = r_index; 1440 | w_id = w_index; 1441 | 1442 | tr0.x = rectangles_array0[haar_counter]; 1443 | tr0.width = rectangles_array2[haar_counter]; 1444 | tr0.y = rectangles_array1[haar_counter]; 1445 | tr0.height = rectangles_array3[haar_counter]; 1446 | 1447 | tr1.x = rectangles_array4[haar_counter]; 1448 | tr1.width = rectangles_array6[haar_counter]; 1449 | tr1.y = rectangles_array5[haar_counter]; 1450 | tr1.height = rectangles_array7[haar_counter]; 1451 | 1452 | tr2.x = rectangles_array8[haar_counter]; 1453 | tr2.width = rectangles_array10[haar_counter]; 1454 | tr2.y = rectangles_array9[haar_counter]; 1455 | tr2.height = rectangles_array11[haar_counter]; 1456 | 1457 | /* Calculates addresses/locations of all the 12 co-ordinates */ 1458 | addr_list[ 0] = tr0.y *25+ tr0.x; 1459 | addr_list[ 1] = tr0.y *25+tr0.x+tr0.width; 1460 | addr_list[ 2] = (tr0.y+tr0.height)*25+tr0.x; 1461 | addr_list[ 3] = (tr0.y+tr0.height)*25+tr0.x+tr0.width; 1462 | addr_list[ 4] = tr1.y *25+tr1.x; 1463 | addr_list[ 5] = tr1.y *25+tr1.x+tr1.width; 1464 | addr_list[ 6] = (tr1.y+tr1.height)*25+tr1.x; 1465 | addr_list[ 7] = (tr1.y+tr1.height)*25+tr1.x+tr1.width; 1466 | 1467 | 1468 | if (!(tr2.x ==0 && tr2.width==0 && tr2.y==0 && tr2.height==0 ) && tr2.width!=0 && tr2.height!=0) 1469 | { 1470 | 1471 | addr_list[ 8] = tr2.y *25+tr2.x; 1472 | addr_list[ 9] = tr2.y *25+tr2.x+tr2.width; 1473 | addr_list[10] = (tr2.y+tr2.height)*25+tr2.x; 1474 | addr_list[11] = (tr2.y+tr2.height)*25+tr2.x+tr2.width; 1475 | enable_list[ 8] = 1; 1476 | enable_list[ 9] = 1; 1477 | enable_list[10] = 1; 1478 | enable_list[11] = 1; 1479 | 1480 | } 1481 | else 1482 | { 1483 | addr_list[ 8] = addr_list[0]; 1484 | addr_list[ 9] = addr_list[1]; 1485 | addr_list[10] = addr_list[2]; 1486 | addr_list[11] = addr_list[3]; 1487 | enable_list[ 8] = 0; 1488 | enable_list[ 9] = 0; 1489 | enable_list[10] = 0; 1490 | enable_list[11] = 0; 1491 | 1492 | } 1493 | 1494 | /* Read the values corresponding to the 12 locations from _II which is the copy of integral image window */ 1495 | get_all_data(values, addr_list, _II); 1496 | 1497 | for ( k = 0; k < 12; k++ ){ 1498 | if ( enable_list[k] == 0 ) 1499 | coord[k] = 0; 1500 | else 1501 | coord[k] = values[k]; 1502 | } 1503 | 1504 | s = weakClassifier ( stddev, 1505 | coord, 1506 | haar_counter, 1507 | w_id 1508 | ); 1509 | 1510 | stage_sum = stage_sum + s; 1511 | haar_counter = haar_counter+1; 1512 | w_index = w_index+3; 1513 | r_index = r_index+12; 1514 | 1515 | } /* end of j loop */ 1516 | if( stage_sum < 0.4*stages_thresh_array[i] ){ 1517 | return -i; 1518 | } 1519 | } /* end of i loop */ 1520 | 1521 | return 1; 1522 | } 1523 | 1524 | int weakClassifier 1525 | ( 1526 | int stddev, 1527 | uint18_t coord[12], 1528 | int haar_counter, 1529 | int w_id 1530 | ) 1531 | { 1532 | /* weights and threshold values for various classifiers */ 1533 | 1534 | #include "haar_dataEWC_with_partitioning.h" 1535 | # pragma HLS INLINE 1536 | 1537 | int t = tree_thresh_array[haar_counter] * stddev; 1538 | 1539 | int sum0 =0; 1540 | int sum1 =0; 1541 | int sum2 =0; 1542 | int final_sum =0; 1543 | int return_value; 1544 | 1545 | sum0 = (coord[0] - coord[1] - coord[2] + coord[3]) * weights_array0[haar_counter]; 1546 | sum1 = (coord[4] - coord[5] - coord[6] + coord[7]) * weights_array1[haar_counter]; 1547 | sum2 = (coord[8] - coord[9] - coord[10] + coord[11]) * weights_array2[haar_counter]; 1548 | final_sum = sum0+sum1+sum2; 1549 | 1550 | if(final_sum >= t) 1551 | return_value = alpha2_array[haar_counter]; 1552 | else 1553 | return_value = alpha1_array[haar_counter]; 1554 | 1555 | return return_value ; 1556 | } 1557 | 1558 | 1559 | void imageScaler 1560 | ( 1561 | int src_height, 1562 | int src_width, 1563 | unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH], 1564 | int dest_height, 1565 | int dest_width, 1566 | unsigned char IMG1_data[IMAGE_HEIGHT][IMAGE_WIDTH] 1567 | ) 1568 | { 1569 | int y; 1570 | int j; 1571 | int x; 1572 | int i; 1573 | unsigned char* t; 1574 | unsigned char* p; 1575 | int w1 = src_width; 1576 | int h1 = src_height; 1577 | int w2 = dest_width; 1578 | int h2 = dest_height; 1579 | 1580 | int rat = 0; 1581 | 1582 | int x_ratio = (int)((w1<<16)/w2) +1; 1583 | int y_ratio = (int)((h1<<16)/h2) +1; 1584 | 1585 | 1586 | imageScalerL1: for ( i = 0 ; i < IMAGE_HEIGHT ; i++ ){ 1587 | imageScalerL1_1: for (j=0;j < IMAGE_WIDTH ;j++){ 1588 | #pragma HLS pipeline 1589 | if ( j < w2 && i < h2 ) 1590 | IMG1_data[i][j] = Data[(i*y_ratio)>>16][(j*x_ratio)>>16]; 1591 | 1592 | } 1593 | } 1594 | } 1595 | 1596 | unsigned int int_sqrt 1597 | ( 1598 | ap_uint<32> value 1599 | ) 1600 | { 1601 | int i; 1602 | unsigned int a = 0, b = 0, c = 0; 1603 | 1604 | for ( i = 0 ; i < (32 >> 1) ; i++ ) 1605 | { 1606 | #pragma HLS unroll 1607 | c<<= 2; 1608 | #define UPPERBITS(value) (value>>30) 1609 | c += UPPERBITS(value); 1610 | #undef UPPERBITS 1611 | value <<= 2; 1612 | a <<= 1; 1613 | b = (a<<1) | 1; 1614 | if ( c >= b ) 1615 | { 1616 | c -= b; 1617 | a++; 1618 | } 1619 | } 1620 | return a; 1621 | } 1622 | 1623 | int max 1624 | ( 1625 | int a, 1626 | int b 1627 | ) 1628 | { 1629 | if ( a > b ) 1630 | return a; 1631 | else 1632 | return b; 1633 | } 1634 | 1635 | int min 1636 | ( 1637 | int a, 1638 | int b 1639 | ) 1640 | { 1641 | if ( a < b ) 1642 | return a; 1643 | else 1644 | return b; 1645 | } 1646 | 1647 | -------------------------------------------------------------------------------- /Pipelined/haar.h: -------------------------------------------------------------------------------- 1 | #ifndef __HAAR_H__ 2 | #define __HAAR_H__ 3 | 4 | #include "ap_int.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "ap_int.h" 11 | 12 | const int ROWS = 25; 13 | const int COLS = 25; 14 | 15 | const int NUM_BANKS = 12; 16 | const int SIZE = 2913; 17 | 18 | typedef ap_uint<18> uint18_t; 19 | typedef ap_uint<10> uint10_t; 20 | typedef ap_uint<1> bit; 21 | typedef ap_uint<5> uint5_t; 22 | 23 | 24 | #ifndef __PARAMETERS__ 25 | #define __PARAMETERS__ 26 | 27 | #define IMAGE_HEIGHT 240 28 | #define IMAGE_WIDTH 320 29 | #define IMAGE_MAXGREY 255 30 | #define IMAGE_SIZE ( IMAGE_HEIGHT * IMAGE_WIDTH ) 31 | 32 | #define RESULT_SIZE 100 33 | 34 | #define TOTAL_NODES 2913 35 | #define TOTAL_STAGES 25 36 | #define TOTAL_COORDINATES TOTAL_NODES*12 37 | #define TOTAL_WEIGHTS TOTAL_NODES*3 38 | 39 | #define WINDOW_SIZE 25 40 | #define SQ_SIZE 2 41 | #define PYRAMID_HEIGHT 12 42 | 43 | #define OUTPUT_FILENAME "Output.pgm" 44 | #define INPUT_IMAGE "image0_320_240.h" 45 | 46 | 47 | #endif 48 | 49 | 50 | typedef ap_uint<13> int_I; 51 | typedef ap_uint<21> int_SI; 52 | typedef ap_uint<18> int_II; 53 | typedef ap_uint<26> int_SII; 54 | 55 | #ifdef __cplusplus 56 | extern "C" { 57 | #endif 58 | 59 | typedef struct MyPoint 60 | { 61 | int x; 62 | int y; 63 | } 64 | MyPoint; 65 | 66 | typedef struct 67 | { 68 | int width; 69 | int height; 70 | } 71 | MySize; 72 | 73 | typedef struct 74 | { 75 | int x; 76 | int y; 77 | int width; 78 | int height; 79 | } 80 | MyRect; 81 | 82 | typedef struct 83 | { 84 | int width; 85 | int height; 86 | int maxgrey; 87 | int flag; 88 | } 89 | MyInputImage; 90 | 91 | void detectFaces( unsigned char Data[IMAGE_WIDTH], 92 | int _result_x[RESULT_SIZE], 93 | int _result_y[RESULT_SIZE], 94 | int _result_w[RESULT_SIZE], 95 | int _result_h[RESULT_SIZE], 96 | int *result_size); 97 | 98 | #ifdef __cplusplus 99 | } 100 | #endif 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /Pipelined/haar_mapping.h: -------------------------------------------------------------------------------- 1 | 2 | static int bank_mapping[ROWS * COLS] = 3 | {8, 13, 20, 14, 21, 12, 10, 1, 15, 2, 14, 17, 16, 20, 9, 6, 19, 14, 1, 0, 2, 18, 11, 5, 4, 15, 16, 13, 2, 0, 15, 24, 21, 25, 4, 14, 27, 23, 7, 12, 10, 3, 6, 18, 20, 11, 9, 4, 2, 16, 23, 25, 0, 5, 12, 6, 3, 15, 4, 13, 19, 12, 18, 20, 25, 1, 14, 17, 16, 19, 26, 22, 1, 21, 2, 12, 12, 17, 25, 3, 19, 21, 7, 16, 24, 22, 25, 13, 23, 26, 20, 27, 22, 7, 5, 5, 3, 2, 27, 14, 0, 5, 11, 10, 17, 4, 12, 27, 21, 3, 25, 20, 19, 24, 23, 26, 24, 19, 13, 9, 15, 16, 6, 15, 22, 17, 20, 26, 4, 24, 25, 13, 0, 22, 23, 7, 11, 11, 6, 5, 12, 3, 26, 22, 18, 18, 10, 9, 1, 1, 9, 9, 14, 1, 20, 3, 11, 11, 24, 7, 17, 0, 4, 9, 1, 12, 22, 13, 2, 15, 19, 5, 21, 10, 10, 13, 27, 6, 14, 4, 5, 20, 24, 11, 11, 9, 19, 2, 2, 23, 21, 1, 15, 0, 21, 7, 18, 18, 9, 18, 20, 3, 27, 17, 6, 23, 19, 17, 1, 12, 11, 22, 7, 2, 23, 6, 25, 15, 4, 16, 0, 11, 5, 19, 21, 22, 4, 24, 6, 1, 20, 6, 10, 2, 16, 11, 23, 7, 7, 0, 1, 15, 9, 17, 17, 12, 12, 13, 14, 3, 6, 1, 16, 0, 25, 19, 1, 20, 7, 14, 2, 2, 9, 3, 17, 16, 21, 5, 10, 7, 14, 15, 26, 23, 15, 5, 24, 2, 27, 10, 1, 16, 16, 7, 0, 15, 9, 6, 19, 19, 14, 11, 18, 3, 20, 20, 20, 23, 25, 17, 16, 18, 9, 2, 22, 22, 15, 6, 6, 0, 7, 5, 5, 16, 2, 9, 12, 18, 21, 13, 25, 14, 3, 17, 11, 19, 19, 15, 7, 2, 18, 18, 18, 5, 13, 13, 14, 14, 21, 20, 9, 10, 16, 9, 11, 19, 4, 12, 26, 23, 18, 22, 22, 11, 23, 7, 2, 19, 9, 9, 21, 14, 0, 18, 4, 5, 6, 17, 15, 4, 26, 13, 19, 20, 10, 2, 2, 11, 16, 26, 24, 18, 14, 3, 1, 0, 10, 13, 4, 16, 5, 6, 21, 14, 3, 13, 0, 5, 11, 20, 17, 17, 25, 15, 24, 10, 4, 22, 3, 5, 5, 6, 12, 12, 13, 3, 14, 11, 11, 25, 10, 7, 20, 22, 6, 4, 5, 7, 3, 9, 26, 22, 23, 18, 15, 6, 20, 21, 25, 10, 4, 17, 13, 5, 12, 3, 25, 0, 0, 0, 1, 0, 2, 4, 11, 25, 17, 23, 4, 3, 24, 26, 20, 5, 12, 7, 0, 27, 6, 18, 24, 10, 22, 14, 15, 21, 15, 23, 1, 3, 17, 9, 27, 16, 18, 26, 4, 19, 10, 9, 12, 25, 0, 24, 24, 22, 16, 6, 23, 2, 25, 13, 14, 24, 15, 21, 1, 9, 19, 10, 4, 11, 23, 26, 24, 22, 16, 1, 20, 2, 9, 19, 18, 7, 11, 9, 10, 1, 17, 2, 12, 0, 3, 20, 12, 12, 2, 5, 15, 6, 11, 26, 1, 19, 13, 14, 27, 7, 13, 22, 26, 2, 4, 22, 1, 6, 27, 7, 22, 11, 12, 18, 0, 15, 3, 13, 24, 2, 15, 27, 7, 5, 9, 1, 21, 3, 1, 9, 16, 17, 24, 19, 16, 26, 11, 20, 12, 18, 22, 17, 25, 9, 27, 7, 4, 16, 15, 2, 3, 5, 14, 21, 24, 13, 13, 23, 7, 26, 5, 6, 20, 3, 10, 11, 22, 2, 23, 24, 12, 17, 27, 1, 25, 18, 18}; 4 | 5 | static int offset_mapping[ROWS * COLS] = 6 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 2, 1, 2, 0, 1, 0, 1, 3, 0, 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 3, 2, 1, 1, 2, 1, 2, 2, 1, 3, 3, 2, 1, 3, 2, 3, 2, 2, 4, 1, 3, 2, 0, 0, 3, 2, 4, 4, 5, 2, 3, 2, 3, 3, 1, 4, 1, 1, 4, 3, 2, 1, 4, 1, 2, 2, 2, 3, 3, 5, 2, 5, 3, 4, 2, 2, 3, 4, 6, 3, 4, 4, 5, 5, 4, 2, 3, 2, 3, 5, 4, 2, 4, 5, 3, 5, 3, 4, 6, 3, 5, 4, 6, 5, 4, 4, 4, 3, 3, 4, 4, 5, 7, 5, 4, 5, 3, 4, 3, 3, 4, 5, 4, 5, 6, 6, 7, 6, 5, 6, 5, 4, 5, 5, 6, 6, 7, 8, 6, 6, 6, 6, 6, 6, 5, 4, 5, 7, 4, 5, 7, 7, 7, 8, 6, 7, 8, 7, 7, 7, 8, 5, 6, 8, 7, 6, 7, 5, 5, 6, 8, 7, 9, 7, 5, 6, 6, 6, 8, 7, 9, 9, 9, 7, 6, 9, 7, 7, 7, 8, 8, 6, 7, 10, 8, 9, 8, 8, 9, 7, 8, 10, 10, 9, 6, 10, 7, 11, 8, 7, 8, 8, 11, 9, 9, 8, 9, 10, 11, 8, 8, 8, 10, 12, 8, 9, 8, 10, 13, 11, 9, 9, 11, 12, 10, 9, 10, 9, 9, 9, 7, 10, 10, 10, 5, 9, 11, 10, 8, 13, 6, 8, 14, 10, 11, 11, 10, 12, 11, 11, 11, 12, 11, 12, 8, 10, 12, 13, 14, 10, 9, 11, 12, 9, 12, 14, 9, 10, 13, 12, 13, 11, 12, 11, 12, 13, 15, 13, 12, 10, 10, 9, 10, 12, 11, 12, 13, 13, 14, 14, 13, 16, 11, 12, 13, 13, 10, 11, 13, 14, 11, 15, 14, 9, 14, 15, 14, 15, 10, 13, 6, 11, 14, 11, 12, 15, 12, 14, 17, 16, 16, 17, 12, 15, 12, 15, 11, 14, 14, 13, 15, 12, 7, 12, 17, 16, 10, 18, 19, 16, 15, 8, 9, 16, 16, 12, 15, 13, 11, 13, 13, 16, 15, 15, 13, 17, 13, 14, 14, 16, 17, 17, 14, 15, 11, 16, 10, 12, 14, 13, 14, 17, 18, 16, 14, 15, 15, 15, 18, 18, 19, 12, 13, 15, 18, 14, 17, 15, 19, 16, 16, 18, 9, 15, 13, 17, 17, 18, 19, 14, 13, 14, 16, 16, 16, 20, 16, 17, 14, 15, 16, 17, 16, 18, 20, 17, 20, 15, 17, 14, 18, 18, 11, 10, 20, 21, 17, 17, 19, 7, 19, 18, 12, 15, 16, 19, 18, 15, 19, 15, 17, 19, 18, 19, 8, 17, 19, 11, 19, 18, 16, 20, 18, 16, 20, 13, 14, 17, 18, 20, 16, 21, 17, 17, 20, 15, 20, 16, 18, 21, 19, 17, 20, 21, 17, 12, 16, 18, 19, 19, 21, 22, 22, 20, 20, 18, 22, 23, 18, 20, 19, 23, 19, 21, 20, 22, 20, 21, 24, 22, 21, 21, 23, 13, 21, 21, 18, 21, 9, 19, 19, 19, 14, 25, 21, 20, 22, 22, 10, 20, 21, 24, 22, 21, 22, 22, 21, 20, 17, 26, 23, 11, 21, 23, 24, 23, 17, 22, 24, 25, 20, 20, 18, 22, 21, 15, 25, 23, 23, 22, 22, 21, 18, 26, 12, 22, 22, 22, 24, 27, 23, 24, 22, 18, 19, 21, 22, 18, 23, 16, 25, 23, 24, 24, 19, 26, 23, 28, 19, 20, 24, 22, 13, 25, 19, 23, 24}; 7 | -------------------------------------------------------------------------------- /Pipelined/image.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "image.h" 5 | 6 | #define MYDEBUG 7 | 8 | char* strrev(char* str) 9 | { 10 | char *p1, *p2; 11 | if (!str || !*str) 12 | return str; 13 | for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2) 14 | { 15 | *p1 ^= *p2; 16 | *p2 ^= *p1; 17 | *p1 ^= *p2; 18 | } 19 | return str; 20 | } 21 | 22 | void itochar(int x, char* szBuffer, int radix) 23 | { 24 | int i = 0, n, xx; 25 | n = x; 26 | while (n > 0) 27 | { 28 | xx = n%radix; 29 | n = n/radix; 30 | szBuffer[i++] = '0' + xx; 31 | } 32 | szBuffer[i] = '\0'; 33 | strrev(szBuffer); 34 | } 35 | 36 | /* Writes a Pgm file using the hex image */ 37 | int writePgm(char *fileName, unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH] ) 38 | { 39 | char parameters_str[5]; 40 | int i; 41 | const char *format = "P5"; 42 | FILE *fp = fopen(fileName, "w"); 43 | 44 | if (!fp){ 45 | printf("Unable to open file %s\n", fileName); 46 | return -1; 47 | } 48 | 49 | fputs(format, fp); 50 | fputc('\n', fp); 51 | 52 | itochar(IMAGE_WIDTH, parameters_str, 10); 53 | fputs(parameters_str, fp); 54 | parameters_str[0] = 0; 55 | fputc(' ', fp); 56 | 57 | itochar(IMAGE_HEIGHT, parameters_str, 10); 58 | fputs(parameters_str, fp); 59 | parameters_str[0] = 0; 60 | fputc('\n', fp); 61 | 62 | itochar(IMAGE_MAXGREY, parameters_str, 10); 63 | fputs(parameters_str, fp); 64 | fputc('\n', fp); 65 | 66 | for (i = 0; i < IMAGE_HEIGHT; i++) 67 | for (int j = 0; j < IMAGE_WIDTH ; j++) 68 | fputc(Data[i][j], fp); 69 | 70 | fclose(fp); 71 | return 0; 72 | } 73 | 74 | /* draw white bounding boxes around detected faces */ 75 | void drawRectangle(unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH], MyRect r) 76 | { 77 | int i; 78 | int col = IMAGE_WIDTH; 79 | 80 | for (i = 0; i < r.width; i++) 81 | Data[r.y][r.x + i] = 255; 82 | for (i = 0; i < r.height; i++) 83 | Data[r.y+i][r.x + r.width] = 255; 84 | for (i = 0; i < r.width; i++) 85 | Data[r.y + r.height][r.x + r.width - i] = 255; 86 | for (i = 0; i < r.height; i++) 87 | Data[r.y + r.height - i][r.x] = 255; 88 | } 89 | -------------------------------------------------------------------------------- /Pipelined/image.h: -------------------------------------------------------------------------------- 1 | #ifndef __IMAGE_H__ 2 | #define __IMAGE_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "haar.h" 8 | 9 | #ifndef __PARAMETERS__ 10 | #define __PARAMETERS__ 11 | 12 | #define TOTAL_NODES 2913 13 | #define TOTAL_STAGES 25 14 | #define TOTAL_COORDINATES TOTAL_NODES*12 15 | #define TOTAL_WEIGHTS TOTAL_NODES*3 16 | #define IMAGE_HEIGHT 240 17 | #define IMAGE_WIDTH 320 18 | 19 | 20 | #endif 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | void drawRectangle ( unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH], 27 | MyRect r); 28 | 29 | int writePgm(char *fileName, unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH] ); 30 | 31 | #ifdef __cplusplus 32 | } 33 | #endif 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /Pipelined/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "haar.h" 5 | #include "image.h" 6 | 7 | using namespace std; 8 | 9 | int main ( int argc, char *argv[] ) 10 | { 11 | 12 | int flag; 13 | int in_flag , in_width , in_height , in_maxgrey; 14 | int ret_val=1; 15 | 16 | printf ("-- entering main function --\r\n"); 17 | printf ("-- loading image --\r\n"); 18 | 19 | // 320 X 240 Input image in hex format 20 | #include INPUT_IMAGE 21 | 22 | double duration; 23 | 24 | // Arguments to be passed to DUT 25 | MyRect result[RESULT_SIZE]; 26 | int result_x[RESULT_SIZE]; 27 | int result_y[RESULT_SIZE]; 28 | int result_w[RESULT_SIZE]; 29 | int result_h[RESULT_SIZE]; 30 | 31 | int res_size=0; 32 | int *result_size = &res_size; 33 | int i; 34 | 35 | // As the SDSoC generated data motion network does not support sending 320 X 240 images at once 36 | // We needed to send all the 240 rows using 240 iterations. The last invokation of detectFaces() does the actual face detection 37 | 38 | for ( i = 0; i < IMAGE_HEIGHT-1; i+=1 ){ 39 | detectFaces ( Data[i], result_x, result_y, result_w, result_h, result_size); 40 | } 41 | 42 | printf ("-- detecting faces --\r\n"); 43 | 44 | std::clock_t start = std::clock(); 45 | detectFaces ( Data[IMAGE_HEIGHT-1], result_x, result_y, result_w, result_h, result_size); 46 | duration = ( std::clock() - start ) / (double) CLOCKS_PER_SEC; 47 | 48 | printf("\nresult_size = %d", *result_size); 49 | 50 | for (int j = 0; j < RESULT_SIZE; j++){ 51 | result[j].x = result_x[j]; 52 | result[j].y = result_y[j]; 53 | result[j].width = result_w[j]; 54 | result[j].height = result_h[j]; 55 | } 56 | 57 | for( int i=0 ; i < *result_size ; i++ ) 58 | printf("\n [Test Bench (main) ] detected rects: %d %d %d %d",result[i].x,result[i].y,result[i].width,result[i].height); 59 | 60 | if ( *result_size > 0 ) ret_val = 0; 61 | 62 | printf("\n-- saving output image [Start] --\r\n"); 63 | 64 | // Draw the rectangles onto the images and save the outputs. 65 | for(i = 0; i < *result_size ; i++ ) 66 | { 67 | MyRect r = result[i]; 68 | drawRectangle(Data, r); 69 | } 70 | 71 | flag = writePgm((char *)(OUTPUT_FILENAME),Data); 72 | printf("\n-- saving output image [Done] --\r\n"); 73 | printf("DURATION: %2f", duration); 74 | 75 | return ret_val; 76 | 77 | } 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Publications 2 | ------------------------------------------------------------------------ 3 | 4 | If you use this benchmark in your research, please cite our [FPGA'17 5 | paper][4]: 6 | 7 | ``` 8 | @inproceedings{srivastava-facedetect-fpga2017, 9 | title = {Accelerating Face Detection on Programmable SoC Using 10 | C-Based Synthesis}, 11 | author = {Nitish Srivastava and Steve Dai and Rajit Manohar and 12 | Zhiru Zhang}, 13 | booktitle = {25\textsuperscript{th} ACM/SIGDA International 14 | Symposium on Field-Programmable Gate Arrays}, 15 | month = {Feb}, 16 | year = {2017}, 17 | doi = {10.1145/3020078.3021753}, 18 | } 19 | ``` 20 | 21 | [4]: http://dx.doi.org/10.1145/3020078.3021753 22 | 23 | **NOTE: If you face any issues while running anything in this repo, 24 | shoot me an email at nks45@cornell.edu** 25 | 26 | facedetect-fpga is an open-source implementation of Viola-Jones face 27 | detection algorithm suitable for C-based synthesis. It was introduced 28 | at FPGA-25 in February, 2017. 29 | 30 | This design explores the flow from software based implementation to 31 | an optimized C/C++ design suitable for High Level Synthesis (HLS) flow. 32 | The face detection system is optimized for performance at the 33 | C/C++ level and is synthesizable with a full-system compiler 34 | SDSoC from Xilinx. The design is suitable for real-time face detection 35 | applications and achieves a frame rate of 30 fps. The design has been 36 | tested using Vivado HLS 2016 and SDSoC 2016 on ZC-706 board with 37 | Xilinx Zynq-7000 XC7Z045 FPGA and ARM Cortex-A9 CPU. The generated 38 | RTL code (SystemC, VHDL and Verilog) from the HLS compilers can 39 | potentially be used for other purposes as well. 40 | 41 | Tutorial 42 | ------------------------------------------------------------------------ 43 | ### Pre-requisites 44 | 45 | You will need to install Vivado-HLS and SDSoC to compile and run this 46 | project. 47 | 48 | ### C-simulation 49 | 50 | The face detection benchmark has been written in C. The current version 51 | also supports C simulation so that functionality of the algorithm can be 52 | tested without going through the painful process of bitstream generation. 53 | 54 | To do the C-simulation of the design enter the following command in the 55 | main directory: 56 | 57 | % make csim 58 | 59 | This will create a hls.prj directory containing all the logs for the C 60 | simulation. The output of the face-detection can be seen in the directory 61 | hls.prj/solution/csim/build/Output.pgm Make sure that all the faces have 62 | been detected and marked using rectangles. 63 | 64 | One should always do C-simulation before synthesizing the design as it 65 | is fast and detects the trivial syntactic/algorithmic errors. 66 | 67 | ### Bitstream generation 68 | 69 | To synthesize the design for FPGA type the following command in the main 70 | directory: 71 | 72 | % make 73 | 74 | This will produce two folders: 75 | 76 | ./_sds 77 | ./sd_card 78 | 79 | The \_sds folder will have all the reports generated by SDSoC and 80 | Vivado-HLS. The sd\_card folder will have the bitstream and the 81 | associated files which will be used to port face-detection accelerator 82 | onto the FPGA. 83 | 84 | The timing and utilization reports generated by Vivado-HLS can be found 85 | in the following directory: 86 | 87 | _sds/vhls/haar/solution/syn/report 88 | 89 | The log generated by Vivado-HLS can be found as: 90 | 91 | _sds/vhls/vivado_hls.log 92 | 93 | The area, utilzation and timing reports generated by SDSoC can be found 94 | in the following directory: 95 | 96 | _sds/reports 97 | 98 | For reference I have uploaded these two folders from my own compilation 99 | here: http://people.ece.cornell.edu/nks45/face-detect-compiled/ 100 | 101 | ### Porting Face-detection accelerator onto the FPGA 102 | 103 | To port the face-detection accelerator onto the FPGA copy all the files 104 | in the sd\_card folder into the SD-card of the FPGA. After that you can 105 | reboot the FPGA board and connect it to your computer using UART. Go to 106 | the mnt folder and run face.elf binary 107 | 108 | $ cd /mnt 109 | $ ./face.elf 110 | 111 | This will print the co-ordinates of all the rectangles detected on the 112 | screen and will also give the time taken to detect the faces. Wait for a 113 | while ( 4-5 seconds ) and remove the SD-card and insert it in your 114 | computer. You will see an Output.pgm file with rectangles drawn around 115 | all the faces. The wait time of 4-5 seconds is to make sure that this 116 | image is written properly. 117 | 118 | ### Adding a new image 119 | 120 | The face-detection algorithm can only process the images when each pixel 121 | in the image is represented as a 8-bit number. The gen\_dataset folder 122 | has the files to generate the hex images using the images in pgm format. 123 | To add a new 320 X 240 image (pgm format) copy it to the folder 124 | gen\_dataset. Edit the input and the output file names in the main 125 | function in gen\_dataset/gen\_image.cpp and compile and run it: 126 | 127 | % cd gen_dataset 128 | % cp /path/to/image/test-image.pgm . 129 | 130 | Compile the code 131 | % g++ gen_image.cpp -o gen_image 132 | % ./gen_image test-image.pgm test-image.h 133 | 134 | 135 | This will produce the .h file for the image with the image pixels in the 136 | hex format. Note that the original pgm image must be 320 X 240 pixels. 137 | Copy this .h file to the main directory: 138 | 139 | % cp test-image.h ../. 140 | 141 | And then edit the main.cpp file to have this line instead: 142 | 143 | #include "image0_320_240.h" 144 | 145 | Now you have added a new image. Do the C-simulation as described above. 146 | Make sure the C-simulation is working and producing the right results. 147 | Generate the bitstream and run it on the FPGA. 148 | 149 | 150 | ### Stages of Optimizations 151 | 152 | The source code for different stages of optimizations mentioned in our 153 | paper is also added to the repository so that users can get a feel of 154 | the effects of each and every optimzation. There are 3 extra folders 155 | which are added to the repo: 156 | 157 | Baseline : This folder has the baseline implementation which replaces 158 | all the non synthesizable constructs. 159 | 160 | Pipelined : This folder has the code when all the classifiers are 161 | pipelined. 162 | 163 | Parallel\_and\_Pipeline : This folder has the code when the classifiers 164 | in the first 3 stages are in parallel and the ones in the other 22 165 | stages are in pipeline. 166 | 167 | The main folder has the code which combines all these optimizations. 168 | 169 | ### Resource Usage 170 | 171 | The resource usage at each stage of optimization is given below: 172 | 173 | 174 | License 175 | ------------------------------------------------------------------------ 176 | 177 | face-detection benchmark is offered under the terms of the Open Source 178 | Initiative BSD 3-Clause License. More information about this license can 179 | be found here: 180 | 181 | - http://choosealicense.com/licenses/bsd-3-clause 182 | - http://opensource.org/licenses/BSD-3-Clause 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /csim.tcl: -------------------------------------------------------------------------------- 1 | #============================================================================= 2 | # run.tcl 3 | #============================================================================= 4 | # @brief: A Tcl script for C simulation of the face-detection design 5 | 6 | # Open/reset the project 7 | open_project hls.prj -reset 8 | 9 | # Top function of the design is "haar" 10 | set_top detectFaces 11 | 12 | # Add design and testbench files 13 | add_files haar.cpp 14 | 15 | add_files -tb main.cpp 16 | add_files -tb image.cpp 17 | 18 | open_solution solution 19 | 20 | # Use Zynq device 21 | # zc-706 22 | set_part xc7z045ffg900-2 23 | 24 | config_rtl -reset state 25 | 26 | # Simulate the C++ design 27 | csim_design 28 | 29 | # Co-simulate the design 30 | # cosim_design 31 | 32 | exit 33 | -------------------------------------------------------------------------------- /gen_dataset/gen_image.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | //#include "image.h" 7 | 8 | #define MYDEBUG 9 | 10 | char* strrev(char* str) 11 | { 12 | char *p1, *p2; 13 | if (!str || !*str) 14 | return str; 15 | for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2) 16 | { 17 | *p1 ^= *p2; 18 | *p2 ^= *p1; 19 | *p1 ^= *p2; 20 | } 21 | return str; 22 | } 23 | 24 | 25 | 26 | int myatoi (char* string) 27 | { 28 | int sign = 1; 29 | int length = strlen(string); 30 | int i = 0; 31 | int number = 0; 32 | 33 | // handle sign 34 | if (string[0] == '-') 35 | { 36 | sign = -1; 37 | i++; 38 | } 39 | 40 | for (i; i < length; i++) 41 | while(i < length) 42 | { 43 | if (string[i] == '.') 44 | break; 45 | number = number * 10 + (string[i]- 48); 46 | i++; 47 | } 48 | 49 | number *= sign; 50 | 51 | return number; 52 | } 53 | 54 | void itochar(int x, char* szBuffer, int radix) 55 | { 56 | int i = 0, n, xx; 57 | n = x; 58 | while (n > 0) 59 | { 60 | xx = n%radix; 61 | n = n/radix; 62 | szBuffer[i++] = '0' + xx; 63 | } 64 | szBuffer[i] = '\0'; 65 | strrev(szBuffer); 66 | } 67 | 68 | 69 | int readPgm(char* imagefile, char* outputfile){ 70 | 71 | FILE *in_file; 72 | FILE *out_file; 73 | char ch; 74 | int type; 75 | char version[3]; 76 | char line[100]; 77 | char mystring [20]; 78 | char *pch; 79 | int i,j; 80 | long int position; 81 | int height, width, maxgrey; 82 | 83 | in_file = fopen(imagefile, "r"); 84 | out_file = fopen(outputfile,"w"); 85 | 86 | if (in_file == NULL) 87 | { 88 | printf("ERROR: Unable to open file %s\n\n","Face.pgm"); 89 | return -1; 90 | } 91 | 92 | if (out_file == NULL) 93 | { 94 | printf("ERROR: Unable to open file %s\n\n", "image_data.h"); 95 | return -1; 96 | } 97 | 98 | fprintf(out_file,"in_flag =1;\n"); 99 | 100 | printf("\nReading image file: %s\n",imagefile); 101 | 102 | /* Determine image type (only pgm format is allowed)*/ 103 | ch = fgetc(in_file); 104 | if(ch != 'P') 105 | { 106 | printf("ERROR: Not valid pgm file type\n"); 107 | return -1; 108 | } 109 | 110 | ch = fgetc(in_file); 111 | 112 | /*convert the one digit integer currently represented as a character to */ 113 | 114 | type = ch - 48; 115 | 116 | if(type != 5) 117 | { 118 | printf("ERROR: only pgm raw format is allowed\n"); 119 | return -1; 120 | } 121 | 122 | while ((ch = fgetc(in_file)) != EOF && isspace(ch)); 123 | position = ftell(in_file); 124 | 125 | // skip comments 126 | if (ch == '#'){ 127 | fgets(line, sizeof(line), in_file); 128 | while ((ch = fgetc(in_file)) != EOF && isspace(ch)); 129 | position = ftell(in_file); 130 | } 131 | 132 | fseek(in_file, position-1, SEEK_SET); 133 | 134 | fgets (mystring , 20, in_file); 135 | pch = (char *)strtok(mystring," "); 136 | width = atoi(pch); 137 | fprintf(out_file,"in_width = %d;\n",width); 138 | 139 | pch = (char *)strtok(NULL," "); 140 | 141 | height = atoi(pch); 142 | fprintf(out_file,"in_height = %d;\n",height); 143 | 144 | fgets (mystring , 5, in_file); 145 | maxgrey = atoi(mystring); 146 | 147 | fprintf(out_file,"in_maxgrey = %d;\n",maxgrey); 148 | 149 | fprintf(out_file,"unsigned char Data[%d][%d]={\n",height,width); 150 | 151 | for(i=0;i 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "ap_int.h" 11 | 12 | const int ROWS = 25; 13 | const int COLS = 25; 14 | 15 | const int NUM_BANKS = 12; 16 | const int SIZE = 2913; 17 | 18 | typedef ap_uint<18> uint18_t; 19 | typedef ap_uint<10> uint10_t; 20 | typedef ap_uint<1> bit; 21 | typedef ap_uint<5> uint5_t; 22 | 23 | 24 | #ifndef __PARAMETERS__ 25 | #define __PARAMETERS__ 26 | 27 | #define IMAGE_HEIGHT 240 28 | #define IMAGE_WIDTH 320 29 | #define IMAGE_MAXGREY 255 30 | #define IMAGE_SIZE ( IMAGE_HEIGHT * IMAGE_WIDTH ) 31 | 32 | #define RESULT_SIZE 100 33 | 34 | #define TOTAL_NODES 2913 35 | #define TOTAL_STAGES 25 36 | #define TOTAL_COORDINATES TOTAL_NODES*12 37 | #define TOTAL_WEIGHTS TOTAL_NODES*3 38 | 39 | #define WINDOW_SIZE 25 40 | #define SQ_SIZE 2 41 | #define PYRAMID_HEIGHT 12 42 | 43 | #define OUTPUT_FILENAME "Output.pgm" 44 | #define INPUT_IMAGE "image0_320_240.h" 45 | 46 | 47 | #endif 48 | 49 | 50 | typedef ap_uint<13> int_I; 51 | typedef ap_uint<21> int_SI; 52 | typedef ap_uint<18> int_II; 53 | typedef ap_uint<26> int_SII; 54 | 55 | #ifdef __cplusplus 56 | extern "C" { 57 | #endif 58 | 59 | typedef struct MyPoint 60 | { 61 | int x; 62 | int y; 63 | } 64 | MyPoint; 65 | 66 | typedef struct 67 | { 68 | int width; 69 | int height; 70 | } 71 | MySize; 72 | 73 | typedef struct 74 | { 75 | int x; 76 | int y; 77 | int width; 78 | int height; 79 | } 80 | MyRect; 81 | 82 | typedef struct 83 | { 84 | int width; 85 | int height; 86 | int maxgrey; 87 | int flag; 88 | } 89 | MyInputImage; 90 | 91 | void detectFaces( unsigned char Data[IMAGE_WIDTH], 92 | int _result_x[RESULT_SIZE], 93 | int _result_y[RESULT_SIZE], 94 | int _result_w[RESULT_SIZE], 95 | int _result_h[RESULT_SIZE], 96 | int *result_size); 97 | 98 | #ifdef __cplusplus 99 | } 100 | #endif 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /haar_dataEWC_with_partitioning.h: -------------------------------------------------------------------------------- 1 | static int weights_array0[2913] = { 2 | -4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096,-4096}; 3 | 4 | static int weights_array1[2913] = { 5 | 12288,12288,12288,12288,8192,8192,8192,8192,8192,12288,12288,12288,12288,12288,8192,12288,12288,12288,12288,8192,12288,12288,12288,12288,8192,12288,8192,8192,12288,8192,12288,12288,8192,8192,12288,8192,12288,8192,8192,12288,8192,8192,12288,12288,8192,12288,8192,8192,8192,8192,8192,12288,12288,12288,12288,12288,8192,8192,8192,12288,12288,8192,8192,12288,8192,12288,12288,8192,8192,8192,8192,12288,12288,12288,12288,8192,8192,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,8192,12288,8192,12288,8192,8192,8192,8192,8192,8192,12288,8192,8192,12288,12288,8192,8192,8192,8192,8192,12288,8192,8192,8192,12288,12288,12288,12288,12288,8192,8192,8192,8192,8192,8192,8192,12288,8192,8192,8192,12288,8192,8192,8192,8192,12288,12288,12288,12288,12288,8192,12288,8192,12288,12288,12288,8192,8192,8192,8192,8192,12288,12288,12288,8192,8192,12288,12288,8192,8192,12288,8192,8192,8192,12288,8192,12288,8192,12288,12288,12288,12288,12288,12288,12288,8192,8192,8192,12288,8192,8192,8192,8192,8192,8192,8192,12288,12288,8192,12288,8192,12288,8192,8192,8192,8192,12288,12288,8192,8192,12288,8192,8192,12288,12288,8192,8192,12288,12288,8192,8192,12288,12288,8192,8192,12288,12288,12288,8192,12288,8192,8192,8192,12288,12288,12288,8192,8192,12288,12288,8192,12288,12288,8192,12288,12288,12288,8192,8192,8192,8192,12288,12288,8192,8192,8192,12288,12288,8192,8192,8192,8192,8192,12288,12288,12288,12288,8192,8192,12288,8192,12288,12288,12288,8192,8192,8192,8192,12288,8192,12288,8192,8192,12288,12288,8192,12288,12288,12288,8192,12288,8192,8192,8192,8192,12288,12288,12288,12288,8192,8192,8192,12288,12288,8192,8192,8192,12288,8192,12288,12288,8192,12288,12288,12288,12288,12288,8192,8192,8192,8192,8192,12288,12288,12288,12288,12288,12288,12288,8192,8192,8192,8192,8192,12288,12288,12288,12288,12288,12288,8192,8192,8192,12288,8192,12288,12288,8192,12288,8192,8192,12288,12288,12288,12288,8192,12288,12288,12288,12288,12288,12288,8192,12288,8192,12288,8192,8192,8192,12288,12288,12288,8192,8192,8192,8192,8192,12288,12288,8192,8192,12288,12288,12288,12288,12288,8192,8192,8192,12288,8192,8192,8192,12288,12288,12288,12288,8192,12288,12288,12288,12288,12288,12288,12288,8192,12288,12288,12288,12288,12288,8192,12288,12288,12288,12288,8192,8192,12288,12288,12288,12288,12288,8192,12288,8192,8192,8192,8192,8192,12288,12288,12288,12288,8192,8192,12288,12288,12288,8192,12288,12288,12288,12288,8192,8192,12288,12288,8192,8192,12288,8192,12288,12288,12288,12288,8192,8192,8192,8192,12288,8192,12288,12288,8192,8192,8192,8192,8192,8192,8192,12288,8192,8192,8192,12288,8192,8192,12288,8192,12288,12288,12288,8192,12288,12288,8192,8192,12288,12288,12288,8192,12288,12288,8192,8192,12288,12288,12288,12288,8192,8192,8192,8192,12288,12288,12288,12288,8192,8192,12288,12288,12288,12288,12288,12288,12288,12288,8192,12288,12288,12288,8192,12288,12288,12288,12288,12288,12288,12288,8192,12288,12288,8192,8192,8192,8192,8192,8192,12288,12288,12288,8192,12288,8192,12288,12288,12288,12288,12288,8192,8192,8192,8192,12288,8192,8192,12288,12288,8192,12288,8192,8192,8192,12288,8192,8192,8192,12288,12288,12288,12288,8192,12288,12288,12288,12288,8192,8192,8192,8192,12288,12288,12288,12288,8192,12288,8192,8192,12288,12288,12288,12288,12288,12288,12288,12288,8192,12288,12288,8192,8192,12288,12288,8192,8192,12288,8192,8192,12288,12288,8192,12288,8192,8192,8192,8192,12288,12288,8192,8192,12288,8192,12288,8192,8192,12288,8192,12288,12288,12288,12288,12288,8192,12288,8192,8192,8192,8192,8192,8192,12288,8192,8192,8192,12288,8192,12288,12288,12288,8192,12288,8192,12288,12288,12288,12288,8192,12288,12288,12288,8192,12288,12288,12288,12288,12288,12288,8192,12288,12288,12288,8192,12288,12288,12288,8192,8192,8192,8192,8192,12288,8192,8192,12288,12288,8192,8192,8192,12288,12288,8192,8192,8192,8192,8192,8192,8192,12288,8192,12288,12288,12288,8192,8192,12288,12288,8192,8192,8192,12288,12288,8192,8192,8192,12288,8192,8192,8192,8192,12288,12288,8192,8192,12288,12288,8192,8192,8192,12288,8192,8192,8192,12288,8192,8192,12288,8192,8192,8192,8192,8192,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,8192,8192,8192,8192,8192,12288,8192,12288,12288,12288,8192,8192,8192,8192,8192,12288,12288,8192,8192,8192,12288,12288,8192,12288,12288,8192,8192,8192,12288,12288,12288,8192,12288,12288,8192,12288,8192,8192,8192,8192,12288,8192,8192,8192,8192,8192,12288,8192,12288,12288,12288,12288,12288,12288,8192,8192,12288,12288,12288,8192,12288,8192,8192,12288,8192,8192,12288,12288,8192,12288,8192,8192,12288,8192,12288,12288,8192,8192,8192,12288,8192,12288,12288,12288,12288,8192,8192,12288,12288,8192,12288,12288,8192,12288,8192,12288,12288,12288,12288,12288,12288,12288,12288,8192,8192,8192,12288,12288,12288,12288,8192,8192,8192,12288,12288,12288,8192,8192,12288,12288,8192,12288,8192,8192,8192,8192,8192,8192,12288,8192,12288,8192,12288,8192,8192,8192,12288,8192,8192,12288,12288,12288,12288,12288,8192,12288,12288,12288,12288,12288,12288,12288,12288,8192,8192,8192,12288,8192,8192,12288,8192,8192,12288,8192,12288,8192,8192,8192,8192,8192,12288,12288,8192,8192,8192,12288,8192,12288,12288,12288,12288,8192,12288,8192,8192,12288,12288,12288,12288,12288,12288,12288,12288,12288,8192,8192,12288,12288,12288,12288,8192,8192,12288,12288,12288,12288,8192,8192,8192,12288,8192,8192,8192,12288,8192,8192,8192,8192,8192,12288,8192,8192,8192,8192,8192,8192,8192,8192,12288,8192,8192,12288,8192,8192,8192,12288,12288,12288,8192,8192,12288,8192,8192,8192,8192,8192,12288,8192,12288,8192,12288,8192,8192,12288,12288,8192,8192,12288,12288,8192,8192,12288,12288,12288,12288,8192,8192,8192,12288,12288,8192,12288,12288,8192,8192,8192,12288,8192,8192,8192,12288,12288,8192,12288,12288,12288,8192,8192,8192,8192,8192,12288,12288,12288,12288,12288,8192,8192,12288,8192,8192,12288,12288,12288,12288,8192,12288,8192,8192,8192,12288,12288,8192,8192,8192,12288,12288,12288,8192,8192,8192,8192,12288,8192,12288,8192,12288,8192,12288,12288,8192,12288,12288,12288,12288,8192,12288,12288,12288,8192,8192,8192,8192,12288,8192,8192,8192,12288,8192,8192,8192,12288,8192,12288,12288,8192,8192,8192,12288,8192,8192,8192,8192,8192,8192,8192,12288,8192,12288,12288,8192,12288,12288,12288,12288,8192,12288,8192,8192,12288,12288,8192,8192,8192,8192,12288,12288,8192,8192,12288,12288,12288,8192,8192,8192,12288,8192,8192,8192,8192,8192,12288,8192,12288,12288,8192,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,8192,12288,12288,12288,12288,12288,8192,12288,12288,12288,12288,12288,12288,12288,12288,8192,8192,12288,12288,12288,12288,12288,8192,8192,8192,8192,8192,12288,12288,8192,12288,12288,8192,8192,12288,8192,8192,8192,12288,12288,12288,12288,12288,12288,8192,8192,8192,12288,8192,12288,12288,12288,12288,12288,8192,8192,8192,8192,12288,12288,12288,12288,12288,12288,12288,12288,8192,12288,12288,12288,12288,8192,8192,12288,8192,12288,8192,12288,8192,8192,8192,12288,8192,8192,12288,8192,8192,8192,8192,8192,12288,12288,12288,8192,12288,8192,8192,12288,8192,12288,12288,8192,12288,12288,12288,12288,8192,8192,8192,8192,8192,8192,12288,12288,12288,12288,8192,8192,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,8192,12288,8192,8192,8192,12288,8192,8192,8192,8192,8192,8192,8192,8192,8192,8192,8192,8192,8192,8192,12288,12288,12288,8192,12288,12288,8192,12288,12288,12288,8192,12288,12288,12288,12288,8192,8192,8192,8192,12288,8192,8192,12288,12288,12288,12288,8192,8192,8192,8192,8192,8192,12288,12288,8192,8192,12288,8192,12288,8192,12288,12288,12288,12288,8192,8192,8192,12288,8192,8192,12288,8192,12288,12288,12288,8192,12288,12288,12288,12288,8192,8192,8192,8192,8192,12288,12288,12288,8192,12288,12288,8192,8192,8192,8192,8192,12288,12288,12288,12288,8192,8192,8192,8192,8192,8192,12288,12288,12288,8192,8192,8192,12288,8192,12288,8192,12288,8192,8192,8192,8192,12288,8192,8192,8192,12288,8192,8192,8192,8192,8192,12288,8192,8192,8192,8192,8192,12288,8192,12288,12288,12288,12288,12288,12288,12288,12288,8192,8192,8192,8192,12288,12288,12288,12288,12288,12288,12288,12288,8192,12288,12288,8192,8192,12288,8192,12288,12288,12288,12288,8192,8192,8192,8192,12288,8192,12288,12288,8192,8192,8192,8192,8192,8192,8192,8192,8192,12288,12288,12288,8192,12288,8192,8192,8192,8192,8192,12288,8192,8192,8192,8192,8192,8192,8192,12288,12288,8192,8192,12288,12288,8192,12288,8192,8192,8192,8192,8192,12288,8192,8192,8192,8192,12288,8192,12288,8192,12288,8192,12288,12288,8192,8192,12288,12288,8192,12288,12288,8192,12288,12288,8192,12288,8192,12288,12288,8192,8192,12288,8192,12288,12288,8192,8192,12288,8192,8192,8192,8192,8192,8192,8192,8192,12288,8192,8192,8192,8192,12288,8192,8192,12288,12288,12288,12288,8192,8192,8192,8192,12288,8192,8192,8192,8192,12288,12288,12288,8192,8192,12288,12288,12288,8192,8192,8192,8192,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,8192,8192,12288,12288,8192,8192,12288,12288,12288,8192,12288,8192,12288,8192,8192,8192,8192,12288,8192,8192,8192,12288,12288,12288,12288,8192,8192,8192,12288,8192,12288,8192,12288,8192,8192,12288,12288,12288,8192,8192,8192,12288,12288,8192,8192,8192,8192,12288,8192,8192,8192,8192,8192,8192,8192,8192,8192,8192,12288,12288,12288,8192,8192,8192,8192,8192,8192,12288,12288,12288,8192,12288,8192,8192,8192,8192,12288,12288,8192,8192,8192,8192,12288,12288,8192,8192,8192,8192,8192,8192,8192,12288,12288,12288,12288,12288,8192,8192,12288,12288,12288,12288,12288,8192,12288,12288,8192,8192,8192,12288,12288,8192,12288,8192,12288,12288,12288,8192,8192,12288,12288,8192,8192,12288,8192,8192,8192,12288,12288,8192,8192,8192,12288,12288,12288,8192,8192,8192,12288,8192,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,8192,12288,8192,8192,12288,8192,12288,8192,12288,8192,8192,12288,8192,12288,8192,8192,8192,12288,8192,8192,8192,8192,12288,12288,12288,12288,8192,8192,8192,8192,8192,12288,12288,8192,12288,12288,8192,12288,8192,12288,8192,8192,8192,8192,12288,8192,8192,8192,12288,12288,12288,12288,8192,12288,8192,8192,12288,8192,8192,8192,8192,12288,8192,12288,12288,8192,12288,8192,8192,12288,8192,12288,8192,8192,12288,12288,12288,8192,12288,12288,12288,12288,8192,12288,12288,8192,12288,12288,12288,8192,8192,12288,8192,8192,8192,8192,12288,8192,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,8192,12288,12288,12288,12288,12288,8192,12288,12288,12288,8192,12288,12288,12288,12288,12288,8192,8192,8192,8192,8192,8192,8192,12288,8192,12288,12288,8192,8192,8192,8192,12288,12288,12288,12288,12288,8192,8192,8192,12288,12288,12288,12288,8192,8192,8192,12288,12288,12288,12288,12288,12288,12288,12288,12288,8192,12288,8192,8192,8192,8192,8192,12288,12288,8192,8192,8192,8192,8192,12288,12288,12288,12288,8192,12288,12288,8192,12288,8192,12288,12288,12288,12288,12288,8192,8192,8192,8192,12288,12288,8192,8192,12288,8192,8192,8192,12288,12288,12288,8192,8192,12288,8192,12288,8192,12288,8192,8192,12288,8192,12288,8192,12288,8192,12288,8192,8192,12288,12288,8192,8192,8192,8192,12288,12288,12288,12288,12288,8192,8192,8192,8192,12288,8192,12288,12288,8192,8192,12288,12288,8192,8192,8192,12288,8192,8192,12288,8192,8192,8192,12288,8192,12288,8192,12288,8192,12288,12288,8192,8192,12288,8192,8192,8192,8192,8192,12288,8192,12288,8192,12288,12288,12288,12288,12288,12288,12288,8192,12288,12288,8192,8192,12288,8192,8192,8192,8192,8192,8192,12288,8192,8192,12288,12288,12288,12288,12288,8192,8192,12288,8192,12288,12288,12288,8192,8192,12288,12288,12288,12288,12288,8192,8192,8192,8192,8192,8192,8192,8192,12288,8192,12288,8192,12288,8192,8192,8192,8192,8192,12288,12288,12288,12288,8192,8192,8192,8192,12288,8192,8192,8192,12288,12288,8192,12288,12288,8192,8192,8192,8192,8192,12288,8192,8192,8192,12288,8192,8192,8192,8192,12288,8192,12288,12288,12288,12288,12288,12288,12288,12288,12288,8192,12288,12288,12288,8192,8192,8192,12288,8192,12288,8192,8192,12288,12288,8192,8192,12288,12288,12288,8192,8192,8192,12288,12288,12288,12288,8192,12288,8192,8192,8192,12288,12288,12288,12288,12288,12288,8192,8192,8192,8192,12288,12288,8192,12288,12288,12288,8192,12288,12288,8192,8192,12288,12288,8192,12288,12288,12288,12288,8192,12288,12288,8192,8192,8192,8192,12288,12288,12288,12288,8192,12288,8192,12288,12288,8192,12288,8192,8192,8192,12288,12288,12288,12288,12288,12288,8192,8192,12288,12288,12288,8192,12288,12288,12288,12288,12288,12288,8192,8192,12288,12288,12288,8192,12288,12288,12288,12288,12288,12288,8192,8192,8192,8192,12288,8192,8192,8192,8192,8192,8192,8192,12288,8192,12288,8192,8192,12288,8192,12288,12288,12288,12288,12288,12288,12288,8192,8192,8192,8192,12288,12288,8192,8192,8192,8192,8192,8192,8192,12288,8192,8192,8192,12288,8192,12288,12288,12288,12288,8192,8192,12288,8192,8192,8192,8192,12288,12288,8192,8192,12288,8192,8192,8192,12288,12288,12288,12288,8192,8192,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,8192,8192,8192,8192,8192,8192,8192,12288,8192,8192,12288,12288,8192,12288,8192,8192,12288,12288,12288,12288,8192,8192,8192,12288,8192,12288,12288,12288,12288,8192,8192,8192,8192,8192,8192,12288,12288,8192,12288,8192,8192,8192,8192,8192,8192,12288,12288,12288,8192,12288,12288,8192,8192,8192,8192,8192,12288,8192,12288,8192,8192,8192,12288,12288,8192,8192,8192,8192,8192,8192,8192,8192,12288,12288,8192,8192,8192,12288,8192,12288,12288,12288,12288,8192,8192,8192,12288,8192,8192,12288,12288,12288,12288,12288,8192,8192,12288,12288,12288,8192,12288,12288,8192,8192,8192,12288,12288,12288,8192,12288,8192,8192,8192,12288,12288,12288,8192,8192,8192,8192,8192,8192,8192,12288,8192,12288,8192,8192,8192,12288,12288,8192,8192,12288,12288,8192,8192,8192,12288,8192,8192,12288,12288,8192,12288,8192,8192,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,8192,8192,8192,12288,8192,12288,8192,8192,8192,12288,8192,12288,12288,12288,12288,8192,8192,8192,8192,8192,12288,8192,12288,12288,8192,12288,8192,12288,12288,8192,8192,8192,8192,8192,12288,8192,8192,12288,8192,12288,8192,8192,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,8192,8192,12288,8192,8192,8192,12288,12288,8192,8192,8192,12288,8192,8192,12288,8192,8192,8192,12288,12288,12288,12288,12288,8192,12288,12288,8192,12288,8192,12288,8192,8192,8192,12288,8192,8192,12288,12288,12288,12288,12288,8192,8192,12288,12288,8192,8192,12288,12288,12288,12288,12288,12288,8192,8192,8192,8192,8192,8192,8192,8192,12288,8192,8192,8192,8192,12288,12288,8192,12288,8192,8192,12288,12288,12288,12288,8192,8192,8192,12288,12288,8192,12288,12288,8192,8192,8192,8192,12288,8192,12288,12288,12288,12288,12288,8192,8192,8192,12288,8192,8192,8192,12288,12288,12288,8192,8192,12288,8192,8192,8192,12288,8192,12288,8192,8192,8192,12288,8192,8192,8192,8192,8192,8192,12288,12288,8192,12288,12288,8192,12288,12288,12288,12288,12288,12288,12288,12288,8192,8192,12288,12288,12288,8192,8192,12288,12288,8192,8192,8192,12288,12288,8192,12288,8192,8192,12288,12288,8192,8192,12288,12288,8192,12288,8192,12288,8192,8192,12288,12288,12288,12288,12288,12288,12288,12288,8192,8192,8192,8192,8192,12288,12288,12288,8192,8192,12288,12288,8192,8192,12288,8192,8192,8192,12288,8192,8192,12288,12288,12288,12288,8192,8192,12288,8192,8192,12288,12288,12288,8192,12288,8192,12288,12288,12288,12288,12288,8192,8192,12288,8192,8192,8192,8192,8192,12288,12288,12288,8192,8192,8192,12288,8192,12288,8192,8192,8192,12288,12288,12288,12288,12288,8192,8192,8192,12288,8192,8192,8192,8192,8192,8192,8192,12288,12288,12288,12288,8192,12288,8192,12288,12288,8192,8192,8192,8192,8192,8192,8192,12288,8192,8192,8192,8192,8192,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,12288,8192,8192,8192,8192,8192,8192,12288,8192,12288,12288,12288,12288,12288,8192,12288,12288,12288,12288,8192,8192,12288,12288,12288,12288,8192,8192,12288,12288,12288,12288,12288,12288,12288,8192,12288,12288,12288,12288,8192,8192,12288,12288,8192,8192,8192,8192,8192,8192,8192,8192,8192,8192,12288,8192,8192,12288,12288,12288,8192,12288,8192,12288,8192,8192,8192,8192,8192,8192,8192,8192,8192,12288,12288,12288,12288,12288,12288,8192,12288,12288,12288,8192,8192,8192,8192,8192,8192,12288,8192,12288,8192,12288,12288,12288,12288,12288,12288,12288,8192,8192}; 6 | 7 | static int weights_array2[2913] = { 8 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,8192,0,0,0,0,0,8192,0,0,0,0,0,0,0,8192,0,0,0,0,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,8192,8192,0,0,0,0,0,0,0,8192,0,8192,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,8192,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,8192,8192,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,8192,8192,0,0,0,0,0,0,0,8192,0,8192,0,0,0,0,0,8192,8192,0,0,0,0,0,8192,0,0,0,8192,8192,0,0,0,0,0,8192,8192,0,0,0,0,0,8192,8192,0,0,0,0,0,8192,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,8192,8192,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,8192,8192,8192,8192,0,0,8192,8192,0,0,0,0,0,8192,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,8192,0,8192,8192,0,0,0,0,8192,8192,8192,0,8192,8192,0,0,0,0,0,0,0,0,8192,0,0,0,0,8192,0,0,8192,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,8192,0,0,0,8192,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,8192,0,8192,8192,0,0,0,0,8192,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,8192,0,0,8192,8192,0,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,8192,0,0,0,0,0,8192,8192,0,0,0,0,0,0,0,0,8192,0,0,8192,8192,8192,0,0,8192,0,0,8192,0,0,0,0,8192,0,0,8192,0,0,0,0,8192,8192,0,0,0,8192,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,8192,0,0,0,8192,8192,8192,0,0,8192,0,0,0,0,0,0,0,0,8192,0,0,0,0,8192,0,0,8192,0,0,0,0,0,8192,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,8192,0,0,0,8192,0,8192,8192,0,0,8192,8192,0,8192,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,8192,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,8192,0,8192,8192,8192,0,8192,0,8192,0,8192,0,8192,0,0,8192,0,0,8192,8192,0,8192,0,0,0,0,0,0,0,0,8192,8192,0,8192,8192,0,0,0,0,0,0,0,0,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,8192,8192,0,0,8192,8192,8192,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,8192,8192,0,0,0,0,0,0,0,0,0,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,8192,8192,0,8192,0,0,0,8192,0,0,0,0,0,0,8192,8192,8192,0,8192,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,8192,8192,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,8192,8192,8192,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,8192,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,8192,8192,0,0,0,8192,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,8192,0,8192,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,8192,0,8192,0,8192,0,8192,8192,8192,0,8192,8192,8192,8192,8192,8192,8192,8192,0,0,0,8192,0,0,8192,0,0,0,0,0,0,0,0,0,8192,8192,0,0,8192,8192,0,0,0,0,8192,8192,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,8192,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,8192,8192,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,8192,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,8192,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,8192,8192,8192,0,8192,0,0,0,0,0,0,0,0,0,8192,8192,8192,8192,0,8192,8192,8192,8192,8192,0,8192,0,0,8192,8192,0,0,8192,0,8192,8192,8192,8192,0,0,0,0,8192,8192,0,8192,0,8192,0,0,0,0,8192,8192,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,8192,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,8192,8192,0,0,0,0,8192,0,0,0,0,8192,8192,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,8192,0,8192,0,0,8192,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,8192,8192,8192,0,0,0,8192,8192,0,8192,0,0,0,0,0,0,0,8192,8192,0,0,0,0,0,0,0,8192,0,0,8192,0,0,8192,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,8192,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,8192,8192,0,8192,0,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,8192,0,8192,0,0,0,0,0,0,0,0,8192,0,0,0,0,8192,0,0,0,0,8192,0,0,8192,0,0,8192,0,0,0,8192,8192,0,0,0,0,0,0,0,0,8192,0,0,8192,0,0,0,8192,8192,0,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,8192,0,0,8192,8192,0,0,0,0,0,0,0,8192,8192,0,0,0,0,0,0,8192,8192,0,0,0,0,0,0,0,0,0,0,0,8192,8192,8192,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,8192,8192,0,8192,8192,8192,0,0,0,0,8192,0,8192,0,0,0,0,8192,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,8192,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,8192,8192,8192,0,0,0,8192,0,0,0,0,0,8192,0,8192,0,8192,8192,8192,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,8192,0,0,8192,8192,8192,8192,0,0,0,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,8192,0,0,8192,0,8192,8192,8192,0,8192,0,0,0,0,0,0,0,8192,0,0,0,0,8192,8192,8192,8192,0,0,8192,8192,0,0,0,0,0,8192,8192,8192,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,8192,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,8192,8192,8192,8192,0,0,8192,0,0,0,8192,0,0,0,0,0,0,8192,0,0,0,0,8192,0,0,8192,0,0,8192,0,0,0,0,8192,0,8192,0,0,0,0,8192,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,8192,0,0,0,0,0,0,8192,8192,0,0,0,0,0,0,0,0,0,0,8192,8192,0,0,0,0,0,0,0,8192,0,8192,0,0,8192,8192,0,0,0,0,0,0,0,8192,0,8192,8192,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,8192,8192,8192,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,8192,8192,8192,0,8192,0,0,0,0,8192,8192,0,0,8192,8192,0,0,8192,0,8192,0,0,0,0,0,0,0,0,8192,0,0,8192,8192,0,0,0,0,8192,0,0,0,8192,0,0,0,8192,8192,0,0,8192,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,8192,8192,0,0,0,8192,0,0,8192,8192,8192,0,0,8192,0,0,0,8192,0,0,8192,0,0,0,0,0,0,0,8192,8192,0,0,8192,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,8192,0,0,0,0,8192,8192,8192,8192,0,0,8192,0,0,0,0,8192,0,0,0,0,0,0,0,0,8192,8192,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,8192,8192,0,8192,8192,0,8192,8192,8192,0,0,0,0,0,0,0,0,8192,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,8192,8192,8192,8192,8192,0,0,8192,0,8192,8192,0,8192,0,0,8192,0,8192,8192,0,0,0,0,0,0,0,0,0,8192,0,0,8192,8192,0,0,0,8192,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,8192,0,0,8192,8192,0,8192,0,0,0,0,8192,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,8192,0,0,8192,8192,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,8192,0,0,0,8192,0,0,0,0,0,0,8192,0,0,0,0,8192,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,8192,0,0,0,0,0,0,0,0,0,8192,8192,8192,0,0,8192,0,8192,8192,8192,8192,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,8192,8192,0,8192,8192,8192,8192,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,8192,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,8192,0,0,0,0,0,8192,0,0,0,0,0,0,0,8192,0,0,0,0,8192,0,0,0,0,0,8192,8192,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,8192,8192,8192,8192,8192,8192,8192,8192,8192,0,0,0,0,0,0,0,0,0,0,8192,8192,0,0,8192,8192,0,8192,0,0,0,0,0,0,0,0,0,0,8192}; 9 | 10 | static int alpha1_array[2913] = { 11 | 534,-477,-386,-223,-199,142,-432,-378,-219,318,-414,-497,-142,68,-684,-277,-90,237,296,-107,373,286,-89,-155,99,-259,-421,118,-167,-357,-129,93,-77,-103,269,-416,72,-259,-42,388,451,-80,-25,-103,43,227,-95,16,-447,-240,-13,-468,295,-400,-147,-373,-213,-80,-111,381,-246,-626,44,124,45,-501,253,-660,368,-126,-596,-216,-369,46,17,100,37,63,-193,-93,-594,108,284,-851,-311,-123,-276,-307,-112,-47,77,319,-152,72,123,68,-335,116,-443,-49,-412,190,-68,-15,-89,-268,211,52,52,-332,-335,-269,-351,-9,-255,370,-95,-147,4,-20,-294,95,67,193,57,-323,222,-355,16,-137,-90,-150,-85,178,220,49,-228,-322,-220,-191,-323,-251,164,-61,-87,281,402,-70,-280,78,66,-315,104,-24,-105,64,-240,318,-83,89,14,-262,263,55,-408,-263,-378,-61,74,-59,-309,62,-350,54,83,-72,-591,73,-69,-392,19,36,-282,3,-88,51,-104,-569,-73,-227,-285,-258,66,-146,-141,-329,446,-269,145,334,-118,-106,92,-228,75,-203,39,8,-100,22,141,-473,-123,-115,-216,90,47,-320,-208,-237,144,205,-217,-103,-391,161,150,-65,74,-101,53,112,240,2,-259,-96,-206,-270,51,-97,54,-262,-263,-53,225,267,35,-425,204,-245,50,-265,-315,-194,-99,-183,141,-114,-279,214,-65,80,-268,41,-176,63,-129,10,36,-229,-116,86,-202,-584,100,8,-277,-481,37,-260,39,-197,-29,17,-450,245,119,181,-281,-279,-67,-56,47,-237,502,54,-300,-287,-43,211,-295,-268,-279,108,-235,-408,-169,49,-162,-48,-27,-276,87,121,249,-556,-164,-377,108,6,40,-103,-510,-159,259,-262,-291,-145,78,-440,59,-311,83,-81,-28,101,0,192,-212,-152,40,8,-133,-136,51,11,-233,23,54,-69,-26,16,-237,34,50,-292,43,-121,-553,11,-8,-337,94,-65,-19,-201,435,198,-382,-546,145,173,63,3,-2,115,-243,-515,101,-63,-14,11,-125,-76,-153,-7,95,-255,36,-54,-337,126,108,-7,-202,-576,-65,-57,-73,-8,152,-122,58,-66,-153,181,-143,-182,-285,-104,-97,-179,-139,-25,216,67,39,-509,-82,152,5,-112,-228,54,3,257,-376,-208,29,33,-301,161,47,-238,9,93,50,-429,-787,54,-293,214,-71,45,246,2,-136,210,-50,-6,-347,-165,215,49,-186,-92,14,120,-290,251,-72,-163,95,-334,-523,198,44,-384,73,354,-57,-406,-305,-39,66,-22,192,31,-93,-19,200,-229,211,4,289,-147,-5,-139,-313,37,-71,-62,-219,177,-42,112,-250,-231,-202,-77,-230,-107,117,233,-376,-268,74,-329,-219,41,40,5,-42,-249,252,121,-245,-134,43,-290,66,50,-13,272,-47,-7,255,-7,0,-391,8,196,41,-250,118,65,-206,-336,51,249,-48,-174,48,-60,63,-266,131,414,764,154,-158,169,-287,-275,207,-5,173,14,-33,-96,-149,-77,151,248,233,-154,11,-239,46,-330,-11,-3,-68,-131,106,-63,-57,16,48,-242,94,246,-785,58,0,243,-25,2,165,-9,177,-103,-165,250,-26,156,-260,-105,-149,-237,30,-148,-98,301,-220,-191,235,68,-72,-157,147,83,22,88,60,-190,-231,-88,-239,-136,235,-181,-222,-58,-77,68,-302,-139,-69,-233,-112,6,202,205,-51,-11,-231,90,-50,-358,0,-125,-312,95,-75,-368,-577,96,-75,-255,12,38,-3,-36,-4,-443,-61,1,9,19,-434,161,-85,58,49,23,-446,-61,301,35,-139,-55,16,175,445,78,-54,-203,95,-3,310,-5,-271,-8,9,-20,-491,123,-50,50,-49,463,199,39,-42,-26,-9,-14,71,32,5,48,18,12,-69,13,97,39,6,41,-157,-217,-208,-93,-304,84,-130,-268,-129,-254,-24,59,-26,0,-167,72,39,-74,349,312,-209,-312,30,-299,-273,-92,125,150,-19,70,-1,210,33,-232,2,455,146,-82,49,17,-99,-6,-491,-328,-103,-186,148,234,-132,61,42,-349,-437,-80,38,190,-104,208,84,-321,353,-9,-47,-114,173,-3,86,-271,37,-62,33,-268,-387,35,73,-69,47,83,29,-283,205,-67,4,3,-78,-411,19,-1,-61,490,-64,-177,46,-7,16,2,38,99,-397,55,-12,-65,-46,139,-177,75,236,-203,84,-351,16,92,-39,34,27,-2,0,-120,-2,-88,383,-254,-147,-8,102,46,139,174,-230,-144,92,-142,-274,-183,-120,54,171,-244,208,315,-78,54,-231,57,-101,47,39,55,-378,-43,9,85,1,115,39,-333,-62,7,-57,52,175,-2,-51,121,-283,259,106,54,-296,90,-393,51,-6,43,-306,-279,71,-11,-67,154,97,33,30,-87,-43,156,-124,-1030,-100,-22,293,-5,9,144,-44,323,171,-105,-234,0,-95,-108,-42,38,352,-86,195,-177,-3,-26,273,47,-56,65,-2,-73,-9,84,-89,-368,-302,566,-478,-196,-161,218,-8,-49,527,-29,-4,-10,-170,-14,156,-146,14,44,-171,75,-72,-27,-13,115,-520,43,-5,77,-79,-460,-13,53,-51,-244,-36,-279,26,15,-343,12,-262,21,-37,168,-232,-127,-108,-122,130,-59,103,115,-217,-238,-327,149,-13,-222,-19,-63,-287,-371,137,17,292,-63,-10,150,39,43,-38,-102,71,0,105,-365,-64,11,-240,-69,-264,161,41,-64,-74,-2,28,-49,79,-1,-117,-3,-19,-68,46,-48,-37,-134,-98,-1,-148,5,-166,-86,38,-64,-28,-249,97,-266,-1410,244,2,57,42,-221,-721,-331,-208,168,1,78,65,-367,-43,-166,-13,-235,137,-139,39,-62,-130,-55,29,-3,311,-64,57,64,-83,-14,0,-78,-62,120,98,-12,54,-43,29,-11,-103,-84,-185,-40,49,210,-110,-7,28,557,-12,-83,294,-99,-429,-249,53,-42,60,-237,-188,36,2,-304,622,183,40,-208,238,-144,-202,-362,97,-104,-61,-223,39,-293,39,10,111,111,-24,-97,228,220,153,-406,43,130,-110,-80,270,-183,63,-176,-151,11,-157,-78,-351,-143,1,400,-404,-397,44,-334,-353,-181,-10,147,-126,-125,-154,60,-20,-308,59,-207,157,-75,-156,-136,-329,-43,-28,261,-200,-225,29,-207,-18,-329,121,-15,44,-51,-17,-326,31,3,158,-92,134,-43,-304,214,90,-225,-36,-74,-8,177,-165,-7,-2,217,-531,-219,98,-441,140,-9,149,-3,38,132,-5,-220,-116,33,33,-64,5,-100,21,-46,-158,-12,45,-215,-48,-203,-60,-14,67,-171,172,77,37,-47,48,115,34,-53,82,-51,40,-160,42,-64,39,145,146,-98,56,-73,-166,-74,116,-131,4,100,304,-174,-217,-282,-50,-104,-75,-334,60,74,-620,225,205,37,-208,-181,-186,43,708,29,-1,59,-79,-12,-297,-69,-138,46,160,61,-240,-19,10,43,-8,24,-101,-58,-70,-27,-12,38,-5,-205,-53,51,-46,127,299,-16,-59,-210,155,-10,-294,-2,96,-25,171,40,97,38,-174,65,-7,-90,-9,-6,27,119,-72,-5,-83,-313,-4,167,-133,-200,0,-13,4,-159,45,11,116,85,-598,-169,117,-68,-47,-6,-8,1,108,-5,-8,28,74,30,37,-137,-15,-115,310,-590,-183,18,-313,34,-7,34,-37,49,-95,207,214,-242,11,-497,-54,153,-56,161,-59,46,-178,88,-224,60,-15,-50,247,-15,-116,29,463,59,126,155,102,-217,-202,-172,9,35,-35,35,-51,-119,-241,83,70,60,-147,-156,-144,-205,-207,35,-42,369,34,-86,-29,-254,-123,9,-278,244,-265,230,-259,157,-21,16,-239,-215,155,-7,33,-289,194,76,5,-218,-15,91,0,-8,151,152,-300,-4,41,-57,70,-194,-58,49,42,328,-138,162,-127,-303,5,7,-53,0,-56,-2,114,-52,-196,-361,49,215,32,-119,132,-7,62,250,51,-65,43,-219,143,-65,1,-154,107,58,23,-68,-185,-89,29,-2,52,148,4,-84,351,0,-3,96,-703,121,-148,-2,89,364,61,-2,-4,-231,-54,50,-23,-141,47,496,-67,-140,-655,-63,41,56,79,-244,32,-15,10,-11,10,7,264,-17,-152,-16,14,-1,37,-45,-152,-276,199,-16,-4,-14,87,-67,-33,7,6,115,-50,-138,-3,17,174,-52,182,-94,-220,-69,-88,-81,-176,-53,-126,343,11,-182,257,-3,-209,138,-86,-306,-227,42,160,-72,-163,-196,116,-195,11,-12,-5,-245,-179,-72,-64,-178,117,46,-161,-263,88,-74,-113,45,-2,423,-1,0,-158,180,100,-6,120,82,-314,11,-42,86,-218,14,133,160,-157,-216,-16,-45,-7,-62,-60,100,-68,44,-277,184,-304,161,338,-86,-65,36,-298,-101,126,479,-227,-298,-171,-122,30,-19,-51,236,-68,-138,4,-3,-45,53,5,-4,-48,104,-52,-434,-7,-51,-115,60,-46,-70,-118,106,37,192,-48,90,-164,4,270,76,-55,61,-8,-1,19,20,-35,-476,-47,36,411,-207,-356,8,-141,5,113,46,-16,51,-81,222,163,44,61,138,612,40,0,-29,-269,-51,-54,28,-439,165,-2,50,-221,35,86,-640,129,-750,-153,86,-283,114,-266,8,135,-137,-128,-84,-81,27,-36,241,-139,3,-80,-1,-195,61,-24,-202,-26,-103,52,0,-1,-93,-365,-10,67,-214,-125,-48,59,-9,-456,-55,-45,-2,77,-243,8,250,-5,-14,167,6,-1,87,-1,-134,-149,5,-93,9,-37,-55,-277,-39,11,-396,42,-197,28,283,70,-206,36,50,-12,-42,-32,-8,-16,-93,30,-133,166,44,-50,-130,-17,-104,-54,-127,-52,46,3,-53,63,-488,-182,-43,48,1,43,-578,616,-69,80,-371,-4,-59,36,-56,-29,6,45,-37,-134,225,-123,-54,-18,-63,2,-45,33,-11,44,-289,-57,116,-38,-174,166,114,-22,-119,74,-309,-11,-68,-33,497,39,-182,235,-57,-185,319,-370,-200,-218,-38,140,93,-8,-157,-16,-87,-77,19,-249,47,-15,83,-75,-310,33,-169,42,-13,51,-201,73,442,4,-19,81,196,47,-60,44,-11,205,-209,38,-186,145,10,-507,128,102,-196,221,-143,10,-49,47,-12,362,337,12,-53,-319,66,58,-220,80,64,68,-138,183,-149,-190,45,-275,6,-115,-69,-125,106,41,-282,166,107,90,-74,-338,-224,66,-253,162,6,-144,0,-24,-167,-119,-271,129,-78,-285,-222,168,-58,46,-84,-30,98,-228,137,-14,-390,19,-50,-163,21,-110,102,135,-99,224,-298,279,35,34,-3,45,-135,-28,100,-65,-6,202,-122,-44,0,4,51,47,-15,-83,-159,-8,50,52,-145,191,217,42,-340,-15,195,57,-407,30,-335,0,167,18,-172,85,116,-11,68,-212,-172,-18,7,34,-152,103,-278,74,167,-501,-58,40,-99,439,-97,-791,-35,-16,-144,64,-670,15,239,35,-3,15,182,37,-95,-60,-7,47,-39,38,-42,-18,-5,-46,-116,68,-39,17,70,-787,-374,226,35,-263,19,30,172,54,114,9,-50,34,215,44,-45,-36,267,28,-201,-155,-3,-523,-107,6,-44,-56,-17,330,-297,17,-45,56,158,-118,-32,-77,-57,64,74,49,-193,21,-68,34,-103,41,79,-68,39,293,-182,106,-341,36,-12,163,-55,-206,-81,-164,-117,117,93,6,44,-246,-181,18,-191,174,-32,18,244,-72,98,0,217,-236,-139,-1,184,49,29,-13,-27,-46,42,52,239,0,0,185,256,-11,3,-241,-111,-45,148,-5,-36,249,-21,-529,112,73,-146,88,143,-37,61,110,5,46,38,-50,0,323,166,-264,-122,-53,132,-54,46,-37,-72,-114,10,101,563,-71,87,73,163,20,-114,-251,58,214,29,-9,-346,-45,32,205,41,39,-471,-206,-35,-6,-188,-116,53,102,-5,-127,45,11,44,-118,13,38,35,-73,-77,-251,12,60,120,-53,42,-144,-911,-9,-144,-7,-136,-56,36,-88,245,445,355,13,-23,9,243,-34,58,-56,329,-1012,96,-6,43,-239,33,-292,126,-79,-97,-47,-151,-39,82,-40,193,-226,61,-479,33,-6,119,102,-400,-492,34,261,-24,28,154,-48,29,-71,185,-49,39,-14,-412,-15,41,-45,1190,-43,233,56,-230,-96,-97,-46,-57,181,122,-47,10,-59,-117,85,-42,57,38,-380,-49,34,-277,-151,-125,152,-302,-156,-292,-421,-79,-177,-183,57,264,115,-218,148,-96,-67,-7,52,171,44,-214,-8,107,17,-40,-181,-41,99,4,12,-69,216,39,-237,132,35,-230,50,24,-15,62,156,232,-80,-170,15,204,48,150,-65,-3,52,-274,-148,-169,-123,147,-13,31,28,-444,34,-120,178,431,203,-259,36,129,-40,-139,-44,64,238,-8,89,17,36,-263,-50,-198,33,-39,38,-182,284,238,-50,107,-132,-11,13,-60,-226,-52,34,-44,14,40,182,-40,-88,-142,-924,132,-22,7,60,-10,117,-195,-957,-163,49,-41,5,-434,303,-104,39,125,-62,-12,111,48,-112,-52,79,-79,35,-130,122,115,33,-10,-88,1,20,297,-82,-46,0,-37,-101,-46,37,-15,87,79,-9,-45,-258,-137,123,67,9,-153,39,-37,3,-4,91,306,-158,-467,-7680,-61,-8,-39,-15,-165,278,-66,35,-53,37,7,323,-32,-175,-122,-120,65,-123,-61,194,-89,-202,120,171,63,-55,71,14,-255,-305,38,-363,-72,121,-15,-219,42,-300,67,9,-10,73,-360,-54,86,-64,10,135,64,1,-127,21,-133,-161,329,213,28,-345,-346,103,-67,150,-42,3,-4,-61,-137,192,-41,-44,59,64,33,-214,603,48,37,-11,45,-252,-41,-61,36,-266,50,-232,-7,-255,187,71,1,-51,165,-47,-74,-17,-3,-53,-91,277,54,132,-112,8,3,87,84,-64,35,-3,48,89,-9,-109,170,-125,33,-14,-147,249,45,-207,71,-34,-17,-46,-40,74,113,-49,-2,-108,-218,214,25,-47,64,-90,41,-37,-54,-182,8,-69,92,-12,33,-275,6,-66,-454,76,50,-110,-130,199,-161,-11,30,-4,22,10,-486,-15,227,-56,147,-138,-20,-51,106,-7,-30,84,-5,-112,30,234,28,-36,51,83,40,-19,29,-42,57,-49,29,-229,91,-117,60,-7,-130,-138,-227,206,3,-11,18,-50,-1391,114,-3,-38,118,-422,-9,88,31,-15,4,-70,-45,-82,32,-127,11,-10,0,-391,9,25,159,-238,-103,24,95,-59,10,-127,8,-128,9,-16,124,34,-113,7,3,3,74,-103,84,-136,-369,-202,-68,-139,5,-127,-202,204,-84,-69,-135,-144,-44,-23,-14,60,45,-109,148,8,17,-321,136,298,100,-188,-36,30,-362,113,-356,131,-14,-20,-221,133,-41,-43,-1,162,-86,-8,165,13,167,49,-238,-174,3,257,-59,-185,-56,42,-61,130,231,35,-169,205,-85,-142,-15,87,71,300,209,-47,83,50,-239,6,-54,189,-49,178,100,-18,244,-13,19,13,184,36,10,137,-11,8,-66,40,-187,21,-90,72,-215,38,-48,113,-14,-79,420,-199,-59,-92,199,302,-120,56,-9,107,-42,40,-1,-7,-58,-15,-76,56,311,3,-382,-98,-54,0,-159,-108,6,33,301,8,-81,216,94,-133,-15,202,-299,10,-91,53,-48,65,8,-253,-34,86,-46,-251,-8,298,163,-59,-56,41,-43,66,-196,-69,19,-9,-45,48,180,17,192,49,-12,-114,166,-14,-39,-156,-12,28,-204,-48,-34,124 12 | }; 13 | static int alpha2_array[2913] = { 14 | -567,339,272,301,322,-479,112,113,218,-402,302,179,442,-558,116,137,238,-169,-76,347,-50,-135,292,197,-387,375,256,-408,212,108,269,-344,371,310,-117,39,-400,59,327,-77,-13,393,239,246,-757,-112,102,-677,72,59,275,25,-274,196,353,132,149,299,244,-35,70,60,-343,-230,-418,46,-97,63,-75,161,13,99,25,-322,-609,-70,-291,-324,69,181,9,-12,-89,54,277,359,189,96,323,117,-245,11,138,-381,-134,-409,39,-184,17,174,19,-55,335,312,217,76,-83,-214,-171,35,19,49,17,199,31,3,135,100,-542,252,24,-37,-148,-43,-163,64,-69,60,-323,77,135,61,132,-3,-66,-151,267,141,163,136,92,92,-128,218,292,-46,-80,267,50,-340,-179,57,-131,158,121,-175,29,-14,211,-45,-396,61,-81,-211,13,33,9,126,-146,163,16,-255,9,-266,-138,113,0,-165,205,54,-270,-219,16,162,144,-385,96,31,173,243,125,127,-320,152,77,57,-25,47,-119,-67,106,151,-117,36,-249,46,-339,-536,131,-328,-118,11,88,109,42,-120,-427,9,59,25,-48,-97,50,129,59,-81,-3,266,-213,116,-384,-98,-27,-430,61,119,45,18,-395,96,-317,13,58,314,-11,-55,-486,1,-21,16,-195,210,75,148,229,129,-180,181,68,-98,66,-150,43,-224,60,-144,98,-355,-273,50,111,-114,57,-1,-133,-386,47,0,-568,15,-303,31,181,-269,49,-64,-54,-71,62,14,50,269,-440,15,7,-123,41,10,82,-67,38,10,39,-108,47,0,79,-166,39,391,166,9,-25,-87,-4,-7,42,0,-45,-327,-388,83,38,284,-157,101,73,115,-174,15,-442,31,-207,172,215,-121,242,-80,45,63,-109,-409,96,63,-369,-348,69,-208,-191,207,220,-253,39,-180,-103,18,-184,67,37,-275,311,3,-39,180,85,19,12,-62,31,-6,-30,-68,-165,-317,260,-92,52,-5,-75,277,311,-272,43,132,63,-592,-83,18,-441,260,38,-74,-86,-600,39,-7,60,236,79,-693,-8,58,-267,196,71,-65,280,135,103,189,188,97,93,203,-84,-247,-271,34,154,-54,-375,52,26,-102,-411,-34,2,66,-183,-421,6,-26,-137,51,-258,-70,-136,53,-9,-182,4,-16,203,-175,-55,319,37,-3,276,291,-1,61,-52,-312,13,74,-171,4,6,7,151,67,-85,40,-6,-11,-114,36,-97,16,203,29,-1,104,-98,196,-57,-372,66,124,-56,37,-51,69,-48,40,-419,61,-1,-115,112,64,6,0,389,-55,5,164,147,336,74,136,-114,-70,52,17,-133,11,47,-176,-215,-349,66,16,-4,-83,51,57,-274,9,-183,-136,249,-60,117,-682,6,-555,191,2,254,-63,-156,7,-34,-133,38,0,-157,-53,122,28,-383,208,-17,12,-1,-47,24,-69,40,-60,50,5,-4,-444,-14,-197,171,79,65,105,4,-53,10,43,209,6,-87,0,64,-366,85,33,-79,181,49,-227,-70,6,-44,-51,29,-116,100,-51,52,-261,-23,-493,-17,47,56,-47,95,-68,147,258,144,79,-286,84,134,-8,30,53,-72,-179,187,39,-87,-33,-245,-119,-134,55,16,55,12,44,-56,46,14,134,143,-179,11,66,148,50,54,197,-63,-9,282,184,11,-96,286,49,-297,42,-3,-21,152,34,-8,4,136,41,-192,-167,-314,110,-305,36,138,144,-203,379,-7,8,76,-97,-135,538,-10,91,-45,-332,35,100,-184,16,-42,-42,187,52,-75,103,-44,178,0,137,-191,85,-9,4,186,-125,197,17,-47,-410,304,100,-412,138,-81,-263,-202,-214,-160,402,98,134,-72,-78,-223,-51,20,145,114,173,49,-182,29,51,93,32,147,-134,122,-398,48,-114,-54,133,7,-57,37,4,-252,5,50,97,-37,-71,154,-96,264,-57,-303,11,274,-44,-18,102,-311,-182,46,-395,42,-4,60,14,-4,-54,47,-101,-657,-3,42,84,-124,-57,48,-53,-153,-5,15,-394,95,35,-4,-313,0,-3,-317,131,-181,0,37,-119,-106,111,-243,-78,-506,-2,-8,99,150,-242,54,-7,297,-285,53,-40,46,11,-191,-428,195,-226,-630,-76,41,-95,152,141,104,-60,40,-87,24,8,-13,-5,234,-73,136,-113,-655,-283,145,32,223,53,14,-2,43,-355,0,-106,4,-50,132,180,-171,91,48,67,68,-276,-71,61,-63,1,181,-368,12,-114,88,-343,-132,-186,-6,49,-224,-61,-320,-21,-124,46,159,236,198,-278,-59,158,258,11,1,4,-73,-42,-2,-75,-7,-182,-388,-99,-5,37,-105,105,141,4,-75,-118,-132,53,367,-10,34,27,57,96,-50,149,-171,-19,298,11,-55,51,10,91,49,62,325,-551,-41,54,-50,55,-255,125,-44,-191,139,-129,-245,43,-336,3,61,39,-3,16,-11,39,13,1,-341,95,-38,65,-267,101,8,96,-53,45,-165,-253,8,0,120,146,-487,-2,-13,-314,-277,-94,60,39,-486,5,156,47,550,33,-132,316,-8,411,-1,243,495,-178,78,146,148,110,-51,281,14,-85,57,15,47,-66,182,19,232,185,53,-3,-29,-196,10,151,83,-65,-143,-134,75,64,-120,-289,-67,-4,40,-179,59,116,36,-65,-453,138,85,-298,-638,245,-65,-258,49,-256,106,100,-92,237,85,23,62,-322,43,-224,33,56,-129,117,142,4,-43,1,28,-47,210,-88,-356,0,29,-6,30,-53,136,-79,-13,-3,107,10,162,2,-16,21,-102,131,35,160,-698,-276,8,112,-61,-78,66,-501,189,67,43,-66,-73,-451,-6,263,-319,-439,52,52,51,427,-90,-46,31,-296,-1198,-37,87,78,6,55,40,-2,-176,311,-105,-4,49,-107,200,-8,16,-48,-202,150,-75,106,43,6,-106,91,220,25,-177,9,-177,-247,0,-83,185,77,-26,-55,-40,-5,-97,-69,67,142,7,16,-53,16,71,-226,40,108,40,31,210,-43,37,-7,-177,-6,37,9,205,-63,50,34,47,-89,53,-3,-116,3,8,69,44,17,30,284,117,-47,36,2,-282,0,89,-7,-37,-634,-112,180,157,-6,-275,-181,8,44,3,287,44,-46,-61,0,66,66,150,-55,39,-290,318,-48,31,2,-29,-14,-10,-276,0,-216,-203,-54,109,0,57,-98,-203,104,203,29,320,197,40,-471,-39,0,43,1,63,-469,-98,5,-3,-72,-360,204,-21,-56,-330,139,-41,136,-43,10,-264,81,-418,-51,-172,231,-327,193,57,79,-98,70,-310,-79,-52,52,9,40,302,84,106,45,-114,-28,-10,-12,-52,-290,4,57,10,-285,-37,-1014,-252,-191,77,134,-1,60,20,-171,-53,-267,0,157,-217,-130,-325,696,39,35,87,123,-514,-28,-298,36,157,-192,256,-8,-47,74,152,45,-54,154,-6,145,-69,63,-52,-194,-65,-73,8,-68,-293,76,-339,180,-115,-15,112,180,61,29,-280,19,29,42,-218,107,-166,39,-87,202,-57,-1,-15,51,-57,63,186,73,-285,170,-67,48,-281,-750,-70,-160,-94,49,-498,47,-39,28,5,252,-11,-301,-239,-383,400,-173,27,7,-43,33,-133,33,124,2,138,-5,127,-56,4,18,-2,-73,-571,104,-51,69,22,-280,-37,-108,-52,7,-55,36,-3,32,-162,-120,499,-542,126,195,101,-162,-147,-175,70,62,69,29,61,-169,107,-48,-234,100,113,0,43,-205,46,-53,56,-48,37,-60,55,-154,39,3,-23,-358,-126,-3,0,-75,51,12,38,-67,266,-301,-14,-62,43,-273,-342,116,-95,4,60,-82,-261,-44,61,-53,44,-8,257,-153,96,-183,82,-198,-15,147,32,-13,-162,-46,-543,22,4,-282,-98,-43,-98,90,-233,-5,0,88,89,10,-13,-82,2560,85,45,42,-394,-255,3,-51,277,50,17,-215,93,-70,27,-59,44,-214,-44,-37,3,-194,195,-2,56,-91,66,7,-171,-37,53,12,33,102,-182,-74,0,-2,-301,-475,99,-284,252,-177,17,-639,38,-547,200,-184,-349,186,49,-10,0,-465,53,-362,-30,66,44,-156,77,-58,53,17,133,-126,20,128,-149,153,55,156,129,105,24,60,46,10,-209,57,-50,206,5,-19,108,39,2,-232,-66,68,25,57,-67,35,-185,131,-277,37,7,64,119,33,-61,-157,8,44,-70,61,36,-61,-242,24,-220,98,7,12,-61,64,-59,-52,-10,154,229,-69,5,163,-59,8,8,42,-508,97,-235,58,138,-32,82,-155,-7,7,-11,2,-38,43,121,-89,-10,40,-51,22,-1,36,1,38,-115,71,172,23,85,35,-174,138,201,-122,-156,106,189,-34,157,37,-279,57,14,-54,158,64,10,0,-86,2,123,-44,2,81,-44,-2,121,-68,-261,146,-107,737,534,36,138,-400,-37,33,-14,147,5,95,-58,-104,-433,-117,39,8,-47,-122,-67,13,-34,-173,-187,78,-8,83,111,-1218,-15,-8,-196,-21,-6,-570,-61,32,-50,35,7,-36,-12,-17,-10,209,-48,155,112,140,118,-251,182,-55,64,-276,131,-318,52,-89,52,5,140,68,-261,-223,205,58,36,-489,-83,0,42,213,-18,-295,38,129,74,-228,-11,-5,247,-44,70,-455,-6,-180,84,-77,148,11,48,-176,39,-153,96,132,36,302,234,-14,-256,-1,-431,-39,-47,-4,-65,-79,107,237,103,-253,65,30,-263,8,0,-87,38,7,47,20,57,16,56,-111,97,102,-68,-17,40,198,-154,-158,-181,-18,21,70,-15,-15,129,78,-128,100,51,-136,-160,363,40,-42,38,108,37,68,110,177,-86,-346,-15,-10,60,-54,53,-2,11,-60,70,19,-5,-10,128,67,81,-35,-7,-3,11,81,43,-37,31,-6,42,288,9,-52,138,0,107,32,55,-105,28,-76,63,-59,39,-13,-595,-2,-171,-324,3,-6,-7,-36,96,-867,4,-45,-79,84,-46,-289,17,-4,-47,-4,3,-106,30,-50,-6,-6,16,0,125,130,-41,-289,22,-37,219,86,30,-62,-75,0,-36,-72,-72,156,-105,75,36,-175,31,-262,54,124,80,-76,-255,5,-7,-68,-96,105,33,0,-54,-2,-14,-187,42,-238,64,17,41,-5,-39,188,46,-3,-9,108,-252,54,76,-62,36,-52,102,-13,318,153,40,-116,57,-61,10,36,21,-8,13,-86,-104,-209,-83,11,56,-56,45,-223,5,13,88,-167,150,-82,-60,-411,38,3,142,-96,-109,11,11,-45,-76,-12,47,-46,-16,-15,-361,-13,113,-47,208,0,14,-51,58,-66,33,4,36,-143,-75,3,0,-10,-64,-46,37,87,-258,21,15,21,30,486,66,11,-10,-18,220,-40,-654,-181,422,-44,-20,25,68,-217,-143,248,-281,210,73,-200,52,16,-45,283,178,-64,29,-13,11,-88,29,-112,-186,-46,9,-53,71,139,-28,-42,-201,170,41,-40,-1149,3,33,-187,35,20,107,165,36,-599,21,-13,188,178,-52,-45,48,839,60,76,-34,-74,-174,-3,278,50,-145,36,-142,-58,50,-87,23,0,6,-12,-131,-305,9,126,102,176,65,79,-70,-69,-226,-139,6,54,-174,60,-54,172,-206,4,120,-15,-260,1,0,63,-240,2,-91,-417,-434,132,243,-296,-84,0,-198,190,-47,8,-327,170,-5,59,219,7,-247,132,-46,81,-15,5,-74,59,-66,15,419,-114,-60,206,-84,-363,149,99,-40,2,-8,41,139,-3,194,-189,393,52,13,75,-72,22,64,4,-64,22,-104,44,-9,-206,-44,-503,-263,31,190,-113,-44,-31,-85,37,-7,84,-213,45,17,-96,-53,116,19,-72,-141,-53,17,193,-81,-291,48,42,-5,135,-71,16,130,-371,6,30,-261,47,-212,36,122,-156,30,16,-36,16,-138,100,-138,9,586,-153,95,12,-18,-11,-204,-161,-10,-404,-12,-8,43,41,144,30,237,-41,260,8,-2,-29,-17,-172,-190,-6,-54,36,-17,-579,-38,106,-106,15,118,-338,49,19,117,-127,-394,29,-375,-28,146,24,222,14,-71,75,155,100,150,163,-37,-74,134,-228,113,45,-76,409,-136,-107,33,251,-144,-2,34,24,-10,-7,57,-7,32,65,39,0,-141,-44,10,-3,-4,35,60,-331,-47,-50,-83,-1,151,-60,187,279,43,257,-13,-240,139,103,8,-89,43,-51,-126,-4,-42,-106,181,-78,6,-42,51,1,224,-44,-155,-49,41,-196,-29,-9,47,1,31,-49,62,-99,-7680,-16,-179,15,0,-36,0,-4,-107,-52,45,7,77,-67,18,-219,-12,-115,-119,-11,73,-2,-902,375,-333,-2,21,-43,64,-62,51,-272,127,106,34,149,-805,177,77,-81,14,235,51,5,33,-49,40,-141,-11,-241,-1,-5,28,2,-21,290,195,-15,23,21,-281,-51,36,-315,3,-82,58,130,18,40,-45,14,-18,-50,-220,-290,40,-157,178,-38,44,158,108,320,36,152,-201,-364,7,-57,81,166,28,5,8,-65,232,2,-245,350,55,-226,16,-38,32,-16,28,93,70,276,52,6,14,53,-400,134,-335,-130,16,787,99,115,109,-170,71,113,-64,88,8,-15,-62,-123,184,-87,-210,48,-7,-138,-10,39,-56,155,-3,-70,-10,-14,-140,123,-84,32,138,11,106,176,-58,-55,-185,47,-118,61,8,19,-47,-7680,-12,40,-64,47,-49,58,-170,165,89,53,-45,78,256,-16,-78,-240,-6,21,-79,-216,-342,-155,-9,83,75,-384,-11,-37,-9,153,-9,14,-67,91,131,0,157,46,-493,157,113,62,-38,-46,-48,58,-132,89,-55,-73,67,-127,-197,-82,-57,131,12,1,17,-485,-365,46,-42,-71,-4,-1,650,73,167,69,-64,14,119,65,18,43,-45,611,159,-16,27,-234,381,50,0,267,69,14,-247,-89,-13,71,53,29,-57,-25,20,41,-44,32,-284,-1234,-163,628,-130,28,-362,10,85,11,0,91,112,-11,-235,51,-59,68,12,-724,-40,-510,334,-11,-52,-244,-541,-412,179,-102,113,-403,-10,-3,6,-16,-215,41,1,34,-41,141,-275,299,97,28,-47,47,243,9,-16,107,-54,-544,-380,82,48,71,68,-155,5,124,-238,87,-15,164,-101,-117,55,108,-162,-77,103,-199,41,-204,65,-181,189,-62,-33,35,229,-220,218,-75,49,-65,55,-11,48,80,42,-159,49,-3,-8,53,47,13,49,244,63,-419,-23,-91,51,-48,209,-117,36,-52,13,-56,36,458,-483,-14,-26,-12,-23,-365,82,-8,-4,279,79,-176,-1,32,100,-51,232,-50,-132,-8,32,-162,16,79,43,90,-190,106,0,-42,-133,0,15,37,33,-350,-1,-79,21,-45,36,-60,-5,-5,118,102,7,111,17,-53,92,-39,71,-93,106,-43,-167,-117,18,-257,108,67,-266,-5,400,37,0,-9,-223,152,-14,-348,65,-36,43,73,52,-39,19,20,-94,-236,20,183,-224,-151,123,86,80,45,-75,-36,142,-16,50,75,171,0,30,-129,-55,-38,102,29,21,-48,40,-273,13,-15,169,15,-63,101,-24,-117,37,404,19,120,30,-214,20,-45,32,69,-110,150,-9,-5,36,-106,53,162,-131,-45,175,-40,-62,-225,45,-42,88,221,30,-230,-277,-8,55,430,0 15 | }; 16 | static int tree_thresh_array[2913] = { 17 | -129,50,89,23,61,407,11,-77,24,-86,83,87,375,148,-78,33,75,-28,-40,64,-84,-563,58,41,374,285,129,58,59,-12,134,-29,206,192,-284,-200,347,-7,473,-210,-174,1522,79,71,162,-37,7,123,-322,8,110,-184,-269,64,596,25,27,75,81,-1136,37,-154,75,-45,138,-146,-46,-267,-173,7,-529,93,-139,107,91,-23,178,234,9,53,-108,-23,-67,-279,163,770,319,0,348,36,36,-96,28,138,-13,119,-34,-44,-100,15,-50,-19,314,117,80,-119,-119,80,17,-145,-66,-90,-93,68,-54,-138,69,13,342,1056,-149,-67,-15,-26,-15,-186,-98,-317,96,-10,491,9,285,-191,-205,123,373,52,65,9,130,11,-49,87,124,-184,-293,242,27,168,-3,-124,-52,153,100,233,-66,-722,721,-30,249,-119,-186,152,-99,-244,-123,30,-8,85,-27,76,-181,93,-4,70,-141,274,973,-52,43,69,-29,43,25,53,12,-447,33,128,130,27,107,52,107,-61,-159,-23,-6,-116,271,36,46,-11,46,29,130,103,30,134,-11,-155,-159,11,-221,-34,138,-460,-42,-20,-38,-48,-95,69,-98,-151,-252,88,-15,183,234,-46,-49,92,-81,65,-37,-18,521,195,219,-162,-275,546,-856,-268,253,-104,-142,-74,61,189,63,52,201,51,-76,171,-210,-290,68,-25,-161,0,-91,7,4,160,254,8,3,-28,-97,-420,-39,163,-53,-207,102,-31,175,0,37,45,-214,-942,-67,-70,-150,-42,-56,120,98,25,-91,-28,-166,-100,10,-80,-121,-61,-248,-52,-82,-125,-84,-7,-128,77,25,-41,-5,-16,-180,-248,-134,-603,-48,594,210,12,-178,528,-373,58,134,51,60,-137,583,-25,74,102,190,-36,167,-140,-162,10,112,143,18,11,144,106,-64,-31,85,245,159,88,-112,42,101,-65,199,5,-360,75,144,-835,-68,154,9,-60,-197,-120,-189,-114,-23,-41,46,212,136,-59,-140,-330,-3,397,149,211,-100,1340,31,662,-19,-75,318,77,-325,-278,-24,130,-122,-329,15,137,33,413,-40,29,102,1143,-181,-57,564,141,76,102,234,61,36,124,-180,75,43,-188,339,-36,175,-35,-17,33,396,-125,-249,-156,-39,200,-170,-82,-4,-137,79,-1,-1,-382,-318,69,-87,-52,32,421,-153,104,2,-1182,373,493,-302,-135,-179,741,-48,18,28,-97,-275,-267,93,-77,-28,-164,-166,-50,-111,-361,-32,-171,187,-577,-242,17,-8,1127,-108,167,22,130,-169,-393,-47,75,-139,-100,200,-84,-94,264,51,-49,-108,-104,160,-24,-139,166,104,817,50,160,-126,-145,-252,-48,274,-84,-91,4,146,125,22,-25,-124,-39,-233,16,138,-141,192,-35,268,-180,70,135,-86,121,226,-137,80,-85,133,-44,-40,-15,-171,-140,41,-368,106,-15,130,79,7,-180,-183,-440,-526,-183,-180,-502,-81,-63,-200,229,-40,55,26,29,19,39,-112,-161,-125,-6,781,21,98,-108,22,222,0,62,69,124,26,580,79,-70,-25,-65,-414,-30,181,-476,19,91,-49,229,-35,27,-74,-93,52,-56,128,381,106,67,-7,-36,92,-154,-22,-97,-108,50,395,-112,-64,-8,49,-63,-17,-86,-69,-167,-33,-78,-181,-255,-4,97,87,82,-117,14,233,-384,72,935,-749,-286,62,27,-65,53,53,-163,61,-84,-91,-32,62,-129,-126,-63,144,-73,-13,64,122,12,347,-240,183,165,154,248,-81,-679,282,46,6,326,-234,30,-73,387,22,28,141,-212,-283,-22,280,-274,-86,83,-192,768,-177,81,33,111,-375,-51,60,119,35,-224,-60,102,190,72,668,53,-64,329,144,135,49,176,124,145,-59,51,41,118,2,198,132,136,26,-23,52,24,10,-69,115,42,40,106,-104,-14,37,86,-209,-255,-135,-153,508,-36,-245,25,-72,72,21,-43,855,-108,241,-47,188,-93,-33,14,202,14,-126,354,-559,-23,-73,-81,-235,-340,-220,-34,226,-275,-97,22,87,-100,-80,-218,29,-92,-337,536,58,26,-188,236,-24,-213,190,30,88,-73,-152,-1,102,38,132,-25,210,-108,-63,79,137,118,0,-201,313,97,15,-366,-61,-45,387,2254,169,101,208,-69,-498,-14,474,151,47,-82,-117,-23,-227,-60,-29,-184,263,-60,184,-4,202,119,142,-25,63,11,-219,-78,-226,230,-97,7,-154,-98,112,473,-91,54,-15,-10,13,154,-56,-11,-157,-142,95,143,-54,52,14,412,0,47,-147,-86,60,-21,96,-102,-3,-165,115,187,162,206,-70,328,400,-63,-62,-67,-107,36,-110,31,-65,85,350,97,-160,-319,-69,486,639,-188,-42,392,56,9,136,-136,11,-269,8,91,-235,27,50,-33,150,-1647,-90,-53,-52,88,48,-80,263,446,-139,-15,-44,-47,106,17,-195,1,472,65,231,-43,508,-22,48,-176,-135,-87,-50,-69,-10,-184,159,27,-67,25,187,16,0,29,-204,-102,126,189,-13,-99,49,53,242,-168,-344,182,100,-17,100,-348,89,-68,133,10,226,-435,-32,309,-380,202,-48,351,331,-138,63,224,87,32,-153,652,-282,-138,-259,30,-39,-535,235,-29,127,146,-129,-79,-29,33,-178,108,131,-295,128,-1,11,134,-59,155,11,-170,-101,41,-85,91,-152,-43,227,88,0,59,441,147,-16,85,-122,106,43,35,87,305,19,7,4,115,-133,92,-88,31,59,114,23,-40,-16,-92,-162,-71,36,-32,110,-84,-294,-110,-194,-446,55,-27,-16,-154,35,-131,239,-167,-81,-18,68,38,-80,44,155,67,-81,45,21,-45,-43,431,224,72,-127,-234,-46,125,7,46,333,219,-98,27,-132,155,63,-181,-94,79,425,-77,158,93,-128,39,-201,-161,196,210,58,-375,26,146,207,-59,-158,-165,97,35,-544,40,20,-250,-1,13,86,30,101,-145,81,61,-94,-76,1846,48,-101,-183,-59,-100,94,-102,4,63,-109,5,-2,-130,-20,127,-137,49,-142,40,244,-267,-380,-168,87,-104,-168,-72,36,-47,-30,3,-125,-77,-33,-142,77,-77,-364,28,-115,-1,-443,65,35,-103,-55,-31,293,-55,12,-208,-36,877,57,174,81,-137,260,89,-321,58,-275,534,-189,-122,-1,-91,-6,49,99,-193,-101,89,770,-318,-199,-70,-11,-404,-89,250,-100,138,156,-82,101,-99,-108,-14,438,184,181,4,292,146,-85,1741,46,-62,-62,-77,-13,381,-51,-110,-96,-58,115,208,47,-60,935,454,13,349,90,-64,1356,36,188,-154,-335,891,60,214,37,32,-106,-12,234,-25,-165,-83,-70,-99,232,1,40,-215,-56,-124,-1230,-147,-225,138,-33,-22,12,219,-513,379,157,-8,39,98,-73,-43,-29,98,-75,64,-199,27,40,60,397,197,40,-163,93,27,244,28,64,-203,214,91,168,-88,-339,34,323,-369,-119,28,-33,80,-60,103,-64,120,-34,100,-138,-8,124,16,113,32,180,-132,85,103,26,-239,130,-124,61,-200,340,97,67,-48,0,78,-41,-57,-422,-391,-169,9,439,13,119,46,-49,-52,100,188,-111,164,94,-97,317,-54,-88,-292,-22,109,-161,106,200,151,323,118,25,-269,-282,-477,-5,-182,209,-129,86,-566,213,106,-49,-99,-103,51,234,68,-93,0,-31,385,-255,71,-90,-42,-38,-118,-86,-151,43,670,388,144,52,569,48,-40,-24,-5,132,-57,4,0,-1,16,58,-226,383,109,15,-130,-92,103,-127,-108,-56,-257,-183,-83,-32,35,-111,-67,-56,119,153,-102,-261,-38,-3,-89,-73,-101,643,282,-45,-56,-126,87,381,121,0,-172,-92,-52,114,-113,-25,-83,-50,-165,121,28,66,205,8,102,-64,152,-324,-70,134,-481,493,17,-297,725,34,-53,77,87,259,-132,-96,76,127,-45,-52,-52,281,21,-158,25,717,476,-94,-210,920,38,-485,154,90,-148,-540,-170,-135,64,-161,-277,-109,163,412,-331,-87,-43,3,14,77,-104,-16,-3,-202,47,141,-33,-91,-126,179,176,111,38,386,697,-193,458,-58,139,88,89,337,346,-225,-265,-93,224,0,402,-29,205,-23,57,87,-119,1,7,35,260,-114,200,-120,508,32,124,103,41,-68,-11,173,-198,118,-164,-168,48,-87,-97,73,-178,-37,194,-58,15,14,-119,-26,-123,32,36,393,-134,-54,62,49,-312,-49,89,-11,-199,-42,-27,35,81,90,-213,80,94,-61,-204,-283,19,-138,-66,-205,233,167,-12,-133,403,-156,-188,-489,-493,289,34,93,2,141,-18,96,52,-46,-170,-382,-111,-89,-39,284,127,-203,-83,-62,-207,-84,-126,-18,-187,68,13,100,-326,182,-513,73,78,163,55,66,45,160,-39,114,-96,110,1,-168,27,196,-12,-35,-30,-7,-353,191,0,-66,187,-112,-113,31,-2,452,281,7,787,644,-202,212,204,-174,-153,-152,57,-1,131,-17,40,382,70,34,-57,-31,114,-77,-76,-149,132,244,40,-144,11,33,364,-123,-89,154,11,-43,531,-72,-315,-78,-209,8,104,-97,-26,-154,886,-54,291,229,165,258,42,256,-161,-22,441,69,127,-94,-45,-19,-71,77,29,77,127,85,46,-233,295,-81,-68,-163,110,-16,93,-282,176,35,59,-47,-449,185,-110,73,206,-122,155,760,-16,41,-47,-26,43,-83,9,-6,35,-99,304,69,-100,123,49,355,-173,-10,-232,96,-85,29,1399,25,133,0,2,223,-41,-77,-21,-44,-204,49,-9,12,16,-30,212,75,716,221,-1312,-110,317,97,47,133,-181,-239,79,-183,-247,47,114,267,39,10,130,135,194,-80,-224,-92,438,-149,57,85,201,148,168,64,-66,-12,-564,-39,-101,-571,-336,15,-27,-65,-208,68,65,14,-352,135,-16,-98,35,-113,-796,-445,-79,12,242,-222,-161,337,-30,30,28,-63,-11,-289,-47,2,-151,-133,-306,169,-118,189,1041,9,-339,-46,-528,157,417,-78,-248,101,109,61,107,-153,-21,72,-139,-65,80,-424,-78,-52,-66,-522,78,133,38,20,169,-312,-298,244,83,-328,-73,46,-104,-3,-59,35,224,-443,94,11,-8,-92,340,-27,313,22,-42,113,-95,-227,-166,-30,69,-151,-80,-96,-177,-90,67,-134,292,3,-34,-70,-76,-37,75,-206,-96,-111,26,95,53,-27,-92,-261,-204,27,-228,1308,331,-61,191,24,-140,-143,12,-57,-27,-216,-8,75,51,52,-73,7,-60,-61,59,-44,-37,18,96,130,-75,80,1685,-170,-42,50,-35,66,-42,-50,-206,202,-168,4,-205,-35,-205,418,-58,42,-48,295,-77,-19,-238,4,-202,-487,-74,-32,212,273,-56,-72,-172,-55,-45,-503,195,130,17,-251,-11,-280,424,64,-40,-36,-261,159,-163,206,189,254,-265,112,1,-17,193,51,188,813,68,8,91,-56,-31,-54,200,83,-68,-693,-464,-318,-63,-270,34,145,-159,-40,-94,12,53,60,-246,212,101,-49,-404,481,-77,-116,53,-477,-15,127,103,-115,149,-296,-170,195,269,56,-113,-65,303,-3,73,-10,-37,201,-125,410,13,145,1,103,-21,6,-66,-121,-6,-221,-271,114,118,-83,50,177,762,130,57,-25,-22,68,106,-109,-69,24,-11,-179,211,33,-216,215,-51,47,-97,-252,-7,144,-75,-157,408,345,164,241,612,2,-136,38,176,-276,-1276,121,43,-118,-23,116,-118,102,49,-174,42,-283,-19,-57,-62,-41,-208,125,-45,-25,321,-41,127,164,66,-186,-74,-57,-158,129,-44,49,289,2176,-60,-9,204,-195,-374,155,-63,-63,-235,-24,-286,-102,70,-181,180,65,-379,290,236,-67,98,51,-222,-54,25,118,-90,21,352,-35,27,-26,36,13,169,-27,125,-30,364,29,-74,-105,447,-46,-235,420,110,-55,-1317,837,-288,154,-287,258,149,16,-201,-293,-155,-12,79,46,-137,376,15,52,-586,-396,-36,65,288,-155,2113,-134,-148,27,-66,34,-563,724,32,449,-124,-94,-12,-136,54,60,-54,-66,-118,-415,154,-1169,629,0,-84,153,234,20,-223,103,99,147,-409,345,65,138,-253,286,-114,-52,88,411,106,116,158,-190,-175,15,173,80,3,-17,69,147,-290,-258,121,155,-136,-129,4,-293,-332,18,-172,-268,74,-211,-193,71,-103,-166,-154,-54,0,-46,152,13,-92,95,-57,30,-47,215,215,-48,392,-65,142,142,66,-181,-22,-269,-300,67,-37,24,-3,841,-69,-78,-106,-89,-98,193,-188,108,-199,-76,51,-4,-201,-71,-60,-938,-520,42,28,1188,-975,255,19,-113,-69,-203,-306,131,-386,-63,-16,12,-41,-158,141,-19,2,144,-96,-7,-68,2705,449,55,-93,-335,-215,-103,-179,-74,96,140,105,-108,249,592,218,46,-9,-121,111,-14,-51,-363,-78,-68,52,-55,77,-26,-99,-121,20,-23,68,156,-233,-220,-10,1217,-364,-230,151,-34,-9,-293,21,-25,63,106,-49,-277,-60,102,77,-87,38,940,-155,-55,148,27,395,-146,44,324,134,-113,-16,30,459,-486,-170,-114,-512,969,-120,154,295,40,213,-179,-157,-404,-499,-490,126,44,232,4,-115,-655,20,192,99,287,40,-230,449,85,143,163,-19,9,103,-131,308,-75,-52,-108,90,600,14,38,-35,-160,101,-143,-75,-55,25,-75,58,-133,-10,-3,194,-28,-176,84,-91,204,253,-171,-13,99,-70,-16,-58,-37,-506,-336,268,-129,-326,-77,-20,-50,5,121,115,124,-70,-344,30,231,-21,-61,224,-80,-275,-58,122,212,168,-526,9,31,186,-322,32,-55,118,-112,-298,-57,177,120,-130,155,-91,241,127,153,-85,-104,-29,-208,-84,43,130,-97,-24,97,114,59,445,-57,16,-20,-348,8,1490,904,-66,-197,71,-140,-18,528,124,180,12,-107,-114,48,6,-14,-129,-131,636,360,-6,38,152,328,-3,-20,489,-18,-121,109,181,-99,80,22,-950,-104,-26,16,-146,-58,-517,281,351,63,332,75,-353,296,-320,396,-163,-39,1,49,-85,237,0,-70,125,-3,360,-159,328,161,84,-274,191,321,271,123,70,82,135,-60,-42,-117,-19,1318,-69,-30,-122,-46,19,20,792,22,-279,-143,20,390,-257,-697,43,-170,520,338,349,227,18,53,237,-93,197,105,28,-141,120,-9,-392,68,106,1,-27,77,0,-312,205,-11,66,154,-50,237,19,187,87,642,-42,9,-95,-28,-140,-86,8,-17,-58,-33,-38,-155,19,-18,21,-39,184,58,670,10,-15,-103,-79,59,211,-155,-121,-160,-119,-342,1720,245,-77,-24,-238,-50,190,4,-363,-94,176,0,36,-72,25,93,-88,252,-319,46,-104,-155,40,-56,34,-292,40,450,144,-457,-465,68,-32,-135,51,-172,103,-99,-50,-466,-347,-100,-36,45,-120,26,57,-54,1164,-971,-457,523,-257,71,5,112,-178,45,85,-91,133,50,34,153,-57,233,20,-100,-46,141,99,-32,143,18,-340,-57,5,-68,-314,-969,-411,5,90,-460,67,278,65,19,27,19,10,11,-123,58,-247,-81,127,74,4,-150,49,306,-961,577,25,-234,-226,-88,105,-53,9,36,-36,16,102,-24,17,-138,182,-167,161,-288,146,-175,-86,-644,32,96,305,-2,-66,-135,199,9,185,438,-165,130,-235,55,292,-61,-41,15,66,-164,110,214,-78,-15,310,-90 18 | }; 19 | -------------------------------------------------------------------------------- /haar_mapping.h: -------------------------------------------------------------------------------- 1 | 2 | static int bank_mapping[ROWS * COLS] = 3 | {8, 13, 20, 14, 21, 12, 10, 1, 15, 2, 14, 17, 16, 20, 9, 6, 19, 14, 1, 0, 2, 18, 11, 5, 4, 15, 16, 13, 2, 0, 15, 24, 21, 25, 4, 14, 27, 23, 7, 12, 10, 3, 6, 18, 20, 11, 9, 4, 2, 16, 23, 25, 0, 5, 12, 6, 3, 15, 4, 13, 19, 12, 18, 20, 25, 1, 14, 17, 16, 19, 26, 22, 1, 21, 2, 12, 12, 17, 25, 3, 19, 21, 7, 16, 24, 22, 25, 13, 23, 26, 20, 27, 22, 7, 5, 5, 3, 2, 27, 14, 0, 5, 11, 10, 17, 4, 12, 27, 21, 3, 25, 20, 19, 24, 23, 26, 24, 19, 13, 9, 15, 16, 6, 15, 22, 17, 20, 26, 4, 24, 25, 13, 0, 22, 23, 7, 11, 11, 6, 5, 12, 3, 26, 22, 18, 18, 10, 9, 1, 1, 9, 9, 14, 1, 20, 3, 11, 11, 24, 7, 17, 0, 4, 9, 1, 12, 22, 13, 2, 15, 19, 5, 21, 10, 10, 13, 27, 6, 14, 4, 5, 20, 24, 11, 11, 9, 19, 2, 2, 23, 21, 1, 15, 0, 21, 7, 18, 18, 9, 18, 20, 3, 27, 17, 6, 23, 19, 17, 1, 12, 11, 22, 7, 2, 23, 6, 25, 15, 4, 16, 0, 11, 5, 19, 21, 22, 4, 24, 6, 1, 20, 6, 10, 2, 16, 11, 23, 7, 7, 0, 1, 15, 9, 17, 17, 12, 12, 13, 14, 3, 6, 1, 16, 0, 25, 19, 1, 20, 7, 14, 2, 2, 9, 3, 17, 16, 21, 5, 10, 7, 14, 15, 26, 23, 15, 5, 24, 2, 27, 10, 1, 16, 16, 7, 0, 15, 9, 6, 19, 19, 14, 11, 18, 3, 20, 20, 20, 23, 25, 17, 16, 18, 9, 2, 22, 22, 15, 6, 6, 0, 7, 5, 5, 16, 2, 9, 12, 18, 21, 13, 25, 14, 3, 17, 11, 19, 19, 15, 7, 2, 18, 18, 18, 5, 13, 13, 14, 14, 21, 20, 9, 10, 16, 9, 11, 19, 4, 12, 26, 23, 18, 22, 22, 11, 23, 7, 2, 19, 9, 9, 21, 14, 0, 18, 4, 5, 6, 17, 15, 4, 26, 13, 19, 20, 10, 2, 2, 11, 16, 26, 24, 18, 14, 3, 1, 0, 10, 13, 4, 16, 5, 6, 21, 14, 3, 13, 0, 5, 11, 20, 17, 17, 25, 15, 24, 10, 4, 22, 3, 5, 5, 6, 12, 12, 13, 3, 14, 11, 11, 25, 10, 7, 20, 22, 6, 4, 5, 7, 3, 9, 26, 22, 23, 18, 15, 6, 20, 21, 25, 10, 4, 17, 13, 5, 12, 3, 25, 0, 0, 0, 1, 0, 2, 4, 11, 25, 17, 23, 4, 3, 24, 26, 20, 5, 12, 7, 0, 27, 6, 18, 24, 10, 22, 14, 15, 21, 15, 23, 1, 3, 17, 9, 27, 16, 18, 26, 4, 19, 10, 9, 12, 25, 0, 24, 24, 22, 16, 6, 23, 2, 25, 13, 14, 24, 15, 21, 1, 9, 19, 10, 4, 11, 23, 26, 24, 22, 16, 1, 20, 2, 9, 19, 18, 7, 11, 9, 10, 1, 17, 2, 12, 0, 3, 20, 12, 12, 2, 5, 15, 6, 11, 26, 1, 19, 13, 14, 27, 7, 13, 22, 26, 2, 4, 22, 1, 6, 27, 7, 22, 11, 12, 18, 0, 15, 3, 13, 24, 2, 15, 27, 7, 5, 9, 1, 21, 3, 1, 9, 16, 17, 24, 19, 16, 26, 11, 20, 12, 18, 22, 17, 25, 9, 27, 7, 4, 16, 15, 2, 3, 5, 14, 21, 24, 13, 13, 23, 7, 26, 5, 6, 20, 3, 10, 11, 22, 2, 23, 24, 12, 17, 27, 1, 25, 18, 18}; 4 | 5 | static int offset_mapping[ROWS * COLS] = 6 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 2, 1, 2, 0, 1, 0, 1, 3, 0, 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 3, 2, 1, 1, 2, 1, 2, 2, 1, 3, 3, 2, 1, 3, 2, 3, 2, 2, 4, 1, 3, 2, 0, 0, 3, 2, 4, 4, 5, 2, 3, 2, 3, 3, 1, 4, 1, 1, 4, 3, 2, 1, 4, 1, 2, 2, 2, 3, 3, 5, 2, 5, 3, 4, 2, 2, 3, 4, 6, 3, 4, 4, 5, 5, 4, 2, 3, 2, 3, 5, 4, 2, 4, 5, 3, 5, 3, 4, 6, 3, 5, 4, 6, 5, 4, 4, 4, 3, 3, 4, 4, 5, 7, 5, 4, 5, 3, 4, 3, 3, 4, 5, 4, 5, 6, 6, 7, 6, 5, 6, 5, 4, 5, 5, 6, 6, 7, 8, 6, 6, 6, 6, 6, 6, 5, 4, 5, 7, 4, 5, 7, 7, 7, 8, 6, 7, 8, 7, 7, 7, 8, 5, 6, 8, 7, 6, 7, 5, 5, 6, 8, 7, 9, 7, 5, 6, 6, 6, 8, 7, 9, 9, 9, 7, 6, 9, 7, 7, 7, 8, 8, 6, 7, 10, 8, 9, 8, 8, 9, 7, 8, 10, 10, 9, 6, 10, 7, 11, 8, 7, 8, 8, 11, 9, 9, 8, 9, 10, 11, 8, 8, 8, 10, 12, 8, 9, 8, 10, 13, 11, 9, 9, 11, 12, 10, 9, 10, 9, 9, 9, 7, 10, 10, 10, 5, 9, 11, 10, 8, 13, 6, 8, 14, 10, 11, 11, 10, 12, 11, 11, 11, 12, 11, 12, 8, 10, 12, 13, 14, 10, 9, 11, 12, 9, 12, 14, 9, 10, 13, 12, 13, 11, 12, 11, 12, 13, 15, 13, 12, 10, 10, 9, 10, 12, 11, 12, 13, 13, 14, 14, 13, 16, 11, 12, 13, 13, 10, 11, 13, 14, 11, 15, 14, 9, 14, 15, 14, 15, 10, 13, 6, 11, 14, 11, 12, 15, 12, 14, 17, 16, 16, 17, 12, 15, 12, 15, 11, 14, 14, 13, 15, 12, 7, 12, 17, 16, 10, 18, 19, 16, 15, 8, 9, 16, 16, 12, 15, 13, 11, 13, 13, 16, 15, 15, 13, 17, 13, 14, 14, 16, 17, 17, 14, 15, 11, 16, 10, 12, 14, 13, 14, 17, 18, 16, 14, 15, 15, 15, 18, 18, 19, 12, 13, 15, 18, 14, 17, 15, 19, 16, 16, 18, 9, 15, 13, 17, 17, 18, 19, 14, 13, 14, 16, 16, 16, 20, 16, 17, 14, 15, 16, 17, 16, 18, 20, 17, 20, 15, 17, 14, 18, 18, 11, 10, 20, 21, 17, 17, 19, 7, 19, 18, 12, 15, 16, 19, 18, 15, 19, 15, 17, 19, 18, 19, 8, 17, 19, 11, 19, 18, 16, 20, 18, 16, 20, 13, 14, 17, 18, 20, 16, 21, 17, 17, 20, 15, 20, 16, 18, 21, 19, 17, 20, 21, 17, 12, 16, 18, 19, 19, 21, 22, 22, 20, 20, 18, 22, 23, 18, 20, 19, 23, 19, 21, 20, 22, 20, 21, 24, 22, 21, 21, 23, 13, 21, 21, 18, 21, 9, 19, 19, 19, 14, 25, 21, 20, 22, 22, 10, 20, 21, 24, 22, 21, 22, 22, 21, 20, 17, 26, 23, 11, 21, 23, 24, 23, 17, 22, 24, 25, 20, 20, 18, 22, 21, 15, 25, 23, 23, 22, 22, 21, 18, 26, 12, 22, 22, 22, 24, 27, 23, 24, 22, 18, 19, 21, 22, 18, 23, 16, 25, 23, 24, 24, 19, 26, 23, 28, 19, 20, 24, 22, 13, 25, 19, 23, 24}; 7 | -------------------------------------------------------------------------------- /image.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "image.h" 5 | 6 | #define MYDEBUG 7 | 8 | char* strrev(char* str) 9 | { 10 | char *p1, *p2; 11 | if (!str || !*str) 12 | return str; 13 | for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2) 14 | { 15 | *p1 ^= *p2; 16 | *p2 ^= *p1; 17 | *p1 ^= *p2; 18 | } 19 | return str; 20 | } 21 | 22 | void itochar(int x, char* szBuffer, int radix) 23 | { 24 | int i = 0, n, xx; 25 | n = x; 26 | while (n > 0) 27 | { 28 | xx = n%radix; 29 | n = n/radix; 30 | szBuffer[i++] = '0' + xx; 31 | } 32 | szBuffer[i] = '\0'; 33 | strrev(szBuffer); 34 | } 35 | 36 | /* Writes a Pgm file using the hex image */ 37 | int writePgm(char *fileName, unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH] ) 38 | { 39 | char parameters_str[5]; 40 | int i; 41 | const char *format = "P5"; 42 | FILE *fp = fopen(fileName, "w"); 43 | 44 | if (!fp){ 45 | printf("Unable to open file %s\n", fileName); 46 | return -1; 47 | } 48 | 49 | fputs(format, fp); 50 | fputc('\n', fp); 51 | 52 | itochar(IMAGE_WIDTH, parameters_str, 10); 53 | fputs(parameters_str, fp); 54 | parameters_str[0] = 0; 55 | fputc(' ', fp); 56 | 57 | itochar(IMAGE_HEIGHT, parameters_str, 10); 58 | fputs(parameters_str, fp); 59 | parameters_str[0] = 0; 60 | fputc('\n', fp); 61 | 62 | itochar(IMAGE_MAXGREY, parameters_str, 10); 63 | fputs(parameters_str, fp); 64 | fputc('\n', fp); 65 | 66 | for (i = 0; i < IMAGE_HEIGHT; i++) 67 | for (int j = 0; j < IMAGE_WIDTH ; j++) 68 | fputc(Data[i][j], fp); 69 | 70 | fclose(fp); 71 | return 0; 72 | } 73 | 74 | /* draw white bounding boxes around detected faces */ 75 | void drawRectangle(unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH], MyRect r) 76 | { 77 | int i; 78 | int col = IMAGE_WIDTH; 79 | 80 | for (i = 0; i < r.width; i++) 81 | Data[r.y][r.x + i] = 255; 82 | for (i = 0; i < r.height; i++) 83 | Data[r.y+i][r.x + r.width] = 255; 84 | for (i = 0; i < r.width; i++) 85 | Data[r.y + r.height][r.x + r.width - i] = 255; 86 | for (i = 0; i < r.height; i++) 87 | Data[r.y + r.height - i][r.x] = 255; 88 | } 89 | -------------------------------------------------------------------------------- /image.h: -------------------------------------------------------------------------------- 1 | #ifndef __IMAGE_H__ 2 | #define __IMAGE_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "haar.h" 8 | 9 | #ifndef __PARAMETERS__ 10 | #define __PARAMETERS__ 11 | 12 | #define TOTAL_NODES 2913 13 | #define TOTAL_STAGES 25 14 | #define TOTAL_COORDINATES TOTAL_NODES*12 15 | #define TOTAL_WEIGHTS TOTAL_NODES*3 16 | #define IMAGE_HEIGHT 240 17 | #define IMAGE_WIDTH 320 18 | 19 | 20 | #endif 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | void drawRectangle ( unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH], 27 | MyRect r); 28 | 29 | int writePgm(char *fileName, unsigned char Data[IMAGE_HEIGHT][IMAGE_WIDTH] ); 30 | 31 | #ifdef __cplusplus 32 | } 33 | #endif 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "haar.h" 5 | #include "image.h" 6 | 7 | using namespace std; 8 | 9 | int main ( int argc, char *argv[] ) 10 | { 11 | 12 | int flag; 13 | int in_flag , in_width , in_height , in_maxgrey; 14 | int ret_val=1; 15 | 16 | printf ("-- entering main function --\r\n"); 17 | printf ("-- loading image --\r\n"); 18 | 19 | // 320 X 240 Input image in hex format 20 | #include INPUT_IMAGE 21 | 22 | double duration; 23 | 24 | // Arguments to be passed to DUT 25 | MyRect result[RESULT_SIZE]; 26 | int result_x[RESULT_SIZE]; 27 | int result_y[RESULT_SIZE]; 28 | int result_w[RESULT_SIZE]; 29 | int result_h[RESULT_SIZE]; 30 | 31 | int res_size=0; 32 | int *result_size = &res_size; 33 | int i; 34 | 35 | // As the SDSoC generated data motion network does not support sending 320 X 240 images at once 36 | // We needed to send all the 240 rows using 240 iterations. The last invokation of detectFaces() does the actual face detection 37 | 38 | for ( i = 0; i < IMAGE_HEIGHT-1; i+=1 ){ 39 | detectFaces ( Data[i], result_x, result_y, result_w, result_h, result_size); 40 | } 41 | 42 | printf ("-- detecting faces --\r\n"); 43 | 44 | std::clock_t start = std::clock(); 45 | detectFaces ( Data[IMAGE_HEIGHT-1], result_x, result_y, result_w, result_h, result_size); 46 | duration = ( std::clock() - start ) / (double) CLOCKS_PER_SEC; 47 | 48 | printf("\nresult_size = %d", *result_size); 49 | 50 | for (int j = 0; j < RESULT_SIZE; j++){ 51 | result[j].x = result_x[j]; 52 | result[j].y = result_y[j]; 53 | result[j].width = result_w[j]; 54 | result[j].height = result_h[j]; 55 | } 56 | 57 | for( int i=0 ; i < *result_size ; i++ ) 58 | printf("\n [Test Bench (main) ] detected rects: %d %d %d %d",result[i].x,result[i].y,result[i].width,result[i].height); 59 | 60 | if ( *result_size > 0 ) ret_val = 0; 61 | 62 | printf("\n-- saving output image [Start] --\r\n"); 63 | 64 | // Draw the rectangles onto the images and save the outputs. 65 | for(i = 0; i < *result_size ; i++ ) 66 | { 67 | MyRect r = result[i]; 68 | drawRectangle(Data, r); 69 | } 70 | 71 | flag = writePgm((char *)(OUTPUT_FILENAME),Data); 72 | printf("\n-- saving output image [Done] --\r\n"); 73 | printf("DURATION: %2f", duration); 74 | 75 | return ret_val; 76 | 77 | } 78 | --------------------------------------------------------------------------------