AutoCV第一课:Python基础

Python基础

注意事项

一、2023/3/24更新

新增字符串的基本使用,第4节内容

一、2023/3/25更新

新增字符串的扩展使用,第5节内容

前言

手写AI推出的全新保姆级从零手写自动驾驶CV课程,链接。记录下个人学习笔记,仅供自己参考。

本次课程为第一课,主要讲解课程开发环境介绍,以及Python基础:变量和基本数据类型,算数运算和变量解包以及字符串使用。

课程大纲可看下面的思维导图。

在这里插入图片描述

1.开发环境

内容:认识代码的构成和运行

1.1 作业

作业1:配置环境在PyCharm中写一个打印hello python程序并执行

运行效果如下:
在这里插入图片描述

作业2:启动Jupyter Lab并写一个打印hello python的程序

运行效果如下:
在这里插入图片描述

2.变量和基本数据类型

内容:认识变量,和常见基本数据类型表示数据

2.1 python常见数据类型

在Python中,有许多基本数据类型,包括:(from chatGPT)

  1. int(整型):表示整数,例如:2、-5、100等。整型数据在计算机视觉中广泛应用,如图像中像素值[0-255]的表示。
  2. float(浮点型):表示实数,包括小数和科学计数法表示,例如:2.5、-0.5、1.0e-3等。在计算机视觉中,浮点型数据常用于描述图像中的坐标或物体位置等连续性的量。
  3. str(字符串型):表示字符串,即一系列字符组成的序列,例如:“hello”、"world"等。在计算机视觉中,字符串常用于图像文件名、标注信息、日志记录等。
  4. bool(布尔型):表示逻辑值,只有两种取值:True和False。在计算机视觉中,布尔型数据常用于图像二值化、图像处理中的条件判断等。
  5. list(列表型):表示可变序列,即一系列元素的有序集合,例如:[1, 2, 3]、[‘a’, ‘b’, ‘c’]等。在计算机视觉中,列表常用于存储图像特征向量、多个图像文件路径等。
  6. tuple(元组型):表示不可变序列,即一系列元素的有序集合,但元素值不能被修改,例如:(1, 2, 3)、(‘a’, ‘b’, ‘c’)等。在计算机视觉中,元组常用于多个返回值的封装、存储图像大小等。
  7. dict(字典型):表示键值对的无序集合,例如:{‘name’: ‘Tom’, ‘age’: 20}、{‘x’: 100, ‘y’: 200}等。在计算机视觉中,字典常用于图像标注信息的存储、数据集的组织等。
  8. set(集合型):表示无序集合,包含唯一元素,例如:{1, 2, 3}、{‘a’, ‘b’, ‘c’}等。在计算机视觉中,集合常用于图像特征向量去重、图像分类器的类别标签等。
  9. type(类型):表示数据类型。在计算机视觉中,type常用于类型检查、动态类型转换等。

以上基本数据类型在计算机视觉中都有广泛的应用场景,能够方便地存储和处理各种类型的数据。

2.2 作业

作业3:定义一个字典存储身份信息,通过名字查询并打印

运行效果如下:

在这里插入图片描述

示例代码如下:

one_piece_dict = {
    '蒙奇·D·路飞': {'职业': '海贼', '海贼旗': '草帽海贼团'},
    '罗罗诺亚·索隆': {'职业': '剑士', '梦想': '成为世界第一剑豪'},
    '娜美': {'职业': '航海士', '特长': '制作天候棒'},
    '乌索普': {'职业': '狙击手', '梦想': '成为勇敢的海上战士'},
    '山治': {'职业': '厨师', '招牌菜': '海鲜汤饭'},
    '托尼托尼·乔巴': {'职业': '医生', '种族': '人鱼'},
    '尼可·罗宾': {'职业': '考古学家', '梦想': '解开历史的真相'},
    '弗兰奇': {'职业': '船匠', '梦想': '建造世界最伟大的船'},
    '布鲁克': {'职业': '音乐家', '特长': '演奏骷髅琴'},
}

# python格式化输出的常用三种方式:1.占位符`%` 2.`format()`方法 3.f-string
print("路飞的职业是: %s" % one_piece_dict["蒙奇·D·路飞"]["职业"])
print("索隆的梦想是: {}".format(one_piece_dict["罗罗诺亚·索隆"]["梦想"]))
# print(f"山治的招牌菜:{one_piece_dict["山治"]["招牌菜"]}")    # 存在问题
print(f"山治的招牌菜:{one_piece_dict['山治']['招牌菜']}")

遇到的问题:以下代码存在语法错误

print(f"山治的招牌菜:{one_piece_dict["山治"]["招牌菜"]}")    # 存在问题

原因分析:由于在字符串中嵌套类双引号,导致语法错误。Python解释器无法正确解析这个字符串,因为它会将第一个双引号和第二个双引号之间的内容解析为一个字符串,而将后面的内容视为代码。🙃

解决方案:将双引号替换为单引号或使用原始字符串r

print(f"山治的招牌菜:{one_piece_dict['山治']['招牌菜']}")

或者

print(rf"山治的招牌菜:{one_piece_dict['山治']['招牌菜']}")

2.3 拓展-Python格式化输出

在Python中,格式化输出是一种非常常用的功能。以下是几种Python格式化输出的方式:(from chatGPT)

  1. 使用占位符 % 进行格式化输出。例如,使用 %d 表示整数类型, %f 表示浮点数类型, %s 表示字符串类型等。示例如下:

    num1 = 10
    num2 = 20
    print("num1 is %d, num2 is %d" % (num1, num2))
    
  2. 使用字符串的 format() 方法进行格式化输出。这种方式可以通过参数名或者参数位置进行替换。示例如下:

    name = "Alice"
    age = 25
    print("My name is {}, and I am {} years old.".format(name, age))
    
  3. 使用 f-string(格式化字符串)进行格式化输出。f-string 是 Python 3.6 引入的一种新的字符串格式化方式,可以在字符串中使用表达式,并在字符串前添加 f。示例如下:

    num = 100
    print(f"The value of num is {num * 2}")
    

以上是几种Python格式化输出的方式,每种方式都有其特点和适用场景,根据不同的需求进行选择。

3.算数运算和变量解包

内容:认识算法运算以及多个变量解包

3.1 zip函数

提到解包,不知道为什么首先想到的就是zip函数😂,脑中浮现的是一段杜老师写过的检测器后处理代码(一直似懂非懂🤔)

for img_id, box_id in zip(*np.where(pred[...,4] > conf_thresh)):
    ...

zip函数是Python内置的一个函数,用于将多个序列封包成一个元组序列,也可以将元组序列解包成多个序列。(from chatGPT)

对于封包,zip函数可以接受多个序列作为参数,并将它们封包成一个元组序列,例如:

a = [1, 2, 3]
b = ['a', 'b', 'c']
c = [True, False, True]
zipped = zip(a, b, c)

在这个例子中,zip函数将列表abc封包成一个元组序列,即:

((1, 'a', True), (2, 'b', False), (3, 'c', True))

这个元组序列可以用于迭代,例如:

for x, y, z in zip(a, b, c):
    print(x, y, c)

这个代码将输出:

1 a True
2 b False
3 c True

对于解包,我们可以将一个元组序列解包成多个序列,例如:

zipped = [(1, 'a', True), (2, 'b', False), (3, 'c', True)]
a, b, c = zip(*zipped)

在这个例子中,我们使用*运算符将元组序列解包成多个序列,即:

a = (1, 2, 3)
b = ('a', 'b', 'c')
c = (True, False, True)

这个技巧在某些场景下很有用,例如在CV中处理图像数据时,我们经常需要将图像数据和标签数据分别存储在不同的序列中。这是,我们可以使用zip函数将它们封包成一个元组序列,然后使用解包语法将它们分别存储在不同的序列中。

例如,假设现在我们有一个包含图像数据的列表images和一个包含标签数据的列表labels,我们可以使用zip函数将它们封包成一个元组序列:

data = zip(images, labels)

然后,我们可以使用解包语法将它们分别存储在image_datalabel_data两个列表中:

image_data, label_data = zip(*data)

这样,我们就可以分别处理图像数据和标签数据了。

3.2 拓展-后处理代码详解

完整的后处理代码如下:

def postprocess(pred, IM, conf_thres=0.25):
    # 输入是模型推理的结果,即25200个预测框
    # 1,25200,85 [cx,cy,w,h,obj_conf,cls]
    boxes = []
    for img_id, box_id in zip(*np.where(pred[...,4] > conf_thres)):
        item = pred[img_id, box_id]
        cx, cy, w, h, obj_conf = item[:5]
        label = item[5:].argmax()
        confidence = obj_conf * item[5 + label]
        if confidence < conf_thres:
            continue
        left  = cx - w * 0.5
        top = cy - h* 0.5
        right = cx + w * 0.5
        bottom  = cy + h * 0.5
        boxes.append([left, top, right, bottom, confidence, img_id, label])

    boxes = np.array(boxes)
    lr = boxes[:,[0, 2]]
    tb = boxes[:,[1, 3]]
    boxes[:,[0,2]] = IM[0][0] * lr + IM[0][2]
    boxes[:,[1,3]] = IM[1][1] * tb + IM[1][2]
    boxes = sorted(boxes.tolist(), key=lambda x:x[4], reverse=True)
    
    return NMS(boxes)

通过对zip函数封包、解包的简单介绍,再回过头来看下面这段代码:

for img_id, box_id in zip(*np.where(pred[...,4] > conf_thres)):
    ...

该段代码使用NUmpy数据库中的where函数和zip函数,用于遍历预测结果中所有预测框的obj_conf值(即置信度)是否大于设定的置信度阈值(conf_thres),并得到满足条件的预测框的img_id和box_id用于后续decode解码

具体解释如下:

  1. where函数的作用是找到满足条件的元素的坐标,即返回一个元组,其中第一个元素是行坐标数组,第二个元素是列坐标数组,用于定位数组中满足条件的元素。(np.array(x), np.array(y))
  2. pred[…,4]表示预测结果中所有预测框的obj_conf值,即置信度,是一个(1,25200)的数组
  3. pred[…,4]>conf_thres表示预测结果中置信度大于阈值的预测框,返回一个(1,25200)的布尔数组
  4. np.where(pred[…,4]>conf_thres)找到满足条件的预测框的坐标,返回一个元组
  5. zip(*np.where(pred[…,4]>conf_thres))将元组中的两个数组拆开,组合一个新的元组,用于遍历满足条件的预测框的坐标
  6. for img_id, box_id in …遍历所有满足条件的预测框的坐标,其中img_id表示图像的ID,box_ID表示预测框的ID

困惑原因:为什么存在*解包后zip封包操作呢?不是相当于没操作吗?

自我解答:*解包是将行、列坐标(即img,box)进行拆分,zip是将对应的行、列坐标进行封包拼接,简单来说假设batch为1,满足置信度阈值的只有三个框,则np.where(pred[…,4]>conf_thresh)应该是这样的形式即(np.array([0,0,0]),np.array([1,2,3])),进行*解包后应该是[0,0,0] [1,2,3],进行zip封包后应该是[0,1] [0,2] [0,3]即将每张图片中满足条件的预测框进行循环从而decode解码。

4.字符串基本使用

内容:认识python中的字符串基本使用方法如拼接、重复、索引、切片等

Python中的字符串(string)是一种基本的数据类型,用于表示文本数据。

4.1 拼接

在Python中,可以使用加号(+)来拼接多个字符串,如:

str1 = "hello"
str2 = "world"
result = str1 + " " + str2
print(result)	# 输出 "hello world"

另外,还可以使用join方法来拼接多个字符串。该方法将一个可迭代对象中的所有字符串按照指定的分隔符拼接成一个字符串,如:

str_list = ['hello', 'world']
result = ' '.join(str_list)
print(result)	# 输出 "hello world"

4.2 重复

在Python中,可以使用乘号(*)来实现字符串的重复,如:

str = "hello "
result = str * 3
print(result)	# 输出 "hello hello hello "

4.3 提取单个字符

在Python中,可以使用下标(索引)来提取字符串中某个位置的字符。字符串的下标从0开始,如:

str = "hello"
print(str[0])	# 输出 'h'
print(str[1])	# 输出 'e'

4.4 提取子串

在Python中,可以使用切片(slice)来提取字符串中的子串。切片的语法如下:

[start:end:step]

其中start表示起使位置(包含该位置的字符),end表示结束位置(不包含该位置的字符),也就是我们常说的左闭右开([)),step表示步长(默认为1)。切片可以使用正向索引(从左往右)和反向索引(从右往左)来指定位置。

  • 使用正向索引提取子串:

    # start:默认是0 end:默认是字符串长度
    s = "hello world"
    print(s[0:5])	# 提取前 5 个字符,结果为 'hello'
    print(s[6:])	# 提取从第 7 个字符到字符串末尾所有字符,结果为 'world'
    print(s[::2])	# 提取所有偶数位置的字符,结果为 'hlowrd'
    print(s[1::3])	# 从第 2 个字符开始,每隔 3 个字符提取一个字符,结果为 'eood'
    
  • 使用反向索引提取子串

    # start:默认是-1 end:默认是字符串长度
    s = "hello world"
    print(s[::-1])		# 将字符串反转,结果为 'dlrod olleh'
    print(s[:-5:-1])	# 提取从倒数第 1 个字符开始,到倒数第 5 个字符,结果为 'dlro'
    print(s[-2::-3])	# 提取从倒数第 2 个字符开始,每隔 3 隔字符提取一个字符,结果为 'lwlh'
    

5.字符串扩展使用

内容:认识python中的字符串扩展使用方法如格式化、查找、替换等

5.1 格式化

在Python 3.6版本之后,引入了一种新的字符串格式化方法f-string,即在字符串前添加字母f或者F

使用f-string可以直接在字符串中使用**花括号{}**来嵌入表达式,而不需要使用格式化函数或格式字符串操作。这样可以使代码更加简洁,易于理解。

示例如下:

name = 'Tom'
age = 18
s = f"My name is {name} and I'm {age} years old."
print(s)	# 输出结果为:My name is Tom and I'm 18 years old.

f-string还支持格式化字符串,通过在花括号中添加冒号和格式说明符来实现,例如:

pi = 3.1415926
s = f"pi is approximately {pi:.2f}"
print(s)	# 输出结果为:pi is approximately 3.14

5.2 查找字符串

在Python中,str.find()方法用于查找一个子字符串在另一个字符串中第一次出现的位置。如果找到了子字符串,则返回第一字符的索引,如果没有找到,则返回-1。

str.find(sub, start, end)方法可以接受三个参数,其中:

  • sub:要查找的子字符串
  • start:查找的起始位置。默认值为0,表示从字符串的开头开始查找。
  • end:查找的结束位置。默认值为字符串的长度,表示在整个字符串中查找。

示例如下:

text = "Hello world, welcome to Python world."
print(text.find("world"))   # 输出 6
print(text.find("Python"))  # 输出 21
print(text.find("Java"))    # 输出 -1

需要注意的是,str.find()方法区分大小写。如果要进行不区分大小写的查找,可以使用str.lower()str.upper()方法将字符串转换为小写或大写形式,再进行查找。例如:

text = "Hello world, welcome to Python world."
print(text.lower().find("python"))  # 输出 21

另外,还可以使用in运算符来判断一个字符串是否包含另一个字符串,例如:

text = "Hello world, welcome to Python world."
print("world" in text)    # 输出 True
print("Java" in text)     # 输出 False

5.3 替换字符串

在Python中,str.replace()方法用于将一个字符串中的所有旧字符串替换为新字符串。其语法如下:

str.replace(old, new[, count])方法可以接受三个参数,其中:

  • old:被替换的旧字符串
  • new:新字符串
  • count:替换次数(可选参数,默认为全部替换)

示例如下:

text = "The quick brown fox jumps over the lazy dog."
new_text = text.replace("fox", "cat")
print(new_text)		# 输出结果为:The quick brown cat jumps over the lazy dog.

另外,str.replace()方法还可以用于删除指定字符串,例如删除字符串中的空格:

text = "  The quick brown fox jumps over the lazy dog.   "
new_text = text.replace(" ", "")
print(new_text)	# 输出结果为:Thequickbrownfoxjumpsoverthelazydog.

6.总结

本次课程于我而言主要掌握了一些工具使用的重要性如chatGPT、DeepL、Grammarly,然后重新复习了Python格式化输出和zip封包以及字符串的使用,感谢杜老师👍

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱听歌的周童鞋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值