Saving binary mask, opens as a trinary mask. Why?

This driving me nuts. I’m trying to convert my 3-channel (0,255) image into a 1-channel (0,1) image.

I’m using the function below. When I convert the image, I even have an assertion that checks ONLY [0,1] is in the numpy array.

def check_channels(img):
    
    # Get dimensions
    dim = img.shape[-1]
    assert dim == 3
    
    # Check that all channels are identical data
    for i in range(dim-1):
        assert img[:, :, i].all() == img[:, :, i+1].all()
    
    # Convert 0/255 to 0/1
    img = img.clip(max=1)
    #img = img // 255
    img = img[:, :, -1]
    
    uniques = np.unique(img).tolist()
    assert uniques == [0, 1]
    return img

I then use the following opencv function to save it.

cv2.imwrite(filename, img, [int(cv2.IMWRITE_JPEG_QUALITY), 95])

I immediately reload the file

cv2.imread(filename, cv2.IMREAD_UNCHANGED)

I check for uniques and now it is [0,1,2]… Are you kidding me?

I’ve been dealing with assertions error the whole day, and it finally boiled down (I think) to the extra 2 that is coming up whenever I read the image. Also this appears to be random, some converted images only have [0,1], but others have [0,1,2]. But all images only had [0,1] before I saved them. So it has to be something with opencv save/load image commands??

Has anyone seen this before?

JPEG is a lossy compression format so will introduce some noise. I would suggest using a non-lossy format for masks where exact pixel values are important. If you want to view the masks as images then something like PNG or TIFF would be possible non-lossy formats (or BMP though PNG/TIFF will use lossless compression so should be a fair bit smaller).
Or you could just save the tensors using torch.save (or pickle) if you don’t care about viewing outside python. I suspect that torch files would load a bit faster than images, especially if you saved all masks in one file (assuming you can fit all masks in RAM).

I tried PNG without compression, and it too had the same effect.

I did try TIFF and that finally worked.

Thanks for the advice!