Skip to content

Instantly share code, notes, and snippets.

@daveshah1
Created November 28, 2019 20:00
Show Gist options
  • Save daveshah1/4111eba3477511257f17c5a16b6c0265 to your computer and use it in GitHub Desktop.
Save daveshah1/4111eba3477511257f17c5a16b6c0265 to your computer and use it in GitHub Desktop.
elasticc examples
// Harris
block harris(clock<rising,126e6>, enable, unsigned<6>[3] input) => (unsigned<6>[3] output) {
/*convert image to greyscale*/
stream2d<unsigned<6>, 7, 7, 1024> greyscale;
greyscale << ((input[0] + input[1] + input[2]) / 3);
/*obtain x and y derivatives*/
/*signed<7>[5][5] mx = {{0, 1, 0, -1, 0},
{2, 20, 0, -20, -2},
{5, 55, 0, -55, -5},
{2, 20, 0, -20, -2},
{0, 1, 0, -1, 0}};
signed<7>[5][5] my = {{0, 2, 5, 2, 0},
{1, 20, 55, 20, 1},
{0, 0, 0, 0, 0},
{-1, -20, -55, -20, -1},
{0, -2, -5, -2, 0}};*/
signed<8>[7][7] mx = {{0, 1, 1, 0, -1 ,-1 ,0},
{1, 6, 11, 0, -11, -6, -1},
{4, 22, 41, 0, -41, -22, -4},
{5, 34, 64, 0, -64, -34, -5},
{4, 22, 41, 0, -41, -22, -4},
{1, 6, 11, 0, -11, -6, -1},
{0, 1, 1, 0, -1, -1, 0}};
signed<8>[7][7] my = {{0, 1, 4, 5, 4, 1, 0},
{1, 6, 22, 34, 22, 6, 1},
{1, 11, 41, 64, 41, 11, 1},
{0, 0, 0, 0, 0, 0, 0},
{-1, -11, -41, -64, -41, -11, -1},
{-1, -6, -22, -34, -22, -6, -1},
{0, -1, -4, -5, -4, -1, 0}};
signed<20> sx = 0;
signed<20> sy = 0;
int j, k;
for(j = 0; j != 7; j++) {
for(k = 0; k != 7; k++) {
sx += greyscale[j][k] * mx[j][k];
sy += greyscale[j][k] * my[j][k];
}
}
if(sx < 0) {
sx = 0-sx;
}
if(sy < 0) {
sy = 0-sy;
}
unsigned<6> Ix, Iy;
if(sx > 4095) {
Ix = 63;
} else {
Ix = sx >> 6;
}
if(sy > 4095) {
Iy = 63;
} else {
Iy = sy >> 6;
}
/*Obtain Ixx, Ixy and Iyy, then filter them with a 3x3 Gaussian filter kernel
to obtain Wxx, Wxy and Wyy*/
stream2d<unsigned<6>, 3, 3, 1024> Ixx, Ixy, Iyy;
Ixx << ((Ix * Ix) >> 6);
Ixy << ((Ix * Iy) >> 6);
Iyy << ((Iy * Iy) >> 6);
unsigned<3>[3][3] mg = {{1, 2, 1},
{2, 4, 2},
{1, 2, 1}};
unsigned<10> sum_Ixx = 0, sum_Ixy = 0, sum_Iyy = 0;
for(j = 0; j != 3; j++) {
for(k = 0; k != 3; k++) {
sum_Ixx += Ixx[j][k] * mg[j][k];
sum_Ixy += Ixy[j][k] * mg[j][k];
sum_Iyy += Iyy[j][k] * mg[j][k];
}
}
unsigned<8> Wxx = (sum_Ixx >> 2), Wxy = (sum_Ixy >> 2), Wyy = (sum_Iyy >> 2);
/*The harris detection itself*/
signed<17> Wdet = (Wxx*Wyy) - (Wxy*Wxy);
unsigned<12> Wdmag = Wdet;
if(Wdet < 0) {
Wdmag = 0 - Wdet;
}
unsigned<7> N = Wdmag >> 5;
unsigned<9> Wtr = Wxx + Wyy;
unsigned<15> Wtr2 = (Wtr * Wtr);
signed<16> R = Wdet - Wtr2 * 2;
unsigned<6> harris = R / 16;
if(R < 0) {
harris = 0;
}
if(R > 1023) {
harris = 63;
}
/*output harris value*/
for(j = 0; j != 3; j++) {
output[j] = harris;
}
}
// Canny
#include "libelastic/convolution.h"
#include "libelastic/math.h"
#include "libelastic/pixel_types.h"
//arctan2, returning 0==0deg, 1==45deg, 2==90deg, 3==135deg
unsigned<2> atan2_rounded(signed<8> y, signed<8> x) {
unsigned<2> res = 0;
bool quad_2 = false;
if(x < 0) {
quad_2 = true;
x = 0 - x;
}
if(y < 0) {
quad_2 = ~quad_2;
y = 0 - y;
}
if(x >= (2 * y)) {
res = 0;
} else {
if(y >= (2 * x)) {
if(quad_2) {
res = 3;
} else {
res = 2;
}
} else {
res = 1;
}
}
return res;
}
bool should_suppress(unsigned<2>[3][3] angles, unsigned<8>[3][3] mags) {
bool is_valid;
if(angles[1][1] == 0) {
is_valid = ((mags[1][1] > mags[1][0]) && (mags[1][1] > mags[1][2]));
} else {
if(angles[1][1] == 1) {
is_valid = ((mags[1][1] > mags[0][2]) && (mags[1][1] > mags[2][0]));
} else {
if(angles[1][1] == 2) {
is_valid = ((mags[1][1] > mags[0][1]) && (mags[1][1] > mags[2][1]));
} else {
is_valid = ((mags[1][1] > mags[0][0]) && (mags[1][1] > mags[2][2]));
}
}
}
return !is_valid;
}
bool apply_hysteresis(unsigned<2>[3][3] thresholded) {
int i, j;
bool valid = false;
if(thresholded[1][1] >= 1) {
for(i = 0; i < 3; i++) {
for(j = 0; j < 3; j++) {
if(thresholded[i][j] == 2) {
valid = true;
}
}
}
}
return valid;
}
block canny_edge(clock<rising, 84e6>, enable, RGB666 input) => (RGB666 output) {
//this stream is used to delay the colour values
stream2d<unsigned<2>, 11, 11, 1024> colour;
if((input.R > (input.G + input.G / 2)) && (input.R > (input.B + input.B / 2)) && (input.R > 10)) {
colour << 1;
} else {
if((input.G > (input.R + input.R / 2)) && (input.G > (input.B + input.B / 2)) && (input.G > 10)) {
colour << 2;
} else {
if((input.B > (input.R + input.R / 2)) && (input.B > (input.G + input.G / 2)) && (input.B > 10)) {
colour << 3;
} else {
colour << 0;
}
}
}
stream2d<unsigned<6>, 5, 5, 1024> greyscale;
greyscale << to_greyscale(input);
stream2d<unsigned<6>, 3, 3, 1024> filtered;
filtered << (convolute_5x5(greyscale, gaussian_5x5) / 256);
signed<8> sobel_h = convolute_3x3(filtered, sobel_horizontal_3x3);
signed<8> sobel_v = convolute_3x3(filtered, sobel_vertical_3x3);
unsigned<2> theta = atan2_rounded(sobel_v, sobel_h);
unsigned<8> mag = (abs(sobel_v) + abs(sobel_h));
stream2d<unsigned<2>, 3, 3, 1024> angles;
stream2d<unsigned<8>, 3, 3, 1024> mags;
angles << theta;
mags << mag;
unsigned<8> suppressed;
if(should_suppress(angles, mags)) {
suppressed = 0;
} else {
suppressed = mags[1][1];
}
//0=N/A, 1=weak, 2=strong
stream2d<unsigned<2>, 3, 3, 1024> comp;
unsigned<8> weak = 10;
unsigned<8> strong = 15;
if(suppressed >= strong) {
comp << 2;
} else {
if(suppressed >= weak) {
comp << 1;
} else {
comp << 0;
}
}
bool hist = apply_hysteresis(comp);
from_monochrome(hist, output); //default to white
if((colour[7][7] == 1) || (colour[10][10] == 1)) { //red
output.G = 0;
output.B = 0;
}
if((colour[7][7] == 2) || (colour[10][10] == 2)) {
output.R = 0;
output.B = 0;
}
if((colour[7][7] == 3) || (colour[10][10] == 3)) {
output.R = 0;
output.G = 0;
}
}
// Debayering
#include "libelastic/pixel_types.h"
#include "libelastic/math.h"
block debayer(clock<rising, 212e6>, enable, register unsigned<12> x, register unsigned<12> y,
register bool hsync_in, register bool vsync_in, register bool disp_in, register unsigned<8> pixel_in)
=> (register RGB888 pixel_out, register bool hsync_out,
register bool vsync_out, register bool disp_out) {
stream2d<unsigned<8>, 3, 3, 4046> pixel_region;
pixel_region << pixel_in;
RGB888 pixel;
pixel.R = 0;
pixel.G = 0;
pixel.B = 0;
if((x & 0x01) == 1) {
if((y & 0x01) == 1) {
pixel.R = pixel_region[1][1];
pixel.G = (pixel_region[0][1] + pixel_region[1][0] + pixel_region[1][2] + pixel_region[2][1]) / 4;
pixel.B = (pixel_region[0][0] + pixel_region[0][2] + pixel_region[2][0] + pixel_region[2][2]) / 4;
} else {
pixel.R = (pixel_region[0][1] + pixel_region[2][1]) / 2;
pixel.G = (pixel_region[1][1]);
pixel.B = (pixel_region[1][0] + pixel_region[1][2]) / 2;
}
} else {
if((y & 0x01) == 1) {
pixel.R = (pixel_region[1][0] + pixel_region[1][2]) / 2;
pixel.G = (pixel_region[1][1]);
pixel.B = (pixel_region[0][1] + pixel_region[2][1]) / 2;
} else {
pixel.R = (pixel_region[0][0] + pixel_region[0][2] + pixel_region[2][0] + pixel_region[2][2]) / 4;
pixel.G = (pixel_region[0][1] + pixel_region[1][0] + pixel_region[1][2] + pixel_region[2][1]) / 4;
pixel.B = pixel_region[1][1];
}
}
pixel_out.R = clamp((pixel.R * 9) / 8, 255);
pixel_out.G = pixel.G;
pixel_out.B = clamp((pixel.B * 9) / 8, 255);
disp_out = disp_in;
hsync_out = hsync_in;
vsync_out = vsync_in;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment