Playing the game of Chaos
midpoint()

This function could be written more elegantly using zip(), and it would work for any number of dimensions. (I suspect it might be slower, though.)

def midpoint(p1, p2):
    """
    Find the midpoint of two cartesian points.
    """
    return tuple((c1 + c2) / 2 for c1, c2 in zip(p1, p2))


translate() and image_rep()

Since translate() gives a result in Pillow coordinates, I think that the result should be quantized as integers. You should round to the nearest integer rather than truncating.

Pillow coordinates increase towards the right and towards the bottom.  Conventionally, cartesian coordinates increase towards the right and towards the top.  I would therefore incorporate a reflection of the vertical axis in the translation.

I don't see why the image must be square.

You can just pass point instead of packing it into a new tuple.    

translated = translate(point, img_size)


I suggest hiding these two helper functions inside a plotting routine. (See below.)

play_chaos()

I would split this into the mathematical concept and its visualization.

def chaos_points(attractors, start_point):
    attractor_stream = (random.choice(attractors) for _ in itertools.count())
    return itertools.accumulate(itertools.chain([start_point], attractor_stream), midpoint)

def plot(img, points):
    half_width, half_height = img.size[0] / 2, img.size[1] / 2
    to_pillow = lambda p: (int(round(half_width + p[0])), int(round(half_height - p[1])))
    for point in points:
        img.putpixel(to_pillow(point), 1)


Demo

Your GUIDERS don't form an equilateral triangle as suggested.

def main():
    """
    Create an image and populate it with chaos.
    """
    IMAGE_SIZE = 300, 300
    SEED = (0.0, 0.0)
    GUIDERS = [(-100.0, -50 * 3**.5),
               (+100.0, -50 * 3**.5),
               (   0.0, +50 * 3**.5)]
    img = Image.new('1', IMAGE_SIZE)
    plot(img, itertools.islice(chaos_points(GUIDERS, SEED), 1000))
    img.save('chaos.png')


if __name__ == '__main__':
    main()