// see https://nanonets.com/blog/optical-flow/ srecord noeq GoodThingsToTrack(BWImage image) { settable int windowSize = 3; settable double scoreFactor = 1/255.0; gettable BWImage outputImage; run { int w = image.getWidth(), h = image.getHeight(); int wn = windowSize*windowSize; outputImage = new BWImage(w, h); for (int y = 0; y < h-windowSize-1; y++) { for (int x = 0; x < w-windowSize-1; x++) { double[] ix = new[wn]; double[] iy = new[wn]; int iw = 0; for yy to windowSize: for xx to windowSize: { double value = image.getInt(x+xx, y+yy); double right = image.getInt(x+xx+1, y+yy); double below = image.getInt(x+xx, y+yy+1); ix[iw] = right-value; iy[iw] = below-value; iw++; } double sideSum = 0; for i to wn: sideSum += ix[i]*iy[i]; double xSum = 0; for i to wn: xSum += sqr(ix[i]); double ySum = 0; for i to wn: ySum += sqr(iy[i]); double[][] matrix = new double[][] { { xSum, sideSum }, { sideSum, ySum } }; Complex[] lambdas = eigenvaluesOfSymmetricMatrix(matrix); if (l(lambdas) == 2) { double score = min(abs(lambdas[0]), abs(lambdas[1])); outputImage.setInt(x+windowSize/2, y+windowSize/2, iround(score*scoreFactor)); } } } } }