Brain Plasticity!

Over the past 2 days, I spent about eight hours building a custom vision improving application. Modeled after RevitalVision and UltimEyes, this application is entirely web based.

These products defy intuition by improving our vision without directly affecting our eyes. At the foundation of these technologies, is the idea that our brains are always plastic - flexible and able to adapt and change. By presenting challenging and new visual patterns, our brains get challenged and flex. With enough practice, your vision can noticibly improve.

Building the app utilized a lot of Math I haven't used in ages, which made it extra enjoyable. Some of that math related to the score and level building systems; but most of it dealt with the image generation.

To create visual stimuli, optometrists can use an image known as a Gabor Patch. This image is built using sinusoids and gaussian fading to create a very subtly alternative wave pattern. As these patterns grow smaller and finer, they also become harder for our eyes and brain to process.

To build my own gabor patches, I ported some python code into javascript. This involved implementing some python library functions in JS, like linspace, meshgrid, and others. Originally, I built every function, including a Matrix exponential helper function. But, even on V8, doing all that math in JS is still too slow. Matrix exponentials are a extremely complex computation, involving integrals, factorials, and powers approaching infinity. Unfortunately, that resultant function is drastically too slow to work in real time, and I needed to find an alternative algorithm.

Because the gaussian was static throughout the application, the application could use a cached solution. Rather than calculating the gaussian every time (~30sec+ operation, even when greedily computed), I stored the solution data in an application-wide image. When needed, I convert that image to a matrix of the required size, and continued with the gabor algorithm.

//use an image for the gaussian, because the math is too slow;  
ctx.drawImage(this.gaussian,0,0,size,size);  
var gauss=[];  
for(var i=0;i<Xm.length;i++){  
    grating[i]=[];  
    gauss[i]=[];  
    for(var j=0;j<Xm[i].length;j++){  
        grating[i][j]=Math.sin((Xm[i][j]*Math.cos(thetaRad)+Ym[i][j]*Math.sin(thetaRad))*freq*2*Math.PI+phaseRad);  
        gauss[i][j]=ctx.getImageData(i, j, 1, 1).data[0]/255;  
    }  
}

This was one of the coolest weekday projects I've ever built - largely because it has such a tangibly productive outcome. Unfortunately, I'm not sure if the app would infringe any patents, so it will remain private and unused until I can know for sure. If it doesnt't break any patent laws, I hope to work with some of my optometry friends in the future to test the science behind it. #neuralplasticity!