Python 批量修改图片亮度和饱和度

在Photoshop里也可以做到批量修改图片的亮度和饱和度,但是很多人都没有条件使用Photoshop,此外,Photoshop里的批量修改其实很耗性能,而且使用起来并不是很方便。

那我们能不能用Python做一个小工具,先找到合适的亮度和饱和度,然后再根据这个指定的值对所有需要做相似调整的图片做批量修改呢?答案是肯定的。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上噢,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal). 输入以下命令安装我们所需要的模块:

pip install numpy
pip install opencv-python

看到 Successfully installed xxx 则说明安装成功。

2.开发调整工具

这一部分,我们将开发出一个能够调整图像亮度和饱和度的工具,而且这个工具支持滑动调整。其实放到别的语言里,这可是个小工程,但是放到Python里,我们用50行代码就能解决了。

首先是加载图片,然后需要将图片转化为HLS模式才能够调整亮度和饱和度。这是因为默认的图片颜色空间是RGB,它非常适合显示器显示,但由于只有三个颜色分类,并不适合图像处理。而HLS模式相对于RGB颜色空间则复杂得多,HLS分别代表H: Hue(色调),L: Lightness(亮度), S: Saturation(饱和度)。

其颜色空间是一个三维空间,如下图所示:

这样的颜色空间才使得我们可以调整图片的细节部分。Python代码中,将RGB转化为HLS空间是很简单的,两行代码就能做到:

import numpy as np
import cv2

# 加载图片 读取彩色图像归一化且转换为浮点型
image = cv2.imread('2.jpg', cv2.IMREAD_COLOR).astype(np.float32) / 255.0

# 颜色空间转换 BGR转为HLS
hlsImg = cv2.cvtColor(image, cv2.COLOR_BGR2HLS)

然后我们需要做两个滑动块,一个调节亮度,一个调节饱和度:

# 滑动条最大值
MAX_VALUE = 100
# 滑动条最小值
MIN_VALUE = 0

# 调节饱和度和亮度的窗口
cv2.namedWindow("lightness and saturation", cv2.WINDOW_GUI_NORMAL)

# 创建滑动块
cv2.createTrackbar("lightness", "lightness and saturation", MIN_VALUE, MAX_VALUE, lambda x:x)
cv2.createTrackbar("saturation", "lightness and saturation", MIN_VALUE, MAX_VALUE, lambda x:x)

调节前还需要保存一下原图,所以我们会在内存里复制一个新的变量用于调节图片,然后获得两个滑动块的值,再根据值进行亮度和饱和度的调整:

# 调整饱和度和亮度
while True:
    # 复制原图
    hlsCopy = np.copy(hlsImg)
    # 得到 lightness 和 saturation 的值
    lightness = cv2.getTrackbarPos('lightness', 'lightness and saturation')
    saturation = cv2.getTrackbarPos('saturation', 'lightness and saturation')
    # 1.调整亮度(线性变换)
    hlsCopy[:, :, 1] = (1.0 + lightness / float(MAX_VALUE)) * hlsCopy[:, :, 1]
    hlsCopy[:, :, 1][hlsCopy[:, :, 1] > 1] = 1
    # 饱和度
    hlsCopy[:, :, 2] = (1.0 + saturation / float(MAX_VALUE)) * hlsCopy[:, :, 2]
    hlsCopy[:, :, 2][hlsCopy[:, :, 2] > 1] = 1
    # HLS2BGR
    lsImg = cv2.cvtColor(hlsCopy, cv2.COLOR_HLS2BGR)
    # 显示调整后的效果
    cv2.imshow("lightness and saturation", lsImg)

效果如下图所示:

到这里还不够,由于是while循环支持的调节,我们还需要让其可以退出和保存:

    ch = cv2.waitKey(5)
    # 按 ESC 键退出
    if ch == 27:
        break
    elif ch == ord('s'):
        # 按 s 键保存并退出
        lsImg = lsImg * 255
        lsImg = lsImg.astype(np.uint8)
        cv2.imwrite("lsImg.jpg", lsImg)
        break

这样,按s键可以保存图片并退出,按ESC键可以直接退出编辑器。 完整文字版50行代码请在Python实用宝典公众号后台回复:批量修改图片 获得。

3.批量修改

前面根据我们的小工具获得了需要的饱和度和亮度,把这对值记下来就可以批量修改图片了。当然,我们没有自动批量修改到正确值这么逆天的功能,这个工具只适合相同场景下,能够用同一对亮度和饱和度进行调整的图片:

def update(input_img_path, output_img_path, lightness, saturation):
    """
    用于修改图片的亮度和饱和度
    :param input_img_path: 图片路径
    :param output_img_path: 输出图片路径
    :param lightness: 亮度
    :param saturation: 饱和度
    """

    # 加载图片 读取彩色图像归一化且转换为浮点型
    image = cv2.imread(input_img_path, cv2.IMREAD_COLOR).astype(np.float32) / 255.0

    # 颜色空间转换 BGR转为HLS
    hlsImg = cv2.cvtColor(image, cv2.COLOR_BGR2HLS)

    # 1.调整亮度(线性变换)
    hlsImg[:, :, 1] = (1.0 + lightness / float(MAX_VALUE)) * hlsImg[:, :, 1]
    hlsImg[:, :, 1][hlsImg[:, :, 1] > 1] = 1
    # 饱和度
    hlsImg[:, :, 2] = (1.0 + saturation / float(MAX_VALUE)) * hlsImg[:, :, 2]
    hlsImg[:, :, 2][hlsImg[:, :, 2] > 1] = 1
    # HLS2BGR
    lsImg = cv2.cvtColor(hlsImg, cv2.COLOR_HLS2BGR) * 255
    lsImg = lsImg.astype(np.uint8)
    cv2.imwrite(output_img_path, lsImg)

这部分其实比制作刚刚的工具简单,可以说是工具的简化版。分为以下六个步骤:

1.加载图片。
2.转化为HLS空间。
3.调整亮度。
4.调整饱和度。
5.转化为RGB空间。
6.保存。

然后我们只需要批量地将图片传入该函数,就能实现批量转化:

dataset_dir = 'imgs'
output_dir = 'output'
lightness = 10
saturation = 20

# 获得需要转化的图片路径, 并生成目标路径
image_filenames = [(os.path.join(dataset_dir, x), os.path.join(output_dir, x))
                    for x in os.listdir(dataset_dir)]
# 转化所有图片
for path in image_filenames:
    update(path[0], path[1], lightness, saturation)

通过这份Python代码,你能在1分钟内修改几千张图片,这样的效率并非Photoshop能比的。当然,它也有它的缺点,那就是只能根据你输入的值进行修改,而Photoshop能够进行自动优化(虽然精度评价因人而异)。

我们的文章到此就结束啦,如果你希望我们今天的Python 教程,请持续关注我们,如果对你有帮助,麻烦在下面点一个赞/在看哦有任何问题都可以在下方留言区留言,我们都会耐心解答的!


​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注