     fscanf(src, "%d\n", &ignored);
 
     int pixels = source.width * source.height;
+    int imageSize = source.width * source.height * sizeof(unsigned char);
     source.img = (unsigned char *)malloc(pixels*3);
     if (fread(source.img, sizeof(unsigned char), pixels*3, src) != pixels*3)
     {

};

    __global__
void filter(unsigned char *grayScale, unsigned char *filtered)
{
    // @TODO Make this a variable somehow
    __shared__ unsigned char cache[32][32];

    int tid = (blockIdx.x * gridDim.y * blockDim.x * blockDim.y) + (blockIdx.y * blockDim.x * blockDim.y) + (threadIdx.x * blockDim.y) + threadIdx.y;

    int i = tid % WIDTH;
    int j = tid / WIDTH;

    if (i <= 0 || i >= WIDTH - 1 || j <= 0 || j >= HEIGHT - 1)
    {
        return;
    }

    int gradX = tex2D(imageTex, i-1, j+1) - tex2D(imageTex, i-1, j-1) + 2*tex2D(imageTex, i, j+1) - 2*tex2D(imageTex, i, j-1) + tex2D(imageTex, i+1, j+1) - tex2D(imageTex, i+1, j-1);
    int gradY = tex2D(imageTex, i-1, j-1) + 2*tex2D(imageTex, i-1, j) + tex2D(imageTex, i-1, j+1) - tex2D(imageTex, i+1, j-1) - 2*tex2D(imageTex, i+1, j) - tex2D(imageTex, i+1, j+1);

    int magnitude = gradX*gradX + gradY*gradY;

    if (magnitude  > 10000)
    {
        cache[blockIdx.x][blockIdx.y] = 255;
    }
    else
    {
        cache[blockIdx.x][blockIdx.y] = 0;
    }

    filtered[j * WIDTH + i] = cache[blockIdx.x][blockIdx.y];
}

void run(int, char**);

    unsigned char *devFiltered;

    // Initialize Cuda Memory
    CHECK(cudaMalloc(&devGrayScale, imageSize));
    CHECK(cudaMalloc(&devFiltered, imageSize));

    // Copy Cuda Memory
    CHECK(cudaMemcpy(devGrayScale, grayScale.img, imageSize, cudaMemcpyHostToDevice));

    // Set to 0 just in case
    CHECK(cudaMemset(devFiltered, 0, imageSize));

    cudaChannelFormatDesc desc = cudaCreateChannelDesc<unsigned char>();
    CHECK(cudaBindTexture2D(NULL, imageTex, devGrayScale, desc, source.width, source.height, sizeof(unsigned char) * source.width));

    // Run the kernel
    int n = 16;
    dim3 dimBlock(source.width/n, source.height/n - 20);
    dim3 dimGrid(n, n);
    filter<<<dimBlock, dimGrid>>>(devGrayScale, devFiltered, filtered.width, filtered.height);

    // Return the Cuda Memory
    CHECK(cudaMemcpy(filtered.img, devFiltered, imageSize, cudaMemcpyDeviceToHost));

    FILE *out;
    if (!(out = fopen(fname2, "wb")))
