使用Python转换图片中的颜色

0 阅读5分钟

说明:最近在看梵高的画册,我手上的这本画册(《文森特·梵高》杨建飞 主编)书中说,梵高用的颜料里有不耐久的合成颜料,原本的紫色褪成了我们现在所看到的灰蓝色。于是我想,能不能用程序将画中的颜色还原成原本的紫色。


盛开的桃花,1888年

盛开的桃花

生成图片

首先,写一段代码,用来读取图片,生成一个副本,代码如下:

from PIL import Image, ImageDraw
import numpy as np


# 生成转换后的画
def generate_img(in_path, out_path):
    # 打开图片
    im = Image.open(in_path)
    # 生成后的图片大小,使用im.size[0],im.size[1],即原图大小
    new_im_size = np.array([im.size[0], im.size[1]]).astype(int)
    # 生成图片的背景颜色
    bg_color = "black"
    # 生成图片
    im_out = Image.new("RGB", tuple(new_im_size), bg_color)
    # 获取图片的颜色
    im_color = np.array(im)
    # 生成图片
    draw = ImageDraw.Draw(im_out)
    # 用于统计进度
    count = 0
    total_pixels = im.size[0] * im.size[1]
    # 遍历图片的每个像素点,将颜色填充到新图片中
    for i in range(im.size[0]):
        for j in range(im.size[1]):
            color = tuple(im_color[j, i])
            draw.point((i, j), fill=color)
            count += 1
        print('生成进度:%d%%' % ((count / total_pixels) * 100))
    # 保存图片
    im_out.save(out_path)

if __name__ == "__main__":
    in_path = r'C:\Users\10765\Desktop\1.jpg'
    out_path = r'C:\Users\10765\Desktop\2.jpg'
    # 读取图片,并将图片中的颜色转换
    generate_img(in_path, out_path)

运行

在这里插入图片描述

可在桌面上生成一张几乎一模一样大小的图片;

在这里插入图片描述

颜色转换

接着,我们就是对颜色进行处理,也就是上面for循环里的这行代码;

            color = tuple(im_color[j, i])

我们要写一个方法,对这里面的色值进行转换,我的思路是这样的,首先找到紫色和灰蓝色的RGB色值范围,然后对图片中的色值进行判断,如果是在灰蓝色的色值范围内,则对该RGB色值进行映射,映射到紫色的RGB色值范围内。通过问GPT,可知两种颜色的色值范围如下:

  • 紫色:128-255,0-20,128-255;

  • 灰蓝色:100-180,120-200,150-230;

代码如下:

# 色值转换,灰蓝色 => 紫色
def convert_color(gray_blue_rgb):
    # 灰蓝色范围
    gray_blue_range = [(100, 180), (120, 200), (150, 230)]
    # 紫色范围
    violet_range = [(128, 255), (0, 20), (128, 255)]
    # 检查输入的 RGB 值是否在灰蓝色范围内
    for i in range(3):
        if not (gray_blue_range[i][0] <= gray_blue_rgb[i] <= gray_blue_range[i][1]):
            return tuple(gray_blue_rgb)

    # 根据灰蓝色范围的值转换到紫色范围
    violet_color = []
    for i in range(3):
        gray_blue_min, gray_blue_max = gray_blue_range[i]
        violet_min, violet_max = violet_range[i]
        # 灰蓝色范围内的值映射到紫色范围
        violet_val = int(
            (gray_blue_rgb[i] - gray_blue_min)
            / (gray_blue_max - gray_blue_min)
            * (violet_max - violet_min)
            + violet_min
        )
        violet_color.append(violet_val)
    return tuple(violet_color)

为了方便理解,举个例子。如果一个A色值区间是 [20,100],另一个B色值区间是[100,180],现在一个A色值是80,需要转为B色值,过程如下:

  • (80 - 20)/ (100 - 20) * (180 - 100) + 100 = 160

  • (当前色值 - A色值范围的最低值) / (A色值的区间长度,即 100 - 20) * (B色值的区间长度,即 180 - 100) + B色值范围的最低值

160,就是A色值在B色值中的值;

代码写好了,在将颜色填充到图片前做一层转换即可,如下:

    # 遍历图片的每个像素点,将颜色填充到新图片中
    for i in range(im.size[0]):
        for j in range(im.size[1]):
            # 将颜色转换,然后填充到新图片中
            color = tuple(convert_color(im_color[j, i]))
            draw.point((i, j), fill=color)
            count += 1
        print('生成进度:%d%%' % ((count / total_pixels) * 100))

启动,看下效果,有点妖娆,色值范围没控制好;

在这里插入图片描述

我之前选的色值如下:

  • 紫色:80-150,100-180,120-200;

  • 灰蓝色:150-220,0-80,150-220;

转换后的效果如下:

在这里插入图片描述

完整代码

from PIL import Image, ImageDraw
import numpy as np


# 生成转换后的画
def generate_img(in_path, out_path):
    # 打开图片
    im = Image.open(in_path)
    # 生成后的图片大小,使用im.size[0],im.size[1],即原图大小
    new_im_size = np.array([im.size[0], im.size[1]]).astype(int)
    # 生成图片的背景颜色
    bg_color = "black"
    # 生成图片
    im_out = Image.new("RGB", tuple(new_im_size), bg_color)
    # 获取图片的颜色
    im_color = np.array(im)
    # 生成图片
    draw = ImageDraw.Draw(im_out)
    # 用于统计进度
    count = 0
    total_pixels = im.size[0] * im.size[1]
    # 遍历图片的每个像素点,将颜色填充到新图片中
    for i in range(im.size[0]):
        for j in range(im.size[1]):
            # 将颜色转换,然后填充到新图片中
            color = tuple(convert_color(im_color[j, i]))
            draw.point((i, j), fill=color)
            count += 1
        print('生成进度:%d%%' % ((count / total_pixels) * 100))
    # 保存图片
    im_out.save(out_path)


# 色值转换,灰蓝色 => 紫色
def convert_color(gray_blue_rgb):
    # 灰蓝色范围
    gray_blue_range = [(100, 180), (120, 200), (150, 230)]
    # 紫色范围
    violet_range = [(128, 255), (0, 20), (128, 255)]
    # 检查输入的 RGB 值是否在灰蓝色范围内
    for i in range(3):
        if not (gray_blue_range[i][0] <= gray_blue_rgb[i] <= gray_blue_range[i][1]):
            return tuple(gray_blue_rgb)

    # 根据灰蓝色范围的值转换到紫色范围
    violet_color = []
    for i in range(3):
        gray_blue_min, gray_blue_max = gray_blue_range[i]
        violet_min, violet_max = violet_range[i]
        # 灰蓝色范围内的值映射到紫色范围
        violet_val = int(
            (gray_blue_rgb[i] - gray_blue_min)
            / (gray_blue_max - gray_blue_min)
            * (violet_max - violet_min)
            + violet_min
        )
        violet_color.append(violet_val)
    return tuple(violet_color)


if __name__ == "__main__":
    # 输入图片路径
    in_path = r'C:\Users\10765\Desktop\1.png'
    # 输出图片路径
    out_path = r'C:\Users\10765\Desktop\2.png'
    # 读取图片,并将图片中的颜色转换
    generate_img(in_path, out_path)

总结

本文介绍了如何使用Python程序对图片中的颜色进行转换

首次发布

hezhongying.blog.csdn.net/article/det…