Python 图像处理(一)PIL

以前做图像处理时用的是matlab,但是matlab有一些不方便支出:

  • 不开源,当时使用的版本是破解版的,至于版权问题,此处就不讨论了;
  • 其一般只能用于实现,如果实现产业化则有很多不便;
  • 程序运行比较慢;
  • 与其他语言结合有点小问题。 当进入工作岗位之后,做的是大数据方向,接触了java与python后感觉python对于做图像处理会更加好,所以此处简单的对python操作图像做一些简单的介绍。
  1. 首先安装pytyhon,linux系统中 已经自己带了python,至于在window系统只安装则更加简单,下载一个Anaconda直接就可以安装了,后续的模块安装则直接使用pip安装会更加方便。在此处就不一一讲述了。

图像打开与显示

from PIL import Image
import numpy as np
import scipy
import matplotlib.pyplot as plt
lena = Image.open('lena.jpg')           //打开图像  
print(lena.mode)                       //打印图像类型
print(lena.getpixel((0,0)))           //打印图像(0,0)处像素值
lena.show()                            //图像显示

图像类型转化convert函数

python图像处理库PIL对于PNG、BMP和JPG彩色图像格式之间的互相转换都可以通过Image模块的open()和save()函数来完成。具体说就是,在打开这些图像时,PIL会将它们解码为三通道的“RGB”图像。用户可以基于这个“RGB”图像,对其进行处理。处理完毕,使用函数save(),可以将处理结果保存成PNG、BMP和JPG中任何格式。这样也就完成了几种格式之间的转换。同理,其他格式的彩色图像也可以通过这种方式完成转换。当然,对于不同格式的灰度图像,也可通过类似途径完成,只是PIL解码后是模式为“L”的图像。我们以图像输入图片说明为例,分辨率为512x512。

  1. 模式“RGB”转换为其他不同模式

a. 模式“1” 模式“1”为二值图像,非黑即白。但是它每个像素用8个bit表示,0表示黑,255表示白。下面我们将lena图像转换为“1”图像。

lena_1 = lena.convert("1")
print(lena_1.mode)
lena_1.show()

b. 模式“L”
模式“L”为灰色图像,它的每个像素用8个bit表示,0表示黑,255表示白,其他数字表示不同的灰度。在PIL中,从模式“RGB”转换为“L”模式是按照下面的公式转换的: L = R * 299/1000 + G * 587/1000+ B * 114/1000 下面我们将lena图像转换为“L”图像。

lena_1 = lena.convert("L")
print(lena_1.mode)
lena_1.show()

c模式“P”
模式“P”为8位彩色图像,它的每个像素用8个bit表示,其对应的彩色值是按照调色板查询出来的。下面我们使用默认的调色板将lena图像转换为“P”图像。

lena_1 = lena.convert("P")
print(lena_1.mode)
lena_1.show()

d 模式“RGBA” 模式“RGBA”为32位彩色图像,它的每个像素用32个bit表示,其中24bit表示红色、绿色和蓝色三个通道,另外8bit表示alpha通道,即透明通道。

lena_1 = lena.convert("RGBA")
print(lena_1.mode)
lena_1.show()

e 模式“CMYK” 模式“CMYK”为32位彩色图像,它的每个像素用32个bit表示。模式“CMYK”就是印刷四分色模式,它是彩色印刷时采用的一种套色模式,利用色料的三原色混色原理,加上黑色油墨,共计四种颜色混合叠加,形成所谓“全彩印刷”。 四种标准颜色是:C:Cyan = 青色,又称为‘天蓝色’或是‘湛蓝’M:Magenta = 品红色,又称为‘洋红色’;Y:Yellow = 黄色;K:Key Plate(blacK) = 定位套版色(黑色)。

从实例中可以得知PIL中“RGB”转换为“CMYK”的公式如下: C = 255 - R M = 255 - G Y = 255 - B K = 0 由于该转换公式比较简单,转换后的图像颜色有些失真。

f 模式“YCbCr” 模式“YCbCr”为24位彩色图像,它的每个像素用24个bit表示。YCbCr其中Y是指亮度分量,Cb指蓝色色度分量,而Cr指红色色度分量。人的肉眼对视频的Y分量更敏感,因此在通过对色度分量进行子采样来减少色度分量后,肉眼将察觉不到的图像质量的变化。 模式“RGB”转换为“YCbCr”的公式如下: Y= 0.257R+0.504G+0.098B+16 Cb = -0.148R-0.291G+0.439B+128 Cr = 0.439R-0.368G-0.071*B+128

按照公式,Y = 0.257197+0.564111+0.09878+16= 136.877 Cb= -0.148197-0.291111+0.43978+128= 100.785 Cr = 0.439197-0.368111-0.071*78+128 = 168.097 由此可见,PIL中并非按照这个公式进行“RGB”到“YCbCr”的转换。

g 模式“I” 模式“I”为32位整型灰色图像,它的每个像素用32个bit表示,0表示黑,255表示白,(0,255)之间的数字表示不同的灰度。在PIL中,从模式“RGB”转换为“I”模式是按照下面的公式转换的: I = R * 299/1000 + G * 587/1000 + B * 114/1000

h 模式“F” 模式“F”为32位浮点灰色图像,它的每个像素用32个bit表示,0表示黑,255表示白,(0,255)之间的数字表示不同的灰度。在PIL中,从模式“RGB”转换为“F”模式是按照下面的公式转换的: F = R * 299/1000+ G * 587/1000 + B * 114/1000

图像保存

img.save('d:/lena.jpg')

注:后面的转化代码处理模式不一样,其余都是一样的,所以没有写代码

图像通道分离与合并

还是以lena.jpg图像为例,实现图像通道分离合并的操作

from PIL import Image
import numpy as np
import scipy
import matplotlib.pyplot as plt

img = Image.open('len.jpg')
print(img.mode)
print(img.getpixel((0, 0)))
gray = img.convert("L")
r, g, b = img.split()  # 分离三通道
pic = Image.merge('RGB', (r, g, b))  # 合并三通道
plt.figure("beauty")
plt.subplot(2, 3, 1), plt.title('origin')
plt.imshow(img), plt.axis('off')
plt.subplot(2, 3, 2), plt.title('gray')
plt.imshow(gray, cmap='gray'), plt.axis('off')
plt.subplot(2, 3, 3), plt.title('merge')
plt.imshow(pic), plt.axis('off')
plt.subplot(2, 3, 4), plt.title('r')
plt.imshow(r, cmap='gray'), plt.axis('off')
plt.subplot(2, 3, 5), plt.title('g')
plt.imshow(g, cmap='gray'), plt.axis('off')
plt.subplot(2, 3, 6), plt.title('b')
plt.imshow(b, cmap='gray'), plt.axis('off')
plt.show()

结果如图所示 ![输入图片说明]

几何变换

Image类有resize()、rotate()和transpose()方法进行几何变换

  • 1、图像的缩放和旋转
dst = img.resize((128, 128))
dst = img.rotate(45) # 顺时针角度表示
  • 2、转换图像
dst = im.transpose(Image.FLIP_LEFT_RIGHT) #左右互换
dst = im.transpose(Image.FLIP_TOP_BOTTOM) #上下互换
dst = im.transpose(Image.ROTATE_90)  #顺时针旋转
dst = im.transpose(Image.ROTATE_180)
dst = im.transpose(Image.ROTATE_270)

图像矩阵变换

  • 在文章上半部分中主要利用Image.open()来打开一幅图像,然后直接对这个PIL对象进行操作。这种操作对于那些简单的图像操作还可以,但是如果需要对图像进行研究等复杂的操作则局限性很大。因此,通常我们加载完图片后,都是把图片转换成矩阵来进行更加复杂的操作。
  1. 打开图像并转换为矩阵
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
img=np.array(Image.open('d:/lena.jpg'))  #打开图像并转化为数组对象
print(img)                                    #打印数组
print(img.shape)                        #大小  (512, 512, 3)
print(img.dtype)                           # 类型 uint8
print(img.size)                            #图像大小  786432
plt.figure("lena")
plt.imshow(img)
plt.axis('off')
plt.show()

如果是RGB图片,那么转换为array之后,就变成了一个rowscolschannels的三维矩阵,因此,我们可以使用img[i,j,k]来访问像素值

  • 例1:打开图片,并随机添加一些椒盐噪声
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

img = np.array(Image.open('len.jpg'))

# 随机生成5000个椒盐
rows, cols, dims = img.shape
for i in range(5000):
    x = np.random.randint(0, rows)
    y = np.random.randint(0, cols)
    img[x, y, :] = 255

plt.figure("beauty")
plt.imshow(img)
plt.axis('off')
plt.show()

结果如图:

  • 例2:将lena图像二值化,像素值大于128的变为1,否则变为0
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

img = np.array(Image.open('len.jpg').convert('L'))

rows, cols = img.shape
for i in range(rows):
    for j in range(cols):
        if (img[i, j] <= 128):
            img[i, j] = 0
        else:
            img[i, j] = 1

plt.figure("lena")
plt.imshow(img, cmap='gray')
plt.axis('off')
plt.show()

结果如下图所示:输入图片说明

如果要对多个像素点进行操作,可以使用数组切片方式访问。切片方式返回的是以指定间隔下标访问 该数组的像素值。下面是有关灰度图像的一些例子:

img[i,:] = im[j,:] # 将第 j 行的数值赋值给第 i 行

img[:,i] = 100 # 将第 i 列的所有数值设为 100

img[:100,:50].sum() # 计算前 100 行、前 50 列所有数值的和

img[50:100,50:100] # 50~100 行,50~100 列(不包括第 100 行和第 100 列)

img[i].mean() # 第 i 行所有数值的平均值

img[:,-1] # 最后一列

img[-2,:] (or im[-2]) # 倒数第二行

直方图

一、画灰度图直方图

绘图都可以调用matplotlib.pyplot库来进行,其中的hist函数可以直接绘制直方图。

调用方式:
n, bins, patches = plt.hist(arr, bins=50, normed=1, facecolor='green', alpha=0.75)
hist的参数非常多,但常用的就这五个,只有第一个是必须的,后面四个可选

arr: 需要计算直方图的一维数组

bins: 直方图的柱数,可选项,默认为10

normed: 是否将得到的直方图向量归一化。默认为0

facecolor: 直方图颜色

alpha: 透明度

返回值 :

n: 直方图向量,是否归一化由参数设定

bins: 返回各个bin的区间范围

patches: 返回每个bin里面包含的数据,是一个list
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
img=np.array(Image.open('len.jpg').convert('L'))

plt.figure("lena")
arr=img.flatten()
n, bins, patches = plt.hist(arr, bins=256, normed=1, facecolor='green', alpha=0.75)
print(n)
print(bins)
print(patches)
plt.show()

得到如下图所示:输入图片说明

二、彩色图片直方图

实际上是和灰度直方图一样的,只是分别画出三通道的直方图,然后叠加在一起。

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
src=Image.open('len.jpg')
r,g,b=src.split()

plt.figure("lena")
ar=np.array(r).flatten()
plt.hist(ar, bins=256, normed=1,facecolor='r',edgecolor='r',hold=1)
ag=np.array(g).flatten()
plt.hist(ag, bins=256, normed=1, facecolor='g',edgecolor='g',hold=1)
ab=np.array(b).flatten()
plt.hist(ab, bins=256, normed=1, facecolor='b',edgecolor='b')
plt.show()

如图: 输入图片说明

转载于:https://my.oschina.net/112612/blog/1594140

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值