0

Im trying to do a small project on machine learning and in the process of doing so I have to convert a few images into black and white to classify the images. My problem is that the same method produces wildly different results with the same algorithm. Here is the image before it is converted Image 1 and this is what it looks like after its been converted. Yeah that works fine looks okay.

This is the code that I used.

test_img=Image.open(str(idx) + '.png')
test_img=test_img.resize((100,100),Image.ANTIALIAS)
test_img.show()
test_img=test_img.convert('1')

Now I will ty to do the same with this image which produces this result. As you can see aster it is converted I have weird black spots all over the image. This is the code that I used:

source_img=source_img.resize((100,100),Image.ANTIALIAS)
source_img=source_img.convert('1')
source_img.show() 

Ive tried multiple methods to convert an image to black and white including the source_img.convert('L') method and with other methods I'm not able to flatten the image out into a 1D array.

Does anyone know why the conversion works for the first image but not the second?

alkasm
  • 22,094
  • 5
  • 78
  • 94
Arun Mani
  • 17
  • 2
  • 1
    Why is your question tagged with OpenCV if you're not using it? – alkasm Feb 27 '19 at 06:34
  • Are you sure about bw/1bit? Most ML algs work on grayscale, e.g. with 8 bit depth. The reasoning might be indicated in alexanders answer: hard to keep lots of original information with only 1 bit. – sascha Feb 27 '19 at 07:27

1 Answers1

3

The PIL method convert("1") converts to black and white using dithering, as the docs state:

The default method of converting a greyscale (“L”) or “RGB” image into a bilevel (mode “1”) image uses Floyd-Steinberg dither to approximate the original image luminosity levels.

Dithering replicates many colors with fewer by placing noise within the image to approximate the many colors. Check the Wikipedia article for dithering for more. For e.g., from that page, the following image is dithered---there's only black and white pixels, but the dithering makes it look grayscale somewhat. This is why your second image has some stippling---the color is not-quite-white, so it tries to approximate the gray with a few specks of black. Not particularly convincing there, though it is more impressive on other types of images:

Dithered image

If you want to binarize the image, the simplest way is to set a threshold, so that every pixel above that threshold is considered white, and everything below, black. As the docs for convert() state:

If dither is NONE, all non-zero values are set to 255 (white). To use other thresholds, use the point() method.

Which you can find the docs for here. If you want to use OpenCV, you can accomplish this through cv2.threshold(), docs here, tutorial here, and a related previous Stack Overflow answer I've given here.

alkasm
  • 22,094
  • 5
  • 78
  • 94