前言:
Python的列表处理,在机器视觉中经常被用到,这里结合基本的概念+机器视觉实践案例,成文如下:
本身将实现一个,弧线的mask填充:这个mask是我的一个天文项目的应用,目的在于将月球从图中抠出来。
1 基础概念 - 序列:
序列是 Python 中最基本的数据结构。
序列中的每个值都有对应的位置值,称之为索引,第一个索引是 0,第二个索引是 1,依此类推。
1.1 python 序列的类型
Python 有 6 个序列的内置类型,但最常见的是列表和元组。
1.1.1 列表:[List]
列表是最常见的序列类型之一,它是可变的,意味着你可以添加、删除或修改其中的元素。列表使用方括号[]
表示,并包含一系列以逗号分隔的值。列表中的元素可以包含不同的数据类型,不需要全部相同。列表提供了11个内置方法,用于添加、删除、查找元素等操作。
# 定义一个列表
my_list = [1, 'apple', 3.14, True]
# 打印列表
print(my_list)
1.1.1.1 访问列表的索引
#!/usr/bin/python3list = ['red', 'green', 'blue', 'yellow', 'white', 'black']
print( list[0] )
print( list[1] )
print( list[2] )
red
green
blue
1.1.1.2 从后面反向索引
#!/usr/bin/python3list = ['red', 'green', 'blue', 'yellow', 'white', 'black']
print( list[-1] )
print( list[-2] )
print( list[-3] )
black
white
yellow
1.1.1.3 用下标访问列表中的值
#!/usr/bin/python3nums = [10, 20, 30, 40, 50, 60, 70, 80, 90]
print(nums[0:4])
[10, 20, 30, 40]
1.1.1.3 截取和拼接
1.1.2 元祖(Tuple)
元组与列表类似,也是一个序列类型,但是元组是不可变的,一旦创建就不能修改。元组使用小括号()
表示,也可以包含逗号分隔的值。与列表不同,元组没有提供内置的方法,但可以转换为列表进行操作
# 定义一个元组
my_tuple = (1, 'apple', 3.14, True)
# 打印元组
print(my_tuple)
1.1.3 字符串 “string”
字符串是一个不可变的序列类型,用于处理文本数据。字符串使用单引号'
或双引号"
表示,可以包含一系列字符。字符串中的字符可以是字母、数字、标点符号等
# 定义一个字符串
my_string = "Hello, World!"
# 打印字符串
print(my_string)
1.1.4 其他不常用。
Unicode字符串
Unicode字符串与字符串类似,也是不可变的序列类型,但它支持多字节字符编码,可以表示全球各地的语言字符。Unicode字符串使用三个单引号
'''
或三个双引号"""
# 定义一个Unicode字符串
my_unicode = """你好,世界!"""
# 打印Unicode字符串
print(my_unicode)
缓冲区对象(Buffer Object)
缓冲区对象是一个较不常见的序列类型,它主要用于低级编程,如文件操作或内存映射。缓冲区对象使用方括号
[]
表示,但内部是通过缓冲区接口进行操作的13。xrange对象
xrange对象是一个生成器类型,它用于生成一个整数序列。与列表不同,xrange不会占用大量的内存空间,它只生成序列的一部分。xrange对象使用三个参数表示范围,如
xrange(start, stop, step)
# 使用xrange生成一个序列
for i in xrange(10):print(i)
2 实践:
2.1 获取一个图片的四个顶点
2.1.1 拿到图片的尺寸
对应彩色的图片,通过如下的代码,可以先获取图片的尺寸:
import cv2
# 读取图像
image = cv2.imread('path_to_image.jpg')# 获取图像尺寸
height, width, channels = image.shape# 打印尺寸信息
print(f'Width: {width}, Height: {height}, Channels: {channels}')
【案,
在OpenCV中,可以通过多种方式获取图像的尺寸信息。当你使用 cv2.imread()
函数读取图像后,图像会被存储在一个NumPy数组中,你可以通过该数组的 shape
属性来获取图像的尺寸。
对于彩色图像,shape
属性返回一个三元组 (height, width, channels),分别表示图像的高度、宽度和通道数(RGB三个颜色通道)。对于灰度图像,它返回的是二元组 (height, width),因为灰度图像只有一个通道。】
【案,这里图像的属性通过元祖来表示,原因是元祖他可以集成多种数据格式,同时元祖是不可以改变的】
import cv2
# 读取图像
image = cv2.imread('path_to_image.jpg', cv2.IMREAD_GRAYSCALE)# 获取图像尺寸
height, width = image.shape# 打印尺寸信息
print(f'Width: {width}, Height: {height}')
【图像是灰度图像,那么 channels
将不存在】
2.1.2 拿到图片的四个顶点
上小节,拿到尺寸后,我们通过这个嵌套的列表,来表示图片的四个顶点坐标,
# 获取矩形框的四个角点corners = np.array([[0, 0],[width - 1, 0],[width - 1, height - 1],[0, height - 1]])
那么,如果是右侧的顶点
# 获取矩形框的右侧两个角点right_corners = np.array([[width - 1, 0],[width - 1, height - 1]])
2.2 构建一个弧段(含和图片的交点)这里略-将在其他章节介绍
假设弧段的点集为:
arc_points
我们可以拿到弧的起始点的坐标。
交点为:
intersection_points
2.3 现在构建mask区域
要构建一个mask,就必须构建一个封闭的区域。简单的想法,就是通过弧与图像边界的交点,来构建。
# 构建一个封闭区域,包括弧段和右侧顶点polygon_points = np.vstack((arc_points, [arc_end_point], right_corners, [arc_start_point]))# 填充封闭区域为白色cv2.fillPoly(mask, [polygon_points], (255))
但是,问题出来,很明显,在构建MASK区域的时候,顶点的选择,由于顺序的问题,发生了交叉,大家可以看到下面的图片,因为交叉,所以,就出现,下面这个交织的情况。
而,我们希望是将弧段+边界构成MASK区域。
【案,问题的根源就是,我们构建参考点的时候,点的选取顺序也许发生了问题,
【案,这个图的标号,反映了红色错误的情况,和绿色正确的情况】
于是,我们有了下面的修改,
# 构建一个封闭区域,包括弧段和右侧顶点polygon_points = np.vstack((arc_points, [arc_end_point], right_corners[::-1], [arc_start_point]))# 填充封闭区域为白色cv2.fillPoly(mask, [polygon_points], (255))
【案,这里将构建封闭区域的点,构成一个封闭的点集,然后,利用fillPoly函数进行填充,形成mask】
【这里, right_corners[::-1]
反转了右侧顶点的顺序,这里就要用到我们前面关于python的列表的高级应用知识】
理论和实践的结合
right_corners
: 这是一个变量名,代表一个列表或数组。这个列表中存储着一些表示右侧顶点的元素。[::-1]
: 这是Python列表切片的一种特殊用法,用于反转列表。
切片操作的详细解释:
:
: 表示从列表的开头开始。:
: 表示到列表的末尾结束。-1
: 表示步长为-1,即从后向前取元素。
结合起来看:
right_corners[::-1]
的意思是:从right_corners
列表的末尾开始,以步长-1的方式,一直取到列表的开头,从而形成一个新的列表,这个新列表中的元素顺序与原列表正好相反。
示例:
假设 right_corners 的值为 [1, 2, 3, 4],那么 right_corners[::-1] 的结果就是 [4, 3, 2, 1]。
调整结果:
参考:
Python3 列表 | 菜鸟教程