版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1B2A3OpenCV是一套跨平台的开源计算机视觉库,提供C++、Python等多语言接口,可免费商用,它能实现图像与视频的读取、处理、分析等基础操作,还支持特征检测与匹配、目标检测识别、图像分割等功能,广泛应用于人脸检测、二维码识别、手势识别、工业缺陷检测等场景。4OpenCV2和OpenCV3的核心区别,从版本架构、API规范、功能新增等关键维度为你梳理,核心差异如下:模块化架构的重大重构OpenCV2采用相对松散的模块组织,功能划分不够清晰,部分模块存在冗余依赖;而OpenCV3进行了模块化的彻底重构,将库分为两大核心部分:opencv_core(核心基础模块,免费开源)和opencv_contrib(扩展模块,包含更多高级、前沿功能,部分涉及专利或商业授权),扩展模块的分离让核心库更轻量化,也方便高级功能的独立迭代和维护。API命名空间与兼容性变化OpenCV2中大量函数直接暴露在全局命名空间,容易出现命名冲突;OpenCV3则强化了cv命名空间的使用,规范了API命名格式,同时引入了版本化的API设计(部分接口标注cv::v3::xxx)。此外,OpenCV3对2.x版本的部分老旧API进行了废弃或重构,直接迁移2.x代码可能出现兼容性报错,需要进行少量修改。核心功能与性能的升级新增更多高级计算机视觉算法,尤其在opencv_contrib中包含了SIFT/SURF(专利相关)、ORB优化、深度视觉、目标跟踪等前沿功能,这些在OpenCV2中要么缺失,要么实现不够完善;对底层计算进行了优化,更好地支持多核处理器、GPU加速(CUDA接口升级),整体运行效率高于OpenCV2;新增了对机器学习框架的适配、图像分割进阶算法,以及对主流图像/视频格式的更好支持。语言接口与生态的差异OpenCV2对Python接口的支持不够完善,文档和生态相对薄弱;OpenCV3大幅优化了Python、Java等高级语言接口,让非C++开发者更容易上手,同时配套文档更齐全,社区生态更活跃,后续的第三方工具和教程也更多围绕3.x版本展开。构建与部署的优化OpenCV3升级了构建系统,更好地支持CMake最新版本,简化了跨平台编译流程(Windows、Linux、Android等),同时减少了第三方依赖库的冗余,部署后的体积更可控,更适合嵌入式设备和移动应用开发。1A2BGR(蓝-绿-红)(而非日常认知的RGB顺序,这是OpenCV与其他图像处理库(如PIL/Pillow)的重要区别)uint8(8位无符号整数)(取值范围为0~255,这是图像存储中最常见的像素数据类型,用于表示每个颜色通道的亮度等级)。3A参数0(等价于cv2.IMREAD_GRAYSCALE):以灰度单通道模式读取图像,直接返回灰度图4请创建一个大小为300像素×300像素的三通道RGB图像,并将所有像素值设置为0,再以(100,50)与(150,100)为顶点绘制一个红色平面。#导入OpenCV库importcv2#导入numpy库(用于创建图像数组)importnumpyasnp#1.创建300×300三通道图像,所有像素值置0#格式说明:np.zeros((高度,宽度,通道数),数据类型)#注意:OpenCV中图像数组格式为(H,W,C),这里创建的是三通道图像(后续转换为RGB逻辑)img=np.zeros((300,300,3),dtype=np.uint8)#2.绘制红色矩形(顶点(100,50)与(150,100))#关键说明:OpenCV默认图像色彩空间为BGR,红色对应BGR格式(0,0,255)#矩形绘制函数:cv2.rectangle(图像,左上角顶点,右下角顶点,颜色,填充方式)#cv2.FILLED表示填充矩形(绘制红色平面,而非边框)pt1=(100,50)#第一个顶点(x1,y1)pt2=(150,100)#第二个顶点(x2,y2)red_color=(0,0,255)#OpenCV中BGR格式的红色cv2.rectangle(img,pt1,pt2,red_color,cv2.FILLED)#3.显示结果(验证效果,OpenCV窗口显示仍以BGR格式识别)cv2.imshow("RedRectangleImage",img)cv2.waitKey(0)#等待任意按键按下cv2.destroyAllWindows()#关闭所有显示窗口5.请编写一个程序,用于录制计算机摄像头所拍摄的画面,并在画面的左上角绘制自己的名字,最后将录制结果保存在文件夹中。#导入OpenCV库importcv2defrecord_camera_with_name(name="MyName",save_path="camera_record.avi"):#1.初始化摄像头捕获对象#参数0表示默认摄像头(笔记本内置摄像头、台式机外接第一个摄像头)cap=cv2.VideoCapture(0)#校验摄像头是否成功打开ifnotcap.isOpened():print("错误:无法打开摄像头,请检查摄像头是否正常连接或被其他程序占用!")return#2.获取摄像头画面的宽、高和帧率(用于视频写入配置)frame_width=int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))frame_height=int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))fps=int(cap.get(cv2.CAP_PROP_FPS))#若摄像头无法获取有效帧率,默认设置为25帧/秒iffps<=0:fps=25#3.配置视频写入对象(用于保存录制结果)#视频编码格式:XVID兼容性强,跨平台可播放,对应后缀.avifourcc=cv2.VideoWriter_fourcc(*'XVID')#初始化VideoWriter:(保存路径,编码格式,帧率,画面尺寸)out=cv2.VideoWriter(save_path,fourcc,fps,(frame_width,frame_height))#4.配置文字绘制参数(左上角绘制姓名)text=name#要绘制的姓名text_position=(20,50)#文字左上角坐标(x=20,y=50,贴近左上角)font=cv2.FONT_HERSHEY_SIMPLEX#常用无衬线字体font_scale=1.2#文字大小缩放比例font_color=(0,255,0)#文字颜色(BGR格式,这里是绿色)font_thickness=2#文字线条粗细print("提示:摄像头已启动,录制中...按下'q'键停止录制并保存文件")#5.循环捕获、处理、录制画面whileTrue:#读取一帧摄像头画面ret,frame=cap.read()#校验帧是否读取成功(摄像头断开时会读取失败)ifnotret:print("警告:无法读取摄像头画面,停止录制")break#在画面左上角绘制姓名文字cv2.putText(img=frame,text=text,org=text_position,fontFace=font,fontScale=font_scale,color=font_color,thickness=font_thickness)#将处理后的帧写入视频文件out.write(frame)#显示实时录制画面(供预览)cv2.imshow("CameraRecording(Press'q'toquit)",frame)#按下'q'键退出循环(停止录制),等待1ms检测按键ifcv2.waitKey(1)&0xFF==ord('q'):break#6.释放资源(关键步骤,避免内存泄漏和文件损坏)cap.release()#释放摄像头out.release()#释放视频写入对象(确保文件完整保存)cv2.destroyAllWindows()#关闭所有OpenCV显示窗口print(f"录制完成!视频文件已保存至:{save_path}")#调用函数执行录制(可修改姓名和保存路径)if__name__=="__main__":#自定义:修改第一个参数为你的姓名,第二个参数为自定义保存路径(如"./record/我的录制.avi")#注意:若指定子文件夹(如./record/),需提前手动创建该文件夹,否则会保存失败record_camera_with_name(name="ZhangSan",save_path="my_camera_record.avi")第三章1Dcv2.blur()——该函数是OpenCV中专门用于实现**均值滤波(又称方框滤波、平均滤波)**的函数,其原理是取滤波核窗口内所有像素的平均值,作为窗口中心像素的新值,实现图像去噪和平滑。2Acv2.erode()——该函数是OpenCV中专门用于实现**图像腐蚀(Erosion)**的专用函数。腐蚀是形态学操作的基础之一,其原理是用预设的结构元素(卷积核)扫描图像,取窗口内像素的最小值替换中心像素值,最终会让图像中的亮区域(前景)收缩、细化,常用于去除小的亮噪声、分离相邻的物体等。3Ccv2.bilateralFilter()——该函数是OpenCV中专门用于实现双边滤波(BilateralFiltering)的专用函数。双边滤波是一种非线性滤波,它同时考虑了空间距离相似度和像素值灰度相似度,在实现图像去噪平滑的同时,能够有效保留图像的边缘细节(避免普通滤波导致的边缘模糊)。4Bcv2.medianBlur()——这是中值滤波函数。它通过取像素邻域内的中值来替换中心像素值,对椒盐噪声(黑白噪点)有非常好的去除效果,是中值滤波的专用函数。5A6向下采样(高斯模糊+降采样)向上采样(升采样+与高斯金字塔的上一层做差)7代码如下:importcv2importnumpyasnpimportmatplotlib.pyplotasplt#解决matplotlib中文显示问题plt.rcParams['font.sans-serif']=['SimHei']plt.rcParams['axes.unicode_minus']=Falsedefgaussian_blur_demo():#1.读取图像img=cv2.imread('tree.jpg')ifimgisNone:print("错误:未找到tree.jpg,请检查图像路径是否正确!")return#转换为RGB格式(方便matplotlib显示,OpenCV默认BGR)img_rgb=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)#2.不同尺寸高斯核滤波#3×3高斯滤波(sigmaX设为0,OpenCV会自动根据核尺寸计算sigma)blur_3x3=cv2.GaussianBlur(img,(3,3),sigmaX=0)#7×7高斯滤波blur_7x7=cv2.GaussianBlur(img,(7,7),sigmaX=0)#11×11高斯滤波blur_11x11=cv2.GaussianBlur(img,(11,11),sigmaX=0)#3.两次3×3高斯滤波blur_3x3_twice=cv2.GaussianBlur(blur_3x3,(3,3),sigmaX=0)#4.转换为RGB格式用于显示blur_3x3_rgb=cv2.cvtColor(blur_3x3,cv2.COLOR_BGR2RGB)blur_7x7_rgb=cv2.cvtColor(blur_7x7,cv2.COLOR_BGR2RGB)blur_11x11_rgb=cv2.cvtColor(blur_11x11,cv2.COLOR_BGR2RGB)blur_3x3_twice_rgb=cv2.cvtColor(blur_3x3_twice,cv2.COLOR_BGR2RGB)#5.显示所有结果plt.figure(figsize=(16,10))#原图plt.subplot(2,3,1)plt.imshow(img_rgb)plt.title('原图')plt.axis('off')#3×3滤波结果plt.subplot(2,3,2)plt.imshow(blur_3x3_rgb)plt.title('3×3高斯滤波')plt.axis('off')#7×7滤波结果plt.subplot(2,3,3)plt.imshow(blur_7x7_rgb)plt.title('7×7高斯滤波')plt.axis('off')#11×11滤波结果plt.subplot(2,3,4)plt.imshow(blur_11x11_rgb)plt.title('11×11高斯滤波')plt.axis('off')#两次3×3滤波结果plt.subplot(2,3,5)plt.imshow(blur_3x3_twice_rgb)plt.title('两次3×3高斯滤波')plt.axis('off')#差值图像(两次3×3vs7×7)diff=cv2.absdiff(blur_3x3_twice,blur_7x7)diff_rgb=cv2.cvtColor(diff,cv2.COLOR_BGR2RGB)plt.subplot(2,3,6)plt.imshow(diff_rgb)plt.title('两次3×3与7×7的差值')plt.axis('off')plt.tight_layout()plt.show()#6.验证结果是否相同(计算差值的平均值,接近0但非0)diff_mean=np.mean(diff)print(f"两次3×3高斯滤波与7×7高斯滤波的像素差值平均值:{diff_mean:.6f}")ifdiff_mean==0:print("结果完全相同")else:print("结果不相同")#7.解释原因print("\n原因分析:")print("1.高斯滤波的可分离性:高斯滤波是线性操作,连续两次3×3高斯滤波等价于一个“3×3卷积核卷积后再卷积3×3核”的复合核,但复合核的尺寸是5×5(而非7×7),且权重分布与7×7高斯核不同;")print("2.高斯核的权重分布:3×3高斯核的sigma由OpenCV自动计算(sigma=0.85),两次卷积的复合核权重和7×7高斯核(sigma≈1.91)的权重分布差异显著;")print("3.数值精度:即使理论上近似,OpenCV的浮点运算精度限制也会导致像素值存在微小差异。")if__name__=="__main__":gaussian_blur_demo()8代码如下:importcv2importnumpyasnpimportmatplotlib.pyplotasplt#解决matplotlib中文显示问题plt.rcParams['font.sans-serif']=['SimHei']plt.rcParams['axes.unicode_minus']=Falsedefcompare_resize_methods():#1.读取图像img=cv2.imread('mountain.jpg')ifimgisNone:print("错误:未找到mountain.jpg,请检查图像路径是否正确!")return#转换为RGB格式(matplotlib显示用,OpenCV默认BGR)img_rgb=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)h,w=img.shape[:2]print(f"原始图像尺寸:{w}×{h}")#2.方式1:cv2.resize()三次缩小(每次宽高缩为1/2)resize_imgs=[img_rgb]#存储每次resize的结果,初始为原图current_resize=img.copy()foriinrange(3):#计算新尺寸:宽高各缩为1/2new_w=current_resize.shape[1]//2new_h=current_resize.shape[0]//2#使用默认插值方式(cv2.INTER_LINEAR)缩小current_resize=cv2.resize(current_resize,(new_w,new_h))#转换为RGB存储resize_imgs.append(cv2.cvtColor(current_resize,cv2.COLOR_BGR2RGB))print(f"第{i+1}次resize后尺寸:{new_w}×{new_h}")#3.方式2:cv2.pyrDown()三次缩小(高斯金字塔下采样)pyrdown_imgs=[img_rgb]#存储每次pyrDown的结果,初始为原图current_pyr=img.copy()foriinrange(3):current_pyr=cv2.pyrDown(current_pyr)#转换为RGB存储pyrdown_imgs.append(cv2.cvtColor(current_pyr,cv2.COLOR_BGR2RGB))pyr_h,pyr_w=current_pyr.shape[:2]print(f"第{i+1}次pyrDown后尺寸:{pyr_w}×{pyr_h}")#4.可视化对比结果plt.figure(figsize=(16,12))#显示原图plt.subplot(4,3,1)plt.imshow(img_rgb)plt.title('原图')plt.axis('off')#显示resize各次结果foriinrange(1,4):plt.subplot(4,3,i+1)plt.imshow(resize_imgs[i])plt.title(f'第{i}次cv2.resize()')plt.axis('off')#显示pyrDown各次结果foriinrange(1,4):plt.subplot(4,3,i+4)plt.imshow(pyrdown_imgs[i])plt.title(f'第{i}次cv2.pyrDown()')plt.axis('off')#对比最终结果(第三次缩小)plt.subplot(4,3,8)plt.imshow(resize_imgs[3])plt.title('最终:cv2.resize()×3')plt.axis('off')plt.subplot(4,3,9)plt.imshow(pyrdown_imgs[3])plt.title('最终:cv2.pyrDown()×3')plt.axis('off')#计算最终结果的差值(直观显示差异)#先统一尺寸(确保两者尺寸一致,pyrDown和resize理论尺寸相同)final_resize=resize_imgs[3]final_pyr=pyrdown_imgs[3]diff=cv2.absdiff(cv2.cvtColor(final_resize,cv2.COLOR_RGB2BGR),cv2.cvtColor(final_pyr,cv2.COLOR_RGB2BGR))diff_rgb=cv2.cvtColor(diff,cv2.COLOR_BGR2RGB)plt.subplot(4,3,10)plt.imshow(diff_rgb)plt.title('最终结果差值(resize-pyrDown)')plt.axis('off')plt.tight_layout()plt.show()#5.输出差异分析print("\n=====两种缩小方式的核心差异=====")print("1.处理逻辑:")print("-cv2.resize():直接对图像像素进行插值缩放(默认双线性插值),无预处理,仅改变像素排列;")print("-cv2.pyrDown():先对图像进行高斯模糊(消除混叠效应),再移除偶数行/列缩小,属于高斯金字塔下采样。")print("2.视觉效果:")print("-cv2.resize():多次缩小后易出现锯齿、摩尔纹、细节失真(混叠);")print("-cv2.pyrDown():多次缩小后图像更平滑,无明显锯齿,细节过渡自然,但会丢失更多高频细节。")print("3.尺寸一致性:")print("-两者每次缩小后宽高均为原来的1/2,3次后尺寸均为原图的1/8(宽高)、1/64(面积);")print("-但像素值分布差异显著,pyrDown因高斯模糊整体更“柔”,resize保留更多原始像素的硬边缘。")if__name__=="__main__":compare_resize_methods()第四章1A2A3B4A5A6计算图像的直方图,对图像进行直方图均衡化处理。7程序代码如下:importcv2importnumpyasnpimportmatplotlib.pyplotasplt#解决matplotlib中文显示问题plt.rcParams['font.sans-serif']=['SimHei']plt.rcParams['axes.unicode_minus']=Falsedefcanny_threshold_experiment():#1.读取图像并转为灰度图img_path="DavidL.jpg"img=cv2.imread(img_path)ifimgisNone:print(f"错误:未找到图像{img_path},请检查文件路径是否正确!")returnimg_gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#Canny需基于灰度图处理img_rgb=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)#转换为RGB用于matplotlib显示#2.定义5组测试参数(threshold1:低阈值,threshold2:高阈值)threshold_groups=[(0,50,"threshold1=0,threshold2=50"),(50,100,"threshold1=50,threshold2=100"),(100,150,"threshold1=100,threshold2=150"),(150,200,"threshold1=150,threshold2=200"),(200,250,"threshold1=200,threshold2=250")]#3.对每组参数执行Canny边缘检测canny_results=[]fort1,t2,titleinthreshold_groups:edges=cv2.Canny(img_gray,t1,t2)#核心Canny函数调用canny_results.append((edges,title))#4.可视化所有结果plt.figure(figsize=(18,12))#显示原图plt.subplot(2,3,1)plt.imshow(img_rgb)plt.title("原图")plt.axis("off")#显示5组Canny结果fori,(edges,title)inenumerate(canny_results):plt.subplot(2,3,i+2)plt.imshow(edges,cmap="gray")plt.title(title)plt.axis("off")plt.tight_layout()plt.show()#5.逐一分析每组参数的效果print("\n=====Canny阈值参数对边缘检测效果的影响分析=====")print("【核心原理】:Canny的双阈值规则——")print("-高于threshold2(高阈值):判定为强边缘,直接保留;")print("-低于threshold1(低阈值):判定为非边缘,直接舍弃;")print("-介于两者之间:仅当与强边缘相连时,才判定为边缘保留。")print("\n【各组参数效果】:")#第1组:threshold1=0,threshold2=50print("\n(1)threshold1=0,threshold2=50:")print("效果:边缘数量极多,画面几乎全白,包含大量噪声和伪边缘;")print("原因:高阈值50过低,几乎所有像素梯度都被判定为强边缘,低阈值0无过滤作用,噪声完全保留。")#第2组:threshold1=50,threshold2=100print("\n(2)threshold1=50,threshold2=100:")print("效果:边缘数量较多,能清晰看到主体轮廓,但仍有少量细碎的噪声边缘;")print("原因:阈值适中,核心边缘(如人物轮廓、五官)被保留,同时少量低梯度的噪声/细节也被检测到。")#第3组:threshold1=100,threshold2=150print("\n(3)threshold1=100,threshold2=150:")print("效果:边缘数量适中,主体轮廓清晰且无明显噪声,是本次实验中效果最优的参数组合;")print("原因:高低阈值比例约1:1.5(接近工业界推荐的1:2/1:3),既过滤了噪声,又保留了关键边缘。")#第4组:threshold1=150,threshold2=200print("\n(4)threshold1=150,threshold2=200:")print("效果:边缘数量减少,仅保留高梯度的强边缘(如五官轮廓、头发边缘),部分细节边缘丢失;")print("原因:阈值升高,大量中等梯度的边缘(如皮肤纹理)被舍弃,仅保留对比度极高的核心边缘。")#第5组:threshold1=200,threshold2=250print("\n(5)threshold1=200,threshold2=250:")print("效果:边缘极少,仅能看到极少数超高梯度的边缘(如眼睛、头发的强对比处),主体轮廓几乎丢失;")print("原因:阈值过高,只有极少数像素梯度能达到高阈值,大部分边缘被判定为非边缘舍弃。")if__name__=="__main__":canny_threshold_experiment()8程序代码如下:importcv2importnumpyasnpimportmatplotlib.pyplotasplt#解决matplotlib中文显示问题plt.rcParams['font.sans-serif']=['SimHei']plt.rcParams['axes.unicode_minus']=Falsedefhough_transform_car_demo():#1.读取图像img_path="Car.jpg"img=cv2.imread(img_path)ifimgisNone:print(f"错误:未找到图像{img_path},请检查文件路径是否正确!")return#转换为RGB格式(matplotlib显示用)img_rgb=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)#转为灰度图(霍夫变换的基础)img_gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#边缘检测(预处理,提升霍夫变换准确性)edges=cv2.Canny(img_gray,50,150,apertureSize=3)#----------------------霍夫线变换----------------------#使用概率霍夫线变换(HoughLinesP),参数适配汽车图像特征lines=cv2.HoughLinesP(edges,#边缘图rho=1,#像素精度theta=np.pi/180,#角度精度threshold=80,#阈值(越高检测的直线越少,越精准)minLineLength=50,#最小线段长度(过滤短杂线)maxLineGap=10#线段最大间隙(允许断开的间隙))#绘制霍夫线变换结果img_lines=img_rgb.copy()iflinesisnotNone:forlineinlines:x1,y1,x2,y2=line[0]#用红色绘制检测到的直线(线宽2)cv2.line(img_lines,(x1,y1),(x2,y2),(255,0,0),2)#----------------------霍夫圆变换----------------------#霍夫圆变换对噪声敏感,先做高斯模糊img_blur=cv2.GaussianBlur(img_gray,(9,9),2)#霍夫圆变换(适配汽车车轮检测)circles=cv2.HoughCircles(img_blur,#模糊后的灰度图method=cv2.HOUGH_GRADIENT,#梯度法(唯一支持的方法)dp=1,#分辨率缩放因子(1为原图分辨率)minDist=100,#圆心之间的最小距离(避免重复检测)param1=100,#Canny边缘检测的高阈值param2=30,#圆心检测阈值(越低检测的圆越多)minRadius=20,#最小圆半径(过滤小圆)maxRadius=100#最大圆半径(过滤大圆))#绘制霍夫圆变换结果img_circles=img_rgb.copy()ifcirclesisnotNone:#转换为整数(圆参数是浮点型)circles=np.uint16(np.around(circles))forcircleincircles[0,:]:center=(circle[0],circle[1])#圆心坐标radius=circle[2]#半径#绘制圆心(绿色点,大小6)cv2.circle(img_circles,center,1,(0,255,0),6)#绘制圆周(绿色线,线宽2)cv2.circle(img_circles,center,radius,(0,255,0),2)#----------------------可视化结果----------------------plt.figure(figsize=(18,6))#原图plt.subplot(1,3,1)plt.imshow(img_rgb)plt.title('原图')plt.axis('off')#霍夫线变换结果plt.subplot(1,3,2)plt.imshow(img_lines)plt.title('霍夫线变换结果')plt.axis('off')#霍夫圆变换结果plt.subplot(1,3,3)plt.imshow(img_circles)plt.title('霍夫圆变换结果')plt.axis('off')plt.tight_layout()plt.show()#----------------------效果分析----------------------print("\n=====霍夫变换对Car.jpg的处理效果分析=====")print("1.霍夫线变换的图像变化:")print("-核心变化:图像上叠加了红色的直线,这些直线对应汽车的边缘特征(如车身轮廓、车窗边框、保险杠线条、地面标线等);")print("-视觉效果:原本的汽车图像被“结构化”,能清晰看到构成汽车的直线元素,杂乱的细节被过滤,仅保留直线特征;")print("-特点:检测的直线数量由阈值控制,阈值越高,直线越少,仅保留最明显的强直线(如车身主轮廓)。")print("\n2.霍夫圆变换的图像变化:")print("-核心变化:图像上叠加了绿色的圆形(圆心+圆周),主要检测到汽车的车轮(轮胎/轮毂)等圆形特征;")print("-视觉效果:能精准定位圆形目标的位置和大小,非圆形区域无额外绘制,突出汽车的圆形部件;")print("-特点:对噪声敏感,需先高斯模糊预处理,参数(如minDist、param2)会影响圆的检测数量和准确性。")if__name__=="__main__":hough_transform_car_demo()第五章1A2A3A4C5程序代码如下:importcv2importnumpyasnpimportmatplotlib.pyplotasplt#解决matplotlib中文显示问题plt.rcParams['font.sans-serif']=['SimHei']plt.rcParams['axes.unicode_minus']=Falsedefdetect_circle_contour():#1.读取图像img_path="circle.jpg"img=cv2.imread(img_path)ifimgisNone:print(f"错误:未找到图像{img_path},请检查文件路径是否正确!")return#2.转换为灰度图像img_gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#3.阈值化处理(转为二值图像)#参数:灰度图、阈值、最大值、二值化类型(THRESH_BINARY_INV适用于白底黑圆的情况,可根据图像调整)#若图像是黑底白圆,改用cv2.THRESH_BINARYret,img_binary=cv2.threshold(img_gray,127,255,cv2.THRESH_BINARY_INV)#4.检测轮廓#参数:二值图像、轮廓检索模式(RETR_EXTERNAL只检测最外层)、轮廓逼近方法(CHAIN_APPROX_SIMPLE压缩点)contours,hierarchy=cv2.findContours(img_binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)#5.绘制轮廓(可视化)img_contour=img.copy()#复制原图用于绘制轮廓ifcontours:#取面积最大的轮廓(确保是圆形的主轮廓,过滤噪声)main_contour=max(contours,key=cv2.contourArea)#绘制轮廓:绿色,线宽2,-1表示绘制所有轮廓点cv2.drawContours(img_contour,[main_contour],-1,(0,255,0),2)#输出轮廓关键信息print("=====圆形轮廓关键信息=====")print(f"轮廓点数量:{len(main_contour)}")print(f"轮廓面积:{cv2.contourArea(main_contour):.2f}像素")#计算最小包围圆(验证圆形特征)(cx,cy),radius=cv2.minEnclosingCircle(main_contour)print(f"最小包围圆圆心:({cx:.2f},{cy:.2f}),半径:{radius:.2f}像素")else:print("未检测到任何轮廓,请检查阈值化参数或图像内容!")#6.可视化所有步骤结果plt.figure(figsize=(16,4))#原图plt.subplot(1,4,1)plt.imshow(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))plt.title('原图')plt.axis('off')#灰度图plt.subplot(1,4,2)plt.imshow(img_gray,cmap='gray')plt.title('灰度图像')plt.axis('off')#二值化图像plt.subplot(1,4,3)plt.imshow(img_binary,cmap='gray')plt.title('阈值化二值图像')plt.axis('off')#轮廓检测结果plt.subplot(1,4,4)plt.imshow(cv2.cvtColor(img_contour,cv2.COLOR_BGR2RGB))plt.title('轮廓检测结果')plt.axis('off')plt.tight_layout()plt.show()if__name__=="__main__":detect_circle_contour()6程序代码如下:importcv2importnumpyasnpimportmatplotlib.pyplotasplt#解决matplotlib中文显示问题plt.rcParams['font.sans-serif']=['SimHei']plt.rcParams['axes.unicode_minus']=Falsedefcontour_approx_demo():#1.构造基础轮廓(不规则多边形,周长≈110,作为基长度)#手动构造点集,确保轮廓周长接近110points=np.array([[50,50],[70,30],[100,40],[120,60],[110,90],[90,100],[60,90],[40,70],[50,50]#闭合轮廓],dtype=32)#调整为OpenCV轮廓的格式((N,1,2))original_contour=points.reshape((-1,1,2))#计算原始轮廓的周长(作为基长度参考)base_length=cv2.arcLength(original_contour,closed=True)print(f"原始轮廓周长(基长度参考):{base_length:.2f}(目标基长度110)")#2.定义逼近精度比例(90%、66%、33%、10%)ratios=[0.9,0.66,0.33,0.1]ratio_labels=["90%","66%","33%","10%"]#基于基长度110计算每个比例对应的ε(逼近精度)epsilon_list=[110*ratioforratioinratios]#3.对每个ε执行轮廓逼近approx_contours=[]fori,(epsilon,label)inenumerate(zip(epsilon_list,ratio_labels)):#cv2.approxPolyDP(轮廓,逼近精度ε,是否闭合)approx=cv2.approxPolyDP(original_contour,epsilon,closed=True)approx_contours.append((approx,label,epsilon))#计算逼近后轮廓的周长approx_length=cv2.arcLength(approx,closed=True)print(f"\n{label}逼近(ε={epsilon:.2f}):")print(f"逼近后轮廓顶点数:{len(approx)}")print(f"逼近后轮廓周长:{approx_length:.2f}")#4.可视化原始轮廓和所有逼近结果plt.figure(figsize=(15,10))#绘制原始轮廓plt.subplot(2,3,1)#提取轮廓点的x、y坐标x_ori=original_contour[:,0,0]y_ori=original_contour[:,0,1]plt.plot(x_ori,y_ori,'b-',linewidth=2,label='原始轮廓')plt.fill(x_ori,y_ori,'lightblue',alpha=0.3)plt.title(f'原始轮廓(周长≈{base_length:.2f})')plt.axis('equal')#等比例显示,避免轮廓变形plt.legend()#绘制4种逼近结果fori,(approx,label,epsilon)inenumerate(approx_contours):plt.subplot(2,3,i+2)x_approx=approx[:,0,0]y_approx=approx[:,0,1]plt.plot(x_ori,y_ori,'gray--',linewidth=1,label='原始轮廓(参考)')plt.plot(x_approx,y_approx,'r-',linewidth=2,label=f'{label}逼近')plt.fill(x_approx,y_approx,'lightcoral',alpha=0.3)plt.title(f'{label}逼近(ε={epsilon:.2f})')plt.axis('equal')plt.legend()plt.tight_layout()plt.show()if__name__=="__main__":contour_approx_demo()
第六章1A2A3人脸识别的基本步骤是人脸检测和人脸识别/人脸验证,后者对检测到的人脸进行特征提取与身份匹配/身份确认。4程序代码如下:importcv2importosimportnumpyasnp#=====================1.配置参数=====================#人脸检测分类器路径(OpenCV自带,若找不到需手动指定路径)CASCADE_PATH=cv2.data.haarcascades+"haarcascade_frontalface_default.xml"#训练数据保存路径TRAIN_DIR="train_data"#模型保存路径MODEL_PATH="model/face_model.yml"#人脸图像尺寸(统一大小,方便训练)FACE_SIZE=(100,100)#你的身份标签(数字,比如0,代表唯一身份)YOUR_LABEL=0#你的名字(对应标签,用于识别结果显示)YOUR_NAME="我自己"#=====================2.工具函数=====================defcreate_dir(dir_path):"""创建文件夹(若不存在)"""ifnotos.path.exists(dir_path):os.makedirs(dir_path)defdetect_face(img_gray):"""检测人脸并返回裁剪后的人脸图像"""#加载人脸检测分类器face_cascade=cv2.CascadeClassifier(CASCADE_PATH)ifface_cascade.empty():raiseException("人脸检测分类器加载失败,请检查CASCADE_PATH是否正确!")#检测人脸faces=face_cascade.detectMultiScale(img_gray,scaleFactor=1.1,minNeighbors=5,minSize=(30,30))iflen(faces)==0:returnNone,None#未检测到人脸#取第一个检测到的人脸(默认只有一个人)x,y,w,h=faces[0]#裁剪人脸区域并统一尺寸face_roi=img_gray[y:y+h,x:x+w]face_roi=cv2.resize(face_roi,FACE_SIZE)returnface_roi,(x,y,w,h)#=====================3.采集人脸数据=====================defcollect_face_data(num_photos=20):"""调用摄像头采集num_photos张人脸照片(默认20张,越多训练效果越好)"""create_dir(TRAIN_DIR)cap=cv2.VideoCapture(0)#打开摄像头(0为默认摄像头)count=0#已采集的照片数print(f"\n开始采集人脸数据,需要拍摄{num_photos}张照片...")print("提示:请正对摄像头,缓慢移动头部,按空格键拍摄,按q键退出!")whilecount<num_photos:ret,frame=cap.read()ifnotret:print("摄像头读取失败!")breakimg_gray=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)face_roi,face_rect=detect_face(img_gray)#绘制人脸检测框ifface_rectisnotNone:x,y,w,h=face_rectcv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),2)cv2.putText(frame,f"已采集:{count}/{num_photos}",(10,30),cv2.FONT_HERSHEY_SIMPLEX,1,(255,0,0),2)cv2.imshow("CollectFaceData",frame)#按键操作key=cv2.waitKey(1)&0xFFifkey==ord('q'):#按q退出breakelifkey==ord(''):#按空格键拍摄ifface_roiisnotNone:#保存人脸图像photo_path=os.path.join(TRAIN_DIR,f"face_{count}.png")cv2.imwrite(photo_path,face_roi)count+=1print(f"已保存第{count}张人脸照片:{photo_path}")cap.release()cv2.destroyAllWindows()ifcount==num_photos:print(f"\n人脸数据采集完成!共采集{count}张照片,保存至{TRAIN_DIR}文件夹。")else:print(f"\n采集中断,仅保存了{count}张照片(需要{num_photos}张)。")#=====================4.训练人脸识别模型=====================deftrain_face_model():"""加载训练数据,训练LBPH人脸识别模型"""create_dir(os.path.dirname(MODEL_PATH))faces=[]#存储人脸图像数据labels=[]#存储对应的标签#遍历训练数据文件夹forfilenameinos.listdir(TRAIN_DIR):iffilename.endswith(".png")orfilename.endswith(".jpg"):#读取人脸图像img_path=os.path.join(TRAIN_DIR,filename)face_img=cv2.imread(img_path,0)#以灰度图读取ifface_imgisNone:continue#添加到训练集faces.append(face_img)labels.append(YOUR_LABEL)iflen(faces)==0:raiseException(f"训练数据为空!请先运行collect_face_data()采集人脸照片。")print(f"\n开始训练模型,共加载{len(faces)}张训练图像...")#创建LBPH人脸识别器(适合新手,参数为默认值)recognizer=cv2.face.LBPHFaceRecognizer_create()#训练模型recognizer.train(faces,np.array(labels))#保存模型recognizer.save(MODEL_PATH)print(f"模型训练完成!已保存至{MODEL_PATH}")returnrecognizer#=====================5.测试人脸识别模型=====================deftest_face_recognition(test_mode="camera"):"""测试模型:支持摄像头实时识别(camera)或单张照片识别(photo)"""#加载训练好的模型ifnotos.path.exists(MODEL_PATH):raiseException(f"模型文件不存在!请先运行train_face_model()训练模型。")recognizer=cv2.face.LBPHFaceRecognizer_create()recognizer.read(MODEL_PATH)iftest_mode=="camera":#摄像头实时识别cap=cv2.VideoCapture(0)print("\n开始实时人脸识别,按q键退出!")print("置信度越低,匹配度越高(通常<50为匹配)")whileTrue:ret,frame=cap.read()ifnotret:breakimg_gray=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)face_roi,face_rect=detect_face(img_gray)ifface_rectisnotNone:x,y,w,h=face_rectifface_roiisnotNone:#预测人脸label,confidence=recognizer.predict(face_roi)#判断是否匹配(置信度<50为匹配,可根据实际调整)iflabel==YOUR_LABELandconfidence<50:result=f"{YOUR_NAME}(置信度:{confidence:.1f})"color=(0,255,0)#绿色表示匹配else:result=f"未知人脸(置信度:{confidence:.1f})"color=(0,0,255)#红色表示不匹配#绘制结果cv2.rectangle(frame,(x,y),(x+w,y+h),color,2)cv2.putText(frame,result,(x,y-10),cv2.FONT_HERSHEY_SIMPLEX,0.7,color,2)cv2.imshow("FaceRecognitionTest",frame)ifcv2.waitKey(1)&0xFF==ord('q'):breakcap.release()eliftest_mode=="photo":#单张照片识别(需将测试照片放入test_photo文件夹,命名为test.jpg)test_photo_path="test_photo/test.jpg"create_dir("test_photo")ifnotos.path.exists(test_photo_path):print(f"测试照片不存在!请在test_photo文件夹中放入名为test.jpg的照片。")returnframe=cv2.imread(test_photo_path)img_gray=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)face_roi,face_rect=detect_face(img_gray)iff
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026湖南娄底市妇幼保健院公开招聘专业技术人员考试备考试题及答案解析
- 2026年榆林市第九幼儿园招聘考试备考试题及答案解析
- 2026江西吉安市新庐陵大数据有限公司面向社会招聘派遣员工4人考试备考题库及答案解析
- 2026中国联通甘孜州分公司招聘考试参考试题及答案解析
- 2026年乐平市公安局公开招聘留置看护勤务辅警【56人】考试参考试题及答案解析
- 2026云南玉溪市元江县人民政府办公室编外人员招聘2人考试备考题库及答案解析
- 2026年瑞丽市勐卯街道卫生院招聘备考题库及答案详解1套
- 2026年黄石市园博文化旅游经营管理有限公司招聘备考题库及完整答案详解1套
- 四川新南城乡建设集团有限公司2025年面向社会公开招聘3名一线工作人员的备考题库及参考答案详解一套
- 2026年集团招聘广东省广轻控股集团有限公司招聘备考题库及答案详解参考
- 多趾畸形护理查房
- 伊利并购澳优的财务绩效分析
- 胸腺瘤伴重症肌无力课件
- 安徽省合肥市蜀山区2024-2025学年上学期八年级数学期末试卷
- 电商售后客服主管述职报告
- 十五五安全生产规划思路
- 上海证券有限责任公司校招职位笔试历年参考题库附带答案详解
- 剪刀车专项施工方案
- 2024-2025学年四川省绵阳市七年级(上)期末数学试卷
- 项目预算管理咨询方案
- 合成药物催化技术
评论
0/150
提交评论