使用 PIL 将 RGB 图像变成纯黑白图像

Posted

技术标签:

【中文标题】使用 PIL 将 RGB 图像变成纯黑白图像【英文标题】:Using PIL to turn a RGB image into a pure black and white image 【发布时间】:2012-03-19 09:28:17 【问题描述】:

我正在使用 Python Imaging Library 进行一些非常简单的图像处理,但是我无法将灰度图像转换为单色(黑白)图像。如果我在将图像更改为灰度 (convert('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)

【问题讨论】:

来自PIL documentation: """当转换为双层图像(模式“1”)时,源图像首先转换为黑白。结果值大于127然后设置为白色,并且图像抖动。要使用其他阈值,请使用点方法。"""这听起来很相关,但我不熟悉 PIL 和图像处理。 【参考方案1】:
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')

产量

【讨论】:

非常糟糕的输出。文字无法识别( 这是灰度图,不是黑白图。 @progyammer 这绝对是黑白的。抖动与灰度不同。图像是使用每像素 1 位创建的。灰度通常使用每像素 8 位来为您提供白色(关闭)和黑色(开启)之间的阴影。 @MartijnPieters 你是对的!这是一个 BW 图像。没有注意到它,因为缩小时它看起来是灰色的:P【参考方案2】:

仅用于创建具有自定义阈值的双层(黑白)图像的 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')

只要

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

你会得到一个抖动的图像。

输入图像从左到右,黑白转换结果和抖动结果:

您可以点击图片查看未缩放的版本。

【讨论】:

这应该是公认的答案——它在没有额外库的情况下经济地实现了所要求的结果。 如果我们希望它们透明而不是白色像素怎么办? @ShanerM13 黑白图像的每个像素的颜色值都有一个位:它可以是 1 或 0。这为黑白留出了空间,但没有第三个选项,例如透明(除非您负责图像的处理方式,并且可以定义其中一个选项以在您的应用程序中表示透明)。 @user2616155 对我来说可能是一个更好的问题,至少现在,我如何将“背景”设为白色而不是默认的黑色?【参考方案3】:

另一个选项(例如,当您需要使用分割掩码时,对于科学目的很有用)是简单地应用一个阈值:

#!/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)

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

【讨论】:

binarize_array 的单行代码(我猜也更快):numpy.where(numpy_array > threshold=200, 255, 0) 这非常适合我的谷歌搜索,只将图像转换为黑白......谢谢! 二值化不需要 numpy - PIL is sufficient for this。【参考方案4】:

正如 Martin Thoma 所说,您通常需要应用阈值。但是您可以使用简单的矢量化来做到这一点,这将比该答案中使用的 for 循环运行得更快。

下面的代码将图像的像素转换为 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()

【讨论】:

thresholdedData 给了我一个黑色图像。我将其替换为:thresholdedData = np.where(imgData > THRESHOLD_VALUE, 255, 0)。然后,您可以使用Image.fromarray()(我认为是)将图像加载到 PIL 中,然后执行 .save(".bmp") 将其保存到文件系统中。所以不需要matplotlib。【参考方案5】:

使用 python 的简单方法:

Python
import numpy as np
import imageio

image = imageio.imread(r'[image-path]', as_gray=True)

# getting the threshold value
thresholdValue = np.mean(image)

# getting the dimensions of the image
xDim, yDim = image.shape

# turn the image into a black and white image
for i in range(xDim):
    for j in range(yDim):
        if (image[i][j] > thresholdValue):
            image[i][j] = 255
        else:
            image[i][j] = 0

【讨论】:

【参考方案6】:

我就是这样做的,它有更好的效果,比如灰色过滤器

from PIL import Image
img = Image.open("profile.png")
BaW = img.convert("L")
BaW.save("profileBaW.png")
BaW.show()

【讨论】:

以上是关于使用 PIL 将 RGB 图像变成纯黑白图像的主要内容,如果未能解决你的问题,请参考以下文章

如何用matlab将彩色图片变成黑白图片

如何将 WORD中将彩色图片变成灰度图 或 黑白图 ?

在 GPUImage 中将黑白图像转换为透明和白色图像? RGB -> Alpha 基本上

图像滤镜处理算法:灰度黑白底片浮雕

使用 Python / PIL 检测 HSV 颜色空间中的阈值(来自 RGB)

在 Opencv 中映射 2 图像