1

The code snippet in Python should convert the rgb image to black and white, but only a black image output. I do not know where the problem is (input and output image should be bmp)

from PIL import Image
import numpy as np

raw_img = Image.open(r"image adress")
img = raw_img.load()
x,y = raw_img.size
threshold = 300
bw_img = [[0]*y]*x # blank image

for i in range(x):
  for j in range(y):
    if img[i,j] < threshold:
      bw_img[i][j] = 0
    else:
      bw_img[i][j] = 1


Image.fromarray(np.asarray(bw_img),mode="P").save("your_nwe_image.bmp")
Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
  • Running `for` loops over any image bigger than about 20 pixels on either side is almost always hopelessly inefficient and sub-optimal. You really should use Numpy or something vectorised or implemented in C like PIL's `point` process. – Mark Setchell Apr 10 '22 at 19:53
  • Why did you expect that there are values above 300 in your image? – mkrieger1 Apr 10 '22 at 20:09

1 Answers1

2

You'll need to replace

threshold = 300

with

threshold = 128

because Image.open always returns an 8-bit image where 255 is the maximum value.

Here is how I would go about doing this (without using the OpenCV module):

from PIL import Image
import numpy as np

def not_black(color):
    return (color * [0.2126, 0.7152, 0.0722]).sum(-1) < 128

raw_img = Image.open(r"image adress")
img = np.array(raw_img)

whites = not_black(img)
img[whites] = 255
img[~whites] = 0

Image.fromarray(img).save("your_nwe_image.bmp")

However, with OpenCV, it simplifies to just:

import cv2

img = cv2.imread(r"biss3.png", 0)
_, thresh = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY)

cv2.imwrite("your_nwe_image.bmp", thresh)
mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Red
  • 26,798
  • 7
  • 36
  • 58