# taken from Libor Masek over Dietmar Planitzer
import config, image, vector, util, algo3/fft

complex *def gabor_convolve(V *data, int w, h, nscales, double min_wavelength,
    mult, sigmaOnf):
    int nrows = h
    int ncols = w

    complex *E0 = ALLOCATE(nscales * nrows * ncols * sizeof *E0)

    double filter[ncols]
    for int i = 0; i < ncols; i++: filter[i] = 0
    int ndata_half = ncols / 2
    double radius[ndata_half + 1]
    for int i = 0; i <= ndata_half; i++:
        radius[i] = 0.5 * i / ndata_half
    radius[0] = 1

    complex signal[ncols]
    double wavelength = min_wavelength

    for int s = 0; s < nscales; s++:
        double fo = 1.0 / wavelength

        for int i = 0; i <= ndata_half; i++:
            double alpha = log(radius[i] / fo)
            double beta = log(sigmaOnf)
            filter[i] = exp(-(alpha * alpha) / (2 * beta * beta))
        filter[0] = 0

        for int r = 0; r < nrows; r++:
            for int i = 0; i < ncols; i++:
                signal[i] = data[r * w + i]
            complex imagefft[ncols]
            fft(ncols, signal, imagefft)
            for int i = 0; i < ncols; i++:
                imagefft[i] *= filter[i]
            ifft(ncols, imagefft, E0 + s * nrows * ncols + r * ncols)
        wavelength *= mult
    return E0

Vector *def algo3(Image *texture, Image *mask_image, char const *what):
    int M = 5
    int N = 10
    int w = texture->w
    # Downscale by M in vertical direction, so we get N 1-D signals s.
    int mask[N * w]
    V s[N * w]
    for int x = 0; x < w; x++:
        for int i = 0; i < N; i++:
            int m = 0
            V sum = 0
            for int j = 0; j < M; j++:
                sum += texture->data.b[(j + i * M) * w + x]
                m += mask_image->data.b[(j + i * M) * w + x]
            s[i * w + x] = sum / M
            mask[i * w + x] = m ? 1 : 0

    # normalize the signals from 0..255 to -1..1 range, probably not necessary
    for int i = 0; i < N; i++:
        for int j = 0; j < w; j++:
            s[i * w + j] /= 255.0
            s[i * w + j] -= 0.5

    int nscales = 1
    double min_wavelength = 36
    double mult = 1.0
    double sigmaOnf = 0.5

    int h = N
    complex *E0 = gabor_convolve(s, w, h, nscales, min_wavelength, mult, sigmaOnf)
    int height = h * 2 * nscales

    uint8_t *code = ALLOCATE0(2 * w * height / 8)
    uint8_t *mcode = code + w * height / 8
    int rowpos = 0
    int rowlen = w / 8

    for int k = 0; k < nscales; k++:
        complex *E1 = E0 + w * h * k
        for int y = 0; y < h; y++:
            int codepos = 0, bitpos = 0
            for int x = 0; x < w; x++:
                complex c = E1[y * w + x]
                bool H1 = creal(c) > 0
                bool H2 = cimag(c) > 0
                bool H3 = cabs(c) < 0.0001
                bool MASK = mask[x + w * y] != 0
                MASK |= H3

                if H1: code[rowpos + codepos] |= 1 << bitpos
                if H2: code[rowpos + rowlen + codepos] |= 1 << bitpos
                if MASK:
                    mcode[rowpos + codepos] |= 1 << bitpos
                    mcode[rowpos + rowlen + codepos] |= 1 << bitpos

                bitpos++
                if bitpos == 8:
                    bitpos = 0
                    codepos++
            rowpos += rowlen * 2

    Vector *cv = vector_new(1)
    vector_cat(cv, code, 2 * w * height / 8)
    FREE(code)
    FREE(E0)
    return cv