图像基础操作:图像读取与显示、色彩空间转换、图像缩放与裁剪、图像保存
各位同学,欢迎来到第三讲。今天咱们要聊的,是安防监控系统里最基础、也最绕不开的几个操作。说白了,就是怎么把摄像头里的画面“请”进程序里,怎么给它“换衣服”,怎么“裁剪”出我们关心的区域,最后再“存”下来。
这些操作,我做了这么多年安防项目,几乎每天都在用。你想想看,一个监控画面进来,第一步肯定是读进来看看对不对,然后可能要把彩色转成灰度去分析,再截取掉那些没用的天空、墙壁,只保留关键区域。嗯,今天咱们就把这些基本功练扎实。
图像读取与显示:打开安防世界的第一扇门
在OpenCV里,读取图像用的是imread()函数。我个人习惯,在安防项目中,读取时一定要指定读取模式。为什么?因为默认是彩色图,但很多算法其实只需要灰度图。
import cv2
# 读取彩色图像
img_color = cv2.imread('monitor_frame.jpg', cv2.IMREAD_COLOR)
# 读取灰度图像 —— 我建议在运动检测场景下用这个
img_gray = cv2.imread('monitor_frame.jpg', cv2.IMREAD_GRAYSCALE)
显示图像用imshow(),配合waitKey()和destroyAllWindows()。这里有个坑,我曾经在给客户演示时,窗口一闪而过,场面一度很尴尬。原因就是忘了加waitKey()。
cv2.imshow('Security Monitor', img_color)
cv2.waitKey(0) # 等待按键,0表示无限等待
cv2.destroyAllWindows()
注意:在安防系统中,waitKey(1)常用于实时视频流,表示每1毫秒刷新一次。如果设成0,视频流就会卡住不动。
色彩空间转换:让图像“换装”的艺术
色彩空间转换,说白了就是把图像从一种颜色表示方式变成另一种。在安防监控里,最常用的是BGR转灰度,以及BGR转HSV。
为什么用HSV?我遇到过这样一个场景:要识别监控画面里穿红色衣服的可疑人员。用BGR直接判断红色,光照一变就完蛋。但用HSV,色调H基本不受光照影响,稳定得多。
# BGR 转灰度
gray = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)
# BGR 转 HSV —— 我强烈建议做颜色识别时用这个
hsv = cv2.cvtColor(img_color, cv2.COLOR_BGR2HSV)
小技巧:OpenCV里默认是BGR顺序,不是RGB。我第一次用的时候就被坑了,显示出来的图像颜色怪怪的。记住:OpenCV是BGR,matplotlib是RGB。
还有一个常用的转换是BGR转LAB。我在做夜间监控图像增强时,经常在LAB空间里处理L通道(亮度),效果比直接在BGR里调要好得多。
| 色彩空间 | 安防应用场景 | 我的建议 |
|---|---|---|
| BGR | 默认读取、显示 | 保持原样处理 |
| GRAY | 运动检测、背景建模 | 优先使用,速度快 |
| HSV | 颜色识别、目标跟踪 | 抗光照干扰强 |
| LAB | 夜间图像增强 | 处理亮度通道效果好 |
图像缩放与裁剪:聚焦关键区域
监控画面通常很大,1920x1080很常见。但咱们的算法不需要处理全图,太慢了。所以缩放和裁剪是家常便饭。
缩放用resize()。我一般指定目标尺寸,或者用缩放因子。这里要注意插值方法的选择——缩小用INTER_AREA,放大用INTER_LINEAR或INTER_CUBIC。
# 缩放到指定尺寸
resized = cv2.resize(img_color, (640, 480))
# 按比例缩放 —— 我习惯用这个,保持宽高比
scale_percent = 50 # 缩小到50%
width = int(img_color.shape[1] * scale_percent / 100)
height = int(img_color.shape[0] * scale_percent / 100)
dim = (width, height)
resized = cv2.resize(img_color, dim, interpolation=cv2.INTER_AREA)
重点:缩放时一定要考虑宽高比。我曾经在项目中直接指定尺寸,结果画面里的人都被压扁了,算法识别率直线下降。保持宽高比,这是基本素养。
裁剪就更简单了,其实就是数组切片。监控画面里,我们经常只关心画面下半部分(行人区域),或者某个固定出入口。
# 裁剪:从y=100到y=400,从x=200到x=600
cropped = img_color[100:400, 200:600]
# 实际安防场景:只保留画面下半部分
height = img_color.shape[0]
lower_half = img_color[height//2:, :]
嗯,这里要注意,裁剪的坐标顺序是[y1:y2, x1:x2],不是[x1:x2, y1:y2]。我刚开始学的时候,这个顺序搞反了好几次,显示出来的都是乱七八糟的图案。
图像保存:把处理结果留下来
保存图像用imwrite()。在安防系统里,保存的通常是报警截图、检测结果等。
# 保存为PNG格式
cv2.imwrite('alarm_screenshot.png', img_color)
# 保存为JPEG格式,可以指定质量
cv2.imwrite('result.jpg', img_color, [cv2.IMWRITE_JPEG_QUALITY, 95])
关于保存格式,我个人的经验是:
- PNG:无损压缩,适合保存需要后续分析的图像。缺点是文件大。
- JPEG:有损压缩,文件小。适合保存大量监控截图,但质量会下降。
- BMP:无压缩,文件巨大。除非特殊需求,一般不推荐。
避坑指南:我曾经在项目中用imwrite保存灰度图,结果保存出来的文件是彩色的。原因是我传入的图像虽然是灰度数据,但通道数还是3。保存前一定要确认图像的数据类型和通道数。用img.shape检查一下,养成习惯。
还有一个实用技巧:在保存前,可以给图像画上检测框和文字,这样保存下来的就是带标注的结果,方便事后查看。
# 画一个红色矩形框,标注检测到的目标
cv2.rectangle(img_color, (x1, y1), (x2, y2), (0, 0, 255), 2)
cv2.putText(img_color, 'Person Detected', (x1, y1-10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
cv2.imwrite('detection_result.jpg', img_color)
好了,这一章的内容就这些。图像读取、显示、色彩空间转换、缩放裁剪、保存——这些操作看起来简单,但每一个都有它的门道。你想想看,一个完整的安防系统,从摄像头取流到最终报警存储,每一步都离不开这些基础操作。
下一章,咱们要进入更有意思的部分:视频处理与实时帧分析。到时候,这些基础操作会全部派上用场。
课后练习建议:找一张监控截图,先读取显示,然后转成灰度,再裁剪出画面中某个区域,最后保存成PNG。试试不同的缩放比例,看看图像质量的变化。