找到
2
篇与
opencv
相关的结果
-
Python OpenCV学习第二天:图像读写+BGR颜色空间+摄像头调用 Python OpenCV学习第二天:读个图颜色居然是反的 昨天把环境和NumPy基础搞定了,今天信心满满地开始学图像读写,本来以为就是调几个函数的事,结果第一张图读出来直接给我整懵了——好好的蓝天变成了深蓝,红花变成了蓝花,折腾了半天才搞明白是OpenCV那个反人类的BGR颜色空间搞的鬼。今天踩的坑比昨天还多,不过好歹把核心操作都摸透了。 今日目标完成情况 图像的读取、显示、保存全流程搞定 搞懂了BGR和RGB的区别及转换方法 学会了通道分离与合并 成功调用电脑摄像头实时显示画面 完成了第一个小项目:简易图像查看器 一、图像基本操作:读、显、存(坑最多的部分) 这三个函数看起来简单,但新手能踩的坑一个都不少,我挨个说。 1. 读取图像:cv2.imread() 函数原型:cv2.imread(文件路径, 读取模式) import cv2 import numpy as np # 最常用的读取方式:彩色图模式(默认) img = cv2.imread("test.jpg") # 其他读取模式 img_gray = cv2.imread("test.jpg", cv2.IMREAD_GRAYSCALE) # 灰度图模式 img_unchanged = cv2.imread("test.jpg", cv2.IMREAD_UNCHANGED) # 包含透明通道 路径绝对不能有中文! 这是90%新手第一个踩的坑。如果路径里有中文(虽然我用的是test.jpg),imread()不会报错,但会返回None,后面所有操作都会报错。解决方法:把图片放到纯英文路径下,或者用下面的兼容写法: # 中文路径兼容写法 img = cv2.imdecode(np.fromfile("测试图片.jpg", dtype=np.uint8), cv2.IMREAD_COLOR) 图片不存在/路径写错时,会出警告但不会直接崩溃! 第一步:它会先弹出一串黄色警告(Warning): [ WARN:0@0.032] ... can't open/read file ... mo6rtsk4.png图片 (我把文件名字写错了)意思是“找不到图片了,但我先不跟你玩命,提醒你一下”。 第二步:程序不会停止,继续往下运行,但会把 img 变量赋值为 None(空的)。 第三步:如果你没加判断,后面直接用 img(比如 cv2.imshow),这时候才会弹出红色报错(Error),然后程序直接崩溃闪退。 所以必须加这个判断! 把问题扼杀在摇篮里: if img is None: print("图片读取失败!请检查路径/文件名/是否有中文") else: print("图片读取成功") mo6ryxne.png图片 文件路径错误调用后爆炸 读取模式参数:默认是cv2.IMREAD_COLOR(值为1),会自动忽略透明通道;如果需要保留透明通道(PNG图片),必须用cv2.IMREAD_UNCHANGED(值为-1)。 2. 显示图像:cv2.imshow() 函数原型:cv2.imshow(窗口名, 图像数组) # 显示图像 cv2.imshow("img", img) # ↓必须加这两行!不然窗口会一闪而过 cv2.waitKey(0) # 等待任意按键按下,0表示无限等待 cv2.destroyAllWindows() # 关闭所有窗口注意: 不写waitKey()和destroyAllWindows()会导致程序卡死,窗口关不掉,只能强制结束进程。 waitKey(0)里的数字是等待时间(毫秒),如果写waitKey(1000)就是等待1秒后自动关闭窗口。 多个窗口的话,窗口名不能重复,否则后面的会覆盖前面的。 3. 保存图像:cv2.imwrite() 函数原型:cv2.imwrite(保存路径, 图像数组) # 保存图像 cv2.imwrite("output.jpg", img) # 中文路径兼容写法 cv2.imencode(".jpg", img)[1].tofile("输出图片.jpg")注意:保存格式由后缀名决定,支持jpg、png、bmp等常见格式。保存jpg时可以指定压缩质量(0-100,默认95): cv2.imwrite("output.jpg", img, [cv2.IMWRITE_JPEG_QUALITY, 100]) # 最高质量二、BGR颜色空间:OpenCV最反人类的设计 终于说到今天最大的坑了!为什么我读出来的图颜色不对?因为OpenCV默认的彩色图像格式是BGR,而不是我们平时用的RGB! 也就是说,普通图片的像素顺序是(红、绿、蓝),但OpenCV读进来之后会变成(蓝、绿、红),所以红色会变成蓝色,蓝色会变成红色,绿色不变。 1. BGR转RGB 解决方法很简单,用cv2.cvtColor()转换一下就行: # BGR转RGB img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 其他转换 img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # BGR转灰度图 img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # BGR转HSV(后面颜色识别会用到)2. 通道分离与合并 有时候我们需要单独处理某一个颜色通道,比如只提取红色通道,这就需要用到通道分离和合并: # 分离通道(B、G、R三个通道) b, g, r = cv2.split(img) # 合并通道(注意顺序!) img_merged = cv2.merge([b, g, r]) # 合并成BGR图像 img_rgb_merged = cv2.merge([r, g, b]) # 合并成RGB图像偷鸡技巧:如果想单独显示某个通道,直接cv2.imshow("Red", r)会显示成灰度图,因为单通道数组会被当成灰度图处理。如果想显示成红色,需要把其他两个通道设为0: # 只显示红色通道(彩色,黑白没有红色) red_channel = np.zeros_like(img) red_channel[:, :, 2] = r # 红色通道是第三个通道(索引2) cv2.imshow("Red Channel", red_channel)三、视频与摄像头调用:比想象中简单(康养写过) OpenCV处理视频的逻辑很简单:把视频当成一帧一帧的图像,逐帧处理就行。 1. 读取本地视频 # 创建视频捕获对象,参数是视频文件路径 cap = cv2.VideoCapture("video.mp4") # 循环读取每一帧 while cap.isOpened(): # 读取一帧,ret表示是否读取成功,frame是当前帧的图像 ret, frame = cap.read() if not ret: print("视频读取完毕") break # 显示当前帧 cv2.imshow("Video", frame) # 按q键退出(等待1毫秒,这样视频才能正常播放) if cv2.waitKey(1) & 0xFF == ord('q'): break # 释放资源 cap.release() cv2.destroyAllWindows()2. 调用电脑摄像头 把上面的视频路径换成0就行,0表示默认摄像头: cap = cv2.VideoCapture(0) # 0是默认摄像头,1是第二个摄像头 while cap.isOpened(): ret, frame = cap.read() if not ret: break # 这里可以对frame进行处理,比如转成灰度图(不建议,因为会变成遗照🤔) #gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) cv2.imshow("摄像头", gray) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()踩坑:如果摄像头被其他程序占用,cap.isOpened()会返回False,关闭其他占用摄像头的程序就行。 四、今日小项目:简易图像查看器 把今天学的内容整合起来,写一个能打开、显示、保存图像的小程序: import cv2 import numpy as np def main(): # 读取图像(中文路径兼容) img_path = "test.jpg" img = cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), cv2.IMREAD_COLOR) if img is None: print("图片读取失败!") return # 显示原图 cv2.imshow("原图", img) # 转成灰度图并显示 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) cv2.imshow("灰度图", gray) # 转成RGB并显示 rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) cv2.imshow("RGB图", rgb) # 等待按键 key = cv2.waitKey(0) # 按s键保存灰度图 if key == ord('s'): cv2.imencode(".jpg", gray)[1].tofile("灰度图.jpg") print("灰度图已保存") # 关闭所有窗口 cv2.destroyAllWindows() if __name__ == "__main__": main()运行这个程序,就能同时看到原图、灰度图和RGB图的区别了,按s键还能保存灰度图。 五、今日踩坑总结 中文路径大坑:cv2.imread()和cv2.imwrite()不支持中文路径,必须用imdecode和imencode的兼容写法。 BGR颜色空间:OpenCV默认是BGR,和所有其他库(Matplotlib、PIL)都不一样,显示颜色不对先转RGB。 窗口关闭问题:必须写cv2.waitKey()和cv2.destroyAllWindows(),不然窗口会卡死。 视频播放速度:cv2.waitKey(1)里的数字控制视频播放速度,数字越小播放越快,一般用1-10毫秒。 摄像头权限:如果摄像头打不开,检查一下系统是否给了Python摄像头权限。 六、明天要学的 图像的几何变换:缩放、旋转、平移、翻转 图像阈值处理:简单阈值和自适应阈值 图像滤波:均值滤波、高斯滤波、中值滤波 写一个简单的图像滤镜小程序 今天学了大概两个小时,主要是颜色空间的坑浪费了不少时间,一开始还以为是我电脑出问题了,查了半天才知道是OpenCV的设计问题。不过搞懂之后就觉得其实也不难,都是固定的套路。果然学OpenCV就是不断踩坑然后填坑的过程,多敲代码多踩坑,自然就会了。 -
Python OpenCV学习第一天:环境搭建+NumPy核心基础 Python OpenCV学习第一天:环境搭到一半差点放弃 今天终于下定决心开始学OpenCV了!按照之前定的计划,第一天先搞环境和NumPy基础。本来以为半小时就能搞定环境,结果踩了两个大坑,折腾了快一个小时才弄好,真的服了。 今日目标完成情况 OpenCV环境搭建成功 NumPy核心操作过了一遍 搞懂了为什么OpenCV离不开NumPy 掌握OpenCV、NumPy基础语法,能看懂基础代码 一、环境搭建:别再只装opencv-python了! 真的要吐槽一下网上那些老教程,全都是让你pip install opencv-python,我装完之后才发现后面很多函数都用不了,查了半天才知道原来还有个完整版。而且我之前的python环境乱成狗屎,之前安装中断导致后续安装不上,折腾了好久才理顺。 正确安装方法 先把之前装的乱七八糟的版本全部卸载干净,不然会冲突(卸载时如果提示“跳过opencv-contrib-python,因为未安装”,属于正常情况,不用管,确保已安装的版本被卸载即可): pip uninstall opencv-python opencv-contrib-python -ymo5qcl22.png图片 然后直接装完整版,包含所有contrib模块,后面学特征检测、DNN什么的都不用再重新装了: pip install opencv-contrib-python -i https://pypi.tuna.tsinghua.edu.cn/simplemo5qfmkq.png图片 一定要加清华源!不加的话国外源慢到死,还经常超时(但是我加了也慢,又被校园网美式拦截了)。另外安装时还遇到了清华源网页访问失败的情况(疑似跑路),试了几次后才顺利下载,估计是临时网络波动,遇到这种情况多重试几次就好。 还有个小问题:安装时会提示“默认采用用户安装模式”,因为正常的site-packages目录没有写入权限,无需担心,不影响OpenCV和NumPy的正常使用,最终还是成功安装了opencv-contrib-python 4.13.0.92版本,NumPy也保持了适配的版本。 测试安装 新建个py文件,输入这几行,测试环境是否安装成功(代码含义后面语法板块会详细说): import cv2 import numpy as np print(f"OpenCV版本:{cv2.__version__}") print(f"NumPy版本:{np.__version__}")mo5r7t6a.png图片 我这里实际测试输出的是OpenCV 4.13.0和NumPy 2.2.6,之前写的版本是笔误,实际安装后一切正常。如果报错找不到模块,大概率是你的IDE解释器选错了,去设置里检查一下(比如PyCharm,打开设置→Project→Python Interpreter,选择自己的Python环境即可)。 二、基础语法板块(小白必看,逐行解析) 刚开始看代码肯定一脸懵,这里把今天用到的、后续常用的基础语法,逐行拆解,看不懂的地方对照着看,慢慢就能上手。 1. 模块导入语法(最基础,必须会) Python中使用第三方库(比如OpenCV、NumPy),必须先“导入”,才能使用里面的功能,常用导入方式有2种: # 方式1:导入整个模块,使用时需要加“模块名.功能”(推荐,不容易混淆) import cv2 # 导入OpenCV库,简写为cv2(行业通用写法,固定这么写) import numpy as np # 导入NumPy库,简写为np(行业通用写法,固定这么写) # 方式2:从模块中导入指定功能,使用时不用加模块名(不推荐,容易记混) # from cv2 import * # 导入OpenCV所有功能,不推荐,容易和其他库冲突 # from numpy import array # 只导入NumPy的array功能(创建数组) 补充说明:cv2、np都是行业约定俗成的简写,所有人都这么写,记下来就好,不用纠结为什么叫这个。 2. 打印输出语法(调试必备) 用来打印变量、版本信息、结果等,方便我们查看是否正确,今天用到的是f-string格式化输出(最简洁好用): # 基本格式:print(f"提示文字:{变量/功能}") print(f"OpenCV版本:{cv2.__version__}") # 打印OpenCV版本 print(f"NumPy版本:{np.__version__}") # 打印NumPy版本 # 拆解说明: # 1. print():打印函数,括号里放要打印的内容,必须加括号 # 2. f"":格式化字符串,前面加f,里面可以用 嵌入变量或功能 # 3. cv2.__version__:获取OpenCV的版本号,__version__是固定写法(两个下划线) # 4. 示例:如果想打印数组,也可以用print(f"数组内容:{arr}") 3. NumPy核心语法(OpenCV必备,逐行解析) 结合今天学的NumPy操作,把每个语法、每个参数都拆解开,看不懂就对照着看,多敲几遍就记住了。 (1)创建数组语法 import numpy as np # 先导入NumPy,必写 # 1. 创建普通数组:np.array(数据, dtype=数据类型) # 拆解:np.array() 是创建数组的核心函数,括号里放要创建的数据 gray = np.array([[1,2,3], [4,5,6], [7,8,9]], dtype=np.uint8) # 逐行解析: # gray:变量名,自己起(建议见名知意,gray=灰度图) # np.array():创建数组的函数 # [[1,2,3], [4,5,6], [7,8,9]]:数组数据,二维数组(3行3列),对应灰度图的像素 # dtype=np.uint8:指定数据类型为uint8(重点!图像专用,范围0-255) # 2. 创建全0数组:np.zeros(形状, dtype=数据类型) # 拆解:np.zeros() 生成所有元素都是0的数组,适合创建全黑图像 color = np.zeros((100, 100, 3), dtype=np.uint8) # 逐行解析: # (100, 100, 3):数组形状(高, 宽, 通道数),100行100列,3个通道(对应彩色图) # 其他参数和上面一致 # 3. 创建全1数组:np.ones(形状, dtype=数据类型) white = np.ones((200, 200), dtype=np.uint8) * 255 # 逐行解析: # np.ones() 生成所有元素都是1的数组,乘以255后,所有元素变成255(对应全白图像) # (200, 200):二维数组(200行200列),对应灰度图 # 4. 创建随机数组:np.random.randint(最小值, 最大值, 形状, dtype=数据类型) noise = np.random.randint(0, 256, (200, 200), dtype=np.uint8) # 逐行解析: # np.random.randint():生成随机整数的函数 # 0, 256:随机数范围是0~255(因为最大值256是开区间,不包含256) # (200, 200):数组形状,二维数组,对应灰度图的随机噪声(2)数组索引和切片语法(修改图像必备) 核心:数组索引是「行, 列」(y, x),和我们平时说的「x, y」相反,一定要记牢! import numpy as np # 先创建一个5x5的数组(方便演示) arr = np.array([[1,2,3,4,5], [6,7,8,9,10], [11,12,13,14,15], [16,17,18,19,20], [21,22,23,24,25]]) # 1. 获取单个元素:数组名[行索引, 列索引](索引从0开始,不是从1开始!) print(arr[2, 3]) # 输出14 # 解析:第3行(索引2)、第4列(索引3)的元素,就是14 # 2. 获取切片(一块区域):数组名[行范围, 列范围] # 范围写法:start:end(包含start,不包含end),省略start表示从0开始,省略end表示到最后 print(arr[0:3, 0:3]) # 获取左上角3x3区域(行0-2,列0-2) # 解析:行0到3(不包含3,即0、1、2行),列0到3(不包含3,即0、1、2列) # 3. 修改切片区域:数组名[行范围, 列范围] = 目标值 arr[0:3, 0:3] = 0 # 把左上角3x3区域全部改成0 print(arr) # 打印修改后的数组 (3)数组形状查看/变换语法 import numpy as np arr = np.array([[1,2,3,4,5], [6,7,8,9,10], [11,12,13,14,15], [16,17,18,19,20], [21,22,23,24,25]]) # 1. 查看数组形状:数组名.shape(固定写法) print(arr.shape) # 输出(5, 5),表示5行5列的二维数组 # 补充:如果是彩色图数组,会输出(高, 宽, 3),比如(100, 100, 3) # 2. 变换数组形状:数组名.reshape(新形状) # 注意:变换后的元素总数,必须和原来的一致(5x5=25,所以可以改成25个元素的一维数组) arr_flat = arr.reshape(25) # 改成一维数组(25个元素) print(arr_flat.shape) # 输出(25,),逗号表示一维数组 4. 常见报错/警告语法解析(避坑必备) 今天遇到的警告,拆解一下,以后遇到就知道怎么回事了: 警告1:WARNING: Skipping opencv-contrib-python as it is not installed. 解析:提示“跳过opencv-contrib-python,因为未安装”,正常情况,说明之前没装过这个包,不用处理。 警告2:Defaulting to user installation because normal site-packages is not writeable 解析:提示“默认采用用户安装模式,因为正常的site-packages目录没有写入权限”,不用管,不影响使用,是系统权限问题,不是我们操作错了。 报错:找不到cv2/np模块 解析:要么是没安装成功,要么是IDE解释器选错了,去IDE设置里切换到自己的Python环境即可。 三、NumPy:原来这才是OpenCV的本体 之前就听人说OpenCV学到最后其实是在学NumPy(豆包说的),今天算是有点体会了。原来OpenCV里的图像根本不是什么特殊的东西,就是个三维的NumPy数组而已!所有对图像的操作(比如修改颜色、裁剪、缩放),本质上都是对NumPy数组的操作。 数组和列表的区别(小白必懂) 很多人刚开始会把NumPy数组和Python列表搞混,这里用通俗的话讲清楚,不用记复杂概念: 列表:什么类型都能放(比如数字、字符串、列表),比如[1, "a", [2,3]],但运算很慢,处理图像(大数据)会卡死。 数组:只能放同一种类型(比如全是数字),运算速度比列表快几百倍,专门用来处理图像这种大数据。 数组支持向量化运算:不用写一堆for循环,比如想把数组里所有元素加1,直接arr+1就行,列表则需要写for循环逐个修改。 今天必须记住的几个操作(结合语法,再巩固一遍) 这些都是后面天天要用的,结合上面的语法解析,边敲代码边理解,记起来更快。 1. 创建数组(图像基础) import numpy as np # 灰度图就是二维数组(高×宽) gray = np.array([[1,2,3], [4,5,6], [7,8,9]], dtype=np.uint8) # 彩色图是三维数组(高×宽×3通道) color = np.zeros((100, 100, 3), dtype=np.uint8) # 快速创建全黑、全白、随机噪声图 black = np.zeros((200, 200), dtype=np.uint8) white = np.ones((200, 200), dtype=np.uint8) * 255 noise = np.random.randint(0, 256, (200, 200), dtype=np.uint8) 超级重要提醒:图像的数据类型一定要用np.uint8!范围是0-255,超出的话会溢出,显示出来的颜色会完全不对,这个坑我已经提前踩过了。 2. 索引和切片(修改图像必备) # 创建一个5x5的数组 arr = np.array([[1,2,3,4,5], [6,7,8,9,10], [11,12,13,14,15], [16,17,18,19,20], [21,22,23,24,25]]) # 获取单个元素(行, 列) print(arr[2, 3]) # 14 # 获取左上角3x3区域 print(arr[0:3, 0:3]) # 把左上角3x3区域全部改成0 arr[0:3, 0:3] = 0 print(arr) 3. 形状变换(图像缩放/调整必备) # 查看数组形状 print(arr.shape) # (5, 5) # 改变形状(元素总数要一样) arr_flat = arr.reshape(25) print(arr_flat.shape) # (25,) 四、今日总结 环境一定要装opencv-contrib-python,别装基础版!别装基础版!别装基础版!重要的事情说三遍,基础版缺少很多功能。 图像数据类型必须是np.uint8,0-255,超出范围会导致图像颜色异常。 数组索引是(行, 列),也就是(y, x),和我们平时说的(x, y)是反的,这个很容易搞混,多练几次就能记住。 清华源可能会出现网页访问失败的情况,遇到时多重试几次,大概率是临时网络波动导致的。 安装时可能会提示“默认采用用户安装模式”,因为正常的site-packages目录没有写入权限,无需担心,不影响使用。 卸载旧版本时,可能会提示“跳过opencv-contrib-python,因为未安装”,属于正常情况,只需确保已安装的版本被成功卸载即可。 Python环境混乱会导致安装失败,遇到这种情况,先卸载相关包,再重新安装,实在不行就重新配置Python环境。 基础语法是重点,尤其是NumPy的数组创建、索引、形状变换,后续操作都要用到,一定要多敲代码练习。 五、明天要学的 图像的读取、显示和保存(结合今天学的语法,实操练习) OpenCV那个反人类的BGR颜色空间(为什么OpenCV读出来的颜色和实际不一样) 调用摄像头实时显示画面(简单实操,增加成就感) 写个最简单的图像查看器(综合运用今天学的知识) 今天学了大概一个半小时,感觉还可以。主要是环境浪费了点时间(python环境乱成狗屎,安装中断导致后续安装不上),中途遇到了清华源访问失败(疑似跑路)、权限不足导致的用户安装模式等小问题,慢慢排查后都解决了,后面学NumPy的时候边敲代码边理解,效率还挺高的。果然学编程不能只看视频,一定要自己动手敲,尤其是语法部分,多敲几遍自然就懂了。