You could make a custom lut (lookup table) and apply it to the grayscale image with the point()
method just before saving it. Gray levels in the image besides 0, 128, and 255 will remain unchanged. You could, of course, change that by initializing the table differently.
lut = range(256) # initialize to an identity lut
lut[0] = 2
lut[128] = 1
lut[255] = 0
Image.open(imgname).convert('L').point(lut).save(imgname)