Final demo of doing Gauge Needle Detection on F429.
Dependencies: BSP_DISCO_F429ZI SDFileSystem SDRAM_DISCO_F429ZI mbed
Fork of DISCO-F429ZI_SDRAM_demo by
main.cpp@1:8b8a77b7d715, 2016-05-03 (annotated)
- Committer:
- wsquan171
- Date:
- Tue May 03 08:52:52 2016 +0000
- Revision:
- 1:8b8a77b7d715
- Parent:
- 0:d3bf1776d1c6
Final demo for doing gauge needle detection on F429.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
grein028 | 0:d3bf1776d1c6 | 1 | #include "mbed.h" |
grein028 | 0:d3bf1776d1c6 | 2 | #include "SDRAM_DISCO_F429ZI.h" |
wsquan171 | 1:8b8a77b7d715 | 3 | #include <stdio.h> |
wsquan171 | 1:8b8a77b7d715 | 4 | #include <stdlib.h> |
wsquan171 | 1:8b8a77b7d715 | 5 | #include <string.h> |
wsquan171 | 1:8b8a77b7d715 | 6 | #include <math.h> |
wsquan171 | 1:8b8a77b7d715 | 7 | #include "SDFileSystem.h" |
wsquan171 | 1:8b8a77b7d715 | 8 | |
wsquan171 | 1:8b8a77b7d715 | 9 | #define M_PI 3.14159265358979323846 |
grein028 | 0:d3bf1776d1c6 | 10 | |
grein028 | 0:d3bf1776d1c6 | 11 | SDRAM_DISCO_F429ZI sdram; |
wsquan171 | 1:8b8a77b7d715 | 12 | SDFileSystem sd(PC_12, PC_11, PC_10, PB_2, "sd");// MOSI, MISO, SCK, CS |
grein028 | 0:d3bf1776d1c6 | 13 | DigitalOut led_green(LED1); |
grein028 | 0:d3bf1776d1c6 | 14 | DigitalOut led_red(LED2); |
wsquan171 | 1:8b8a77b7d715 | 15 | SPI spi(PC_12, PC_11, PC_10); // mosi, miso, sclk |
wsquan171 | 1:8b8a77b7d715 | 16 | DigitalOut cs(PB_2); |
grein028 | 0:d3bf1776d1c6 | 17 | Serial pc(USBTX, USBRX); |
grein028 | 0:d3bf1776d1c6 | 18 | |
wsquan171 | 1:8b8a77b7d715 | 19 | #define line_limit 10 // limit on # of lines to be returned by HoughLines |
wsquan171 | 1:8b8a77b7d715 | 20 | |
wsquan171 | 1:8b8a77b7d715 | 21 | |
wsquan171 | 1:8b8a77b7d715 | 22 | typedef struct |
wsquan171 | 1:8b8a77b7d715 | 23 | { |
wsquan171 | 1:8b8a77b7d715 | 24 | int x; |
wsquan171 | 1:8b8a77b7d715 | 25 | int y; |
wsquan171 | 1:8b8a77b7d715 | 26 | } ptvec; |
wsquan171 | 1:8b8a77b7d715 | 27 | |
wsquan171 | 1:8b8a77b7d715 | 28 | typedef struct |
wsquan171 | 1:8b8a77b7d715 | 29 | { |
wsquan171 | 1:8b8a77b7d715 | 30 | float rho, theta; |
wsquan171 | 1:8b8a77b7d715 | 31 | double a, b; |
wsquan171 | 1:8b8a77b7d715 | 32 | double x0, y0; |
wsquan171 | 1:8b8a77b7d715 | 33 | ptvec ptvec1, ptvec2; |
wsquan171 | 1:8b8a77b7d715 | 34 | unsigned int strength; |
wsquan171 | 1:8b8a77b7d715 | 35 | } trans_line; |
wsquan171 | 1:8b8a77b7d715 | 36 | |
wsquan171 | 1:8b8a77b7d715 | 37 | typedef struct |
wsquan171 | 1:8b8a77b7d715 | 38 | { |
wsquan171 | 1:8b8a77b7d715 | 39 | unsigned int rows; |
wsquan171 | 1:8b8a77b7d715 | 40 | unsigned int cols; |
wsquan171 | 1:8b8a77b7d715 | 41 | unsigned int channels; |
wsquan171 | 1:8b8a77b7d715 | 42 | uint32_t data; |
wsquan171 | 1:8b8a77b7d715 | 43 | } Image; |
wsquan171 | 1:8b8a77b7d715 | 44 | |
wsquan171 | 1:8b8a77b7d715 | 45 | typedef struct |
wsquan171 | 1:8b8a77b7d715 | 46 | { |
wsquan171 | 1:8b8a77b7d715 | 47 | int rho; |
wsquan171 | 1:8b8a77b7d715 | 48 | int theta; |
wsquan171 | 1:8b8a77b7d715 | 49 | unsigned int strength; |
wsquan171 | 1:8b8a77b7d715 | 50 | } line_polar; |
wsquan171 | 1:8b8a77b7d715 | 51 | |
grein028 | 0:d3bf1776d1c6 | 52 | |
wsquan171 | 1:8b8a77b7d715 | 53 | int bmpread(char *filename, Image *dst) |
wsquan171 | 1:8b8a77b7d715 | 54 | { |
wsquan171 | 1:8b8a77b7d715 | 55 | pc.printf("Reading Image file: %s\r\n", filename); |
wsquan171 | 1:8b8a77b7d715 | 56 | FILE *file; |
wsquan171 | 1:8b8a77b7d715 | 57 | unsigned char tempSize4[4]; |
wsquan171 | 1:8b8a77b7d715 | 58 | unsigned int width, height; |
wsquan171 | 1:8b8a77b7d715 | 59 | unsigned short planes, bpp; |
wsquan171 | 1:8b8a77b7d715 | 60 | |
wsquan171 | 1:8b8a77b7d715 | 61 | if ((file = fopen(filename, "rb"))==NULL) |
wsquan171 | 1:8b8a77b7d715 | 62 | { |
wsquan171 | 1:8b8a77b7d715 | 63 | pc.printf("File Not Found : %s\r\n", filename); |
wsquan171 | 1:8b8a77b7d715 | 64 | return 0; |
wsquan171 | 1:8b8a77b7d715 | 65 | } |
wsquan171 | 1:8b8a77b7d715 | 66 | |
wsquan171 | 1:8b8a77b7d715 | 67 | // seek through the bmp header, up to the width/height: |
wsquan171 | 1:8b8a77b7d715 | 68 | fseek(file, 18, SEEK_CUR); |
wsquan171 | 1:8b8a77b7d715 | 69 | if ( fread( tempSize4, 1, 4, file) < 4 ) |
wsquan171 | 1:8b8a77b7d715 | 70 | return 0; |
wsquan171 | 1:8b8a77b7d715 | 71 | width = (tempSize4[3]<<24) | (tempSize4[2]<<16) | (tempSize4[1]<<8) | tempSize4[0]; // big endian |
wsquan171 | 1:8b8a77b7d715 | 72 | if ( fread( tempSize4, 1, 4, file) < 4 ) |
wsquan171 | 1:8b8a77b7d715 | 73 | return 0; |
wsquan171 | 1:8b8a77b7d715 | 74 | height = (tempSize4[3]<<24) | (tempSize4[2]<<16) | (tempSize4[1]<<8) | tempSize4[0];; |
wsquan171 | 1:8b8a77b7d715 | 75 | |
wsquan171 | 1:8b8a77b7d715 | 76 | pc.printf("width: %d, height: %d\r\n", width, height); |
wsquan171 | 1:8b8a77b7d715 | 77 | |
wsquan171 | 1:8b8a77b7d715 | 78 | dst->rows = height; |
wsquan171 | 1:8b8a77b7d715 | 79 | dst->cols = width; |
wsquan171 | 1:8b8a77b7d715 | 80 | |
wsquan171 | 1:8b8a77b7d715 | 81 | |
wsquan171 | 1:8b8a77b7d715 | 82 | if ( fread( tempSize4, 1, 2, file) < 2 ) |
wsquan171 | 1:8b8a77b7d715 | 83 | return 0; |
wsquan171 | 1:8b8a77b7d715 | 84 | planes = (tempSize4[1]<<8) | tempSize4[0]; // big endian |
wsquan171 | 1:8b8a77b7d715 | 85 | dst->channels = planes; |
wsquan171 | 1:8b8a77b7d715 | 86 | |
wsquan171 | 1:8b8a77b7d715 | 87 | if ( fread( tempSize4, 1, 2, file) < 2 ) |
wsquan171 | 1:8b8a77b7d715 | 88 | return 0; |
wsquan171 | 1:8b8a77b7d715 | 89 | bpp = (tempSize4[1]<<8) | tempSize4[0]; // big endian |
wsquan171 | 1:8b8a77b7d715 | 90 | pc.printf("planes: %d, bpp: %d\r\n", planes, bpp); |
wsquan171 | 1:8b8a77b7d715 | 91 | |
wsquan171 | 1:8b8a77b7d715 | 92 | fseek(file, 24, SEEK_CUR); |
wsquan171 | 1:8b8a77b7d715 | 93 | unsigned char *readline; |
wsquan171 | 1:8b8a77b7d715 | 94 | unsigned int padding=0; while ((width*3+padding) % 4!=0) padding++; |
wsquan171 | 1:8b8a77b7d715 | 95 | unsigned int linewidth = width * 3 + padding; |
wsquan171 | 1:8b8a77b7d715 | 96 | readline = (unsigned char*)malloc(linewidth * sizeof(unsigned char)); |
wsquan171 | 1:8b8a77b7d715 | 97 | unsigned char R, G, B; |
wsquan171 | 1:8b8a77b7d715 | 98 | int i, j; |
wsquan171 | 1:8b8a77b7d715 | 99 | |
wsquan171 | 1:8b8a77b7d715 | 100 | dst->data = 1; |
wsquan171 | 1:8b8a77b7d715 | 101 | unsigned char *dst_buf= (unsigned char *) malloc(width * sizeof(unsigned char)); |
wsquan171 | 1:8b8a77b7d715 | 102 | uint32_t buffer[width/4]; |
wsquan171 | 1:8b8a77b7d715 | 103 | |
wsquan171 | 1:8b8a77b7d715 | 104 | pc.printf("Converting to grayscale and Storing to SDRAM\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 105 | for(i = height-1; i >= 0; i--) |
wsquan171 | 1:8b8a77b7d715 | 106 | { |
wsquan171 | 1:8b8a77b7d715 | 107 | fread(readline, sizeof(unsigned char), linewidth, file); |
wsquan171 | 1:8b8a77b7d715 | 108 | for(j = 0; j < width; j++) |
wsquan171 | 1:8b8a77b7d715 | 109 | { |
wsquan171 | 1:8b8a77b7d715 | 110 | B = readline[3*j]; |
wsquan171 | 1:8b8a77b7d715 | 111 | G = readline[3*j+1]; |
wsquan171 | 1:8b8a77b7d715 | 112 | R = readline[3*j+2]; |
wsquan171 | 1:8b8a77b7d715 | 113 | dst_buf[j] = (0.299*R) + (0.587*G) + (0.114*B); |
wsquan171 | 1:8b8a77b7d715 | 114 | } |
wsquan171 | 1:8b8a77b7d715 | 115 | for(j = 0; j < width/4; j++) |
wsquan171 | 1:8b8a77b7d715 | 116 | { |
wsquan171 | 1:8b8a77b7d715 | 117 | buffer[j] = (16777216*dst_buf[j*4]) + (65536*dst_buf[j*4+1]) + (dst_buf[j*4+2]*256) + dst_buf[j*4+3]; |
wsquan171 | 1:8b8a77b7d715 | 118 | } |
wsquan171 | 1:8b8a77b7d715 | 119 | sdram.WriteData(SDRAM_DEVICE_ADDR + dst->data + (i*width), buffer, width/4); |
wsquan171 | 1:8b8a77b7d715 | 120 | j = height / 10; |
wsquan171 | 1:8b8a77b7d715 | 121 | if(i%j == 0) |
wsquan171 | 1:8b8a77b7d715 | 122 | pc.printf("%d%%...",(100 - (i/j*10))); |
wsquan171 | 1:8b8a77b7d715 | 123 | } |
wsquan171 | 1:8b8a77b7d715 | 124 | pc.printf("\r\nImage loaded\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 125 | free(readline); |
wsquan171 | 1:8b8a77b7d715 | 126 | free(dst_buf); |
wsquan171 | 1:8b8a77b7d715 | 127 | fclose(file); |
wsquan171 | 1:8b8a77b7d715 | 128 | |
wsquan171 | 1:8b8a77b7d715 | 129 | return 1; |
wsquan171 | 1:8b8a77b7d715 | 130 | } |
wsquan171 | 1:8b8a77b7d715 | 131 | |
wsquan171 | 1:8b8a77b7d715 | 132 | int Round(double number) |
wsquan171 | 1:8b8a77b7d715 | 133 | { |
wsquan171 | 1:8b8a77b7d715 | 134 | double diff_down, diff_up; |
wsquan171 | 1:8b8a77b7d715 | 135 | diff_down = number - (int)number; |
wsquan171 | 1:8b8a77b7d715 | 136 | diff_up = 1 - diff_down; |
wsquan171 | 1:8b8a77b7d715 | 137 | if(diff_down < diff_up) |
wsquan171 | 1:8b8a77b7d715 | 138 | return (int)number; |
wsquan171 | 1:8b8a77b7d715 | 139 | else |
wsquan171 | 1:8b8a77b7d715 | 140 | return 1+(int)number; |
wsquan171 | 1:8b8a77b7d715 | 141 | } |
grein028 | 0:d3bf1776d1c6 | 142 | |
wsquan171 | 1:8b8a77b7d715 | 143 | void matrix_convolution(Image *src, Image *dst, double **mask, int width) |
grein028 | 0:d3bf1776d1c6 | 144 | { |
wsquan171 | 1:8b8a77b7d715 | 145 | unsigned char lines[width][src->cols]; |
wsquan171 | 1:8b8a77b7d715 | 146 | unsigned char result[src->cols]; |
wsquan171 | 1:8b8a77b7d715 | 147 | uint32_t buffer[src->cols/4]; |
wsquan171 | 1:8b8a77b7d715 | 148 | int i, j, k, r, c, actual_r, actual_c, scope; |
wsquan171 | 1:8b8a77b7d715 | 149 | double gaussian_sum; |
wsquan171 | 1:8b8a77b7d715 | 150 | //int flag = 1; |
wsquan171 | 1:8b8a77b7d715 | 151 | scope = width/2; |
wsquan171 | 1:8b8a77b7d715 | 152 | for(i = 0; i < src->rows; i++) |
wsquan171 | 1:8b8a77b7d715 | 153 | { |
wsquan171 | 1:8b8a77b7d715 | 154 | if(i < scope || (src->rows - i <= scope)) |
wsquan171 | 1:8b8a77b7d715 | 155 | { |
wsquan171 | 1:8b8a77b7d715 | 156 | sdram.ReadData(i*(src->cols) + SDRAM_DEVICE_ADDR + (src->data), buffer, src->cols/4); |
wsquan171 | 1:8b8a77b7d715 | 157 | sdram.WriteData(i*(src->cols) + SDRAM_DEVICE_ADDR + (dst->data), buffer, src->cols/4); |
wsquan171 | 1:8b8a77b7d715 | 158 | continue; |
wsquan171 | 1:8b8a77b7d715 | 159 | } |
wsquan171 | 1:8b8a77b7d715 | 160 | for(j = 0; j < width; j++) |
wsquan171 | 1:8b8a77b7d715 | 161 | { |
wsquan171 | 1:8b8a77b7d715 | 162 | sdram.ReadData((i-scope+j)*(src->cols) + SDRAM_DEVICE_ADDR + (src->data), buffer, src->cols/4); |
wsquan171 | 1:8b8a77b7d715 | 163 | for(k = 0; k < src->cols/4; k++) |
wsquan171 | 1:8b8a77b7d715 | 164 | { |
wsquan171 | 1:8b8a77b7d715 | 165 | lines[j][k*4+3] = buffer[k]; |
wsquan171 | 1:8b8a77b7d715 | 166 | lines[j][k*4+2] = buffer[k] >> 8; |
wsquan171 | 1:8b8a77b7d715 | 167 | lines[j][k*4+1] = buffer[k] >> 16; |
wsquan171 | 1:8b8a77b7d715 | 168 | lines[j][k*4] = buffer[k] >> 24; |
wsquan171 | 1:8b8a77b7d715 | 169 | } |
wsquan171 | 1:8b8a77b7d715 | 170 | } |
wsquan171 | 1:8b8a77b7d715 | 171 | //pc.printf("line %d, data = %d\r\n", i, (int)lines[scope][0]); |
wsquan171 | 1:8b8a77b7d715 | 172 | |
wsquan171 | 1:8b8a77b7d715 | 173 | for(j = 0; j < src->cols; j++) |
wsquan171 | 1:8b8a77b7d715 | 174 | { |
wsquan171 | 1:8b8a77b7d715 | 175 | if( (j < scope) || (src->cols - j <= scope)) |
wsquan171 | 1:8b8a77b7d715 | 176 | { |
wsquan171 | 1:8b8a77b7d715 | 177 | result[j] = lines[scope][j]; |
wsquan171 | 1:8b8a77b7d715 | 178 | continue; |
wsquan171 | 1:8b8a77b7d715 | 179 | } |
wsquan171 | 1:8b8a77b7d715 | 180 | gaussian_sum = 0; |
wsquan171 | 1:8b8a77b7d715 | 181 | for(r = 0; r < width; r++) |
wsquan171 | 1:8b8a77b7d715 | 182 | { |
wsquan171 | 1:8b8a77b7d715 | 183 | for(c = 0; c < width; c++) |
wsquan171 | 1:8b8a77b7d715 | 184 | { |
wsquan171 | 1:8b8a77b7d715 | 185 | actual_r = r; |
wsquan171 | 1:8b8a77b7d715 | 186 | actual_c = j + c - scope; |
wsquan171 | 1:8b8a77b7d715 | 187 | /* |
wsquan171 | 1:8b8a77b7d715 | 188 | if(flag == 1) |
wsquan171 | 1:8b8a77b7d715 | 189 | { |
wsquan171 | 1:8b8a77b7d715 | 190 | pc.printf("%d, %d mask = %.4f, value = %d\r\n", r,c,mask[r][c],(int)lines[actual_r][actual_c]); |
wsquan171 | 1:8b8a77b7d715 | 191 | } |
wsquan171 | 1:8b8a77b7d715 | 192 | */ |
wsquan171 | 1:8b8a77b7d715 | 193 | double op1 = mask[r][c]; |
wsquan171 | 1:8b8a77b7d715 | 194 | double op2 = (double) lines[actual_r][actual_c]; |
wsquan171 | 1:8b8a77b7d715 | 195 | double temp = op1 * op2; |
wsquan171 | 1:8b8a77b7d715 | 196 | gaussian_sum = gaussian_sum + temp; |
wsquan171 | 1:8b8a77b7d715 | 197 | } |
wsquan171 | 1:8b8a77b7d715 | 198 | } |
wsquan171 | 1:8b8a77b7d715 | 199 | //flag = 0; |
wsquan171 | 1:8b8a77b7d715 | 200 | if(gaussian_sum > 255) gaussian_sum = 255; |
wsquan171 | 1:8b8a77b7d715 | 201 | if(gaussian_sum < 0) gaussian_sum = 0; |
wsquan171 | 1:8b8a77b7d715 | 202 | result[j] = (unsigned char)Round(gaussian_sum); |
wsquan171 | 1:8b8a77b7d715 | 203 | //pc.printf("%d ", result[j]); |
wsquan171 | 1:8b8a77b7d715 | 204 | } |
wsquan171 | 1:8b8a77b7d715 | 205 | //pc.printf("\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 206 | for(j = 0; j < src->cols/4; j++) |
wsquan171 | 1:8b8a77b7d715 | 207 | { |
wsquan171 | 1:8b8a77b7d715 | 208 | buffer[j] = (16777216*result[j*4]) + (65536*result[j*4+1]) + (result[j*4+2]*256) + result[j*4+3]; |
wsquan171 | 1:8b8a77b7d715 | 209 | } |
wsquan171 | 1:8b8a77b7d715 | 210 | sdram.WriteData(SDRAM_DEVICE_ADDR + dst->data + (i*src->cols), buffer, src->cols/4); |
wsquan171 | 1:8b8a77b7d715 | 211 | j = src->rows / 10; |
wsquan171 | 1:8b8a77b7d715 | 212 | if(i%j == 0) |
wsquan171 | 1:8b8a77b7d715 | 213 | pc.printf("%d%%...",i/j*10); |
wsquan171 | 1:8b8a77b7d715 | 214 | } |
wsquan171 | 1:8b8a77b7d715 | 215 | pc.printf("\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 216 | return; |
wsquan171 | 1:8b8a77b7d715 | 217 | } |
wsquan171 | 1:8b8a77b7d715 | 218 | |
wsquan171 | 1:8b8a77b7d715 | 219 | |
wsquan171 | 1:8b8a77b7d715 | 220 | void myGaussianBlur(Image *src, Image *dst, int width, double sigma) |
wsquan171 | 1:8b8a77b7d715 | 221 | { |
wsquan171 | 1:8b8a77b7d715 | 222 | // build the Gaussian Kernal |
wsquan171 | 1:8b8a77b7d715 | 223 | // ref: http://stackoverflow.com/questions/8204645/implementing-gaussian-blur-how-to-calculate-convolution-matrix-kernel |
wsquan171 | 1:8b8a77b7d715 | 224 | |
wsquan171 | 1:8b8a77b7d715 | 225 | pc.printf("\r\nGaussian Blur Module Invoked\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 226 | dst->rows = src->rows; |
wsquan171 | 1:8b8a77b7d715 | 227 | dst->cols = src->cols; |
wsquan171 | 1:8b8a77b7d715 | 228 | dst->channels = src->channels; |
wsquan171 | 1:8b8a77b7d715 | 229 | dst->data = src->data + (src->rows * src->cols); |
wsquan171 | 1:8b8a77b7d715 | 230 | |
wsquan171 | 1:8b8a77b7d715 | 231 | int W = width; |
wsquan171 | 1:8b8a77b7d715 | 232 | int i, x, y; |
wsquan171 | 1:8b8a77b7d715 | 233 | double **kernel; |
wsquan171 | 1:8b8a77b7d715 | 234 | kernel = (double **) malloc(W * sizeof(double *)); |
wsquan171 | 1:8b8a77b7d715 | 235 | for(i = 0; i < W; i++) |
wsquan171 | 1:8b8a77b7d715 | 236 | kernel[i] = (double *) malloc(W * sizeof(double)); |
wsquan171 | 1:8b8a77b7d715 | 237 | double mean = W/2; |
wsquan171 | 1:8b8a77b7d715 | 238 | double sum = 0.0; // For accumulating the kernel values |
wsquan171 | 1:8b8a77b7d715 | 239 | for (x = 0; x < W; ++x) |
wsquan171 | 1:8b8a77b7d715 | 240 | { |
wsquan171 | 1:8b8a77b7d715 | 241 | for (y = 0; y < W; ++y) |
wsquan171 | 1:8b8a77b7d715 | 242 | { |
wsquan171 | 1:8b8a77b7d715 | 243 | kernel[x][y] = exp( -0.5 * (pow((x-mean)/sigma, 2.0) + pow((y-mean)/sigma,2.0)) ) |
wsquan171 | 1:8b8a77b7d715 | 244 | / (2 * M_PI * sigma * sigma); |
wsquan171 | 1:8b8a77b7d715 | 245 | |
wsquan171 | 1:8b8a77b7d715 | 246 | // Accumulate the kernel values |
wsquan171 | 1:8b8a77b7d715 | 247 | sum += kernel[x][y]; |
wsquan171 | 1:8b8a77b7d715 | 248 | } |
wsquan171 | 1:8b8a77b7d715 | 249 | } |
wsquan171 | 1:8b8a77b7d715 | 250 | // Normalize the kernel |
wsquan171 | 1:8b8a77b7d715 | 251 | //pc.printf("Gaussian Kernal in use:\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 252 | for (x = 0; x < W; ++x) |
wsquan171 | 1:8b8a77b7d715 | 253 | { |
wsquan171 | 1:8b8a77b7d715 | 254 | for (y = 0; y < W; ++y) |
wsquan171 | 1:8b8a77b7d715 | 255 | { |
wsquan171 | 1:8b8a77b7d715 | 256 | kernel[x][y] /= sum; |
wsquan171 | 1:8b8a77b7d715 | 257 | //pc.printf("%.7f ", kernel[x][y]); |
wsquan171 | 1:8b8a77b7d715 | 258 | } |
wsquan171 | 1:8b8a77b7d715 | 259 | //pc.printf("\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 260 | } |
wsquan171 | 1:8b8a77b7d715 | 261 | |
wsquan171 | 1:8b8a77b7d715 | 262 | // do matrix convolution |
wsquan171 | 1:8b8a77b7d715 | 263 | matrix_convolution(src, dst, kernel, width); |
wsquan171 | 1:8b8a77b7d715 | 264 | |
wsquan171 | 1:8b8a77b7d715 | 265 | |
wsquan171 | 1:8b8a77b7d715 | 266 | for(i = 0; i < W; i++) |
wsquan171 | 1:8b8a77b7d715 | 267 | free(kernel[i]); |
wsquan171 | 1:8b8a77b7d715 | 268 | free(kernel); |
wsquan171 | 1:8b8a77b7d715 | 269 | return; |
wsquan171 | 1:8b8a77b7d715 | 270 | } |
grein028 | 0:d3bf1776d1c6 | 271 | |
wsquan171 | 1:8b8a77b7d715 | 272 | void myCanny(Image *src, Image *dst, double min_threshold, double max_threshold) |
wsquan171 | 1:8b8a77b7d715 | 273 | { |
wsquan171 | 1:8b8a77b7d715 | 274 | // ref: |
wsquan171 | 1:8b8a77b7d715 | 275 | // http://dasl.mem.drexel.edu/alumni/bGreen/www.pages.drexel.edu/_weg22/can_tut.html |
wsquan171 | 1:8b8a77b7d715 | 276 | // https://en.wikipedia.org/wiki/Canny_edge_detector |
wsquan171 | 1:8b8a77b7d715 | 277 | |
wsquan171 | 1:8b8a77b7d715 | 278 | pc.printf("\r\nCanny Edge Detection Module Invoked\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 279 | |
wsquan171 | 1:8b8a77b7d715 | 280 | dst->rows = src->rows; |
wsquan171 | 1:8b8a77b7d715 | 281 | dst->cols = src->cols; |
wsquan171 | 1:8b8a77b7d715 | 282 | dst->channels = src->channels; |
wsquan171 | 1:8b8a77b7d715 | 283 | dst->data = src->data + (src->rows * src->cols); |
wsquan171 | 1:8b8a77b7d715 | 284 | |
wsquan171 | 1:8b8a77b7d715 | 285 | // de-noise using local Gaussian Blur, simulating size = 5, sigma = 1.4 |
wsquan171 | 1:8b8a77b7d715 | 286 | pc.printf("Smoothing image...\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 287 | double mask[5][5] = |
wsquan171 | 1:8b8a77b7d715 | 288 | { |
wsquan171 | 1:8b8a77b7d715 | 289 | {2, 4, 5, 4, 2}, |
wsquan171 | 1:8b8a77b7d715 | 290 | {4, 9, 12, 9, 4}, |
wsquan171 | 1:8b8a77b7d715 | 291 | {5, 12, 15, 12, 5}, |
wsquan171 | 1:8b8a77b7d715 | 292 | {4, 9, 12, 9, 4}, |
wsquan171 | 1:8b8a77b7d715 | 293 | {2, 4, 5, 4, 2} |
wsquan171 | 1:8b8a77b7d715 | 294 | }; |
wsquan171 | 1:8b8a77b7d715 | 295 | double **kernel; |
wsquan171 | 1:8b8a77b7d715 | 296 | int i, j; |
wsquan171 | 1:8b8a77b7d715 | 297 | kernel = (double **) malloc(5 * sizeof(double *)); |
wsquan171 | 1:8b8a77b7d715 | 298 | for(i = 0; i < 5; i++) |
wsquan171 | 1:8b8a77b7d715 | 299 | kernel[i] = (double *) malloc(5 * sizeof(double)); |
wsquan171 | 1:8b8a77b7d715 | 300 | for(i = 0; i < 5; i++) |
wsquan171 | 1:8b8a77b7d715 | 301 | { |
wsquan171 | 1:8b8a77b7d715 | 302 | for(j = 0; j < 5; j++) |
wsquan171 | 1:8b8a77b7d715 | 303 | { |
wsquan171 | 1:8b8a77b7d715 | 304 | kernel[i][j] = mask[i][j] / 159; |
wsquan171 | 1:8b8a77b7d715 | 305 | //printf("%.7f ", kernel[i][j]); |
wsquan171 | 1:8b8a77b7d715 | 306 | } |
wsquan171 | 1:8b8a77b7d715 | 307 | //printf("\n"); |
wsquan171 | 1:8b8a77b7d715 | 308 | } |
wsquan171 | 1:8b8a77b7d715 | 309 | matrix_convolution(src, dst, kernel, 5); |
wsquan171 | 1:8b8a77b7d715 | 310 | for(i = 0; i < 5; i++) |
wsquan171 | 1:8b8a77b7d715 | 311 | free(kernel[i]); |
wsquan171 | 1:8b8a77b7d715 | 312 | free(kernel); |
wsquan171 | 1:8b8a77b7d715 | 313 | |
wsquan171 | 1:8b8a77b7d715 | 314 | // find gradient x and gradient y |
wsquan171 | 1:8b8a77b7d715 | 315 | pc.printf("Finding gradient in x and y for each pixel...\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 316 | Image Gx, Gy; // Gx and Gy are used to store x-gradient and y-gradient |
wsquan171 | 1:8b8a77b7d715 | 317 | Gx.cols = src->cols; |
wsquan171 | 1:8b8a77b7d715 | 318 | Gx.rows = src->rows; |
wsquan171 | 1:8b8a77b7d715 | 319 | Gx.data = dst->data + (dst->cols * dst->rows); |
wsquan171 | 1:8b8a77b7d715 | 320 | Gy.cols = src->cols; |
wsquan171 | 1:8b8a77b7d715 | 321 | Gy.rows = src->rows; |
wsquan171 | 1:8b8a77b7d715 | 322 | Gy.data = Gx.data + (dst->cols * dst->rows); |
wsquan171 | 1:8b8a77b7d715 | 323 | |
wsquan171 | 1:8b8a77b7d715 | 324 | // size-3 Sobel mask |
wsquan171 | 1:8b8a77b7d715 | 325 | double sobel_x[3][3] = {{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}}; |
wsquan171 | 1:8b8a77b7d715 | 326 | double sobel_y[3][3] = {{-1, -2, -1}, {0, 0, 0}, {1, 2, 1}}; |
wsquan171 | 1:8b8a77b7d715 | 327 | double **mask_x, **mask_y; |
wsquan171 | 1:8b8a77b7d715 | 328 | mask_x = (double **) malloc(3 * sizeof(double *)); |
wsquan171 | 1:8b8a77b7d715 | 329 | for(i = 0; i < 3; i++) |
wsquan171 | 1:8b8a77b7d715 | 330 | mask_x[i] = (double *) malloc(3 * sizeof(double)); |
wsquan171 | 1:8b8a77b7d715 | 331 | mask_y = (double **) malloc(3 * sizeof(double *)); |
wsquan171 | 1:8b8a77b7d715 | 332 | for(i = 0; i < 3; i++) |
wsquan171 | 1:8b8a77b7d715 | 333 | mask_y[i] = (double *) malloc(3 * sizeof(double)); |
wsquan171 | 1:8b8a77b7d715 | 334 | for(i = 0; i < 3; i++) |
wsquan171 | 1:8b8a77b7d715 | 335 | { |
wsquan171 | 1:8b8a77b7d715 | 336 | for(j = 0; j < 3; j++) |
wsquan171 | 1:8b8a77b7d715 | 337 | { |
wsquan171 | 1:8b8a77b7d715 | 338 | mask_x[i][j] = sobel_x[i][j]; |
wsquan171 | 1:8b8a77b7d715 | 339 | mask_y[i][j] = sobel_y[i][j]; |
wsquan171 | 1:8b8a77b7d715 | 340 | } |
wsquan171 | 1:8b8a77b7d715 | 341 | } |
wsquan171 | 1:8b8a77b7d715 | 342 | pc.printf("in x: "); |
wsquan171 | 1:8b8a77b7d715 | 343 | matrix_convolution(src, &Gx, mask_x, 3); |
wsquan171 | 1:8b8a77b7d715 | 344 | pc.printf("in y: "); |
wsquan171 | 1:8b8a77b7d715 | 345 | matrix_convolution(src, &Gy, mask_y, 3); |
wsquan171 | 1:8b8a77b7d715 | 346 | for(i = 0; i < 3; i++) |
wsquan171 | 1:8b8a77b7d715 | 347 | { |
wsquan171 | 1:8b8a77b7d715 | 348 | free(mask_x[i]); |
wsquan171 | 1:8b8a77b7d715 | 349 | free(mask_y[i]); |
wsquan171 | 1:8b8a77b7d715 | 350 | } |
wsquan171 | 1:8b8a77b7d715 | 351 | free(mask_x); |
wsquan171 | 1:8b8a77b7d715 | 352 | free(mask_y); |
wsquan171 | 1:8b8a77b7d715 | 353 | //pc.printf("dst at %d, Gx at %d, Gy at %d\r\n", dst->data, Gx.data, Gy.data); |
wsquan171 | 1:8b8a77b7d715 | 354 | |
wsquan171 | 1:8b8a77b7d715 | 355 | // calculate gradient strength (store in Gx) and direction (store in Gy) |
wsquan171 | 1:8b8a77b7d715 | 356 | pc.printf("Calculating gradient strength and direction...\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 357 | double gx_val, gy_val; |
wsquan171 | 1:8b8a77b7d715 | 358 | double arctan_val; |
wsquan171 | 1:8b8a77b7d715 | 359 | int over_threshold_count = 0; // number used for adaptive non-max suppression |
wsquan171 | 1:8b8a77b7d715 | 360 | uint32_t buffer[src->cols/4]; |
wsquan171 | 1:8b8a77b7d715 | 361 | unsigned char Gx_buf[src->cols], Gy_buf[src->cols]; |
wsquan171 | 1:8b8a77b7d715 | 362 | //pc.printf("%d %d %d %d %d %d", src->rows, src->cols, Gx.cols, Gx.rows, Gy.cols, Gy.rows); |
wsquan171 | 1:8b8a77b7d715 | 363 | for(i = 0; i < src->rows; i++) |
wsquan171 | 1:8b8a77b7d715 | 364 | { |
wsquan171 | 1:8b8a77b7d715 | 365 | sdram.ReadData(i*(Gx.cols) + SDRAM_DEVICE_ADDR + (Gx.data), buffer, Gx.cols/4); |
wsquan171 | 1:8b8a77b7d715 | 366 | for(j = 0; j < Gx.cols/4; j++) |
wsquan171 | 1:8b8a77b7d715 | 367 | { |
wsquan171 | 1:8b8a77b7d715 | 368 | Gx_buf[j*4+3] = buffer[j]; |
wsquan171 | 1:8b8a77b7d715 | 369 | Gx_buf[j*4+2] = buffer[j] >> 8; |
wsquan171 | 1:8b8a77b7d715 | 370 | Gx_buf[j*4+1] = buffer[j] >> 16; |
wsquan171 | 1:8b8a77b7d715 | 371 | Gx_buf[j*4] = buffer[j] >> 24; |
wsquan171 | 1:8b8a77b7d715 | 372 | } |
wsquan171 | 1:8b8a77b7d715 | 373 | sdram.ReadData(i*(Gy.cols) + SDRAM_DEVICE_ADDR + (Gy.data), buffer, Gy.cols/4); |
wsquan171 | 1:8b8a77b7d715 | 374 | for(j = 0; j < Gy.cols/4; j++) |
wsquan171 | 1:8b8a77b7d715 | 375 | { |
wsquan171 | 1:8b8a77b7d715 | 376 | Gy_buf[j*4+3] = buffer[j]; |
wsquan171 | 1:8b8a77b7d715 | 377 | Gy_buf[j*4+2] = buffer[j] >> 8; |
wsquan171 | 1:8b8a77b7d715 | 378 | Gy_buf[j*4+1] = buffer[j] >> 16; |
wsquan171 | 1:8b8a77b7d715 | 379 | Gy_buf[j*4] = buffer[j] >> 24; |
wsquan171 | 1:8b8a77b7d715 | 380 | } |
wsquan171 | 1:8b8a77b7d715 | 381 | |
wsquan171 | 1:8b8a77b7d715 | 382 | for(j = 0; j < src->cols; j++) |
wsquan171 | 1:8b8a77b7d715 | 383 | { |
wsquan171 | 1:8b8a77b7d715 | 384 | gx_val = Gx_buf[j]; |
wsquan171 | 1:8b8a77b7d715 | 385 | gy_val = Gy_buf[j]; |
wsquan171 | 1:8b8a77b7d715 | 386 | |
wsquan171 | 1:8b8a77b7d715 | 387 | Gx_buf[j] = (unsigned char)sqrt(pow(gx_val, 2) + pow(gy_val, 2)); |
wsquan171 | 1:8b8a77b7d715 | 388 | if(Gx_buf[j] > max_threshold) |
wsquan171 | 1:8b8a77b7d715 | 389 | over_threshold_count++; |
wsquan171 | 1:8b8a77b7d715 | 390 | arctan_val = atan(gy_val / gx_val); |
wsquan171 | 1:8b8a77b7d715 | 391 | if(arctan_val >= 0.41421 && arctan_val < 2.414421) // 22.5 to 67.5 deg |
wsquan171 | 1:8b8a77b7d715 | 392 | Gy_buf[j] = 45; |
wsquan171 | 1:8b8a77b7d715 | 393 | else if(arctan_val >= 2.41421 || arctan_val < -2.41421) // 67.5 to 112.5 deg |
wsquan171 | 1:8b8a77b7d715 | 394 | Gy_buf[j] = 90; |
wsquan171 | 1:8b8a77b7d715 | 395 | else if(arctan_val >= -2.41421 && arctan_val < 0.41421) // 112.5 to 157.5 deg |
wsquan171 | 1:8b8a77b7d715 | 396 | Gy_buf[j] = 135; |
wsquan171 | 1:8b8a77b7d715 | 397 | else // 0 to 22.5 and 157.5 to 180 deg |
wsquan171 | 1:8b8a77b7d715 | 398 | Gy_buf[j] = 0; |
wsquan171 | 1:8b8a77b7d715 | 399 | } |
wsquan171 | 1:8b8a77b7d715 | 400 | |
wsquan171 | 1:8b8a77b7d715 | 401 | for(j = 0; j < Gx.cols/4; j++) |
wsquan171 | 1:8b8a77b7d715 | 402 | { |
wsquan171 | 1:8b8a77b7d715 | 403 | buffer[j] = (16777216*Gx_buf[j*4]) + (65536*Gx_buf[j*4+1]) + (Gx_buf[j*4+2]*256) + Gx_buf[j*4+3]; |
wsquan171 | 1:8b8a77b7d715 | 404 | } |
wsquan171 | 1:8b8a77b7d715 | 405 | sdram.WriteData(SDRAM_DEVICE_ADDR + Gx.data + (i*Gx.cols), buffer, Gx.cols/4); |
wsquan171 | 1:8b8a77b7d715 | 406 | for(j = 0; j < Gy.cols/4; j++) |
wsquan171 | 1:8b8a77b7d715 | 407 | { |
wsquan171 | 1:8b8a77b7d715 | 408 | buffer[j] = (16777216*Gy_buf[j*4]) + (65536*Gy_buf[j*4+1]) + (Gy_buf[j*4+2]*256) + Gy_buf[j*4+3]; |
wsquan171 | 1:8b8a77b7d715 | 409 | } |
wsquan171 | 1:8b8a77b7d715 | 410 | sdram.WriteData(SDRAM_DEVICE_ADDR + Gy.data + (i*Gy.cols), buffer, Gy.cols/4); |
wsquan171 | 1:8b8a77b7d715 | 411 | } |
wsquan171 | 1:8b8a77b7d715 | 412 | |
wsquan171 | 1:8b8a77b7d715 | 413 | // Non-maximum suppression. Aim is to shrink the edge width |
wsquan171 | 1:8b8a77b7d715 | 414 | pc.printf("Non-maximum suppression...\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 415 | int mask_radius = 1; // hard-coded parameter |
wsquan171 | 1:8b8a77b7d715 | 416 | int r, c, not_max_flag, vertical_neighbor; |
wsquan171 | 1:8b8a77b7d715 | 417 | Image sup_matrix; // maxtrix used to keep track of local maxima stutas for each pixel |
wsquan171 | 1:8b8a77b7d715 | 418 | sup_matrix.cols = dst->cols; |
wsquan171 | 1:8b8a77b7d715 | 419 | sup_matrix.rows = dst->rows; |
wsquan171 | 1:8b8a77b7d715 | 420 | sup_matrix.data = Gy.data + (dst->cols * dst->rows); |
wsquan171 | 1:8b8a77b7d715 | 421 | double skip_sup_ratio = (double)over_threshold_count/8800; // 10000 pixels should be found in a 800x600 pic |
wsquan171 | 1:8b8a77b7d715 | 422 | if(skip_sup_ratio < 1) |
wsquan171 | 1:8b8a77b7d715 | 423 | skip_sup_ratio = 1; |
wsquan171 | 1:8b8a77b7d715 | 424 | else if(skip_sup_ratio > 1.8) |
wsquan171 | 1:8b8a77b7d715 | 425 | skip_sup_ratio = 1.8; |
wsquan171 | 1:8b8a77b7d715 | 426 | pc.printf("Over max threshold count: %d\r\n", over_threshold_count); |
wsquan171 | 1:8b8a77b7d715 | 427 | //pc.printf("Skip suppression ratio: %.2f\r\n", skip_sup_ratio); |
wsquan171 | 1:8b8a77b7d715 | 428 | unsigned char sup_buf[dst->cols], Gx_buf_array[3][dst->cols], Gy_buf_array[3][dst->cols]; |
wsquan171 | 1:8b8a77b7d715 | 429 | for(i = mask_radius; i < src->rows - mask_radius; i++) |
wsquan171 | 1:8b8a77b7d715 | 430 | { |
wsquan171 | 1:8b8a77b7d715 | 431 | sup_buf[j] = 0; // in sup_matrix, 0 is default value |
wsquan171 | 1:8b8a77b7d715 | 432 | for(r = 0; r < 3; r++) |
wsquan171 | 1:8b8a77b7d715 | 433 | { |
wsquan171 | 1:8b8a77b7d715 | 434 | sdram.ReadData((i+r-1)*(Gx.cols) + SDRAM_DEVICE_ADDR + (Gx.data), buffer, Gx.cols/4); |
wsquan171 | 1:8b8a77b7d715 | 435 | for(j = 0; j < Gx.cols/4; j++) |
wsquan171 | 1:8b8a77b7d715 | 436 | { |
wsquan171 | 1:8b8a77b7d715 | 437 | Gx_buf_array[r][j*4+3] = buffer[j]; |
wsquan171 | 1:8b8a77b7d715 | 438 | Gx_buf_array[r][j*4+2] = buffer[j] >> 8; |
wsquan171 | 1:8b8a77b7d715 | 439 | Gx_buf_array[r][j*4+1] = buffer[j] >> 16; |
wsquan171 | 1:8b8a77b7d715 | 440 | Gx_buf_array[r][j*4] = buffer[j] >> 24; |
wsquan171 | 1:8b8a77b7d715 | 441 | } |
wsquan171 | 1:8b8a77b7d715 | 442 | } |
wsquan171 | 1:8b8a77b7d715 | 443 | for(r = 0; r < 3; r++) |
wsquan171 | 1:8b8a77b7d715 | 444 | { |
wsquan171 | 1:8b8a77b7d715 | 445 | sdram.ReadData((i+r-1)*(Gy.cols) + SDRAM_DEVICE_ADDR + (Gy.data), buffer, Gy.cols/4); |
wsquan171 | 1:8b8a77b7d715 | 446 | for(j = 0; j < Gy.cols/4; j++) |
wsquan171 | 1:8b8a77b7d715 | 447 | { |
wsquan171 | 1:8b8a77b7d715 | 448 | Gy_buf_array[r][j*4+3] = buffer[j]; |
wsquan171 | 1:8b8a77b7d715 | 449 | Gy_buf_array[r][j*4+2] = buffer[j] >> 8; |
wsquan171 | 1:8b8a77b7d715 | 450 | Gy_buf_array[r][j*4+1] = buffer[j] >> 16; |
wsquan171 | 1:8b8a77b7d715 | 451 | Gy_buf_array[r][j*4] = buffer[j] >> 24; |
wsquan171 | 1:8b8a77b7d715 | 452 | } |
wsquan171 | 1:8b8a77b7d715 | 453 | } |
wsquan171 | 1:8b8a77b7d715 | 454 | |
wsquan171 | 1:8b8a77b7d715 | 455 | for(j = mask_radius; j < src->cols - mask_radius; j++) |
wsquan171 | 1:8b8a77b7d715 | 456 | { |
wsquan171 | 1:8b8a77b7d715 | 457 | if( j < mask_radius || (j >= src->rows - mask_radius)) |
wsquan171 | 1:8b8a77b7d715 | 458 | { |
wsquan171 | 1:8b8a77b7d715 | 459 | sup_buf[j] = 1; |
wsquan171 | 1:8b8a77b7d715 | 460 | continue; |
wsquan171 | 1:8b8a77b7d715 | 461 | } |
wsquan171 | 1:8b8a77b7d715 | 462 | not_max_flag = 0; |
wsquan171 | 1:8b8a77b7d715 | 463 | |
wsquan171 | 1:8b8a77b7d715 | 464 | // pixels with significant high magnitute will never be suppressed |
wsquan171 | 1:8b8a77b7d715 | 465 | if(Gx_buf_array[1][j] > 1.8 * max_threshold) |
wsquan171 | 1:8b8a77b7d715 | 466 | { |
wsquan171 | 1:8b8a77b7d715 | 467 | sup_buf[j] = 2; // in sup matrix, 2 means maxima's |
wsquan171 | 1:8b8a77b7d715 | 468 | continue; |
wsquan171 | 1:8b8a77b7d715 | 469 | } |
wsquan171 | 1:8b8a77b7d715 | 470 | |
wsquan171 | 1:8b8a77b7d715 | 471 | // for other pixels, compare its gradient magnitute with its neighbor |
wsquan171 | 1:8b8a77b7d715 | 472 | for(r = -mask_radius; r <= mask_radius; r++) |
wsquan171 | 1:8b8a77b7d715 | 473 | { |
wsquan171 | 1:8b8a77b7d715 | 474 | if(not_max_flag == 1) |
wsquan171 | 1:8b8a77b7d715 | 475 | break; |
wsquan171 | 1:8b8a77b7d715 | 476 | for(c = -mask_radius; c <= mask_radius; c++) |
wsquan171 | 1:8b8a77b7d715 | 477 | { |
wsquan171 | 1:8b8a77b7d715 | 478 | vertical_neighbor = 0; |
wsquan171 | 1:8b8a77b7d715 | 479 | // only neighbors vertical to the gradient direction will be checked |
wsquan171 | 1:8b8a77b7d715 | 480 | switch (Gy_buf_array[1][j]) |
wsquan171 | 1:8b8a77b7d715 | 481 | { |
wsquan171 | 1:8b8a77b7d715 | 482 | case 0: |
wsquan171 | 1:8b8a77b7d715 | 483 | if(c == 0 && (r == -1 || r ==1)) |
wsquan171 | 1:8b8a77b7d715 | 484 | vertical_neighbor = 1; |
wsquan171 | 1:8b8a77b7d715 | 485 | break; |
wsquan171 | 1:8b8a77b7d715 | 486 | case 45: |
wsquan171 | 1:8b8a77b7d715 | 487 | if((r == 1 && c == -1) || (r == -1 && c == 1)) |
wsquan171 | 1:8b8a77b7d715 | 488 | vertical_neighbor = 1; |
wsquan171 | 1:8b8a77b7d715 | 489 | break; |
wsquan171 | 1:8b8a77b7d715 | 490 | case 90: |
wsquan171 | 1:8b8a77b7d715 | 491 | if(r == 0 && (c == -1 || c == 1)) |
wsquan171 | 1:8b8a77b7d715 | 492 | vertical_neighbor = 1; |
wsquan171 | 1:8b8a77b7d715 | 493 | case 135: |
wsquan171 | 1:8b8a77b7d715 | 494 | if((r == 1 && c == 1) || (r == -1 && c == -1)) |
wsquan171 | 1:8b8a77b7d715 | 495 | vertical_neighbor = 1; |
wsquan171 | 1:8b8a77b7d715 | 496 | default: |
wsquan171 | 1:8b8a77b7d715 | 497 | break; |
wsquan171 | 1:8b8a77b7d715 | 498 | } |
wsquan171 | 1:8b8a77b7d715 | 499 | if(vertical_neighbor != 1) |
wsquan171 | 1:8b8a77b7d715 | 500 | continue; |
wsquan171 | 1:8b8a77b7d715 | 501 | |
wsquan171 | 1:8b8a77b7d715 | 502 | if(Gy_buf_array[1][j] == Gy_buf_array[1+r][j+c]) |
wsquan171 | 1:8b8a77b7d715 | 503 | { |
wsquan171 | 1:8b8a77b7d715 | 504 | if(Gx_buf_array[1][j] < Gx_buf_array[1+r][j+c]) |
wsquan171 | 1:8b8a77b7d715 | 505 | { |
wsquan171 | 1:8b8a77b7d715 | 506 | not_max_flag = 1; |
wsquan171 | 1:8b8a77b7d715 | 507 | sup_buf[j] = 1; |
wsquan171 | 1:8b8a77b7d715 | 508 | break; |
wsquan171 | 1:8b8a77b7d715 | 509 | } |
wsquan171 | 1:8b8a77b7d715 | 510 | } |
wsquan171 | 1:8b8a77b7d715 | 511 | } |
wsquan171 | 1:8b8a77b7d715 | 512 | } |
wsquan171 | 1:8b8a77b7d715 | 513 | } |
wsquan171 | 1:8b8a77b7d715 | 514 | |
wsquan171 | 1:8b8a77b7d715 | 515 | for(j = 0; j < sup_matrix.cols/4; j++) |
wsquan171 | 1:8b8a77b7d715 | 516 | { |
wsquan171 | 1:8b8a77b7d715 | 517 | buffer[j] = (16777216*sup_buf[j*4]) + (65536*sup_buf[j*4+1]) + (sup_buf[j*4+2]*256) + sup_buf[j*4+3]; |
wsquan171 | 1:8b8a77b7d715 | 518 | } |
wsquan171 | 1:8b8a77b7d715 | 519 | sdram.WriteData(SDRAM_DEVICE_ADDR + sup_matrix.data + (i*sup_matrix.cols), buffer, sup_matrix.cols/4); |
wsquan171 | 1:8b8a77b7d715 | 520 | } |
wsquan171 | 1:8b8a77b7d715 | 521 | |
wsquan171 | 1:8b8a77b7d715 | 522 | // Gy is no longer used |
wsquan171 | 1:8b8a77b7d715 | 523 | |
wsquan171 | 1:8b8a77b7d715 | 524 | // Double threshold |
wsquan171 | 1:8b8a77b7d715 | 525 | pc.printf("Double threshold...\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 526 | unsigned char dst_buf[dst->cols]; |
wsquan171 | 1:8b8a77b7d715 | 527 | int a = 0, b = 0, d = 0; |
wsquan171 | 1:8b8a77b7d715 | 528 | for(i = 0; i < src->rows; i++) |
wsquan171 | 1:8b8a77b7d715 | 529 | { |
wsquan171 | 1:8b8a77b7d715 | 530 | sdram.ReadData(i*(Gx.cols) + SDRAM_DEVICE_ADDR + (Gx.data), buffer, Gx.cols/4); |
wsquan171 | 1:8b8a77b7d715 | 531 | for(j = 0; j < Gx.cols/4; j++) |
wsquan171 | 1:8b8a77b7d715 | 532 | { |
wsquan171 | 1:8b8a77b7d715 | 533 | Gx_buf[j*4+3] = buffer[j]; |
wsquan171 | 1:8b8a77b7d715 | 534 | Gx_buf[j*4+2] = buffer[j] >> 8; |
wsquan171 | 1:8b8a77b7d715 | 535 | Gx_buf[j*4+1] = buffer[j] >> 16; |
wsquan171 | 1:8b8a77b7d715 | 536 | Gx_buf[j*4] = buffer[j] >> 24; |
wsquan171 | 1:8b8a77b7d715 | 537 | } |
wsquan171 | 1:8b8a77b7d715 | 538 | sdram.ReadData(i*(sup_matrix.cols) + SDRAM_DEVICE_ADDR + (sup_matrix.data), buffer, sup_matrix.cols/4); |
wsquan171 | 1:8b8a77b7d715 | 539 | for(j = 0; j < Gx.cols/4; j++) |
wsquan171 | 1:8b8a77b7d715 | 540 | { |
wsquan171 | 1:8b8a77b7d715 | 541 | sup_buf[j*4+3] = buffer[j]; |
wsquan171 | 1:8b8a77b7d715 | 542 | sup_buf[j*4+2] = buffer[j] >> 8; |
wsquan171 | 1:8b8a77b7d715 | 543 | sup_buf[j*4+1] = buffer[j] >> 16; |
wsquan171 | 1:8b8a77b7d715 | 544 | sup_buf[j*4] = buffer[j] >> 24; |
wsquan171 | 1:8b8a77b7d715 | 545 | } |
wsquan171 | 1:8b8a77b7d715 | 546 | |
wsquan171 | 1:8b8a77b7d715 | 547 | for(j = 0; j < src->cols; j++) |
wsquan171 | 1:8b8a77b7d715 | 548 | { |
wsquan171 | 1:8b8a77b7d715 | 549 | if(i == 0 || j == 0 || i == src->rows-1 || j == src->cols-1) |
wsquan171 | 1:8b8a77b7d715 | 550 | { |
wsquan171 | 1:8b8a77b7d715 | 551 | dst_buf[j] = 0; |
wsquan171 | 1:8b8a77b7d715 | 552 | b++; |
wsquan171 | 1:8b8a77b7d715 | 553 | continue; |
wsquan171 | 1:8b8a77b7d715 | 554 | } |
wsquan171 | 1:8b8a77b7d715 | 555 | if(sup_buf[j] == 1) |
wsquan171 | 1:8b8a77b7d715 | 556 | Gx_buf[j] = 0; |
wsquan171 | 1:8b8a77b7d715 | 557 | if(Gx_buf[j] > max_threshold) // strong edge |
wsquan171 | 1:8b8a77b7d715 | 558 | { |
wsquan171 | 1:8b8a77b7d715 | 559 | dst_buf[j] = 255; |
wsquan171 | 1:8b8a77b7d715 | 560 | a++; |
wsquan171 | 1:8b8a77b7d715 | 561 | } |
wsquan171 | 1:8b8a77b7d715 | 562 | else if(Gx_buf[j] < min_threshold) // weak edge |
wsquan171 | 1:8b8a77b7d715 | 563 | { |
wsquan171 | 1:8b8a77b7d715 | 564 | dst_buf[j] = 0; |
wsquan171 | 1:8b8a77b7d715 | 565 | b++; |
wsquan171 | 1:8b8a77b7d715 | 566 | } |
wsquan171 | 1:8b8a77b7d715 | 567 | else // in middle: later check if it is connected to a strong edge |
wsquan171 | 1:8b8a77b7d715 | 568 | { |
wsquan171 | 1:8b8a77b7d715 | 569 | dst_buf[j] = Gx_buf[j]; |
wsquan171 | 1:8b8a77b7d715 | 570 | d++; |
wsquan171 | 1:8b8a77b7d715 | 571 | } |
wsquan171 | 1:8b8a77b7d715 | 572 | } |
wsquan171 | 1:8b8a77b7d715 | 573 | for(j = 0; j < dst->cols/4; j++) |
wsquan171 | 1:8b8a77b7d715 | 574 | { |
wsquan171 | 1:8b8a77b7d715 | 575 | buffer[j] = (16777216*dst_buf[j*4]) + (65536*dst_buf[j*4+1]) + (dst_buf[j*4+2]*256) + dst_buf[j*4+3]; |
wsquan171 | 1:8b8a77b7d715 | 576 | } |
wsquan171 | 1:8b8a77b7d715 | 577 | sdram.WriteData(SDRAM_DEVICE_ADDR + dst->data + (i*dst->cols), buffer, dst->cols/4); |
wsquan171 | 1:8b8a77b7d715 | 578 | } |
wsquan171 | 1:8b8a77b7d715 | 579 | pc.printf("strong = %d, weak = %d, middle = %d\r\n", a, b, d); |
wsquan171 | 1:8b8a77b7d715 | 580 | |
wsquan171 | 1:8b8a77b7d715 | 581 | int k; |
wsquan171 | 1:8b8a77b7d715 | 582 | // Gx and sup_matrix is no longer used |
wsquan171 | 1:8b8a77b7d715 | 583 | |
wsquan171 | 1:8b8a77b7d715 | 584 | // pixel which has magnitude in-middle will be preserved if connected to a strong edge |
wsquan171 | 1:8b8a77b7d715 | 585 | pc.printf("Edge tracking by hysteresis...\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 586 | short min_neighbor; |
wsquan171 | 1:8b8a77b7d715 | 587 | unsigned char dst_buf_array[3][dst->cols]; |
wsquan171 | 1:8b8a77b7d715 | 588 | for(i = 0; i < 10; i++) |
wsquan171 | 1:8b8a77b7d715 | 589 | { |
wsquan171 | 1:8b8a77b7d715 | 590 | for(j = 1; j < dst->rows-1; j++) |
wsquan171 | 1:8b8a77b7d715 | 591 | { |
wsquan171 | 1:8b8a77b7d715 | 592 | for(r = 0; r < 3; r++) |
wsquan171 | 1:8b8a77b7d715 | 593 | { |
wsquan171 | 1:8b8a77b7d715 | 594 | sdram.ReadData((i+r-1)*(dst->cols) + SDRAM_DEVICE_ADDR + (dst->data), buffer, dst->cols/4); |
wsquan171 | 1:8b8a77b7d715 | 595 | for(k = 0; k < dst->cols/4; k++) |
wsquan171 | 1:8b8a77b7d715 | 596 | { |
wsquan171 | 1:8b8a77b7d715 | 597 | dst_buf_array[r][k*4+3] = buffer[k]; |
wsquan171 | 1:8b8a77b7d715 | 598 | dst_buf_array[r][k*4+2] = buffer[k] >> 8; |
wsquan171 | 1:8b8a77b7d715 | 599 | dst_buf_array[r][k*4+1] = buffer[k] >> 16; |
wsquan171 | 1:8b8a77b7d715 | 600 | dst_buf_array[r][k*4] = buffer[k] >> 24; |
wsquan171 | 1:8b8a77b7d715 | 601 | } |
wsquan171 | 1:8b8a77b7d715 | 602 | } |
wsquan171 | 1:8b8a77b7d715 | 603 | for(k = 1; k < dst->cols - 1; k++) |
wsquan171 | 1:8b8a77b7d715 | 604 | { |
wsquan171 | 1:8b8a77b7d715 | 605 | if(dst_buf_array[1][j] == 0 || dst_buf_array[1][j] == 255) |
wsquan171 | 1:8b8a77b7d715 | 606 | continue; |
wsquan171 | 1:8b8a77b7d715 | 607 | min_neighbor = 0; |
wsquan171 | 1:8b8a77b7d715 | 608 | for(r = -1; r <= 1; r++) |
wsquan171 | 1:8b8a77b7d715 | 609 | { |
wsquan171 | 1:8b8a77b7d715 | 610 | for(c = -1; c <= 1; c++) |
wsquan171 | 1:8b8a77b7d715 | 611 | { |
wsquan171 | 1:8b8a77b7d715 | 612 | if(dst_buf_array[1+r][j+c] > max_threshold) |
wsquan171 | 1:8b8a77b7d715 | 613 | dst_buf_array[1][j] = 255; |
wsquan171 | 1:8b8a77b7d715 | 614 | else if(dst_buf_array[1+r][j+c] < min_threshold) |
wsquan171 | 1:8b8a77b7d715 | 615 | min_neighbor++; |
wsquan171 | 1:8b8a77b7d715 | 616 | } |
wsquan171 | 1:8b8a77b7d715 | 617 | } |
wsquan171 | 1:8b8a77b7d715 | 618 | if(min_neighbor == 8) |
wsquan171 | 1:8b8a77b7d715 | 619 | dst_buf_array[1][j] = 0; |
wsquan171 | 1:8b8a77b7d715 | 620 | } |
wsquan171 | 1:8b8a77b7d715 | 621 | for(k = 0; k < dst->cols/4; k++) |
wsquan171 | 1:8b8a77b7d715 | 622 | { |
wsquan171 | 1:8b8a77b7d715 | 623 | buffer[j] = (16777216*dst_buf_array[1][k*4]) + (65536*dst_buf_array[1][k*4+1]) + (dst_buf_array[1][k*4+2]*256) + dst_buf_array[1][k*4+3]; |
wsquan171 | 1:8b8a77b7d715 | 624 | } |
wsquan171 | 1:8b8a77b7d715 | 625 | sdram.WriteData(SDRAM_DEVICE_ADDR + dst->data + (i*dst->cols), buffer, dst->cols/4); |
wsquan171 | 1:8b8a77b7d715 | 626 | } |
wsquan171 | 1:8b8a77b7d715 | 627 | } |
wsquan171 | 1:8b8a77b7d715 | 628 | |
wsquan171 | 1:8b8a77b7d715 | 629 | // those can't reach to a strong edge in 10 pixels will be supressed |
wsquan171 | 1:8b8a77b7d715 | 630 | for(i = 0; i < src->rows; i++) |
wsquan171 | 1:8b8a77b7d715 | 631 | { |
wsquan171 | 1:8b8a77b7d715 | 632 | sdram.ReadData((i)*(dst->cols) + SDRAM_DEVICE_ADDR + (dst->data), buffer, dst->cols/4); |
wsquan171 | 1:8b8a77b7d715 | 633 | for(k = 0; k < dst->cols/4; k++) |
wsquan171 | 1:8b8a77b7d715 | 634 | { |
wsquan171 | 1:8b8a77b7d715 | 635 | dst_buf[k*4+3] = buffer[k]; |
wsquan171 | 1:8b8a77b7d715 | 636 | dst_buf[k*4+2] = buffer[k] >> 8; |
wsquan171 | 1:8b8a77b7d715 | 637 | dst_buf[k*4+1] = buffer[k] >> 16; |
wsquan171 | 1:8b8a77b7d715 | 638 | dst_buf[k*4] = buffer[k] >> 24; |
wsquan171 | 1:8b8a77b7d715 | 639 | } |
wsquan171 | 1:8b8a77b7d715 | 640 | for(j = 0; j < src->cols; j++) |
wsquan171 | 1:8b8a77b7d715 | 641 | { |
wsquan171 | 1:8b8a77b7d715 | 642 | if((dst_buf[j] == 255) || (dst_buf[j] == 0)) |
wsquan171 | 1:8b8a77b7d715 | 643 | continue; |
wsquan171 | 1:8b8a77b7d715 | 644 | else |
wsquan171 | 1:8b8a77b7d715 | 645 | dst_buf[j] = 0; |
wsquan171 | 1:8b8a77b7d715 | 646 | } |
wsquan171 | 1:8b8a77b7d715 | 647 | for(j = 0; j < dst->cols/4; j++) |
wsquan171 | 1:8b8a77b7d715 | 648 | { |
wsquan171 | 1:8b8a77b7d715 | 649 | buffer[j] = (16777216*dst_buf[j*4]) + (65536*dst_buf[j*4+1]) + (dst_buf[j*4+2]*256) + dst_buf[j*4+3]; |
wsquan171 | 1:8b8a77b7d715 | 650 | } |
wsquan171 | 1:8b8a77b7d715 | 651 | sdram.WriteData(SDRAM_DEVICE_ADDR + dst->data + (i*dst->cols), buffer, dst->cols/4); |
wsquan171 | 1:8b8a77b7d715 | 652 | } |
wsquan171 | 1:8b8a77b7d715 | 653 | |
wsquan171 | 1:8b8a77b7d715 | 654 | int zero = 0, max = 0, in_middle = 0; |
wsquan171 | 1:8b8a77b7d715 | 655 | for(i = 0; i < src->rows; ++i) |
wsquan171 | 1:8b8a77b7d715 | 656 | { |
wsquan171 | 1:8b8a77b7d715 | 657 | |
wsquan171 | 1:8b8a77b7d715 | 658 | sdram.ReadData((i)*(dst->cols) + SDRAM_DEVICE_ADDR + (dst->data), buffer, dst->cols/4); |
wsquan171 | 1:8b8a77b7d715 | 659 | for(k = 0; k < dst->cols/4; k++) |
wsquan171 | 1:8b8a77b7d715 | 660 | { |
wsquan171 | 1:8b8a77b7d715 | 661 | dst_buf[k*4+3] = buffer[k]; |
wsquan171 | 1:8b8a77b7d715 | 662 | dst_buf[k*4+2] = buffer[k] >> 8; |
wsquan171 | 1:8b8a77b7d715 | 663 | dst_buf[k*4+1] = buffer[k] >> 16; |
wsquan171 | 1:8b8a77b7d715 | 664 | dst_buf[k*4] = buffer[k] >> 24; |
wsquan171 | 1:8b8a77b7d715 | 665 | } |
wsquan171 | 1:8b8a77b7d715 | 666 | |
wsquan171 | 1:8b8a77b7d715 | 667 | for ( j = 0; j < src->cols; ++j) |
wsquan171 | 1:8b8a77b7d715 | 668 | { |
wsquan171 | 1:8b8a77b7d715 | 669 | if(dst_buf[j] == 0) |
wsquan171 | 1:8b8a77b7d715 | 670 | zero++; |
wsquan171 | 1:8b8a77b7d715 | 671 | else if(dst_buf[j] == 255) |
wsquan171 | 1:8b8a77b7d715 | 672 | max++; |
wsquan171 | 1:8b8a77b7d715 | 673 | else |
wsquan171 | 1:8b8a77b7d715 | 674 | in_middle++; |
wsquan171 | 1:8b8a77b7d715 | 675 | } |
wsquan171 | 1:8b8a77b7d715 | 676 | } |
wsquan171 | 1:8b8a77b7d715 | 677 | pc.printf("zero = %ld, max = %ld, in_middle = %ld\r\n", zero, max, in_middle); |
wsquan171 | 1:8b8a77b7d715 | 678 | pc.printf("SDRAM peak usage %ld\r\n", sup_matrix.data + (src->cols * src->rows) -1); |
wsquan171 | 1:8b8a77b7d715 | 679 | |
wsquan171 | 1:8b8a77b7d715 | 680 | return; |
wsquan171 | 1:8b8a77b7d715 | 681 | } |
grein028 | 0:d3bf1776d1c6 | 682 | |
wsquan171 | 1:8b8a77b7d715 | 683 | int myHoughLines(Image *src, line_polar *line_list, int threshold, int number) |
wsquan171 | 1:8b8a77b7d715 | 684 | { |
wsquan171 | 1:8b8a77b7d715 | 685 | // ref: |
wsquan171 | 1:8b8a77b7d715 | 686 | // http://www.keymolen.com/2013/05/hough-transformation-c-implementation.html |
wsquan171 | 1:8b8a77b7d715 | 687 | // https://en.wikipedia.org/wiki/Hough_transform |
wsquan171 | 1:8b8a77b7d715 | 688 | |
wsquan171 | 1:8b8a77b7d715 | 689 | pc.printf("\r\nHoughLines Module Invoked\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 690 | |
wsquan171 | 1:8b8a77b7d715 | 691 | // initialize the accumulator for lines. rho and theta are resolutions in distance and angle (all set to 1) |
wsquan171 | 1:8b8a77b7d715 | 692 | unsigned int dimension_r, dimension_t, i, j; |
wsquan171 | 1:8b8a77b7d715 | 693 | //if(src->channels != 1) // only accept grayscal images |
wsquan171 | 1:8b8a77b7d715 | 694 | // return -1; |
wsquan171 | 1:8b8a77b7d715 | 695 | if(src->rows >= src->cols) |
wsquan171 | 1:8b8a77b7d715 | 696 | dimension_r = src->rows; |
wsquan171 | 1:8b8a77b7d715 | 697 | else |
wsquan171 | 1:8b8a77b7d715 | 698 | dimension_r = src->cols; |
wsquan171 | 1:8b8a77b7d715 | 699 | dimension_r = (unsigned int) ((double)dimension_r * sqrt((double)2)) + 1; |
wsquan171 | 1:8b8a77b7d715 | 700 | dimension_t = 360; |
wsquan171 | 1:8b8a77b7d715 | 701 | |
wsquan171 | 1:8b8a77b7d715 | 702 | uint32_t error_count = 0, addr = src->data + (src->rows * src->cols); |
wsquan171 | 1:8b8a77b7d715 | 703 | pc.printf("accumulator start at %ld\r\n", addr-1); |
wsquan171 | 1:8b8a77b7d715 | 704 | uint32_t *accumulator = (uint32_t*)malloc(dimension_t*sizeof(uint32_t)); |
wsquan171 | 1:8b8a77b7d715 | 705 | for(i = 0; i < dimension_r; i++) |
wsquan171 | 1:8b8a77b7d715 | 706 | { |
wsquan171 | 1:8b8a77b7d715 | 707 | for(j = 0; j < dimension_t; j++) |
wsquan171 | 1:8b8a77b7d715 | 708 | accumulator[j] = 0; |
wsquan171 | 1:8b8a77b7d715 | 709 | sdram.WriteData(SDRAM_DEVICE_ADDR + (4*i*dimension_t) + addr, accumulator, dimension_t); |
wsquan171 | 1:8b8a77b7d715 | 710 | } |
wsquan171 | 1:8b8a77b7d715 | 711 | for(i = 0; i < dimension_r;i++) |
wsquan171 | 1:8b8a77b7d715 | 712 | { |
wsquan171 | 1:8b8a77b7d715 | 713 | sdram.ReadData(SDRAM_DEVICE_ADDR + (4*i*dimension_t) + addr, accumulator, dimension_t); |
wsquan171 | 1:8b8a77b7d715 | 714 | for(j = 0; j < dimension_t; j++) |
wsquan171 | 1:8b8a77b7d715 | 715 | { |
wsquan171 | 1:8b8a77b7d715 | 716 | if(accumulator[j] != 0) |
wsquan171 | 1:8b8a77b7d715 | 717 | { |
wsquan171 | 1:8b8a77b7d715 | 718 | error_count++; |
wsquan171 | 1:8b8a77b7d715 | 719 | } |
wsquan171 | 1:8b8a77b7d715 | 720 | } |
wsquan171 | 1:8b8a77b7d715 | 721 | } |
wsquan171 | 1:8b8a77b7d715 | 722 | pc.printf("error_count = %ld\r\n", error_count); |
wsquan171 | 1:8b8a77b7d715 | 723 | |
wsquan171 | 1:8b8a77b7d715 | 724 | pc.printf("Accumulator dimension: %d(rho) by %d(theta)\r\n", dimension_r, dimension_t); |
wsquan171 | 1:8b8a77b7d715 | 725 | |
wsquan171 | 1:8b8a77b7d715 | 726 | // scan through all edge pixels. |
wsquan171 | 1:8b8a77b7d715 | 727 | int t, neg_r = 0, round_up = 0, round_down = 0, pixel_count = 0; |
wsquan171 | 1:8b8a77b7d715 | 728 | double new_x, new_y, theta_rad, r; |
wsquan171 | 1:8b8a77b7d715 | 729 | unsigned char src_buf[src->cols]; |
wsquan171 | 1:8b8a77b7d715 | 730 | uint32_t buffer[src->cols/4], tmp_accu; |
wsquan171 | 1:8b8a77b7d715 | 731 | |
wsquan171 | 1:8b8a77b7d715 | 732 | for(i = 0; i < src->rows; i++) |
wsquan171 | 1:8b8a77b7d715 | 733 | { |
wsquan171 | 1:8b8a77b7d715 | 734 | sdram.ReadData(i*(src->cols) + SDRAM_DEVICE_ADDR + (src->data), buffer, src->cols/4); |
wsquan171 | 1:8b8a77b7d715 | 735 | for(j = 0; j < src->cols/4; j++) |
wsquan171 | 1:8b8a77b7d715 | 736 | { |
wsquan171 | 1:8b8a77b7d715 | 737 | src_buf[j*4+3] = buffer[j]; |
wsquan171 | 1:8b8a77b7d715 | 738 | src_buf[j*4+2] = buffer[j] >> 8; |
wsquan171 | 1:8b8a77b7d715 | 739 | src_buf[j*4+1] = buffer[j] >> 16; |
wsquan171 | 1:8b8a77b7d715 | 740 | src_buf[j*4] = buffer[j] >> 24; |
wsquan171 | 1:8b8a77b7d715 | 741 | } |
wsquan171 | 1:8b8a77b7d715 | 742 | for(j = 0; j < src->cols; j++) |
wsquan171 | 1:8b8a77b7d715 | 743 | { |
wsquan171 | 1:8b8a77b7d715 | 744 | if(src_buf[j] != 255) // only consider edge pixels (who have value of 255) |
wsquan171 | 1:8b8a77b7d715 | 745 | continue; |
wsquan171 | 1:8b8a77b7d715 | 746 | pixel_count++; |
wsquan171 | 1:8b8a77b7d715 | 747 | for(t = 0; t < dimension_t; t++) // for each theta, calc the corresponding rho |
wsquan171 | 1:8b8a77b7d715 | 748 | { |
wsquan171 | 1:8b8a77b7d715 | 749 | new_x = (double)i; |
wsquan171 | 1:8b8a77b7d715 | 750 | new_y = (double)j; |
wsquan171 | 1:8b8a77b7d715 | 751 | theta_rad = (double)t * (M_PI / 180); |
wsquan171 | 1:8b8a77b7d715 | 752 | r = (new_y * cos(theta_rad)) + (new_x * sin(theta_rad)); |
wsquan171 | 1:8b8a77b7d715 | 753 | |
wsquan171 | 1:8b8a77b7d715 | 754 | if(r <= 0) // negative rho = positive rho, they are duplicated lines that can be discarded |
wsquan171 | 1:8b8a77b7d715 | 755 | { |
wsquan171 | 1:8b8a77b7d715 | 756 | neg_r++; |
wsquan171 | 1:8b8a77b7d715 | 757 | continue; |
wsquan171 | 1:8b8a77b7d715 | 758 | } |
wsquan171 | 1:8b8a77b7d715 | 759 | |
wsquan171 | 1:8b8a77b7d715 | 760 | if( r - (int)r >= 0.5) // round up to the bin |
wsquan171 | 1:8b8a77b7d715 | 761 | { |
wsquan171 | 1:8b8a77b7d715 | 762 | round_up++; |
wsquan171 | 1:8b8a77b7d715 | 763 | sdram.ReadData(4*dimension_t*((int)r +1) + SDRAM_DEVICE_ADDR + (addr) + (4*t), &tmp_accu, 1); |
wsquan171 | 1:8b8a77b7d715 | 764 | tmp_accu++; |
wsquan171 | 1:8b8a77b7d715 | 765 | if(tmp_accu > 503640) |
wsquan171 | 1:8b8a77b7d715 | 766 | printf("(%d, %d)\r\n", (int)r +1, t); |
wsquan171 | 1:8b8a77b7d715 | 767 | sdram.WriteData(4*dimension_t*((int)r +1) + SDRAM_DEVICE_ADDR + (addr) + (4*t), &tmp_accu, 1); |
wsquan171 | 1:8b8a77b7d715 | 768 | } |
wsquan171 | 1:8b8a77b7d715 | 769 | else // round down to the bin |
wsquan171 | 1:8b8a77b7d715 | 770 | { |
wsquan171 | 1:8b8a77b7d715 | 771 | round_down++; |
wsquan171 | 1:8b8a77b7d715 | 772 | sdram.ReadData(4*dimension_t*((int)r) + SDRAM_DEVICE_ADDR + (addr) + (4*t), &tmp_accu, 1); |
wsquan171 | 1:8b8a77b7d715 | 773 | tmp_accu++; |
wsquan171 | 1:8b8a77b7d715 | 774 | sdram.WriteData(4*dimension_t*((int)r) + SDRAM_DEVICE_ADDR + (addr) + (4*t), &tmp_accu, 1); |
wsquan171 | 1:8b8a77b7d715 | 775 | } |
wsquan171 | 1:8b8a77b7d715 | 776 | } |
wsquan171 | 1:8b8a77b7d715 | 777 | } |
wsquan171 | 1:8b8a77b7d715 | 778 | j = src->rows / 10; |
wsquan171 | 1:8b8a77b7d715 | 779 | if(i%j == 0) |
wsquan171 | 1:8b8a77b7d715 | 780 | pc.printf("%d%%...",i/j*10); |
wsquan171 | 1:8b8a77b7d715 | 781 | } |
wsquan171 | 1:8b8a77b7d715 | 782 | pc.printf("\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 783 | pc.printf("negatve rho = %d\r\nround up = %d, round down = %d\r\n", neg_r, round_up, round_down); |
wsquan171 | 1:8b8a77b7d715 | 784 | pc.printf("pixel count = %d\r\n", pixel_count); |
wsquan171 | 1:8b8a77b7d715 | 785 | // find top x lines in rho-theta space |
wsquan171 | 1:8b8a77b7d715 | 786 | int weakest = 0, count = 0, weakest_pt = 0; |
wsquan171 | 1:8b8a77b7d715 | 787 | line_polar local_line_list[number]; |
wsquan171 | 1:8b8a77b7d715 | 788 | for(i = 0; i < dimension_r; i++) |
wsquan171 | 1:8b8a77b7d715 | 789 | { |
wsquan171 | 1:8b8a77b7d715 | 790 | sdram.ReadData(4*i*dimension_t + SDRAM_DEVICE_ADDR + (addr), accumulator, dimension_t); |
wsquan171 | 1:8b8a77b7d715 | 791 | for(j = 0; j < dimension_t; j++) |
wsquan171 | 1:8b8a77b7d715 | 792 | { |
wsquan171 | 1:8b8a77b7d715 | 793 | if(accumulator[j] < threshold || accumulator[j] <= weakest) |
wsquan171 | 1:8b8a77b7d715 | 794 | continue; |
wsquan171 | 1:8b8a77b7d715 | 795 | |
wsquan171 | 1:8b8a77b7d715 | 796 | local_line_list[weakest_pt].rho = i; |
wsquan171 | 1:8b8a77b7d715 | 797 | local_line_list[weakest_pt].theta = j; |
wsquan171 | 1:8b8a77b7d715 | 798 | sdram.ReadData(4*dimension_t*i + SDRAM_DEVICE_ADDR + (addr) + (4*j), &tmp_accu, 1); |
wsquan171 | 1:8b8a77b7d715 | 799 | local_line_list[weakest_pt].strength = tmp_accu; |
wsquan171 | 1:8b8a77b7d715 | 800 | count++; |
wsquan171 | 1:8b8a77b7d715 | 801 | |
wsquan171 | 1:8b8a77b7d715 | 802 | if(count < number) |
wsquan171 | 1:8b8a77b7d715 | 803 | { |
wsquan171 | 1:8b8a77b7d715 | 804 | weakest_pt++; |
wsquan171 | 1:8b8a77b7d715 | 805 | weakest = 0; |
wsquan171 | 1:8b8a77b7d715 | 806 | } |
wsquan171 | 1:8b8a77b7d715 | 807 | else |
wsquan171 | 1:8b8a77b7d715 | 808 | { |
wsquan171 | 1:8b8a77b7d715 | 809 | weakest = local_line_list[0].strength; |
wsquan171 | 1:8b8a77b7d715 | 810 | weakest_pt = 0; |
wsquan171 | 1:8b8a77b7d715 | 811 | for(t = 1; t < number; t++) |
wsquan171 | 1:8b8a77b7d715 | 812 | { |
wsquan171 | 1:8b8a77b7d715 | 813 | if(local_line_list[t].strength < weakest) |
wsquan171 | 1:8b8a77b7d715 | 814 | { |
wsquan171 | 1:8b8a77b7d715 | 815 | weakest = local_line_list[t].strength; |
wsquan171 | 1:8b8a77b7d715 | 816 | weakest_pt = t; |
wsquan171 | 1:8b8a77b7d715 | 817 | } |
wsquan171 | 1:8b8a77b7d715 | 818 | } |
wsquan171 | 1:8b8a77b7d715 | 819 | } |
wsquan171 | 1:8b8a77b7d715 | 820 | } |
wsquan171 | 1:8b8a77b7d715 | 821 | } |
wsquan171 | 1:8b8a77b7d715 | 822 | |
wsquan171 | 1:8b8a77b7d715 | 823 | // copy those found lines baack to main's stack |
wsquan171 | 1:8b8a77b7d715 | 824 | memcpy(line_list, local_line_list, number*sizeof(line_polar)); |
wsquan171 | 1:8b8a77b7d715 | 825 | |
wsquan171 | 1:8b8a77b7d715 | 826 | for(i = 0; i < number; i++) |
wsquan171 | 1:8b8a77b7d715 | 827 | { |
wsquan171 | 1:8b8a77b7d715 | 828 | if(count == i) |
wsquan171 | 1:8b8a77b7d715 | 829 | break; |
wsquan171 | 1:8b8a77b7d715 | 830 | printf("line %d: rho = %d, theta = %d, strength = %d\r\n", i, local_line_list[i].rho, local_line_list[i].theta, local_line_list[i].strength); |
wsquan171 | 1:8b8a77b7d715 | 831 | } |
wsquan171 | 1:8b8a77b7d715 | 832 | printf("\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 833 | free(accumulator); |
wsquan171 | 1:8b8a77b7d715 | 834 | // return the actual number of lines found above threshold |
wsquan171 | 1:8b8a77b7d715 | 835 | return count; |
wsquan171 | 1:8b8a77b7d715 | 836 | } |
wsquan171 | 1:8b8a77b7d715 | 837 | |
wsquan171 | 1:8b8a77b7d715 | 838 | int det(ptvec a, ptvec b) |
wsquan171 | 1:8b8a77b7d715 | 839 | { |
wsquan171 | 1:8b8a77b7d715 | 840 | return (a.x * b.y) - (a.y * b.x); |
wsquan171 | 1:8b8a77b7d715 | 841 | } |
wsquan171 | 1:8b8a77b7d715 | 842 | |
wsquan171 | 1:8b8a77b7d715 | 843 | int line_intersection(trans_line line1, trans_line line2, ptvec *result) |
wsquan171 | 1:8b8a77b7d715 | 844 | { |
wsquan171 | 1:8b8a77b7d715 | 845 | ptvec xdiff, ydiff, d; |
wsquan171 | 1:8b8a77b7d715 | 846 | xdiff.x = line1.ptvec1.x - line1.ptvec2.x; |
wsquan171 | 1:8b8a77b7d715 | 847 | xdiff.y = line2.ptvec1.x - line2.ptvec2.x; |
wsquan171 | 1:8b8a77b7d715 | 848 | ydiff.x = line1.ptvec1.y - line1.ptvec2.y; |
wsquan171 | 1:8b8a77b7d715 | 849 | ydiff.y = line2.ptvec1.y - line2.ptvec2.y; |
wsquan171 | 1:8b8a77b7d715 | 850 | |
wsquan171 | 1:8b8a77b7d715 | 851 | int div = det(xdiff, ydiff); |
wsquan171 | 1:8b8a77b7d715 | 852 | if(div == 0) |
wsquan171 | 1:8b8a77b7d715 | 853 | { |
wsquan171 | 1:8b8a77b7d715 | 854 | // Lines don't intersect |
wsquan171 | 1:8b8a77b7d715 | 855 | return 0; |
wsquan171 | 1:8b8a77b7d715 | 856 | } |
wsquan171 | 1:8b8a77b7d715 | 857 | |
wsquan171 | 1:8b8a77b7d715 | 858 | d.x = det(line1.ptvec1, line1.ptvec2); |
wsquan171 | 1:8b8a77b7d715 | 859 | d.y = det(line2.ptvec1, line2.ptvec2); |
wsquan171 | 1:8b8a77b7d715 | 860 | result->x = (int) det(d, xdiff) / div; |
wsquan171 | 1:8b8a77b7d715 | 861 | result->y = (int) det(d, ydiff) / div; |
wsquan171 | 1:8b8a77b7d715 | 862 | return 1; |
wsquan171 | 1:8b8a77b7d715 | 863 | } |
wsquan171 | 1:8b8a77b7d715 | 864 | |
wsquan171 | 1:8b8a77b7d715 | 865 | double LineAnalysis(trans_line *line_list, int line_count, int dim_x, int dim_y) |
wsquan171 | 1:8b8a77b7d715 | 866 | { |
wsquan171 | 1:8b8a77b7d715 | 867 | printf("Needle Position Detection Module Invoked.\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 868 | int strongest_pt = 0, i = 0, j = 0, upper_count = 0, lower_count = 0; |
wsquan171 | 1:8b8a77b7d715 | 869 | int upper_bin[line_count]; |
wsquan171 | 1:8b8a77b7d715 | 870 | int lower_bin[line_count]; |
wsquan171 | 1:8b8a77b7d715 | 871 | double average_deg = 0, diff, theta_deg; |
wsquan171 | 1:8b8a77b7d715 | 872 | |
wsquan171 | 1:8b8a77b7d715 | 873 | // find the line with highest confidence |
wsquan171 | 1:8b8a77b7d715 | 874 | for(i = 0; i < line_count; i++) |
wsquan171 | 1:8b8a77b7d715 | 875 | { |
wsquan171 | 1:8b8a77b7d715 | 876 | if(line_list[i].strength > line_list[strongest_pt].strength) |
wsquan171 | 1:8b8a77b7d715 | 877 | strongest_pt = i; |
wsquan171 | 1:8b8a77b7d715 | 878 | } |
wsquan171 | 1:8b8a77b7d715 | 879 | printf("Line used as reference of de-noise: rho = %d, ", (int)line_list[strongest_pt].rho); |
wsquan171 | 1:8b8a77b7d715 | 880 | printf("theta = %d\r\n", (int) (line_list[strongest_pt].theta * 180 / M_PI)); |
wsquan171 | 1:8b8a77b7d715 | 881 | |
wsquan171 | 1:8b8a77b7d715 | 882 | // delete lines whose theta varies > 10 deg from the strongest line |
wsquan171 | 1:8b8a77b7d715 | 883 | for(i = 0; i < line_count; i++) |
wsquan171 | 1:8b8a77b7d715 | 884 | { |
wsquan171 | 1:8b8a77b7d715 | 885 | diff = 180 * line_list[strongest_pt].theta / M_PI; |
wsquan171 | 1:8b8a77b7d715 | 886 | diff = diff - (180 * line_list[i].theta / M_PI); |
wsquan171 | 1:8b8a77b7d715 | 887 | if(diff >= 10 || diff <= -10) |
wsquan171 | 1:8b8a77b7d715 | 888 | { |
wsquan171 | 1:8b8a77b7d715 | 889 | printf("Line with confidence of %d is suppressed.\r\n", line_list[i].strength); |
wsquan171 | 1:8b8a77b7d715 | 890 | line_list[i].strength = 0; |
wsquan171 | 1:8b8a77b7d715 | 891 | continue; |
wsquan171 | 1:8b8a77b7d715 | 892 | } |
wsquan171 | 1:8b8a77b7d715 | 893 | average_deg = (180 * line_list[i].theta / M_PI) + average_deg; |
wsquan171 | 1:8b8a77b7d715 | 894 | j++; |
wsquan171 | 1:8b8a77b7d715 | 895 | } |
wsquan171 | 1:8b8a77b7d715 | 896 | average_deg = average_deg / j; |
wsquan171 | 1:8b8a77b7d715 | 897 | printf("Theta used to divide lines into bins: %.2f\r\n", average_deg); |
wsquan171 | 1:8b8a77b7d715 | 898 | |
wsquan171 | 1:8b8a77b7d715 | 899 | // categorize all lines into 2 bins depends on whether its theta is higher than average. |
wsquan171 | 1:8b8a77b7d715 | 900 | for(i = 0; i < line_count; i++) |
wsquan171 | 1:8b8a77b7d715 | 901 | { |
wsquan171 | 1:8b8a77b7d715 | 902 | if(line_list[i].strength == 0) |
wsquan171 | 1:8b8a77b7d715 | 903 | continue; |
wsquan171 | 1:8b8a77b7d715 | 904 | |
wsquan171 | 1:8b8a77b7d715 | 905 | theta_deg = line_list[i].theta * 180 / M_PI; |
wsquan171 | 1:8b8a77b7d715 | 906 | if(theta_deg > average_deg) |
wsquan171 | 1:8b8a77b7d715 | 907 | { |
wsquan171 | 1:8b8a77b7d715 | 908 | upper_bin[upper_count] = i; |
wsquan171 | 1:8b8a77b7d715 | 909 | upper_count++; |
wsquan171 | 1:8b8a77b7d715 | 910 | } |
wsquan171 | 1:8b8a77b7d715 | 911 | else |
wsquan171 | 1:8b8a77b7d715 | 912 | { |
wsquan171 | 1:8b8a77b7d715 | 913 | lower_bin[lower_count] = i; |
wsquan171 | 1:8b8a77b7d715 | 914 | lower_count++; |
wsquan171 | 1:8b8a77b7d715 | 915 | } |
wsquan171 | 1:8b8a77b7d715 | 916 | } |
wsquan171 | 1:8b8a77b7d715 | 917 | |
wsquan171 | 1:8b8a77b7d715 | 918 | // choose the bin with minority of lines. |
wsquan171 | 1:8b8a77b7d715 | 919 | // find a line in the bin with highest / lowest theta if we chose upper / lower bin |
wsquan171 | 1:8b8a77b7d715 | 920 | // the chosen line is considered as the line mostly diverted from the other lines but yet near needle |
wsquan171 | 1:8b8a77b7d715 | 921 | // find all intersections between this line and the lines in the bin with majority of lines |
wsquan171 | 1:8b8a77b7d715 | 922 | // since this line is well seperated from others, points found should be far enough from gauge center |
wsquan171 | 1:8b8a77b7d715 | 923 | int ref_pt = 0, inter_count = 0; |
wsquan171 | 1:8b8a77b7d715 | 924 | ptvec intersect_list[line_count]; |
wsquan171 | 1:8b8a77b7d715 | 925 | if(lower_count < upper_count) |
wsquan171 | 1:8b8a77b7d715 | 926 | { |
wsquan171 | 1:8b8a77b7d715 | 927 | for(i = 0; i < lower_count; i++) |
wsquan171 | 1:8b8a77b7d715 | 928 | { |
wsquan171 | 1:8b8a77b7d715 | 929 | if(line_list[lower_bin[i]].theta < line_list[lower_bin[ref_pt]].theta) |
wsquan171 | 1:8b8a77b7d715 | 930 | ref_pt = i; |
wsquan171 | 1:8b8a77b7d715 | 931 | } |
wsquan171 | 1:8b8a77b7d715 | 932 | average_deg = (180 * line_list[lower_bin[ref_pt]].theta / M_PI); |
wsquan171 | 1:8b8a77b7d715 | 933 | printf("Line in lower_bin is used to find intersections:\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 934 | printf("rho = %d, ", (int) (line_list[lower_bin[ref_pt]].rho)); |
wsquan171 | 1:8b8a77b7d715 | 935 | printf("theta = %d ", (int) (line_list[lower_bin[ref_pt]].theta * 180 / (M_PI))); |
wsquan171 | 1:8b8a77b7d715 | 936 | printf("strength = %d\r\n", (int) (line_list[lower_bin[ref_pt]].strength)); |
wsquan171 | 1:8b8a77b7d715 | 937 | for(i = 0; i < upper_count; i++) |
wsquan171 | 1:8b8a77b7d715 | 938 | { |
wsquan171 | 1:8b8a77b7d715 | 939 | if(line_intersection(line_list[lower_bin[ref_pt]], line_list[upper_bin[i]], &intersect_list[inter_count]) == 1) |
wsquan171 | 1:8b8a77b7d715 | 940 | inter_count++; |
wsquan171 | 1:8b8a77b7d715 | 941 | } |
wsquan171 | 1:8b8a77b7d715 | 942 | ref_pt = 0; |
wsquan171 | 1:8b8a77b7d715 | 943 | for(i = 0; i < upper_count; i++) |
wsquan171 | 1:8b8a77b7d715 | 944 | { |
wsquan171 | 1:8b8a77b7d715 | 945 | if(line_list[upper_bin[i]].theta > line_list[upper_bin[ref_pt]].theta) |
wsquan171 | 1:8b8a77b7d715 | 946 | ref_pt = i; |
wsquan171 | 1:8b8a77b7d715 | 947 | } |
wsquan171 | 1:8b8a77b7d715 | 948 | average_deg = (180 * line_list[upper_bin[ref_pt]].theta / M_PI) + average_deg; |
wsquan171 | 1:8b8a77b7d715 | 949 | average_deg = average_deg / 2; |
wsquan171 | 1:8b8a77b7d715 | 950 | } |
wsquan171 | 1:8b8a77b7d715 | 951 | else |
wsquan171 | 1:8b8a77b7d715 | 952 | { |
wsquan171 | 1:8b8a77b7d715 | 953 | for(i = 0; i < upper_count; i++) |
wsquan171 | 1:8b8a77b7d715 | 954 | { |
wsquan171 | 1:8b8a77b7d715 | 955 | if(line_list[upper_bin[i]].theta > line_list[upper_bin[ref_pt]].theta) |
wsquan171 | 1:8b8a77b7d715 | 956 | ref_pt = i; |
wsquan171 | 1:8b8a77b7d715 | 957 | } |
wsquan171 | 1:8b8a77b7d715 | 958 | average_deg = (180 * line_list[upper_bin[ref_pt]].theta / M_PI); |
wsquan171 | 1:8b8a77b7d715 | 959 | printf("Line in upper_bin is used to find intersections:\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 960 | printf("rho = %d, ", (int) (line_list[upper_bin[ref_pt]].rho)); |
wsquan171 | 1:8b8a77b7d715 | 961 | printf("theta = %d ", (int) (line_list[upper_bin[ref_pt]].theta * 180 / (M_PI))); |
wsquan171 | 1:8b8a77b7d715 | 962 | printf("strength = %d\r\n", (int) (line_list[upper_bin[ref_pt]].strength)); |
wsquan171 | 1:8b8a77b7d715 | 963 | for(i = 0; i < lower_count; i++) |
wsquan171 | 1:8b8a77b7d715 | 964 | { |
wsquan171 | 1:8b8a77b7d715 | 965 | if(line_intersection(line_list[upper_bin[ref_pt]], line_list[lower_bin[i]], &intersect_list[inter_count]) == 1) |
wsquan171 | 1:8b8a77b7d715 | 966 | inter_count++; |
wsquan171 | 1:8b8a77b7d715 | 967 | } |
wsquan171 | 1:8b8a77b7d715 | 968 | ref_pt = 0; |
wsquan171 | 1:8b8a77b7d715 | 969 | for(i = 0; i < lower_count; i++) |
wsquan171 | 1:8b8a77b7d715 | 970 | { |
wsquan171 | 1:8b8a77b7d715 | 971 | if(line_list[lower_bin[i]].theta < line_list[lower_bin[ref_pt]].theta) |
wsquan171 | 1:8b8a77b7d715 | 972 | ref_pt = i; |
wsquan171 | 1:8b8a77b7d715 | 973 | } |
wsquan171 | 1:8b8a77b7d715 | 974 | average_deg = (180 * line_list[lower_bin[ref_pt]].theta / M_PI) + average_deg; |
wsquan171 | 1:8b8a77b7d715 | 975 | average_deg = average_deg / 2; |
wsquan171 | 1:8b8a77b7d715 | 976 | } |
wsquan171 | 1:8b8a77b7d715 | 977 | |
wsquan171 | 1:8b8a77b7d715 | 978 | // categorize all intersections points into 4 bins |
wsquan171 | 1:8b8a77b7d715 | 979 | // ----------------> x |
wsquan171 | 1:8b8a77b7d715 | 980 | // | | |
wsquan171 | 1:8b8a77b7d715 | 981 | // | III | IV |
wsquan171 | 1:8b8a77b7d715 | 982 | // | | |
wsquan171 | 1:8b8a77b7d715 | 983 | // |--------------- |
wsquan171 | 1:8b8a77b7d715 | 984 | // | | |
wsquan171 | 1:8b8a77b7d715 | 985 | // | II | I |
wsquan171 | 1:8b8a77b7d715 | 986 | // v | |
wsquan171 | 1:8b8a77b7d715 | 987 | // y |
wsquan171 | 1:8b8a77b7d715 | 988 | // the reason is that the center of the pic should be close to the center of the gauge. |
wsquan171 | 1:8b8a77b7d715 | 989 | // the angle of the needle is already detected. we don't need actually find the center |
wsquan171 | 1:8b8a77b7d715 | 990 | // to tell the direction of the needle. the distribution of intersections can provide |
wsquan171 | 1:8b8a77b7d715 | 991 | // enough info to do the desicion. |
wsquan171 | 1:8b8a77b7d715 | 992 | |
wsquan171 | 1:8b8a77b7d715 | 993 | int cor_count[4] = {0, 0, 0, 0}; |
wsquan171 | 1:8b8a77b7d715 | 994 | int var_x = 0, var_y = 0; |
wsquan171 | 1:8b8a77b7d715 | 995 | printf("Intersections:\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 996 | for(i = 0; i < inter_count; i++) |
wsquan171 | 1:8b8a77b7d715 | 997 | { |
wsquan171 | 1:8b8a77b7d715 | 998 | if(intersect_list[i].x > dim_x /2) |
wsquan171 | 1:8b8a77b7d715 | 999 | { |
wsquan171 | 1:8b8a77b7d715 | 1000 | if(intersect_list[i].y > dim_y/2) |
wsquan171 | 1:8b8a77b7d715 | 1001 | cor_count[0]++; |
wsquan171 | 1:8b8a77b7d715 | 1002 | else |
wsquan171 | 1:8b8a77b7d715 | 1003 | cor_count[3]++; |
wsquan171 | 1:8b8a77b7d715 | 1004 | } |
wsquan171 | 1:8b8a77b7d715 | 1005 | else |
wsquan171 | 1:8b8a77b7d715 | 1006 | { |
wsquan171 | 1:8b8a77b7d715 | 1007 | if(intersect_list[i].y > dim_y/2) |
wsquan171 | 1:8b8a77b7d715 | 1008 | cor_count[1]++; |
wsquan171 | 1:8b8a77b7d715 | 1009 | else |
wsquan171 | 1:8b8a77b7d715 | 1010 | cor_count[2]++; |
wsquan171 | 1:8b8a77b7d715 | 1011 | } |
wsquan171 | 1:8b8a77b7d715 | 1012 | var_x = var_x + abs(intersect_list[i].x - dim_x/2); |
wsquan171 | 1:8b8a77b7d715 | 1013 | var_y = var_y + abs(intersect_list[i].y - dim_y/2); |
wsquan171 | 1:8b8a77b7d715 | 1014 | printf("(%d, %d)\r\n", intersect_list[i].x, intersect_list[i].y); |
wsquan171 | 1:8b8a77b7d715 | 1015 | } |
wsquan171 | 1:8b8a77b7d715 | 1016 | printf("Variation in x: %d, in y: %d\r\n", var_x, var_y); |
wsquan171 | 1:8b8a77b7d715 | 1017 | |
wsquan171 | 1:8b8a77b7d715 | 1018 | int most_cor_pt = 0; |
wsquan171 | 1:8b8a77b7d715 | 1019 | printf("Intersection points distribution: \r\n"); |
wsquan171 | 1:8b8a77b7d715 | 1020 | for(i = 0; i < 4; i++) |
wsquan171 | 1:8b8a77b7d715 | 1021 | { |
wsquan171 | 1:8b8a77b7d715 | 1022 | if(cor_count[i] > cor_count[most_cor_pt]) |
wsquan171 | 1:8b8a77b7d715 | 1023 | most_cor_pt = i; |
wsquan171 | 1:8b8a77b7d715 | 1024 | printf("Cor %d: %d\r\n", i+1, cor_count[i]); |
wsquan171 | 1:8b8a77b7d715 | 1025 | } |
wsquan171 | 1:8b8a77b7d715 | 1026 | |
wsquan171 | 1:8b8a77b7d715 | 1027 | int correct_vote = 0, revert_vote = 0; |
wsquan171 | 1:8b8a77b7d715 | 1028 | if(average_deg >= 0 && average_deg < 90) // intersections are expected to be in II or IV |
wsquan171 | 1:8b8a77b7d715 | 1029 | { |
wsquan171 | 1:8b8a77b7d715 | 1030 | if(var_x < var_y) // variance in x is smaller, I+II should > III+IV |
wsquan171 | 1:8b8a77b7d715 | 1031 | { |
wsquan171 | 1:8b8a77b7d715 | 1032 | if((cor_count[0]+cor_count[1]) > (cor_count[2]+cor_count[3])) |
wsquan171 | 1:8b8a77b7d715 | 1033 | correct_vote++; |
wsquan171 | 1:8b8a77b7d715 | 1034 | else |
wsquan171 | 1:8b8a77b7d715 | 1035 | revert_vote++; |
wsquan171 | 1:8b8a77b7d715 | 1036 | } |
wsquan171 | 1:8b8a77b7d715 | 1037 | else // variance in y is smaller, II+III should > IV+I |
wsquan171 | 1:8b8a77b7d715 | 1038 | { |
wsquan171 | 1:8b8a77b7d715 | 1039 | if((cor_count[1]+cor_count[2]) > (cor_count[3]+cor_count[0])) |
wsquan171 | 1:8b8a77b7d715 | 1040 | correct_vote++; |
wsquan171 | 1:8b8a77b7d715 | 1041 | else |
wsquan171 | 1:8b8a77b7d715 | 1042 | revert_vote++; |
wsquan171 | 1:8b8a77b7d715 | 1043 | } |
wsquan171 | 1:8b8a77b7d715 | 1044 | if(correct_vote > revert_vote) |
wsquan171 | 1:8b8a77b7d715 | 1045 | printf("Original detected angle is correct.\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 1046 | else |
wsquan171 | 1:8b8a77b7d715 | 1047 | { |
wsquan171 | 1:8b8a77b7d715 | 1048 | average_deg = average_deg + 180; |
wsquan171 | 1:8b8a77b7d715 | 1049 | printf("Reverted angle is correct.\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 1050 | } |
wsquan171 | 1:8b8a77b7d715 | 1051 | } |
wsquan171 | 1:8b8a77b7d715 | 1052 | else if(average_deg >= 90 && average_deg < 180) // intersections are expected to be in III or I |
wsquan171 | 1:8b8a77b7d715 | 1053 | { |
wsquan171 | 1:8b8a77b7d715 | 1054 | if(var_x < var_y) // variance in x is smaller, I+II should < III+IV |
wsquan171 | 1:8b8a77b7d715 | 1055 | { |
wsquan171 | 1:8b8a77b7d715 | 1056 | if((cor_count[0]+cor_count[1]) < (cor_count[2]+cor_count[3])) |
wsquan171 | 1:8b8a77b7d715 | 1057 | correct_vote++; |
wsquan171 | 1:8b8a77b7d715 | 1058 | else |
wsquan171 | 1:8b8a77b7d715 | 1059 | revert_vote++; |
wsquan171 | 1:8b8a77b7d715 | 1060 | } |
wsquan171 | 1:8b8a77b7d715 | 1061 | else // variance in y is smaller, II+III should > IV+I |
wsquan171 | 1:8b8a77b7d715 | 1062 | { |
wsquan171 | 1:8b8a77b7d715 | 1063 | if((cor_count[1]+cor_count[2]) > (cor_count[3]+cor_count[0])) |
wsquan171 | 1:8b8a77b7d715 | 1064 | correct_vote++; |
wsquan171 | 1:8b8a77b7d715 | 1065 | else |
wsquan171 | 1:8b8a77b7d715 | 1066 | revert_vote++; |
wsquan171 | 1:8b8a77b7d715 | 1067 | } |
wsquan171 | 1:8b8a77b7d715 | 1068 | if(correct_vote > revert_vote) |
wsquan171 | 1:8b8a77b7d715 | 1069 | printf("Original detected angle is correct.\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 1070 | else |
wsquan171 | 1:8b8a77b7d715 | 1071 | { |
wsquan171 | 1:8b8a77b7d715 | 1072 | average_deg = average_deg + 180; |
wsquan171 | 1:8b8a77b7d715 | 1073 | printf("Reverted angle is correct.\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 1074 | } |
wsquan171 | 1:8b8a77b7d715 | 1075 | } |
wsquan171 | 1:8b8a77b7d715 | 1076 | else if(average_deg >= 180 && average_deg < 270) // intersections are expected to be in II or IV |
wsquan171 | 1:8b8a77b7d715 | 1077 | { |
wsquan171 | 1:8b8a77b7d715 | 1078 | if(var_x < var_y) // variance in x is smaller, I+II should < III+IV |
wsquan171 | 1:8b8a77b7d715 | 1079 | { |
wsquan171 | 1:8b8a77b7d715 | 1080 | if((cor_count[0]+cor_count[1]) < (cor_count[2]+cor_count[3])) |
wsquan171 | 1:8b8a77b7d715 | 1081 | correct_vote++; |
wsquan171 | 1:8b8a77b7d715 | 1082 | else |
wsquan171 | 1:8b8a77b7d715 | 1083 | revert_vote++; |
wsquan171 | 1:8b8a77b7d715 | 1084 | } |
wsquan171 | 1:8b8a77b7d715 | 1085 | else // variance in y is smaller, II+III should < IV+I |
wsquan171 | 1:8b8a77b7d715 | 1086 | { |
wsquan171 | 1:8b8a77b7d715 | 1087 | if((cor_count[1]+cor_count[2]) < (cor_count[3]+cor_count[0])) |
wsquan171 | 1:8b8a77b7d715 | 1088 | correct_vote++; |
wsquan171 | 1:8b8a77b7d715 | 1089 | else |
wsquan171 | 1:8b8a77b7d715 | 1090 | revert_vote++; |
wsquan171 | 1:8b8a77b7d715 | 1091 | } |
wsquan171 | 1:8b8a77b7d715 | 1092 | if(correct_vote > revert_vote) |
wsquan171 | 1:8b8a77b7d715 | 1093 | printf("Original detected angle is correct.\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 1094 | else |
wsquan171 | 1:8b8a77b7d715 | 1095 | { |
wsquan171 | 1:8b8a77b7d715 | 1096 | average_deg = average_deg - 180; |
wsquan171 | 1:8b8a77b7d715 | 1097 | printf("Reverted angle is correct.\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 1098 | } |
wsquan171 | 1:8b8a77b7d715 | 1099 | } |
wsquan171 | 1:8b8a77b7d715 | 1100 | else if(average_deg >= 270 && average_deg < 360) // intersections are expected to be in III or I |
wsquan171 | 1:8b8a77b7d715 | 1101 | { |
wsquan171 | 1:8b8a77b7d715 | 1102 | if(var_x < var_y) // variance in x is smaller, I+II should > III+IV |
wsquan171 | 1:8b8a77b7d715 | 1103 | { |
wsquan171 | 1:8b8a77b7d715 | 1104 | if((cor_count[0]+cor_count[1]) > (cor_count[2]+cor_count[3])) |
wsquan171 | 1:8b8a77b7d715 | 1105 | correct_vote++; |
wsquan171 | 1:8b8a77b7d715 | 1106 | else |
wsquan171 | 1:8b8a77b7d715 | 1107 | revert_vote++; |
wsquan171 | 1:8b8a77b7d715 | 1108 | } |
wsquan171 | 1:8b8a77b7d715 | 1109 | else // variance in y is smaller, II+III should < IV+I |
wsquan171 | 1:8b8a77b7d715 | 1110 | { |
wsquan171 | 1:8b8a77b7d715 | 1111 | if((cor_count[1]+cor_count[2]) < (cor_count[3]+cor_count[0])) |
wsquan171 | 1:8b8a77b7d715 | 1112 | correct_vote++; |
wsquan171 | 1:8b8a77b7d715 | 1113 | else |
wsquan171 | 1:8b8a77b7d715 | 1114 | revert_vote++; |
wsquan171 | 1:8b8a77b7d715 | 1115 | } |
wsquan171 | 1:8b8a77b7d715 | 1116 | if(correct_vote > revert_vote) |
wsquan171 | 1:8b8a77b7d715 | 1117 | printf("Original detected angle is correct.\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 1118 | else |
wsquan171 | 1:8b8a77b7d715 | 1119 | { |
wsquan171 | 1:8b8a77b7d715 | 1120 | average_deg = average_deg - 180; |
wsquan171 | 1:8b8a77b7d715 | 1121 | printf("Reverted angle is correct.\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 1122 | } |
wsquan171 | 1:8b8a77b7d715 | 1123 | } |
wsquan171 | 1:8b8a77b7d715 | 1124 | else |
wsquan171 | 1:8b8a77b7d715 | 1125 | { |
wsquan171 | 1:8b8a77b7d715 | 1126 | printf("Detection failed. The result may not be correct.\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 1127 | } |
wsquan171 | 1:8b8a77b7d715 | 1128 | return average_deg; |
wsquan171 | 1:8b8a77b7d715 | 1129 | } |
wsquan171 | 1:8b8a77b7d715 | 1130 | |
wsquan171 | 1:8b8a77b7d715 | 1131 | |
wsquan171 | 1:8b8a77b7d715 | 1132 | int main(void) |
wsquan171 | 1:8b8a77b7d715 | 1133 | { |
wsquan171 | 1:8b8a77b7d715 | 1134 | pc.baud(115200); |
wsquan171 | 1:8b8a77b7d715 | 1135 | int i, j; |
wsquan171 | 1:8b8a77b7d715 | 1136 | led_red = 0; |
wsquan171 | 1:8b8a77b7d715 | 1137 | led_green = 0; |
wsquan171 | 1:8b8a77b7d715 | 1138 | |
wsquan171 | 1:8b8a77b7d715 | 1139 | FMC_SDRAM_CommandTypeDef SDRAMCommandStructure; |
grein028 | 0:d3bf1776d1c6 | 1140 | SDRAMCommandStructure.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2; |
wsquan171 | 1:8b8a77b7d715 | 1141 | |
wsquan171 | 1:8b8a77b7d715 | 1142 | pc.printf("\r\nSDRAM demo started\r\n"); |
wsquan171 | 1:8b8a77b7d715 | 1143 | |
wsquan171 | 1:8b8a77b7d715 | 1144 | Image src, dst, bin; |
wsquan171 | 1:8b8a77b7d715 | 1145 | if (bmpread("/sd/1.bmp", &src) == 0) |
wsquan171 | 1:8b8a77b7d715 | 1146 | return 0; |
wsquan171 | 1:8b8a77b7d715 | 1147 | |
wsquan171 | 1:8b8a77b7d715 | 1148 | // smooth the picture using GaussianBlur: void GaussianBlur(Image *src, Image *dst, int width, double sigma) |
wsquan171 | 1:8b8a77b7d715 | 1149 | myGaussianBlur(&src, &dst, 5, 1.5); |
wsquan171 | 1:8b8a77b7d715 | 1150 | myCanny(&dst, &bin, 20, 60); |
wsquan171 | 1:8b8a77b7d715 | 1151 | line_polar my_line_list[10]; |
wsquan171 | 1:8b8a77b7d715 | 1152 | int line_count; |
wsquan171 | 1:8b8a77b7d715 | 1153 | line_count = myHoughLines(&bin, my_line_list, 40, line_limit); |
wsquan171 | 1:8b8a77b7d715 | 1154 | if(line_count >= line_limit) |
wsquan171 | 1:8b8a77b7d715 | 1155 | line_count = line_limit; |
wsquan171 | 1:8b8a77b7d715 | 1156 | |
wsquan171 | 1:8b8a77b7d715 | 1157 | trans_line line_list[line_limit]; |
wsquan171 | 1:8b8a77b7d715 | 1158 | unsigned int m = src.rows, n = src.cols; |
wsquan171 | 1:8b8a77b7d715 | 1159 | for(i = 0; i < line_count; i++) // combined for loops at #64, #73, #83, #92, #101 |
grein028 | 0:d3bf1776d1c6 | 1160 | { |
wsquan171 | 1:8b8a77b7d715 | 1161 | line_list[i].rho = my_line_list[i].rho; |
wsquan171 | 1:8b8a77b7d715 | 1162 | line_list[i].theta = my_line_list[i].theta * (M_PI / 180); |
wsquan171 | 1:8b8a77b7d715 | 1163 | line_list[i].strength = my_line_list[i].strength; |
wsquan171 | 1:8b8a77b7d715 | 1164 | line_list[i].a = cos(line_list[i].theta); |
wsquan171 | 1:8b8a77b7d715 | 1165 | line_list[i].b = sin(line_list[i].theta); |
wsquan171 | 1:8b8a77b7d715 | 1166 | line_list[i].x0 = line_list[i].a * line_list[i].rho; |
wsquan171 | 1:8b8a77b7d715 | 1167 | line_list[i].y0 = line_list[i].b * line_list[i].rho; |
wsquan171 | 1:8b8a77b7d715 | 1168 | line_list[i].ptvec1.x = Round(line_list[i].x0 + (m+n)*(-line_list[i].b)); |
wsquan171 | 1:8b8a77b7d715 | 1169 | line_list[i].ptvec1.y = Round(line_list[i].y0 + (m+n)*line_list[i].a); |
wsquan171 | 1:8b8a77b7d715 | 1170 | line_list[i].ptvec2.x = Round(line_list[i].x0 - (m+n)*(-line_list[i].b)); |
wsquan171 | 1:8b8a77b7d715 | 1171 | line_list[i].ptvec2.y = Round(line_list[i].y0 - (m+n)*line_list[i].a); |
grein028 | 0:d3bf1776d1c6 | 1172 | } |
grein028 | 0:d3bf1776d1c6 | 1173 | |
wsquan171 | 1:8b8a77b7d715 | 1174 | double angle = LineAnalysis(line_list, line_count, src.cols, src.rows); |
wsquan171 | 1:8b8a77b7d715 | 1175 | double value = (angle - 42) / 270 * 50; |
wsquan171 | 1:8b8a77b7d715 | 1176 | pc.printf("Detected angle = %.2f\r\nEstimated value = %.2f\r\n", angle, value); |
grein028 | 0:d3bf1776d1c6 | 1177 | } |