PIL提供了通用的图像处理功能,以及大量的基本图像操作,如图像缩放、裁剪、旋转、颜色转换等。

Matplotlib提供了强大的绘图功能,其下的pylab/pyplot接口包含很多方便用户创建图像的函数。

为了观察和进一步处理图像数据,首先需要加载图像文件,并且为了查看图像数据,我们需要将其绘制出来。

from PIL import Image

import matplotlib.pyplot as plt

import numpy as np

# 加载图像

img = Image.open("tmp.jpg")

# 转为数组

img_data = np.array(img)

# 可视化

plt.imshow(img_data)

plt.show()

对于图像,我们常见的操作有调整图像尺寸,旋转图像以及灰度变换

from PIL import Image

import matplotlib.pyplot as plt

img = Image.open("girl.jpg")

plt.figure()

# 子图

plt.subplot(221)

# 原图

plt.imshow(img)

plt.subplot(222)

# 将图像缩放至 256 * 256

plt.imshow(img.resize((256, 256)))

plt.subplot(223)

# 将图像转为灰度图

plt.imshow(img.convert('L'))

plt.subplot(224)

# 旋转图像

plt.imshow(img.rotate(45))

# 保存图像

plt.savefig("tmp.jpg")

plt.show()

效果演示 :

在平常的使用中,绘制图像的轮廓也经常被使用,因为绘制轮廓需要对每个坐标(x, y)的像数值施加同一个阙值,所以需要将图像灰度化

from PIL import Image

import matplotlib.pyplot as plt

import numpy as np

img = Image.open("girl.jpg")

gray_img = np.array(img.convert('L'))

plt.figure()

# 绘制图像灰度化

plt.gray()

# 关闭坐标轴

plt.axis('off')

# 绘制灰度图像

plt.contour(gray_img, origin='image')

plt.figure()

# 绘制直方图,flatten()表示将数组展平

plt.hist(gray_img.flatten(), 128)

plt.show()

轮廓图及直方图:

图像的直方图用来表征该图像的像素值的分布情况。用一定数目的小区间来指定表征像素值的范围,每个小区间会得到落入该小区间表示范围的像素数目。hist()函数用于绘制图像的直方图,其只接受一维数组作为第一个参数输入,其第二个参数用于指定小区间的数目。

有时用户需要和应用进行交互,如在一幅图像中标记一些点。Pylab/pyplot库中的ginput()函数就可以实现交互式标注

from PIL import Image

import matplotlib.pyplot as plt

img = Image.open(r"girl.jpg")

plt.imshow(img)

x = plt.ginput(3)

print("clicked point: ", x)

注:该交互在集成编译环境(pyCharm)中如果不能调出交互窗口则无法进行点击,可以在命令窗口下成功执行。

以上我们通过numpy的array()函数将Image对象转换成了数组,以下将展示如何从数组转换成Image对象

from PIL import Image

import numpy as np

img = Image.open(r"girl.jpg")

img_array = np.array(img)

img = Image.fromarray(img_array)

在图像灰度变换中有一个非常有用的例子就是直方图均衡化。直方图均衡化是指将一幅图像的灰度直方图变平,使变换后的图像中每个灰度值的分布概率都相同。直方图均衡化通常是对图像灰度值进行归一化的一个非常好的方法,并且可以增强图像的对比度。

直方图均衡化的变换函数是图像中像素值的累积分布函数(cumulative distribution function,将像素值的范围映射到目标范围的归一化操作)。

from PIL import Image

import matplotlib.pyplot as plt

import numpy as np

def histogram_equalization(img: np, nbr_bins=256):

imhist, bins = np.histogram(img.flatten())

cdf = imhist.cumsum() # 累计分布函数

# 归一化

cdf = 255 * cdf / cdf[-1]

# 使用累积分布函数进行线性插值,计算新的像素值

img2 = np.interp(img.flatten(), bins[:-1], cdf)

return img2.reshape(img.shape), cdf

img = Image.open(r"girl.jpg").convert('L')

img2, cdf = histogram_equalization(np.array(img))

plt.figure()

plt.gray()

# 绘制子图

plt.subplot(232)

# 变换函数

plt.plot(cdf)

plt.subplot(231)

plt.hist(np.array(img).flatten(), 256)

# 关闭坐标轴,对上一个子图有效

plt.axis('off')

plt.subplot(233)

plt.hist(np.array(img2).flatten(), 256)

plt.axis('off')

plt.subplot(234)

plt.imshow(img)

plt.axis('off')

plt.subplot(236)

plt.imshow(img2)

plt.axis('off')

# 保存绘制图像

plt.savefig("tmp.jpg")

plt.show()

处理结果

可见,直方图均衡化的图像的对比度增强了,原先图像灰色区域的斜街变得清晰。

PCA(Principal Component Analysis, 主成分分析)是一个非常有用的降维技巧,它可以在使用尽可能少的维数的前提下,尽可能多地保持训练数据的信息。详细介绍及使用见我的另一篇文章:PCA降维

SciPy是建立在Numpy基础上,用于数值运算的开源工具包。Scipy提供很多高效的操作,可以实现数值积分、优化、统计、信号处理,以及对我们来说最为重要的图像处理功能。

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

\[I_\sigma = I * G_\sigma

\]

其中, \(*\) 表示卷积操作;\(G\) 表示标准差为 \(\sigma\) 的二维高斯核,定义为:

\[G_\sigma = \frac{1}{2\pi \sigma^2} e^{-(x^2+y^2) / 2 \sigma^2}

\]

高斯模糊通常是其他图像处理操作的一部分,比如图像插值操作、兴趣点计算以及其他应用。

Scipy有用来做滤波操作的scipy.ndimage.filters模块。该模块使用快速一维分离的方式来计算卷积。使用方式:

from PIL import Image

import numpy as np

from scipy.ndimage import filters

img = Image.open(r"girl.jpg").convert('L')

img = np.array(img)

img2 = filters.gaussian_filter(img, 2)

img3 = filters.gaussian_filter(img, 5)

img4 = filters.gaussian_filter(img, 10)

绘制结果

上面使用的gaussian_filter()函数中的后一个参数表示标准差 \(\sigma\) ,可见随着 \(\sigma\) 的增加,图像变得越来越模糊。 \(\sigma\) 越大,处理后图像细节丢失越多。如果是打算模糊一幅彩色图像,只需要简单地对每一个颜色通道进行高斯模糊:

from PIL import Image

import numpy as np

from scipy.ndimage import filters

img = Image.open(r"girl.jpg")

img = np.array(img)

img2 = np.zeros(img.shape)

for i in range(img2.shape[2]):

img2[:, :, i] = filters.gaussian_filter(img[:, :, i], 5)

# 将像素值用八位表示

img2 = np.array(img2, 'uint8')

模糊结果:

在很多应用中,图像强度的变化情况是非常重要的,强度的变化可以使用灰度图像的 \(x\) 和 \(y\) 方向导数 \(I_x\) 和 \(I_y\)进行描述

图像的梯度向量为 \(\bigtriangledown I = [I_x, I_y]^T\)。梯度有两个重要属性,一是梯度的大小:

\[| \bigtriangledown I | = \sqrt{I_x^2 + I_y^2}

\]

它描述了图像强度变化的强弱,另一个是图像的角度:

\[\alpha = arctan2(I_x, I_y)

\]

它描述了图像在每个点上强度变化最大的方向。Numpy中的arctan2()函数返回弧度表示的有符号角度,角度的变化区间为 \((-\pi, \pi)\)

可以使用离散近似的方式来计算图像的导数。图像倒数大多数可以通过卷积简单地实现:

\[I_x = I*D_x 和 I_y = I*D_y

\]

对于 \(D_x\) 和 \(D_y\),通常选择Prewitt滤波器:

\[D_x = \left[

\begin{matrix}

-1 & 0 & 1 \\

-1 & 0 & 1 \\

-1 & 0 & 1

\end{matrix}

\right]

\]

\[D_y = \left[

\begin{matrix}

-1 & -1 & -1 \\

0 & 0 & 0 \\

1 & 1 & 1

\end{matrix}

\right]

\]

或者Sobel滤波器

\[D_x = \left[

\begin{matrix}

-1 & 0 & 1 \\

-2 & 0 & 2 \\

-1 & 0 & 1

\end{matrix}

\right]

\]

\[D_y = \left[

\begin{matrix}

-1 & -2 & -1 \\

0 & 0 & 0 \\

1 & 2 & 1

\end{matrix}

\right]

\]

这些导数滤波器可以使用scipy.ndimage.filters模块地标准卷积操作来简单地实现

from PIL import Image

import numpy as np

from scipy.ndimage import filters

img = Image.open(r"girl.jpg").convert('L')

img = np.array(img)

imgx = np.zeros(img.shape)

# Sobel导数滤波器

filters.sobel(img, 1, imgx)

imgy = np.zeros(img.shape)

filters.sobel(img, 0, imgy)

magnitude = np.sqrt(imgx**2+imgy**2)

sobel()函数的第二个参数选择 \(x\) 或 \(y\) 方向的导数,第三个参数保存输出变量。在图像中,正导数显示为亮的像素,负导数显示为暗的像素,灰色区域表示导数的值接近零。

上面计算图像导数的方法存在缺陷:在该方法中,滤波器的尺度需要随着图像分辨率的变化而变化(?)。为了在图像噪声方面更稳健,以及在任意尺度上计算导数,我们可以使用高斯导数滤波器:

\[I_x = I * G_{\sigma x} 和 I_y = I*G_{\sigma y}

\]

其中,\(G_{\sigma x}\) 和\(G_{\sigma y}\)表示\(G_\sigma\) 在 \(x\) 和 \(y\) 方向上的导数,\(G_\sigma\) 表示标准差为 \(\sigma\) 的高斯函数。以下给出使用样例:

from PIL import Image

import matplotlib.pyplot as plt

import numpy as np

from scipy.ndimage import filters

img = Image.open(r"girl.jpg").convert('L')

img = np.array(img)

sigma = 2

imgx = np.zeros(img.shape)

imgy = np.zeros(img.shape)

filters.gaussian_filter(img, (sigma, sigma), (0, 1), imgx)

filters.gaussian_filter(img, (sigma, sigma), (1, 0), imgy)

magnitude = np.sqrt(imgx**2+imgy**2)

结果演示:

在对图像进行处理时,去噪也是很重要的一环。图像去噪是在去除图像噪声的同时,尽可能地保留图像细节和结构地处理技术,以下给出使用ROF去噪模型地Demo:

from PIL import Image

import matplotlib.pyplot as plt

import numpy as np

from scipy.ndimage import filters

def de_noise(img, U_init, tolerance=0.1, tau=0.125, tv_weight=100):

U = U_init

Px = Py = img

error = 1

while error > tolerance:

Uold = U

# 变量U梯度的x分量

gradUx = np.roll(U, -1, axis=1)-U

# 变量U梯度的y分量

gradUy = np.roll(U, -1, axis=0)-U

# 更新对偶变量

PxNew = Px + (tau/tv_weight)*gradUx

PyNew = Py + (tau/tv_weight)*gradUy

NormNew = np.maximum(1, np.sqrt(PxNew**2+PyNew**2))

# 更新x,y分量

Px = PxNew / NormNew

Py = PyNew / NormNew

# 更新原始变量

RxPx = np.roll(Px, 1, axis=1) # 将x分量向x轴正方向平移

RyPy = np.roll(Py, 1, axis=0) # 将y分量向y轴正方向平移

DivP = (Px - RxPx) + (Py - RyPy) # 对偶域散度

U = img + tv_weight * DivP

error = np.linalg.norm(U - Uold)/np.sqrt(img.shape[0] * img.shape[1])

return U, img-U

if __name__ == '__main__':

im = np.zeros((500, 500))

im[100:400,100:400] = 128

im[200:300, 200:300] = 255

im = im + 30 * np.random.standard_normal((500, 500))

U, T = de_noise(im, im)

G = filters.gaussian_filter(im, 10)

plt.figure()

plt.gray()

plt.subplot(221).set_title("Original image")

plt.axis('off')

plt.imshow(im)

plt.subplot(222).set_title("Gauss blurred image")

plt.axis('off')

plt.imshow(G)

plt.subplot(223).set_title("ROF")

plt.axis('off')

plt.imshow(U)

plt.savefig('tmp.jpg')

plt.show()

结果演示

ROF去噪后的图像保留了边缘和图像的结构信息,同时模糊了“噪声”。

np.roll()函数可以循环滚动元素,np.linalg.norm()用于衡量两个数组间的差异。

之后有空将补充图像去噪

参考书籍

Python计算机视觉

python的所有基本函数图像_基本图像操作和处理(python)相关推荐

  1. flask渲染图像_用于图像推荐的Flask应用

    flask渲染图像 After creating a Python-based machine learning application you might want to get it runnin ...

  2. php mysql 图像_将图像插入MySQL并使用PHP检索图像

    此文可能比较繁琐,有更好的方法,但是出于教程目的,这是我的""最佳实践"的路线. 今天,我们将讨论一个似乎每个人都有些困惑的话题--在MySQL中存储BLOB图像,然后使 ...

  3. python创建类统计属性_轻松创建统计数据的Python包

    python创建类统计属性 介绍 (Introduction) Sometimes you may need a distribution figure for your slide or class ...

  4. python高斯噪声怎么去除_手把手教你如何实现Python手势识别与控制(含代码及动图)...

    Python手势识别与控制 概述 本文中的手势识别与控制功能主要采用 OpenCV 库实现, OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库, 可以运行在Linux, Windows ...

  5. python image 转成字节_就是这么牛!三行Python代码,让数据处理速度提高2到6倍

    本文可以教你仅使用 3 行代码,大大加快数据预处理的速度. Python 是机器学习领域内的首选编程语言,它易于使用,也有很多出色的库来帮助你更快处理数据.但当我们面临大量数据时,一些问题就会显现-- ...

  6. python新手入门项目推荐_推荐:一个适合于Python新手的入门练手项目

    随着人工智能的兴起,国内掀起了一股Python学习热潮,入门级编程语言,大多选择Python,有经验的程序员,也开始学习Python,正所谓是人生苦短,我用Python 有个Python入门练手项目, ...

  7. python各种包安装顺序_史上最全的Python包管理工具:Anaconda教程

    事实上Anaconda 和 Jupyter notebook已成为数据分析的标准环境. 简单来说,Anaconda是包管理器和环境管理器,Jupyter notebook 可以将数据分析的代码.图像和 ...

  8. python image 转成字节_就是这么流弊!三行Python代码,让数据处理速度提高2到6倍

    选自TowardsDataScience 作者:George Seif 本文转自机器之心(nearhuman2014) 本文可以教你仅使用 3 行代码,大大加快数据预处理的速度. Python 是机器 ...

  9. python制作ai小说网_【案例分享】使用Python创建AI比你想象的轻松

    您可能对AI领域,主要开发阶段,成就,结果和产品使用感兴趣.有数百个免费源和教程描述使用Python的AI.但是,没有必要浪费你的时间看他们.这里是一个详细的指南,你需要知道在使用Python构建人工 ...

  10. python怎么下载pil库_如何在windows下安装Python的PIL库

    最近在学习廖大大的Python教程,今天正好学习到"安装第三方模块"这一章节,第一个任务就是安装"PIL"库. PIL库是个啥?廖大大的告诉我们: Python ...

最新文章

  1. SQL语句在数据库中是如何执行的
  2. 推荐系统常用评价指标和代码实现
  3. USACO-Section1.2 Broken Necklace (枚举法)
  4. [dev][ipsec][esp] ipsec链路中断的感知问题
  5. TypeScript 的存在削弱了 JavaScript 生态系统?
  6. 顶会ICML特别开设“怼日”Workshop,意见不同您尽管来
  7. ElasticSearch 2 (16) - 深入搜索系列之近似度匹配
  8. input 禁止输入特殊字符
  9. redis HSCAN命令及jedis的hscan方法
  10. 微信小程序UI 有赞开源UI尝试(https://github.com/youzan/zanui-weapp)
  11. 笔记本超频会烧吗_CPU超频电脑会坏吗?
  12. 【HTML】HTML网页设计----植物网站设计
  13. linux网络编程常用头文件总结
  14. Window7 Chrome 升级提示关闭
  15. 苹果手机投影到墙上_买家用投影仪必须知道的常识(去专业、简单易懂,绝对无广告)...
  16. IE8跳转谷歌浏览器亲测有效
  17. 人体自身的神奇补肾法 ——你在外面花多少钱都学不到的
  18. vue2.0分页插件官方_Vue 2的最佳和完整分页插件
  19. 基于单片机的多功能定时器
  20. mysql根据经纬度搜周边_根据经纬度查询最近距离,mysql查询经纬度附近范围

热门文章

  1. 穿越火线(CF)策划文章(部分)
  2. java无法调用音频设备_win10下程序无法录音或使用麦克风
  3. LOL手游 -安装教程 含 IOS 与 Android
  4. 【Python】继承、父类、子类、方法重写、子类调用父类方法、super()函数、多继承
  5. 微信小程序定位地址与胶囊对齐
  6. TimeSpan转字符串
  7. 期待已久的—YOLO V3
  8. 小米10pro和荣耀30pro哪个好
  9. Intel I7-8700K开盖换液金对比测试
  10. B站自定义播放倍数(亲测有效)