《Python计算机视觉》——基本的图像操作和处理

1.1 PIL:Python图像处理类库

PIL(Python Imaging Library,图像处理类库)提供了通用的图像处理功能,以及大量有用的基本图像操作,比如图像缩放、裁剪、旋转、颜色转换等。PIL是免费的,可以从http://www.pythonware.com/products/pil/下载。
利用PIL中的函数,我们可以从大多数图像格式的文件中读取数据,然后写入最常见的图像格式文件中。PIL中最重要的模块为Image。要读取一幅图像,可以使用:

from PIL import Image
pil_im = Image.open('one.jpeg')
pil_im.show()

上述代码的返回值pil_im是一个PIL图像对象。
在这里插入图片描述
图像的颜色转换可以使用convert()方法来实现。要读区一幅图像,并将其转换成灰度图像,只需要加上convert(‘L’),如下所示:

from PIL import Image
pil_im = Image.open('one.jpeg').convert('L')
pil_im.show()

上述代码返回值:
在这里插入图片描述
在PIL文档中有一些例子,参见http://www.pythonware.com/library/pil/handbook/index.htm。

1.1.1 转换图像格式

通过save()方法,PIL可以将图像保存成多种格式的文件。下面的例子从文件名列表(filelist)中读取所有的图像文件,并转换成JPG格式:

import os

def batchrename():
    # 遍历整个文件夹中的图像文件
    data_dir = '/Users/hjl/workspace/daily/computer_vision/test'
    filelist = os.listdir(data_dir)      # 返回指定文件夹包含的文件或文件假的名字的列表
    for infile in filelist:
        # 修改原图像文件格式
        outfile = os.path.splitext(infile)               # os.path.splitext()将文件名和扩展名分开
        if outfile[1] == ".png":
            newname = outfile[0] + ".jpg"
            print(infile)
            os.chdir(data_dir)
            os.rename(infile, newname)

def main():
    batchrename()
    return

if __name__ == '__main__':
    batchrename()

上述代码运行结果,如果文件不是JPEG格式,会自动将其转换成JPEG格式;如果转换失败,它会在控制台输出一条报告失败的消息。

本书会处理大量图像列表。下面将创建一个包含文件夹中所有图像文件的文件名列表。首先新建一个问价,命名为imtools.py,来存储一些经常使用的图像操作,然后将下面的函数添加进去:

import os
def get_imlist(path):
    """返回目录中所有的JPG图像的文件名列表"""

    return [os.path.join(path, f) for f in os.listdir(path) if f.endswith('.jpg')]

1.1.2 创建缩略图

使用PIL可以很方便的创建图像的缩略图。thumbnail()方法接受一个元组参数(该参数指定生成缩略图的大小),然后将图像转换成符号元组参数指定大小的缩略图。如:创建最长边为128像素的缩略图,可以使用以下命令:

import pylab as pl
from PIL import Image
from pylab import *
# 读取图像
pil_im = Image.open('0.jpeg')
pl.subplot(121)
imshow(pil_im), title('master_map')
# 创建缩略图
pl.subplot(122)
pil_im = Image.open('0.jpeg')
pil_im.thumbnail((128, 128))
imshow(pil_im), title('minimizing_chart')
pl.show()

上述代码运行结果:
在这里插入图片描述

1.1.3 复制和粘贴图像区域

使用crop()方法可以从一幅图像中裁剪指定区域:

import pylab as pl
from PIL import Image
from pylab import *
# 读取图像
pil_im = Image.open('0.jpeg')
pl.subplot(121)
imshow(pil_im), title('master_map')
# 复制和粘贴
pl.subplot(122)
box = (100, 100, 400, 400)
region = pil_im.crop(box)
region = region.transpose(Image.ROTATE_180)
pil_im.paste(region, box)
imshow(pil_im), title('copy_paste')
pl.show()

代码运行结果如下:
在这里插入图片描述

1.1.4 调整尺寸和旋转

要调整一幅图像的尺寸,我们可以调用resize()方法。该方法的参数是一个元组,用来指定新图像的大小:

import pylab as pl
from PIL import Image
from pylab import *
# 读取图像
pil_im = Image.open('0.jpeg')
pl.subplot(121)
imshow(pil_im), title('master_map')
# 调整尺寸
pl.subplot(122)
out = pil_im.resize((128, 128))
imshow(out), title('adjusted')
pl.show()

运行结果:
在这里插入图片描述

要旋转一幅图像,可以使用逆时针方式表示旋转角度,然后调用rotate()方法:

import pylab as pl
from PIL import Image
from pylab import *
# 读取图像
pil_im = Image.open('0.jpeg')
pl.subplot(121)
imshow(pil_im), title('master_map')
# 旋转图像
pl.subplot(122)
out = pil_im.rotate(45)
imshow(out), title('after_rotation')
pl.show()

运行结果:
在这里插入图片描述

1.2 Matplotlib

Matplotlib可以绘制出高质量的图表,是个很好的类库,具有比PIL更强大的绘图功能。可以从http://matplotlib.sourceforge.net/免费下载。

1.2.1 绘制图像、点和线

from PIL import Image
from pylab import *
import pylab as pl

# 读取图像到数组中
im = array(Image.open('0.jpeg'))
# 绘制图像
pl.subplot(121)
imshow(im), title('master_map')
# 一些点
x = [100, 100, 400, 400]
y = [200, 500, 200, 500]

# # 默认为蓝色实线
# plot(x, y)
# # 带有圆圈标记的绿线
# plot(x, y, 'go-')
# # 带有正方形标记的黑色点线
# plot(x, y, "ks:")

pl.subplot(122)
# 使用红色星状标记绘制点
plot(x, y, 'r*')
# 绘制连接前两个点的线
plot(x[:2], y[:2])
# 添加标题,显示绘制的图像
title('Plotting:"0.jpeg"')
# 使坐标轴不显示
axis('off')
imshow(im)
pl.show()

上述代码运行结果:
在这里插入图片描述

show()命令首先打开图形用户界面(GUI),然后新建一个图像窗口。该图形用户界面会循环阻断脚本,然后暂停,直到最后一个图像窗口关闭。在每个脚本里,你只能调用一次show()命令,而且通常是在脚本的结尾调用。
注意:在Pylab库中,我们约定图像的左上角为坐标原点。图像的坐标轴是一个很有用的调试工具;但如果想绘制出较美观的图像,加上下列命令可以使坐标轴不显示:

axis('off')

1.2.2 图像轮廓和直方图

from PIL import Image
from pylab import *

# 读取图像到数组中
im = array(Image.open('0.jpg').convert('L'))

# 新建一个图像
figure()
# 不使用颜色信息
gray()
# 在原点的左上角显示轮廓图像
contour(im, origin='image')
axis('equal')
axis('off')
# 图像的直方图
figure()
hist(im.flatten(), 128)
show()

运行结果:
原始图像
在这里插入图片描述

等轮廓线图像
在这里插入图片描述
直方图图像
在这里插入图片描述
hist()函数只接受一维数组作为输入,所以在绘制图像直方图之前,必须先对图像进行压平处理。
flatten()方法将任意数组按照行优先准则转换成一维数组

1.2.3 交互式标注

用户有时需要和某些应用交互,例如在一幅图像中标记一些点,或者标注一些训练数据。Pylab库中的ginput()函数可以实现交互式标注。

1.3 NumPy

可以从http://www.scipy.org/Download免费下载

1.3.1 图像数组表示

from PIL import Image
from pylab import *

im = array(Image.open('0.jpeg'))
print(im.shape, im.dtype)
im = array(Image.open('0.jpeg').convert('L'), 'f')
print(im.shape, im.dtype)

控制台输出结果
在这里插入图片描述

1.3.2 灰度变换

import pylab as pl
from PIL import Image
from pylab import *

pl.subplot(231)
im = array(Image.open('0.jpg'))
gray()
imshow(im), title('im')

pl.subplot(232)
im1 = array(Image.open('0.jpg').convert('L'))
imshow(im1), title('im1')

pl.subplot(233)
im2 = 255 - im1    # 对图像进行反向处理
imshow(im2), title('im2')

pl.subplot(234)
im3 = (100.0/255) * im1 + 100    #将图像像素值变换到100~200区间
imshow(im3), title('im3')

pl.subplot(235)
im4 = 255.0 * (im1/255.0) ** 2    #对图像像素值求平方后得到的图像
imshow(im4), title('im4')

pl.show()

上述代码运行结果
在这里插入图片描述

1.3.3 图像缩放

把下面的函数添加到imtools.py文件里:

from pylab import *
from PIL import Image
def imresize(im, sz):
    """使用PIL对象重新定义图像数组的大小"""
    pil_im = Image.fromarray(uint8(im))

    return array(pil_im.resize(sz))

接下来的内容中会使用这个函数

1.3.4 直方图均衡化

图像灰度变换中一个非常有用的例子就是直方图均衡化。
直方图均衡化是指将一幅图像的灰度直方图变平,使变换后的图像中每个灰度值的分布概率都相同。在对图像作进一步处理之前,直方图均衡化通常是对图像灰度值进行归一化的一个非常好的方法,并且可以增强图像的对比度。
在这种情况下,直方图均衡化的变换函数是图像中像素值的累积分布函数。
下面的函数是直方图均衡化的具体实现。将这个函数添加到imtools.py里:

def histeq(im, nbr_bins = 256):
    """对一幅灰度图像进行直方图均衡化"""
    
    # 计算图像的直方图
    imhist, bins = histogram(im,flatten(), nbr_bins, normed=True)
    cdf = imhist.cumsum()  # 累积分布函数
    cdf = 255 * cdf / cdf[-1]   #归一化
    # 使用累积分布函数的线性插值,计算新的像素值
    im2 = interp(im.flatten(), bins[:-1], cdf)
    
    return im2.reshape(im.shape), cdf

该函数有两个输入参数,一个是灰度图像,一个是直方图中使用小区间的数目。函数返回直方图均衡化后的图像,以及用来做像素值映射的累积分布函数。注意:函数中使用到的累积分布函数的最后一个元素(下标为-1),目的是将其归一化到0~1范围。你可以像下面这样使用该函数:

from pylab import *
from PIL import Image
import pylab as pl


def histeq(im, nbr_bins = 256):
    """对一幅灰度图像进行直方图均衡化"""

    # 计算图像的直方图
    imhist, bins = histogram(im.flatten(), nbr_bins, density=True)
    cdf = imhist.cumsum()  # 累积分布函数
    cdf = 255 * cdf / cdf[-1]   #归一化
    # 使用累积分布函数的线性插值,计算新的像素值
    im2 = interp(im.flatten(), bins[:-1], cdf)

    return im2.reshape(im.shape), cdf

# 灰度图像
pl.subplot(221)
gray()
im = array(Image.open('0.jpeg').convert('L'))
axis('equal')
axis('off')
imshow(im)
# 均衡化后图像
im2, cdf = histeq(im)
pl.subplot(222)
imshow(im2)
# 对应直方图
pl.subplot(223)
hist(im.flatten(), 128)

pl.subplot(224)
hist(im2.flatten(), 128)

show()

上述代码运行结果
在这里插入图片描述

1.4 SciPy

SciPy(http://scipy.org/)是建立在NumPy基础上,可以实现数值积分、优化、统计、信号处理,以及对我们来说最重要的图像处理功能。

1.4.1 图像模糊

图像的高斯模糊是非常经典的图像卷积例子。本质上,图像模糊就是将(灰度)图像I和一个高斯核进行卷积操作

高斯模糊通常是其他图像处理操作的一部分,比如图像插值操作、兴趣点计算以及很多其他应用。
SciPy有用来滤波操作的scipy.ndimage.filters模块。该模块使用快速一维分离的方式来计算卷积。

from pylab import *
from PIL import Image
import pylab as pl
from numpy import *
from scipy.ndimage import gaussian_filter

im = array(Image.open('0.jpg'))     # 原始图像

im1 = array(Image.open('0.jpg').convert('L'))     # 原始灰度图像
gray()

im2 = gaussian_filter(im1, 2)    # 标准差为2的高斯滤波器
im3 = gaussian_filter(im1, 5)    # 标准差为5的高斯滤波器
im4 = gaussian_filter(im1, 10)   # 标准差为10的高斯滤波器

# 图片显示
pl.subplot(221)
imshow(im1), title('huidu')
pl.subplot(222)
imshow(im2), title('gaosi_2')
pl.subplot(223)
imshow(im3), title('gaosi_5')
pl.subplot(224)
imshow(im4), title('gaosi_10')

show()

上述代码运行结果
在这里插入图片描述

1.4.2 图像导数

强度变化可以用灰度图像I的x和y方向导数进行描述
我们可以用离散近似的方式来计算图像的导数。图像导数大多数可以通过卷积简单地实现

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值