调试器确实能派上用场

编程错误与调试
语法和语义错误


编程很难,有很多方法可以犯错误。错误通常分为两类:语法错误和语义错误(逻辑错误)。


语法错误发生时,你写了一个声明针对C++语言的语法无效。这包括错误如缺少分号,未声明的变量,不匹配的括号或大括号,和未结束的字符串。例如,下面的程序包含了相当多的语法错误:

#include <iostream>; // preprocessor statements can't have a semicolon on the end
 
int main()
{
    std:cout < "Hi there; << x; // invalid operator (:), unterminated string (missing "), and undeclared variable
    return 0 // missing semicolon at end of statement
}

幸运的是,编译器通常会捕获语法错误并生成警告或错误,因此您很容易识别和修复问题。那就只需要再编译一遍,直到你消除所有的错误。


一旦你的程序编译正确,让它实际生成你想要的结果可能会很棘手。语义错误发生时,语句在语法上是有效的,但不做程序员想要的。


有时这些会导致程序崩溃,例如在除以0的情况下:

1
2
3
4
5
6
7
8
9
#include <iostream>
 
int main()
{
    int a = 10;
    int b = 0;
    std::cout << a << " / " << b << " = " << a / b; // division by 0 is undefined
    return 0;
}

不幸的是,编译器将无法捕捉到这些类型的问题,因为编译器只知道您编写了什么,而不是您打算的内容。


在上面的例子中,这些错误很容易被发现。但在最不平凡的程序,许多语义错误不容易通过目测找到代码。


幸运的是,调试器确实能派上用场。


调试器


调试器是一种计算机程序,它允许程序员控制程序如何执行,并观察程序运行时发生了什么。例如,程序员可以使用调试器一行一行地执行程序,检查变量的值。通过将变量的实际值与预期值进行比较,或者通过代码观察执行路径,调试器可以极大地帮助跟踪语义错误。


早期的调试器,如GDB,有命令行界面,程序员必须在神秘的命令去做。后来的调试器(如Borland的Turbo Debugger)来与自己的“图形”的前端,使他们工作更容易。几乎所有的现代IDE可用这些天已经集成调试器,调试器是内置的编辑器,这样你可以调试使用相同的环境,你写你的代码(而不是切换程序)。


几乎所有的现代调试器包含同一组标准的基本特征,然而,很少有一致性,对于如何使用这些功能的菜单设置,并在键盘快捷键更一致。尽管我们的示例将来自微软Visual Studio 2005 Express,但无论您使用的是哪种开发环境,您都不难理解如何访问我们讨论的每个特性。


在继续之前,请确保您的程序设置为使用调试生成配置。

2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
 
void printValue(int nValue)
{
    std::cout << nValue;
}
 
int main()
{
    printValue(5);
    return 0;
}


import cv2 import matplotlib.pyplot as plt import os import numpy as np # 简单测试 # img = cv2.imread('face.jpg') # #采用级联分类器 # detector = cv2.CascadeClassifier('haarcascade_frontalface_alt.xml') # #进行人脸检测 # rects = detector.detectMultiScale(img,scaleFactor = 1.1,minNeighbors = 3,minSize = (20,20),flags =cv2.CASCADE_SCALE_IMAGE) # #返回的就是人脸的位置 # # print(rects) # for x,y,w,h in rects: # #截取人脸,并且都转化为200*200的固定大小 # cv2.rectangle(img, (x,y),(x+w,y+h), (0,255,0), (2)) # img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # plt.imshow(img) # plt.axis('off') # plt.show() #实战 def face_detect(face_path ,predict_face_path): #如果文件夹不存在则创建文件夹 if not os.path.exists(predict_face_path): os.mkdir(predict_face_path) #循环face_path下面的每个文件夹 for dirs in os.listdir(face_path): #检测是不是文件夹,因为图片文件都是放在单独的文件夹中 if os.path.isdir(os.path.join(face_path ,dirs)): #说明已经得到了人脸照片所在的文件夹,为了方便查看,直接把原来的文件夹名称搬过去 predict_face_sub_path = os.path.join(predict_face_path ,dirs) # print(predict_face_sub_path) if not os.path.exists(predict_face_sub_path): os.mkdir(predict_face_sub_path) #获取各个明星人脸图片所在的文件夹 files = os.path.join(face_path ,dirs) # print(files) for file in os.listdir(files): #获取人脸图片的绝对路径 file = os.path.join(files ,file) print(file) loc_face(file ,predict_face_sub_path) def loc_face(file ,predict_face_sub_path): #获取文件名 name = os.path.basename(file) #加载图像 image = cv2.imread(file) #为了方便识别,习惯变成灰度图 image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) #采用级联分类器 detector = cv2.CascadeClassifier('haarcascade_frontalface_alt.xml') #进行人脸检测,返回的就是人脸的位置 rects = detector.detectMultiScale(image ,scaleFactor = 1.1, minNeighbors = 3 ,minSize = (20 ,20), flags =cv2.CASCADE_SCALE_IMAGE) #这里不直接绘制正方形,直接把识别后的图片给保存下来 print(image) for (x ,y ,w ,h) in rects: #统一裁剪成为200x200的大小,注意这里的切片的顺序不能错了 f = cv2.resize(image[y: y +h ,x: x +w], (200 ,200)) #然后保存,注意这里的 cv2.imwrite(os.path.join(predict_face_sub_path ,name) ,f) #测试一下为什么要进行image[y:y+h,x:x+w] # import numpy as np # data = np.array( # [[216, 216, 215, 212, 212, 212], # [216 ,216 ,215 ,211 ,211 ,211], # [216 ,216 ,215 , 210, 210, 210], # [ 86 , 85 , 82 , 137, 139, 141], # [ 85 , 83 , 81 , 139, 140, 141], # [ 84 , 83 , 80 , 140, 141, 142]]) # x,y,w,h = 1,2,3,4 # print(data[x:x+w,y:y+h]) # print(data[y:y+h,x:x+w]) #制作标签 def get_label(predict_face_path): #生成一个label.txt文件保存图片路径和标签 f = open('label.txt', 'w') #表示人脸的标签,默认是从0开始 label = 0 for dirpath ,dirnames ,files in os.walk(predict_face_path): #获取所有的子文件夹 for sub_dir in dirnames: #完整的子文件夹路径 sub_dir_path = os.path.join(dirpath ,sub_dir) #这时候就可以循环遍历每一个子文件夹,提取图片数据了 for file in os.listdir(sub_dir_path): #注意提取的图片名称是相对路径,需要补充完整 file_path = os.path.join(sub_dir_path ,file) #获得完整路径后就可以判断是不是图片 if file_path.split('.')[-1] in ['png' ,'jpg' ,'jpeg']: f.write(file_path) #为了之后方便提取标签,加一个分割符号 f.write(";") #再写入标签进行换行 f.write(str(label)) f.write("\n") #每个子文件夹遍历完毕后,就进行累加,完成标签制作 label += 1 #关闭文件 f.close() #训练模型 #创建两个列表保存图片数据和标签 def train_model(): images = [] labels = [] f = open('label.txt' ,'r') for line in f: #之前保留的分割符就派上用场了 img_path = line.split(';')[0] # print(img_path) label = line.split(';')[-1] #再将图片和标签分别存放在两个列表中 img = cv2.imread(img_path ,0) #问题就出在这个0上面,imread按单通道的方式读入图像,即灰度图像 images.append(img) #注意最后的标签是要转化为数值 labels.append(int(label)) print(images) #这里需要安装opencv扩展包pip install opencv-contrib-python model = cv2.face.EigenFaceRecognizer_create() #训练模型 model.train(np.array(images) ,np.array(labels)) #保存模型 model.save('my_face_detect_model.xml') #人脸识别 #定义要显示的人脸的名字 def face_test(): name = ['AB' ,'xiaoming' ,'xiaoxiannv'] #定义人脸的识别模型 model = cv2.face.EigenFaceRecognizer_create() #载入训练好的模型 model.read('my_face_detect_model.xml') #读入测试集进行验证 for file in os.listdir('test'): #文件的完整路径 file_path = os.path.join('test', file) #还是判断文件类型 if file_path.split('.')[-1] in ['png' ,'jpg' ,'jpeg']: img = cv2.imread(file_path) #为了方便识别,尽量变成灰度图 img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #级联分类器 detector = cv2.CascadeClassifier('haarcascade_frontalface_alt.xml') rects = detector.detectMultiScale(img_gray ,scaleFactor = 1.1, minNeighbors = 3 ,minSize = (20 ,20), flags =cv2.CASCADE_SCALE_IMAGE) #循环每一张人脸 for (x ,y ,w ,h) in rects: #画矩形框 cv2.rectangle(img ,(x ,y) ,( x +w , y +h) ,(0 ,255 ,0) ,2) #人脸识别 face = cv2.resize(img_gray[y: y +h ,x: x +w] ,(200 ,200)) #预测人物 params = model.predict(face) print(params) #写上人物的名字 cv2.putText(img ,name[params[0]] ,(x , y -20) ,cv2.FONT_HERSHEY_SIMPLEX ,1 ,(255 ,0 ,0) ,2) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) plt.imshow(img) plt.axis('off') plt.show() if __name__ == "__main__": face_test() # train_model() # face_detect('train','predict_faces') # get_label('predict_faces') 检查问题
最新发布
06-17
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值