PS 阴影/高光中阴影提亮效果之 Python 实现

“阴影/高光”命令是一种用于校正由强逆光而形成剪影的照片,或者校正由于太接近相机闪光灯而有些发白的焦点的方法。在用其他方式采光的图像中,这种调整也可用于使阴影区域变亮。“阴影/高光”命令不是简单地使图像变亮或变暗,它基于阴影或高光中的周围像素(局部相邻像素)增亮或变暗。正因为如此,阴影和高光都有各自的控制选项。默认值设置为修复具有逆光问题的图像,来自 Adobe 官网。

阴影
主要用于提亮阴影区域,对非阴影区几乎不产生效果
数量:用于控制阴影区要校正的程度,值越大,阴影区域被提的越亮
色调:控制被提亮的阴影区域的范围,较小的值会限制只对较暗的区域进行提亮,值越大,影响的阴影范围越宽
半径:控制每个像素周围的局部相邻像素的大小

高光:
主要用于压暗高光区域,对非高光区几乎不产生效果
数量:用于控制高光区要校正的程度,值越大,高光区域被压的越暗
色调:控制被压暗的高光区域的范围,较小的值会限制只对较亮的区域进行压暗,值越大,影响的高光范围越宽
半径:控制每个像素周围的局部相邻像素的大小

调整:
颜色:正值增加阴影区被提亮像素和高光区被压暗像素的饱和度,负值为减小饱和度
中间调:用来调整中间调的对比度,负值降低对比度,正值增加对比度
修剪黑色:设定将图像中多少比例的阴影变成纯黑
修剪白色:设定将图像中多少比例的高光变成纯白

PS 阴影/高光中阴影提亮效果之 Python 实现_第1张图片

Python 实现阴影区抠取及阴影区提亮

1、提取阴影区域

自动提前阴影区域,具体方式见我的另一一篇博客《Python 用 OpenCV 实现 PS 高光/阴影选区》

阴影区域提取:
先将原图转成灰度图,然后对灰度图做反相后做为两个输入源做正交叠底,对结果做阈值限制后输出

luminance = (1 - luminance) * (1 - luminance)
luminance = np.where(luminance > shadowThreshold, luminance, 0)

PS 阴影/高光中阴影提亮效果之 Python 实现_第2张图片
PS 阴影/高光中阴影提亮效果之 Python 实现_第3张图片

然后对阴影区提亮,并对非阴影去做过渡,否则会有明显边界。
提亮使用的非线性亮度调整,公式为伽马矫正公式,见《PS 色阶调整之算法公式原理详解及 Python 实现》中的中间调调整。

2、阴影区域提亮及完整代码

依赖的环境:Python3 numpy OpenCV

# -*- coding: utf-8 -*-
# @Time    : 2021-04-26 19:45
# @Author  : AlanWang4523
# @FileName: ps_shadow_highlight.py

import os
import sys
import cv2
import numpy as np

class PSShadowHighlight:
    """
    色阶调整
    """
    def __init__(self, image):
        self.shadows_light = 50

        img = image.astype(np.float)/255.0

        srcR = img[:, :, 2]
        srcG = img[:, :, 1]
        srcB = img[:, :, 0]
        srcGray = 0.299 * srcR + 0.587 * srcG + 0.114 * srcB

        # 高光选区
        # luminance = luminance * luminance
        # luminance = np.where(luminance > 0.64, luminance, 0)

        # 阴影选区
        luminance = (1 - srcGray) * (1 - srcGray)

        self.maskThreshold = np.mean(luminance)
        mask = luminance > self.maskThreshold

        imgRow=np.size(img, 0)
        imgCol=np.size(img, 1)
        print("imgRow:%d, imgCol:%d, maskThreshold:%f" % (imgRow, imgCol, self.maskThreshold))
        print("shape:", img.shape)

        self.rgbMask = np.zeros([imgRow, imgCol, 3], dtype = bool)
        self.rgbMask[:, :, 0] = self.rgbMask[:, :, 1] = self.rgbMask[:, :, 2] = mask

        self.rgbLuminance = np.zeros([imgRow, imgCol, 3], dtype = float)
        self.rgbLuminance[:, :, 0] = self.rgbLuminance[:, :, 1] = self.rgbLuminance[:, :, 2] = luminance

        self.midtonesRate = np.zeros([imgRow, imgCol, 3], dtype = float)
        self.brightnessRate = np.zeros([imgRow, imgCol, 3], dtype = float)


    def adjust_image(self, img):
        maxRate = 4
        brightness = (self.shadows_light / 100.0 - 0.0001) / maxRate
        midtones = 1 + maxRate * brightness

        self.midtonesRate[self.rgbMask] = midtones
        self.midtonesRate[~self.rgbMask] = (midtones - 1.0) / self.maskThreshold * self.rgbLuminance[~self.rgbMask] + 1.0

        self.brightnessRate[self.rgbMask] = brightness
        self.brightnessRate[~self.rgbMask] = (1 / self.maskThreshold * self.rgbLuminance[~self.rgbMask]) * brightness

        outImg = 255 * np.power(img / 255.0, 1.0 / self.midtonesRate) * (1.0 / (1 - self.brightnessRate))

        img = outImg
        img[img < 0] = 0
        img[img > 255] = 255

        img = img.astype(np.uint8)
        return img
                          
def ps_shadow_highlight_adjust_and_save_img(psSH, origin_image):
    psSH.shadows_light = 50
    image = psSH.adjust_image(origin_image)
    cv2.imwrite('py_sh_out_01.png', image)


def ps_shadow_highlight_adjust(path):
    """
    阴影提亮调整
    """
    origin_image = cv2.imread(path)

    psSH = PSShadowHighlight(origin_image)
    # ps_shadow_highlight_adjust_and_save_img(psSH, origin_image)

    def update_shadows_light(x):
        psSH.shadows_light = x
            
    # 创建图片显示窗口
    title = "ShadowHighlight"
    cv2.namedWindow(title, cv2.WINDOW_NORMAL)   
    cv2.resizeWindow(title, 800, 600)
    cv2.moveWindow(title, 0, 0)

    # 创建阴影提亮操作窗口
    option_title = "Option"
    cv2.namedWindow(option_title, cv2.WINDOW_NORMAL)   
    cv2.resizeWindow(option_title, 400, 20)
    cv2.moveWindow(option_title, 0, 630)
    cv2.createTrackbar('shadows_light', option_title, psSH.shadows_light, 100, update_shadows_light)

    while True:
        image = psSH.adjust_image(origin_image)
        cv2.imshow(title, image)
        if cv2.waitKey(1) == ord('q'):
            break
    cv2.destroyAllWindows()        

if __name__ == '__main__':
    '''
        运行环境:Python 3
        执行:python3 ps_shadow_hightlight.py <图片路径>
        如:python3 ps_shadow_hightlight.py test.jpg
    '''
    if len(sys.argv) == 1:
        print("参数错误:未传入图片路径!")
        sys.exit(-1)
    img_path = sys.argv[1]
    print("img_path Params:", img_path)
    ps_shadow_highlight_adjust(img_path)

3、最终效果

默认效果(程度 50%)与 PS 中阴影的默认效果对比:
下图为与 PS 默认效果对比,左边为 PS 默认效果(数量 30,色调 50%,半径 30,饱和度 +20),右边为上面的 python 实现的默认 50% 程度的效果,基本差不多。

其他逆光图片的效果图:
以下是 Python 实现的在其他图片效果,左边是原图,右边是处理后的图,默认参数都是 50%,阴影阈值使用的正交叠底后的均值(每张图自动计算,不需人为修改):
PS 阴影/高光中阴影提亮效果之 Python 实现_第4张图片
PS 阴影/高光中阴影提亮效果之 Python 实现_第5张图片

PS 阴影/高光中阴影提亮效果之 Python 实现_第6张图片
PS 阴影/高光中阴影提亮效果之 Python 实现_第7张图片
PS 阴影/高光中阴影提亮效果之 Python 实现_第8张图片

你可能感兴趣的:(OpenCV,图像处理,Python,python,opencv,图像处理,PS,阴影高光)