前些天学习了Python图像处理库PIL(Python Imaging Library),觉得十分有趣,对于Photoshop的图像处理过程似乎有了新的见解,稍稍记录一下。
想到之前还有好多照片没有处理,这里特别选了一张[新疆那拉提]的照片来试试水。
1. 导入相关库
from PIL import Image
from pylab import *
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.font_manager import FontProperties
font = FontProperties(fname = r"C:\Windows\Fonts\Simsun.ttc",size=14)
2. 读取并查看图片
img=Image.open("./img/xj/green_1.jpg")
print(img.mode, img.size, img.format)
img_array=array(img)
print(img_array.shape)
figure(figsize=(12,5))
subplot(121)
axis('off')
imshow(img)
title(u'原图',fontproperties=font)
subplot(122)
title(u'原图直方图',fontproperties=font)
ax=gca()
ax.yaxis.get_major_formatter().set_powerlimits((0,1))
hist(img_array.flatten())
RGB (6000, 3376) JPEG (3376, 6000, 3)
这张图片是6000x3376像素,有三个通道的JPEG格式。
3. 分通道查看
此处列出2个通道,其他依次类推。
subplot(231)
title(u'R通道',fontproperties=font)
ax=gca()
ax.yaxis.get_major_formatter().set_powerlimits((0,1))
hist(img_array[:,:,0].flatten())
subplot(232)
title(u'G通道',fontproperties=font)
ax=gca()
ax.yaxis.get_major_formatter().set_powerlimits((0,1))
hist(img_array[:,:,1].flatten())
可以看出由于背光拍摄,这张图片的山体部分有些曝光不足。 我们可以试试把图片直方图均衡化看看效果如何。
4、图像调整
def equalization(img_array):
img_shape=img_array.shape
img2=np.zeros(shape=img_shape)
for p in range(3):
imhist,bins = histogram(img_array[:,:,p].flatten(),256)
cdf = imhist.cumsum() # 累积分布函数
cdf = 255 * cdf / cdf[-1] # 归一化
temp = interp(img_array[:,:,p].flatten(),bins[:-1],cdf)
img2[:,:,p] = np.reshape(temp,img_shape[:2])
img2=img2.astype(int)
return img2
然后我们就可以看到图片被处理成了这样子:
它的三个通道的像素值都被均衡调整了一下。
中间到底发生了什么呢?
我们把累计分布函数画出来看看。
其实,均衡化就是通过计算图各像素的像素值的分布,根据总体的情况进行调整。在我们的图片中,由于暗部较多,低像素值的像素数应该会比较多,这点可以从上图的曲线中也可以看出来。这样就会造成我们的曲线变成凸形的,在采用interp()进行插值时,低像素值的像素点就会被提高,也即是从我们图中的橙色线上移至蓝色线。这跟Photoshop里面利用曲线进行调整的道理类似。
可以推出,当我们图片亮部较多时,这个蓝色线会变成陡峭上升的形态,也即是会低于橙色线,这时采用上面的方法将会把图片整体压暗。
回来重新审视我们这张图,其实亮部没有问题,不需要调整。我们试试画一条曲线来直接调整暗部。
x1 = np.array([ 0, 32, 64, 96, 128, 160, 192, 224, 255])
y1 = np.array([ 30, 60, 100, 130, 150, 165, 200, 225, 250])
z1 = np.polyfit(x1, y1, 3)#用3次多项式拟合
p1 = np.poly1d(z1)
yvals=p1(x1)
figure(figsize=(5,5))
plot1=plt.plot(x1, y1, '*',label='original values')
plot2=plt.plot(x1, yvals, 'r',label='polyfit values')
plot(x,y,":")
plt.legend(loc=4)
axis([0,255,0,255])
我绘制了这样一条曲线:
def test1(img_array,curve):
img_shape=img_array.shape
img2=np.zeros(shape=img_shape)
xp=np.arange(0,256,1)
fp=curve(xp)
for p in range(3):
temp = interp(img_array[:,:,p].flatten(),xp,fp)
img2[:,:,p] = np.reshape(temp,img_shape[:2])
img2=img2.astype(int)
return img2
到这里我们就完成了一张图片曝光的粗略调整,相信进一步地可以实现很多PS里面的功能,应该也可以做出来一些滤镜。本人对PS各个功能的算法颇有兴趣,如果有小伙伴有什么创意或见解的话,欢迎在下面评论告诉我哦!