Image similarity measure
Thanks to @wondra for the help. I rewrote the function without the getpixel and just loaded the pixels using the image.load() method. This caused the execution time to reduce down to 3.09 seconds.

Rewritten function:

def fitness_new(new):
    fitness = 0

    new_data = new.load()

    for x in range(0, width):
        for y in range(0, height):
            r1, g1, b1 = optimal_data[x, y]
            r2, g2, b2 = new_data[x, y]

            deltaRed = abs(r1 - r2)
            deltaGreen = abs(g1 - g2)
            deltaBlue = abs(b1 - b2)

            pixelFitness = pixelFitness = math.sqrt(deltaRed ** 2 + deltaGreen ** 2 + deltaBlue ** 2)

            fitness += pixelFitness

    return fitness


optimal_data is preloaded as a global variable instead of being passed as an argument, because it is accessed elsewhere. I know this is probably not the most ideal method.