LOADING . . .

Python 可视化与图像处理

  python绘图库有很多,底层的就是matplotlib,另外还有基于matplotlib的更方便,代码可读性更强的库,比如seaborn、plotnine等。各个库之间的对比:

  https://www.zhihu.com/question/39684179

matplotlib

  在python下一般使用matplotlib包下的pyplot,所以通常import matplotlib.pyplot as plt方便使用它的绘图函数。下面仅记录matplotlib3.2.0之后的版本。

通用函数

plt.show()

  显示绘图窗口。

plt.figure()

  创建绘图新窗口并传给fig:

fig = plt.figure()

  fig能使用下面绘图、创建子图等函数。不创建新窗口直接plt.function()也能绘图,默认一个窗口。

fig.add_subplot()

  给窗口添加子图像,参数有三个,分别是子图像的行、列、索引。两种使用方式:

ax = fig.add_subplot(numbRow, numbCol, plotNum) 
ax = fig.add_subplot(111)

  前一种是一般的用逗号隔开,明确三个参数。后一种是三个整数参数直接合成一个整数传入,这要求这个整数只能是3位的,这样才能唯一确定用户传入的参数。(比如223,就是把图像划分成2*2的格子,添加一个子图像在第三个格子里) 

fig.subplots()

  同时创建窗口和多个子图像的方法,用法如下:

import matplotlib.pyplot as plt
fig, axs = plt.subplots(2,2)
axs[0,0].plot([0,1],[0,1])
plt.show()

  fig为创建的窗口对象,axs为多个子图对象的二维数组,因此可以通过索引获取子图对象。

plt.imsave()

  用于保存图像,因为源代码中没有提示,很容易因为传参顺序而出错。用法如下:

plt.imsave(name,img)#先传名字再传img数组

图例

  为图像添加图例,在画图函数中添加label属性就行。如:

ax.plot(X,Y,label = '图例')

  然后使用legend()函数显示所有的图例,它可以设置图例的位置等参数:

ax.legend(loc='best') #看这个介绍https://blog.csdn.net/qq_35240640/article/details/89478439

  显示中文(不然可能乱码):

plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号

图像标题

ax.set_title('aaa',fontsize=12,color='r')

坐标轴设置

  坐标轴一般设置

ax.set_xlim([-2, 2])#设置x坐标轴范围
ax.set_ylim([-2, 2])#设置y坐标轴范围
ax.set_xlabel('xxxxxxxxxxx')#设置x坐标轴名称
ax.set_ylabel('yyyyyyyyyyy')#设置y坐标轴名称

ticks = np.arange(-2, 2, 0.3)
ax.set_xticks(ticks)#设置x轴刻度
ax.set_yticks(ticks)#设置y轴刻度

ax.axis('scaled')#设置坐标轴宽高等比于x、y范围
ax.axis('image')#类似于scaled,暂时没发现区别
ax.axis('off')#关闭坐标轴
ax.axis('equal')#图像宽高比例不变,坐标轴范围变
ax.axis('tight')#坐标轴紧紧贴合图像,不设置默认就是这个
ax.axis('square')#设置坐标轴宽高比为1:1,坐标轴跨度取较大的那个

ax.spines['right'].set_color('none') #包含'top','bottom','right','left'4个轴。这里设置右边轴消失
ax.spines['left'].set_position(('data',0)) #将左边的轴移动到与横坐标0处对齐
ax.spines['bottom'].set_position(('data',0)) #将下面的轴移动到与纵坐标0处对齐

  变换坐标轴位置(除了使用上述的spines外),给坐标轴加箭头等

import mpl_toolkits.axisartist as axisartist

fig = plt.figure()
ax = axisartist.Subplot(fig, 1,1,1) 
fig.add_axes(ax) #使用这两句定义ax而不是add_subplot

ax.axis[:].set_visible(False) #隐藏'top','bottom','left','right','x','y'六个坐标轴
ax.axis["x"] = ax.new_floating_axis(0, 0) #定义新的坐标轴给x轴,第一个0表示x方向,第二个0表示x轴处于y轴的0位置
ax.axis["y"] = ax.new_floating_axis(1, 0) #定义新的坐标轴给y轴,第一个1表示y方向,第二个0表示y轴处于x轴的0位置
ax.axis["x"].set_axisline_style("->", size = 1)#设置x轴的风格,使用箭头
ax.axis["y"].set_axisline_style("->", size = 1)

动态图像

plt.cla()
ax.clear()

  这两个函数用于将子图清空,配合暂停函数

plt.pause(0.1) 

  即可实现动态图像。

二维图像

contourf()和contour()

  画等高线图。这两个函数差一个字母,但用法一样,区别如下:

  使用方法:

ax.contourf(X, Y, Z, levels=10, alpha=0.5, cmap='jet')

  X是生成网格的X坐标数组(二维数组array,或者matrix),Y是和X相同类型的Y坐标,Z是对应网格的每个格点的函数值数组(也是二维数组array,或者matrix),网格的生成是使用numpy库中的meshgrid()函数。levels是图像中等高线的数量,我这里设置为10。alpha是图像的透明度,介于0~1,我这里设置为0.5半透明。可以设置透明度有个好处就是可以把很多图画在同一个画布上,方便比较。cmap是图像的颜色类型,有很多预设的颜色类型,我这里用一个叫‘jet’的颜色类型,当然也可以自己定义,具体设置网上再找吧。后三项有预设值,可以省略。

  效果图:

  看起来不是很圆润,这是因为我的网格规模就是7*7的,它画图就按照你的网格数量来画,所以有棱有角的。有一点奇怪的就是,网格是有限的,它是怎么画出这么多的等高线的?我猜它应该是线性插值插进去的。反正也就一个图用来看的,不用特别准确。但是如果要准确怎么办?那就把网格设置地密一些!别让等高线的密度比网格的密度大太多就好了。

  另外,可以用clabel()这个函数用来标注等高线图的数值:

plt.clabel(C, inline=False, fontsize=12)

  C代表刚刚画的等高线图(在用contour()等函数画完以后传给C,C = contour(...)),inline是否画在线内,fontsize数字的大小。

plot()

ax.plot(x, y,  ls="-", lw=2, label="plot figure", color='black',alpha=0.5...)

  用来画二维面上的点、线。当然也可以在三维的空间里面画,就画在三维坐标系的xOy面上。重要参数介绍:

  x: 要画的线的各个点在x轴上的坐标(一维数组)

  y: 要画的线的各个点在y轴上的坐标(一维数组或二维数组,第一维规模要和x轴的数组一致,第二维规模的大小就是画线的数量)

  ls:折线图的线条风格,这里是一个减号

  lw:折线图的线条宽度

  label:标记图内容的标签文本

  color:颜色

  alpha:透明度

  还有很多的参数可以调节,这里不一一列举,请看链接。另外,很多其它画线的函数也都支持一些个性化的参数,比如color、alpha、width等等,参数汇总看链接

bar()

ax.bar(range(len(values)), values)

  绘制条形图,第一个参数为横坐标,第二个参数为横坐标对应的值。

  示例代码:

import matplotlib.pyplot as plt
import numpy as np

values = np.random.normal(0,1,[20])
plt.bar(range(len(values)),values)
plt.show()

hist()

ax.hist(data,bins=50,range=[-5,5],density=True,cumulative=True,rwidth=0.9,orientation = 'vertical')

  画频次直方图,这个函数会自动对数据做统计,如果是已经统计好的数据,可以使用上面的bar()函数画图。重要参数介绍:

  x:待统计的一维数据。

  bins:柱子的数量

  range:数据统计的范围

  density:是否转换为频率密度图(密度图,乘以范围宽度才是这个范围内数据的频率占比)

  cumulative:是否累加,若为真,柱子统计的是小于等于这个值的所有数据。

  rwidth:柱子的宽度。

  orientation:柱子是垂直还是水平放置。

  以下统计一个正态分布的累计柱状图:

hist2d()与hexbin()

ax.hist2d(x,y,bins=30,cmap='Blues')

  二维频次直方图。参数与上述一维频次直方图类似。以下显示二维正态分布抽样频次统计图(旁边的色度条是plt.colorbar(),子图如何加还没研究...):

ax.hexbin(x,y,gridsize=30,cmap='Blues')

  就是方格变成六边形格,gridsize表示格子大小:

绘制二维热度图

  以上二维频次直方图函数会先对输入做统计,再进行绘图。如果是已经统计好的二维数据,我们可以用imshow()函数来画。示例代码如下:

import matplotlib.pyplot as plt 
  
values = np.random.randint(0,100,[5,5])

hot = plt.imshow(values, cmap=plt.cm.hot_r) #第二个参数是颜色风格
plt.colorbar(hot)  #设置刻度条
plt.show()

三维图像

建立三维坐标系

fig = plt.figure()  #添加绘图窗口
ax = fig.add_subplot(221,projection = '3d')  #窗口内添加3d子图
ax = fig.add_subplot(projection = '3d')  #如果只画一张图,可以用这个

plot_surface()

ax.plot_surface(X, Y, Z, rstride = 1, cstride = 1, cmap='jet')

  画三维的曲面图,并且带有梯度颜色。

  X、Y、Z就是每个网格点在对应坐标轴的值,cmap是涂色类型。rstride 是在行上每几个网格点计算一次梯度来图上对应梯度的颜色。cstride 就是列上的。它们越大,画梯度颜色的“补丁”也越大,对应地,“补丁”的数量也越少。如下图,一个是1,一个是2,“补丁”就一个是20,一个是10。

外部图像

图像导入与显示

import matplotlib.pyplot as plt
import pylab                #原本在jupyter里才能显示的图片,可以用窗口显示
  
img=plt.imread("image.jpg") #读取图片,读取到的是:高度×宽度×3RGB 的array数组
fig = plt.figure()          #创建窗口
ax = fig.add_subplot(111)   #创建子图
ax.imshow(img)              #子图中添加图片

pylab.show()                #显示窗口

cv2

图像批处理

从压缩包中直接读取图片

import zipfile
import cv2
import numpy as np
import matplotlib.pyplot as plt

path = 'D:/Datasets/dogs-vs-cats/train.zip'#压缩包地址
with zipfile.ZipFile(path,mode='r') as f:
    for name in f.namelist():
        if '.jpg' not in name:
            continue
        print(name) 
        with f.open(name,mode='r') as image_file:
            content = image_file.read() # 读取图片
            img = np.asarray(bytearray(content), dtype='uint8') #将jpg格式转码
            img = cv2.imdecode(img, cv2.IMREAD_COLOR)#再转化为BGR格式,注意不是RGB,顺序反了 ,不重组的话在plt颜色显示异常
            b,g,r = cv2.split(img)  
            img = cv2.merge([r,g,b])  #将BGR拆分再重组为RGB
            plt.imshow(img) 
            plt.show()
        break

图形拉伸

import cv2
cv2.resize(img,(w,h),interpolation=0)

  将存在数组中的图像拉伸成w宽,h高。interpolation=0表示最近邻插值,不作平滑处理。其它插值参数(interpolation)请看链接

seaborn

import seaborn as sns

  seaborn简化了matplotlib的绘图操作,并且让图像更精美,绘制matplotlib图像时,使用sns.set(),可让图像更具特色。

mayavi

import mayavi.mlab as mlab

  mayavi是专门绘制三维图形的库,虽然matplotlib也能绘制,但是matplotlib并不支持光线追踪,所以没有遮挡的效果。绘制各种图像的函数和matplotlib差不多。mayavi文档简易实例

mesh()

  绘制三维图形表面,用法和matplotlib的plot_surface类似,但是创建网格时推荐用mgrid,meshgrid的索引顺序不对。

mlab.mesh(x, y, z )#绘制光滑表面
mlab.mesh(x, y, z, representation="wireframe", line_width=1.0)#绘制线而不是表面

  下图画了一个卷起来的彩带:

  代码如下:

import mayavi.mlab as mlab
import numpy as np

roll = 10
r = 0.5
w = 0.8
theta = np.linspace(np.pi*0.5,np.pi*2*roll,num=roll*100)[:,np.newaxis]
h = np.linspace(-1,1,num=2)[np.newaxis,:]+0.5

x = y = z = np.zeros([len(theta),len(h[0,:])])
x = x + np.cos(theta)*theta*r/np.pi 
y = y + np.sin(theta)*theta*r/np.pi 
z = z + h - theta*w/np.pi 
print(y.shape,z.shape)
mlab.mesh(x, y, z)#绘制光滑表面 
mlab.show() 

plot3d()

  画三维坐标系中的曲线。用法和matplotlib的plot类似。同样推荐用mgrid创建网格。

mlab.plot3d(x,y,z)

numpy

  用numpy的一些函数生成格式化的绘图数据。 

linspace()

  linspace(a, b, n),传回一个在a、b之间的插值列表(包括a、b),插值的数量是n。这个差值列表类型是array,而不是list,array里的数据类型是固定的,都是float。而列表list里面则并不是固定的,里面可以存任何东西。array是numpy下定义的一个类型,这个类型类似C++的数组,随机查找很快。所以处理大批量同类数据的时候,最好使用array类型。

  具体使用和其他参数:

  https://www.cnblogs.com/antflow/p/7220798.html

meshgrid()

  用于生成对应列表的网格(网格也是用列表存,二维网格是对每一维来说是二维列表,三维网格对每一维来说是三维列表),用于绘制梯度图等。使用方法如下:

  1. [X, Y] = meshgrid(x,y)或者python还支持X,Y = meshgrid(x,y),不加方括号也行,当然直接A = meshgrid(x,y),传给一个值也行,就是后面不太好处理。

  2. [X, Y] = meshgrid(x)与[X, Y] = meshgrid(x, x)是等同的

  3. [X, Y, Z] = meshgrid(x, y, z)生成三维的网格

  生成的网格索引顺序在二维X、Y中是先Y再X,三维X、Y、Z中顺序是Y、X、Z。例如,在三维网格中,如果要获得x[2],y[7],z[3]位置的Y轴坐标,就是Y[7][2][3]。在二维网格中,如果要获得x[2],y[7]位置的X轴坐标,就是X[7][2]。

  下图显示8*3的网格的X的列表:

mgrid

  与meshgrid类似,同样能生成对应的网格。但是它并不是函数,而是以索引的形式使用的属性,并且还可以生成类似的2维以上的网格。另外,它和meshgrid的不同之处在于它们生成的网格的索引方式是相反的。推荐使用mgrid,它更容易理解。以下是实例:

import numpy as np
a = np.mgrid[0:10:2,0:10:1] 
print(a)

  索引的第二个冒号传入整数表示数的间隔,不包含最后一个数。传入复整数表示数的个数,比如5j表示范围内5个数,包含最后一个数。

特定图像样例

  https://www.runoob.com/w3cnote/matplotlib-tutorial.html

  https://blog.csdn.net/jasonzhoujx/article/details/81780774

posted @ 2020-01-11 15:56  颀周  阅读(3173)  评论(0编辑  收藏  举报
很高兴能帮到你~
点赞