[笔记]Python计算机视觉编程《一》 基本的图像操作和处理(二)

简介: [笔记]Python计算机视觉编程《一》 基本的图像操作和处理(二)

1.2.2 图像轮廓和直方图

下面来看两个特别的绘图示例:图像的轮廓直方图

图像的轮廓

绘制图像的轮廓(或者其他二维函数的等轮廓线)在工作中非常有用。因为绘制轮廓需要对每个坐标 [x, y] 的

像素值施加同一个阈值,所以首先需要将图像灰度化:

from PIL import Image
from pylab import *
# 读取图像到数组中
im = array(Image.open('data/empire.jpg').convert('L'))
# 新建一个图像
figure()
# 不使用颜色信息
gray()
# 在原点的左上角显示轮廓图像
contour(im, origin='image')
axis('equal')
axis('off')
show()

像之前的例子一样,这里用 PIL 的 convert() 方法将图像转换成灰度图像。

直方图

图像的直方图用来表征该图像像素值的分布情况。用一定数目的小区间(bin)来指定表征像素值的范围,每个小区间会得到落入该小区间表示范围的像素数目。该(灰度)图像的直方图可以使用 hist() 函数绘制:

figure()
hist(im.flatten(),128)
show()

hist() 函数的第二个参数指定小区间的数目。需要注意的是,因为 hist() 只接受一维数组作为输入,所以我们在绘制图像直方图之前,必须先对图像进行压平处理。

flatten() 方法将任意数组按照行优先准则转换成一维数组。图 1-3 为等轮廓线和直方图图像。

图 1-3:用 Matplotlib 绘制图像等轮廓线和直方图

1.2.3【交互式标注】

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

下面是一个简短的例子:

from PIL import Image
from pylab import *
im = array(Image.open('data/empire.jpg'))
imshow(im)
print('Please click 3 points\n')
x = ginput(3)
x_str=[''.join(str(i)) for i in x]
print('\nyou clicked:'.join(x_str))
show()

上面的脚本首先绘制一幅图像,然后等待用户在绘图窗口的图像区域点击三次。程序将这些点击的坐标 [x, y] 自动保存在 x 列表里。

1.3 NumPy

NumPy(http://www.scipy.org/NumPy/)是非常有名的 Python 科学计算工具包,其中包含了大量有用的思想,比如数组对象(用来表示向量、矩阵、图像等)以及线性代数函数。NumPy 中的数组对象几乎贯穿用于本书的所有例子中 1 数组对象可以帮助你实现数组中重要的操作,比如矩阵乘积、转置、解方程系统、向量乘积和归一化,这为图像变形、对变化进行建模、图像分类、图像聚类等提供了基础。

NumPy 可以从 http://www.scipy.org/Download 免费下载,在线说明文档(http://docs.scipy.org/doc/numpy/)包含了你可能遇到的大多数问题的答案。关于 NumPy 的更多

内容,请参考开源书籍 [24]。

1.3.1 图像数组表示

在先前的例子中,当载入图像时,我们通过调用 array() 方法将图像转换成 NumPy 的数组对象,但当时并没有进行详细介绍。NumPy 中的数组对象是多维的,可以用来表示向量、矩阵和图像。一个数组对象很像一个列表(或者是列表的列表),但是数组中所有的元素必须具有相同的数据类型。除非创建数组对象时指定数据类型,否则数据类型会按照数据的类型自动确定。

对于图像数据,下面的例子阐述了这一点:

from PIL import Image
from pylab import *
im = array(Image.open('data/empire.jpg'))
print(str(im.shape)+","+str(im.dtype))
imshow(im)
im = array(Image.open('data/empire.jpg').convert('L'),'f')
print(str(im.shape)+","+str(im.dtype))
imshow(im)
show()

控制台输出结果如下所示:

(800, 569, 3) uint8
(800, 569) float32

每行的第一个元组表示图像数组的大小(行、列、颜色通道),紧接着的字符串表示数组元素的数据类型。

因为图像通常被编码成无符号八位整数(uint8),所以在第一种情况下,载入图像并将其转换到数组中,数组的数据类型为“uint8”。

第二种情况下,对图像进行灰度化处理,并且在创建数组时使用额外的参数“f”;该参数将数据类型转换为浮点型。关于更多数据类型选项,可以参考图书 [24]。

注意,由于灰度图像没有颜色信息,所以在形状元组中,它只有两个数值。

数组中的元素可以使用下标访问。位于坐标 i、j,以及颜色通道 k 的像素值可以像下面这样访问:

value = im[i,j,k]

注 1: PyLab 实际上包含 NumPy 的一些内容,如数组类型。这也是我们能够在 1.2 节使用数组类型的原因。

多个数组元素可以使用数组切片方式访问。切片方式返回的是以指定间隔下标访问该数组的元素值。下面是有关灰度图像的一些例子:

im[i,:] = im[j,:] # 将第 j 行的数值赋值给第 i 行
im[:,i] = 100 # 将第 i 列的所有数值设为 100
im[:100,:50].sum() # 计算前 100 行、前 50 列所有数值的和
im[50:100,50:100] # 50~100 行,50~100 列(不包括第 100 行和第 100 列)
im[i].mean() # 第 i 行所有数值的平均值
im[:,-1] # 最后一列
im[-2,:] (or im[-2]) # 倒数第二行

注意,示例仅仅使用一个下标访问数组。如果仅使用一个下标,则该下标为行下标。

注意,在最后几个例子中,负数切片表示从最后一个元素逆向计数。我们将会频繁地使用切片技术访问像素值,这也是一个很重要的思想。我们有很多操作和方法来处理数组对象。本书将在使用到的地方逐一介绍。你可以查阅在线文档或者开源图书 [24] 获取更多信息。

1.3.2 灰度变换

将图像读入 NumPy 数组对象后,我们可以对它们执行任意数学操作。一个简单的例子就是图像的灰度变换。考虑任意函数 f,它将 0…255 区间(或者 0…1 区间)映射到自身(意思是说,输出区间的范围和输入区间的范围相同)。

下面是关于灰度变换的一些例子:

from PIL import Image
from numpy import *
im = array(Image.open('empire.jpg').convert('L'))
im2 = 255 - im # 对图像进行反相处理
im3 = (100.0/255) * im + 100 # 将图像像素值变换到 100...200 区间
im4 = 255.0 * (im/255.0)**2 # 对图像像素值求平方后得到的图像

第一个例子将灰度图像进行反相处理;第二个例子将图像的像素值变换到 100…200

区间;第三个例子对图像使用二次函数变换,使较暗的像素值变得更小。

图 1-4 为所使用的变换函数图像。

图 1-5 是输出的图像结果。你可以使用下面的命令查看图像中的最小和最大像素值:

print int(im.min()), int(im.max())

完整代码:

from PIL import Image
from numpy import *
from pylab import *
im = array(Image.open('data/empire.jpg').convert('L'))
print(int(im.min()), int(im.max()))
im2 = 255 - im  # invert image
print(int(im2.min()), int(im2.max()))
im3 = (100.0/255) * im + 100  # clamp to interval 100...200
print(int(im3.min()), int(im3.max()))
im4 = 255.0 * (im/255.0)**2  # squared
print(int(im4.min()), int(im4.max()))
figure()
gray()
subplot(1, 3, 1)
imshow(im2)
axis('off')
title(r'$f(x)=255-x$')
subplot(1, 3, 2)
imshow(im3)
axis('off')
title(r'$f(x)=\frac{100}{255}x+100$')
subplot(1, 3, 3)
imshow(im4)
axis('off')
title(r'$f(x)=255(\frac{x}{255})^2$')
show()

1-5:灰度变换。对图像应用图1-4中的函数:f (x)=255-x 对图像进行反相处理(左);f (x)=(100/255)

x+100 对图像进行变换(中);f (x)=255(x/255)2 对图像做二次变换(右)

如果试着对上面例子查看最小值和最大值,可以得到下面的输出结果:

2 255
0 253
100 200
0 255

array() 变换的相反操作可以使用 PIL 的 fromarray() 函数完成:

pil_im = Image.fromarray(im)

如果你通过一些操作将“uint8”数据类型转换为其他数据类型,比如之前例子中的im3 或者 im4,那么在创建 PIL 图像之前,需要将数据类型转换回来:

pil_im = Image.fromarray(uint8(im))

如果你并不十分确定输入数据的类型,安全起见,应该先转换回来。

注意,NumPy总是将数组数据类型转换成能够表示数据的“最低”数据类型。对浮点数做乘积或除法操作会使整数类型的数组变成浮点类型。

1.3.3 图像缩放

NumPy 的数组对象是我们处理图像和数据的主要工具。想要对图像进行缩放处理没有现成简单的方法。我们可以使用之前 PIL 对图像对象转换的操作,写一个简单的用于图像缩放的函数。

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

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

我们将会在接下来的内容中使用这个函数。

1.3.4 直方图均衡化

图像灰度变换中一个非常有用的例子就是直方图均衡化。

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

在这种情况下,直方图均衡化的变换函数是图像中像素值的累积分布函数(cumulative distribution function,简写为 cdf,将像素值的范围映射到目标范围的归一化操作)。

下面的函数是直方图均衡化的具体实现。

将这个函数添加到 imtool.py 里:

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

该函数有两个输入参数,一个是灰度图像,一个是直方图中使用小区间的数目

函数返回直方图均衡化后的图像,以及用来做像素值映射的累积分布函数。注意,函数中使用到累积分布函数的最后一个元素(下标为 -1),目的是将其归一化到 0…1范围。

你可以像下面这样使用该函数:

#imtools.py
from PIL import Image
from numpy import *
def histeq(im,nbr_bins=256):
    """ 对一幅灰度图像进行直方图均衡化 """
    # 计算图像的直方图
    imhist,bins = histogram(im.flatten(),nbr_bins,normed=True)
    cdf = imhist.cumsum() # cumulative distribution function
    cdf = 255 * cdf / cdf[-1] # 归一化
    # 使用累积分布函数的线性插值,计算新的像素值
    im2 = interp(im.flatten(),bins[:-1],cdf)
    return im2.reshape(im.shape), cdf
def imresize(im,sz):
 """ 使用 PIL 对象重新定义图像数组的大小 """
 pil_im = Image.fromarray(uint8(im))
 return array(pil_im.resize(sz))
#test01_03.py
from PIL import Image
from numpy import *
from pylab import *
import imtools
# im = array(Image.open('data/AquaTermi_lowcontrast.jpg').convert('L'))
im = array(Image.open('data/empire.jpg').convert('L'))
im2,cdf = imtools.histeq(im)
imshow(im2)
gray()
show()

图 1-6 和图 1-7 为上面直方图均衡化例子的结果。

上面一行显示的分别是直方图均衡化之前和之后的灰度直方图,以及累积概率分布函数映射图像。

可以看到,直方图均衡化后图像的对比度增强了,原先图像灰色区域的细节变得清晰。

图 1-7:直方图均衡化示例。左侧为原始图像和直方图,中间图为灰度变换函数,右侧为直

方图均衡化后的图像和相应直方图

相关文章
|
28天前
|
存储 数据采集 人工智能
Python编程入门:从零基础到实战应用
本文是一篇面向初学者的Python编程教程,旨在帮助读者从零开始学习Python编程语言。文章首先介绍了Python的基本概念和特点,然后通过一个简单的例子展示了如何编写Python代码。接下来,文章详细介绍了Python的数据类型、变量、运算符、控制结构、函数等基本语法知识。最后,文章通过一个实战项目——制作一个简单的计算器程序,帮助读者巩固所学知识并提高编程技能。
|
16天前
|
Unix Linux 程序员
[oeasy]python053_学编程为什么从hello_world_开始
视频介绍了“Hello World”程序的由来及其在编程中的重要性。从贝尔实验室诞生的Unix系统和C语言说起,讲述了“Hello World”作为经典示例的起源和流传过程。文章还探讨了C语言对其他编程语言的影响,以及它在系统编程中的地位。最后总结了“Hello World”、print、小括号和双引号等编程概念的来源。
102 80
|
29天前
|
机器学习/深度学习 人工智能 算法
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
宠物识别系统,本系统使用Python作为主要开发语言,基于TensorFlow搭建卷积神经网络算法,并收集了37种常见的猫狗宠物种类数据集【'阿比西尼亚猫(Abyssinian)', '孟加拉猫(Bengal)', '暹罗猫(Birman)', '孟买猫(Bombay)', '英国短毛猫(British Shorthair)', '埃及猫(Egyptian Mau)', '缅因猫(Maine Coon)', '波斯猫(Persian)', '布偶猫(Ragdoll)', '俄罗斯蓝猫(Russian Blue)', '暹罗猫(Siamese)', '斯芬克斯猫(Sphynx)', '美国斗牛犬
155 29
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
|
5天前
|
Python
[oeasy]python055_python编程_容易出现的问题_函数名的重新赋值_print_int
本文介绍了Python编程中容易出现的问题,特别是函数名、类名和模块名的重新赋值。通过具体示例展示了将内建函数(如`print`、`int`、`max`)或模块名(如`os`)重新赋值为其他类型后,会导致原有功能失效。例如,将`print`赋值为整数后,无法再用其输出内容;将`int`赋值为整数后,无法再进行类型转换。重新赋值后,这些名称失去了原有的功能,可能导致程序错误。总结指出,已有的函数名、类名和模块名不适合覆盖赋新值,否则会失去原有功能。如果需要使用类似的变量名,建议采用其他命名方式以避免冲突。
27 14
|
15天前
|
分布式计算 大数据 数据处理
技术评测:MaxCompute MaxFrame——阿里云自研分布式计算框架的Python编程接口
随着大数据和人工智能技术的发展,数据处理的需求日益增长。阿里云推出的MaxCompute MaxFrame(简称“MaxFrame”)是一个专为Python开发者设计的分布式计算框架,它不仅支持Python编程接口,还能直接利用MaxCompute的云原生大数据计算资源和服务。本文将通过一系列最佳实践测评,探讨MaxFrame在分布式Pandas处理以及大语言模型数据处理场景中的表现,并分析其在实际工作中的应用潜力。
51 2
|
28天前
|
小程序 开发者 Python
探索Python编程:从基础到实战
本文将引导你走进Python编程的世界,从基础语法开始,逐步深入到实战项目。我们将一起探讨如何在编程中发挥创意,解决问题,并分享一些实用的技巧和心得。无论你是编程新手还是有一定经验的开发者,这篇文章都将为你提供有价值的参考。让我们一起开启Python编程的探索之旅吧!
46 10
|
28天前
|
人工智能 数据挖掘 开发者
探索Python编程之美:从基础到进阶
本文是一篇深入浅出的Python编程指南,旨在帮助初学者理解Python编程的核心概念,并引导他们逐步掌握更高级的技术。文章不仅涵盖了Python的基础语法,还深入探讨了面向对象编程、函数式编程等高级主题。通过丰富的代码示例和实践项目,读者将能够巩固所学知识,提升编程技能。无论你是编程新手还是有一定经验的开发者,这篇文章都将为你提供有价值的参考和启示。让我们一起踏上Python编程的美妙旅程吧!
|
8月前
|
机器学习/深度学习 计算机视觉
AIGC核心技术——计算机视觉(CV)预训练大模型
【1月更文挑战第13天】AIGC核心技术——计算机视觉(CV)预训练大模型
670 3
AIGC核心技术——计算机视觉(CV)预训练大模型
|
4月前
|
人工智能 测试技术 API
AI计算机视觉笔记二十 九:yolov10竹签模型,自动数竹签
本文介绍了如何在AutoDL平台上搭建YOLOv10环境并进行竹签检测与计数。首先从官网下载YOLOv10源码并创建虚拟环境,安装依赖库。接着通过官方模型测试环境是否正常工作。然后下载自定义数据集并配置`mycoco128.yaml`文件,使用`yolo detect train`命令或Python代码进行训练。最后,通过命令行或API调用测试训练结果,并展示竹签计数功能。如需转载,请注明原文出处。
|
4月前
|
人工智能 测试技术 PyTorch
AI计算机视觉笔记二十四:YOLOP 训练+测试+模型评估
本文介绍了通过正点原子的ATK-3568了解并实现YOLOP(You Only Look Once for Panoptic Driving Perception)的过程,包括训练、测试、转换为ONNX格式及在ONNX Runtime上的部署。YOLOP由华中科技大学团队于2021年发布,可在Jetson TX2上达到23FPS,实现了目标检测、可行驶区域分割和车道线检测的多任务学习。文章详细记录了环境搭建、训练数据准备、模型转换和测试等步骤,并解决了ONNX转换过程中的问题。