admin管理员组文章数量:1539828
Python-opencv 实现PS操作
加个目录快速跳转到你想要看的地方嘿嘿😀
- Python-opencv 实现PS操作
- 0. 罗里吧嗦的开头
- 1. 调整色阶操作 - levels-adjust
- 2. 调节饱和度 - Saturation
- 3. 调节亮度 - Illumi-adjust
- 4. 调节颜色曲线 - curves-filter
- 5. 图层混合方式 - layerBlending
0. 罗里吧嗦的开头
最近有个项目要做颜色变换,而对于我这种对色彩不敏感的人可是相当难受。调半天opencv色调,都不知道自己调的是啥。
于是乎。。。。有了个idea!!!
我找了个做美工设计的朋友帮我做了效果图。(photoshop)然后把操作思路和过程都给到我,这下子就只差复现photoshop的操作了。
所以就有了我在网上寻找总结的这一系列,用python-opencv实现的photoshop操作。(网上基本上都是C++ - opencv实现的)
后面如果有需要其他操作我会持续更新。如果没有找到python代码,我也会想办法自己复现一下的。😀(好像后面还要实现一下Photoshop的图层融合操作。😂)
1. 调整色阶操作 - levels-adjust
根据https://blog.csdn/maozefa/article/details/5643459这个链接里面给的公式自己写的python代码:
输入的参数如下图所示,dim代表要修改的分量。(dim单分量:0,1,2;RGB全分量的话:3)
def levels_adjust(img, Shadow, Midtones, Highlight, OutShadow, OutHighlight, Dim):
# print(img)
# dim = 3的时候调节RGB三个分量, 0调节B,1调节G,2调节R
if Dim == 3:
mask_shadow = img < Shadow
img[mask_shadow] = Shadow
mask_Highlight = img > Highlight
img[mask_Highlight] = Highlight
else:
mask_shadow = img[...,Dim]<Shadow
img[mask_shadow] = Shadow
mask_Highlight = img[...,Dim]>Highlight
img[mask_Highlight] = Highlight
if Dim == 3:
Diff = Highlight - Shadow
rgbDiff = img - Shadow
clRgb = np.power(rgbDiff / Diff, 1 / Midtones)
outClRgb = clRgb * (OutHighlight - OutShadow) / 255 + OutShadow
data = np.array(outClRgb*255, dtype='uint8')
img = data
else:
Diff = Highlight - Shadow
rgbDiff = img[...,Dim] - Shadow
clRgb = np.power(rgbDiff/Diff, 1/Midtones)
outClRgb = clRgb*(OutHighlight - OutShadow)/255 + OutShadow
data = np.array(outClRgb * 255, dtype='uint8')
img[..., Dim] = data
return img
2. 调节饱和度 - Saturation
代码我使用了这个博主写的:https://blog.csdn/benja_k/article/details/95478100 他里面也有具体的代码原理解读,有兴趣可以直接跳转过去看。
他的输入是一个比例,范围是(-1,1)
def Saturation(rgb_img, increment):
img = rgb_img * 1.0
img_min = img.min(axis=2)
img_max = img.max(axis=2)
img_out = img
# 获取HSL空间的饱和度和亮度
delta = (img_max - img_min) / 255.0
value = (img_max + img_min) / 255.0
L = value / 2.0
# s = L<0.5 ? s1 : s2
mask_1 = L < 0.5
s1 = delta / (value)
s2 = delta / (2 - value)
s = s1 * mask_1 + s2 * (1 - mask_1)
# 增量大于0,饱和度指数增强
if increment >= 0:
# alpha = increment+s > 1 ? alpha_1 : alpha_2
temp = increment + s
mask_2 = temp > 1
alpha_1 = s
alpha_2 = s * 0 + 1 - increment
alpha = alpha_1 * mask_2 + alpha_2 * (1 - mask_2)
alpha = 1 / alpha - 1
img_out[:, :, 0] = img[:, :, 0] + (img[:, :, 0] - L * 255.0) * alpha
img_out[:, :, 1] = img[:, :, 1] + (img[:, :, 1] - L * 255.0) * alpha
img_out[:, :, 2] = img[:, :, 2] + (img[:, :, 2] - L * 255.0) * alpha
# 增量小于0,饱和度线性衰减
else:
alpha = increment
img_out[:, :, 0] = img[:, :, 0] + (img[:, :, 0] - L * 255.0) * alpha
img_out[:, :, 1] = img[:, :, 1] + (img[:, :, 1] - L * 255.0) * alpha
img_out[:, :, 2] = img[:, :, 2] + (img[:, :, 2] - L * 255.0) * alpha
# img_out = img_out / 255.0
# RGB颜色上下限处理(小于0取0,大于1取1)
# mask_3 = img_out < 0
# mask_4 = img_out > 255
# img_out = img_out * (1 - mask_3)
# img_out = img_out * (1 - mask_4) + mask_4
return np.array(img_out,dtype='uint8')
3. 调节亮度 - Illumi-adjust
代码我使用了这个博主写的:https://blog.csdn/weixin_30896511/article/details/95614626 比较简单哈,同样他里面也有具体的代码原理解读,有兴趣可以直接跳转过去看。
def Illumi_adjust(alpha, img):
if alpha > 0 :
img_out = img * (1 - alpha) + alpha * 255.0
else:
img_out = img * (1 + alpha)
return np.array(img_out,dtype='uint8')
4. 调节颜色曲线 - curves-filter
也就是RGB曲线,这个在PS里面调节有特别多的使用。但是由于曲线都是手动调整的,所以一开始我不觉得能用代码实现。但是后面发现可以把PS中的曲线导出文件,然后再通过Python进行曲线的加载,最后实现RGB曲线的调节。nice!!!😀
具体的代码我是找的这个源码:https://github/pfdevilliers/python-image-filters
操作的话,只要通过PS导出.acv曲线文件(如下):
然后通过源码中的filter.py代码,输入图片以及曲线文件。就可以实现对图片RGB曲线的调节。
class Filter:
def __init__(self, acv_file_path, name):
self.name = name
with open(acv_file_path, 'rb') as acv_file:
self.curves = self._read_curves(acv_file)
self.polynomials = self._find_coefficients()
def _read_curves(self, acv_file):
_, nr_curves = unpack('!hh', acv_file.read(4))
curves = []
for i in range(0, nr_curves):
curve = []
num_curve_points, = unpack('!h', acv_file.read(2))
for j in range(0, num_curve_points):
y, x = unpack('!hh', acv_file.read(4))
curve.append((x, y))
curves.append(curve)
return curves
def _find_coefficients(self):
polynomials = []
for curve in self.curves:
xdata = [x[0] for x in curve]
ydata = [x[1] for x in curve]
p = interpolate.lagrange(xdata, ydata)
polynomials.append(p)
return polynomials
def get_r(self):
return self.polynomials[1]
def get_g(self):
return self.polynomials[2]
def get_b(self):
return self.polynomials[3]
def get_c(self):
return self.polynomials[0]
class FilterManager:
def __init__(self):
self.filters = {}
# add some stuff here
def add_filter(self, filter_obj):
# Overwrites if such a filter already exists
# NOTE: Fix or not to fix?
self.filters[filter_obj.name] = filter_obj
def apply_filter(self, filter_name, image_array):
if image_array.ndim < 3:
raise Exception('Photos must be in color, meaning at least 3 channels')
else:
def interpolate(i_arr, f_arr, p, p_c):
p_arr = p_c(f_arr)
return p_arr
# NOTE: Assumes that image_array is a numpy array
image_filter = self.filters[filter_name]
# NOTE: What happens if filter does not exist?
width, height, channels = image_array.shape
filter_array = numpy.zeros((width, height, 3), dtype=float)
p_r = image_filter.get_r()
p_g = image_filter.get_g()
p_b = image_filter.get_b()
p_c = image_filter.get_c()
filter_array[:, :, 0] = p_r(image_array[:, :, 0])
filter_array[:, :, 1] = p_g(image_array[:, :, 1])
filter_array[:, :, 2] = p_b(image_array[:, :, 2])
filter_array = filter_array.clip(0, 255)
filter_array = p_c(filter_array)
filter_array = numpy.ceil(filter_array).clip(0, 255)
return filter_array.astype(numpy.uint8)
if __name__ == '__main__':
img_filter = Filter('curves/curves.acv', 'rgb')
im = cv2.imread('tmp/test.png')
im.show()
image_array = im
filter_manager = FilterManager()
filter_manager.add_filter(img_filter)
filter_array = filter_manager.apply_filter('rgb', image_array)
cv2.imshow('',filter_array)
cv2.waitKey(0)
5. 图层混合方式 - layerBlending
公式大部分参考https://jingyan.baidu/article/36d6ed1f7c04801bcf4883c2.html
这里也有一部分,原理的讲解,和公式。以及博主用c语言实现的操作。https://wwwblogs/jsxyhelu/p/12934978.html
有一些没有实现,实际上是我参照ps的效果和代码实现的效果进行对比的时候,前面几种混合方式都挺好的。但是从亮光开始,对比效果看差别挺大的,而且不同网上的公式都有些不同,但是也没有和ps一样的效果,所以做到后面就终止了,因为我自己只需要正片叠加这种😂。(这里我反复校对了我的代码,应该没有什么问题,也有可能是代码实现的有问题,有发现哪里有问题的欢迎大家指出。)
import numpy as np
import cv2
def Darken(target, blend):
# 变暗
return np.minimum(target, blend)
def Multiply(target, blend):
# 正片叠底
return np.array(np.multiply(target/256,blend/256)*256, dtype=np.uint8)
def ClolorBurn(target, blend):
# 颜色加深
# return np.array((1-(1-target/256)/(blend/256))*256, dtype=np.uint8)
return (1-(1-target/256)/(blend/256))
def LinearBurn(target, blend):
# 线性加深
return target/256+blend/256-1
def Lighten(target, blend):
# 变亮
return np.maximum(target, blend)
def Screen(target, blend):
# 滤色
return 1-(1-target/256)*(1-blend/256)
def ColorDodge(target, blend):
# 颜色减淡
target = target / 256
blend = blend / 256
return target+(target*blend)/(1-blend)
def LinearDodge(target, blend):
# 线性减淡
return cv2.add(target, blend)
def Overlay(target, blend):
# 叠加
mask1 = target<=128
mask2 = target>128
img = np.zeros(target.shape,dtype=np.float64)
img[mask1] = np.multiply(target[mask1]/256,blend[mask1]/256) #(暗部正片叠底,更暗)
img[mask2] = 1-(1-target[mask2]/256)*(1-blend[mask2]/256) #(亮部滤色,更亮)
return img
def SoftLight(target, blend):
# 柔光
mask1 = blend<=128
mask2 = blend>128
target = target/256
blend = blend/256
img = np.zeros(target.shape, dtype=np.float64)
img[mask1] = (target[mask1]*blend[mask1])/0.5 + (target[mask1]*target[mask1])*(1-2*blend[mask1])
img[mask2] = (target[mask2]*(1-blend[mask2]))/0.5 + np.sqrt(target[mask2]) * (2*blend[mask2] - 1)
return img
def HardLight(target, blend):
# 强光
mask1 = blend <= 128
mask2 = blend > 128
target = target / 256
blend = blend / 256
img = np.zeros(target.shape, dtype=np.float64)
img[mask1] = target[mask1]*blend[mask1]/0.5
img[mask2] = 1 - (1-target[mask2])*(1-blend[mask2])/0.5
return img
def VividLight(target, blend):
# 亮光
mask1 = blend <= 128
mask2 = blend > 128
target = target / 256
blend = blend / 256
img = np.zeros(target.shape, dtype=np.float64)
img[mask1] = target[mask1] - (1-target[mask1])*(1-2*blend[mask1])/(2*blend[mask1])
img[mask2] = target[mask2] + target[mask2]*(2*blend[mask2]-1)/(2*(1-blend[mask2]))
return img
def LinearLight(target, blend):
#线性光
return target/256 + 2*blend/256 -1
版权声明:本文标题:Python-opencv 实现photoshop中的一些基本操作 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dongtai/1725821537a1044295.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论