使用python PIL将RGB图像转换为纯黑白图像

时间:2021-04-14 00:23:49

I'm using the Python Imaging Library for some very simple image manipulation, however I'm having trouble converting a greyscale image to a monochrome (black and white) image. If I save after changing the image to greyscale (convert('L')) then the image renders as you would expect. However, if I convert the image to a monochrome, single-band image it just gives me noise as you can see in the images below. Is there a simple way to take a colour png image to a pure black and white image using PIL / python?

我正在使用Python Imaging Library进行一些非常简单的图像处理,但是我无法将灰度图像转换为单色(黑白)图像。如果我在将图像更改为灰度(转换('L'))后保存,则图像呈现为您所期望的。但是,如果我将图像转换为单色,单波段图像,它只会给我噪声,如下图所示。有没有一种简单的方法可以使用PIL / python将彩色png图像转换为纯黑白图像?

from PIL import Image 
import ImageEnhance
import ImageFilter
from scipy.misc import imsave
image_file = Image.open("convert_image.png") # open colour image
image_file= image_file.convert('L') # convert image to monochrome - this works
image_file= image_file.convert('1') # convert image to black and white
imsave('result_col.png', image_file)

使用python PIL将RGB图像转换为纯黑白图像使用python PIL将RGB图像转换为纯黑白图像

6 个解决方案

#1


55  

from PIL import Image 
image_file = Image.open("convert_image.png") # open colour image
image_file = image_file.convert('1') # convert image to black and white
image_file.save('result.png')

yields

产量

使用python PIL将RGB图像转换为纯黑白图像

#2


16  

Another option (which is useful e.g. for scientific purposes when you need to work with segmentation masks) is simply apply a threshold:

另一个选项(当您需要使用分段掩码时,例如用于科学目的非常有用)只是应用一个阈值:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Binarize (make it black and white) an image with Python."""

from PIL import Image
from scipy.misc import imsave
import numpy


def binarize_image(img_path, target_path, threshold):
    """Binarize an image."""
    image_file = Image.open(img_path)
    image = image_file.convert('L')  # convert image to monochrome
    image = numpy.array(image)
    image = binarize_array(image, threshold)
    imsave(target_path, image)


def binarize_array(numpy_array, threshold=200):
    """Binarize a numpy array."""
    for i in range(len(numpy_array)):
        for j in range(len(numpy_array[0])):
            if numpy_array[i][j] > threshold:
                numpy_array[i][j] = 255
            else:
                numpy_array[i][j] = 0
    return numpy_array


def get_parser():
    """Get parser object for script xy.py."""
    from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
    parser = ArgumentParser(description=__doc__,
                            formatter_class=ArgumentDefaultsHelpFormatter)
    parser.add_argument("-i", "--input",
                        dest="input",
                        help="read this file",
                        metavar="FILE",
                        required=True)
    parser.add_argument("-o", "--output",
                        dest="output",
                        help="write binarized file hre",
                        metavar="FILE",
                        required=True)
    parser.add_argument("--threshold",
                        dest="threshold",
                        default=200,
                        type=int,
                        help="Threshold when to show white")
    return parser


if __name__ == "__main__":
    args = get_parser().parse_args()
    binarize_image(args.input, args.output, args.threshold)

It looks like this for ./binarize.py -i convert_image.png -o result_bin.png --threshold 200:

它看起来像./binarize.py -i convert_image.png -o result_bin.png --threshold 200:

使用python PIL将RGB图像转换为纯黑白图像

#3


4  

Judging by the results obtained by unutbu I conclude that scipy's imsave does not understand monochrome (mode 1) images.

从unutbu获得的结果判断我得出结论,scipy的imsave不理解单色(模式1)图像。

#4


4  

As Martin Thoma has said, you need to normally apply thresholding. But you can do this using simple vectorization which will run much faster than the for loop that is used in that answer.

正如Martin Thoma所说,你需要正常应用阈值。但是你可以使用简单的矢量化来实现这一点,它的运行速度比该答案中使用的for循环要快得多。

The code below converts the pixels of an image into 0 (black) and 1 (white).

下面的代码将图像的像素转换为0(黑色)和1(白色)。

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

#Pixels higher than this will be 1. Otherwise 0.
THRESHOLD_VALUE = 200

#Load image and convert to greyscale
img = Image.open("photo.png")
img = img.convert("L")

imgData = np.asarray(img)
thresholdedData = (imgData > THRESHOLD_VALUE) * 1.0

plt.imshow(thresholdedData)
plt.show()

#5


2  

A PIL only solution for creating a bi-level (black and white) image with a custom threshold:

仅限PIL解决方案,用于创建具有自定义阈值的双层(黑白)图像:

from PIL import Image
img = Image.open('mB96s.png')
thresh = 200
fn = lambda x : 255 if x > thresh else 0
r = img.convert('L').point(fn, mode='1')
r.save('foo.png')

With just

只是

r = img.convert('1')
r.save('foo.png')

you get a dithered image.

你得到一个抖动的图像。

#6


-1  

Because from PIL convert("1") return the value "True" or "False". Try to print it, will be show: [False, False, True] with single bracket.

因为从PIL转换(“1”)返回值“True”或“False”。尝试打印它,将显示:[False,False,True]单支架。

Whereas the numpy array use double bracket like this [[False, False, True]] or [[0, 0, 1]], right?

而numpy数组使用双括号,如[[False,False,True]]或[[0,0,1]],对吗?

#1


55  

from PIL import Image 
image_file = Image.open("convert_image.png") # open colour image
image_file = image_file.convert('1') # convert image to black and white
image_file.save('result.png')

yields

产量

使用python PIL将RGB图像转换为纯黑白图像

#2


16  

Another option (which is useful e.g. for scientific purposes when you need to work with segmentation masks) is simply apply a threshold:

另一个选项(当您需要使用分段掩码时,例如用于科学目的非常有用)只是应用一个阈值:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Binarize (make it black and white) an image with Python."""

from PIL import Image
from scipy.misc import imsave
import numpy


def binarize_image(img_path, target_path, threshold):
    """Binarize an image."""
    image_file = Image.open(img_path)
    image = image_file.convert('L')  # convert image to monochrome
    image = numpy.array(image)
    image = binarize_array(image, threshold)
    imsave(target_path, image)


def binarize_array(numpy_array, threshold=200):
    """Binarize a numpy array."""
    for i in range(len(numpy_array)):
        for j in range(len(numpy_array[0])):
            if numpy_array[i][j] > threshold:
                numpy_array[i][j] = 255
            else:
                numpy_array[i][j] = 0
    return numpy_array


def get_parser():
    """Get parser object for script xy.py."""
    from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
    parser = ArgumentParser(description=__doc__,
                            formatter_class=ArgumentDefaultsHelpFormatter)
    parser.add_argument("-i", "--input",
                        dest="input",
                        help="read this file",
                        metavar="FILE",
                        required=True)
    parser.add_argument("-o", "--output",
                        dest="output",
                        help="write binarized file hre",
                        metavar="FILE",
                        required=True)
    parser.add_argument("--threshold",
                        dest="threshold",
                        default=200,
                        type=int,
                        help="Threshold when to show white")
    return parser


if __name__ == "__main__":
    args = get_parser().parse_args()
    binarize_image(args.input, args.output, args.threshold)

It looks like this for ./binarize.py -i convert_image.png -o result_bin.png --threshold 200:

它看起来像./binarize.py -i convert_image.png -o result_bin.png --threshold 200:

使用python PIL将RGB图像转换为纯黑白图像

#3


4  

Judging by the results obtained by unutbu I conclude that scipy's imsave does not understand monochrome (mode 1) images.

从unutbu获得的结果判断我得出结论,scipy的imsave不理解单色(模式1)图像。

#4


4  

As Martin Thoma has said, you need to normally apply thresholding. But you can do this using simple vectorization which will run much faster than the for loop that is used in that answer.

正如Martin Thoma所说,你需要正常应用阈值。但是你可以使用简单的矢量化来实现这一点,它的运行速度比该答案中使用的for循环要快得多。

The code below converts the pixels of an image into 0 (black) and 1 (white).

下面的代码将图像的像素转换为0(黑色)和1(白色)。

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

#Pixels higher than this will be 1. Otherwise 0.
THRESHOLD_VALUE = 200

#Load image and convert to greyscale
img = Image.open("photo.png")
img = img.convert("L")

imgData = np.asarray(img)
thresholdedData = (imgData > THRESHOLD_VALUE) * 1.0

plt.imshow(thresholdedData)
plt.show()

#5


2  

A PIL only solution for creating a bi-level (black and white) image with a custom threshold:

仅限PIL解决方案,用于创建具有自定义阈值的双层(黑白)图像:

from PIL import Image
img = Image.open('mB96s.png')
thresh = 200
fn = lambda x : 255 if x > thresh else 0
r = img.convert('L').point(fn, mode='1')
r.save('foo.png')

With just

只是

r = img.convert('1')
r.save('foo.png')

you get a dithered image.

你得到一个抖动的图像。

#6


-1  

Because from PIL convert("1") return the value "True" or "False". Try to print it, will be show: [False, False, True] with single bracket.

因为从PIL转换(“1”)返回值“True”或“False”。尝试打印它,将显示:[False,False,True]单支架。

Whereas the numpy array use double bracket like this [[False, False, True]] or [[0, 0, 1]], right?

而numpy数组使用双括号,如[[False,False,True]]或[[0,0,1]],对吗?