第二章

图像基础与 OpenCV

第一层 · 像素/色彩空间/图像IO 一张照片在电脑里到底是什么

一、一张照片 = 一个数字数组

"小陈,视觉开发的第一课:彻底搞懂'图像'在电脑里的表示。"老周打开 Jupyter Notebook:

import cv2
import numpy as np

# 读一张图(灰度图)
img = cv2.imread("book_cover.jpg", cv2.IMREAD_GRAYSCALE)
print(img.shape)          # (800, 600) —— 高 800,宽 600
print(img[100, 200])      # 128 —— 第100行第200列的像素亮度(0-255)

# 显示
cv2.imshow("image", img)
cv2.waitKey(0)
灰度图(Grayscale):
  shape = (高, 宽) 的二维数组
  每个元素 = 一个像素的亮度(0=纯黑,255=纯白)
  0-255 共 256 个灰度级(8 位)

彩色图(RGB):
  shape = (高, 宽, 3) 的三维数组
  每个像素 = 3 个值(红R、绿G、蓝B)

  [ [[245, 23, 12], [250, 20, 10]],
    [[247, 21, 15], [249, 22, 11]], ... ]
    第一个像素:R=245 G=23 B=12(红色系)

  颜色合成:
    (255, 0, 0) = 纯红    (0, 255, 0) = 纯绿
    (0, 0, 255) = 纯蓝    (255, 255, 255) = 白
    (0, 0, 0)   = 黑      (128, 128, 128) = 灰

  一张 1920×1080 彩色图 = 1920×1080×3 ≈ 620 万个数字

"图像在电脑里 = 多维数字数组。 所有图像处理,本质都是'对数组做数学运算'。理解了这一点,后面所有技术都好懂了。"


二、色彩空间:同一个图,不同的"坐标系"

"颜色可以用不同方式描述——这就是色彩空间(Color Space)。"老周说:

常见色彩空间:
  RGB:红/绿/蓝三通道(显示用)
  HSV:色相Hue/饱和度Sat/明度Value(人眼感知,处理用)
  HLS:类似 HSV(亮度 Lightness)
  Lab:L亮度/a红绿/b蓝黄(感知均匀,颜色分析用)
  YUV:亮度Y + 色度UV(视频压缩用)

  为什么要转色彩空间?
    例子:检测"红色书封"
    在 RGB 里判断"红"很难(受光线影响大)
    在 HSV 里:只看 H(色相)在红色范围就行(更稳定)

  OpenCV 注意:
    cv2 默认是 BGR 不是 RGB!(历史原因)
    → 显示/保存前要转换:cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    → 新手最常见坑之一!

  转换示例:
  hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
  gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

"色彩空间是'看待颜色的不同角度'——显示用 RGB,分析用 HSV,压缩用 YUV。视觉开发里'换个色彩空间'常常是解决问题的第一步。"


三、图像 IO 与像素操作:视觉开发的基本功

"读图、存图、改像素——这几招要练熟。"老周演示:

import cv2
import numpy as np

# 图像 IO
img = cv2.imread("photo.jpg")            # 读图(BGR)
cv2.imwrite("out.jpg", img)              # 存图
print(img.shape)                          # (高, 宽, 通道)

# 像素操作
pixel = img[50, 100]                      # 取像素 (B,G,R)
img[50, 100] = [0, 0, 255]               # 改像素(变红)

# 区域操作(切片)
img[100:200, 150:250] = [255, 255, 255]  # 把一块区域涂白
region = img[100:200, 150:250]           # 裁剪一块区域

# 缩放 / 旋转 / 翻转
resized = cv2.resize(img, (400, 300))    # 缩放
rotated = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)  # 旋转
flipped = cv2.flip(img, 1)               # 水平翻转

# 叠加文字/框(可视化用)
cv2.rectangle(img, (50, 50), (200, 200), (0, 255, 0), 2)  # 画框
cv2.putText(img, "Yunjian", (50, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)

"OpenCV(Open Source Computer Vision Library)是视觉开发的事实标准工具库——读图、处理、画框、算法,全都有。'会 OpenCV'是视觉工程师的基本功,就像'会 Git'是程序员的标配。"


四、NumPy 是视觉开发的"幕后英雄"

"OpenCV 处理图像,底层全靠 NumPy。"老周强调:

NumPy 与图像:
  OpenCV 的图 = NumPy 的 ndarray
  所有图像操作,都可以直接用 NumPy 数学运算

  常用 NumPy 图像操作:
    np.zeros((h, w, 3))         # 创建黑色画布
    img + 50                    # 整体变亮(像素值+50)
    img * 0.5                   # 整体变暗
    np.clip(img, 0, 255)        # 把值限制在 0-255
    np.mean(img)                # 平均亮度
    img[::-1]                   # 上下翻转

  数据流向:
    NumPy(数组运算)←→ OpenCV(图像算法)
    深度学习(PyTorch 张量)← 图像也要转成张量

"记住这条链:图 → NumPy 数组 → 各种运算 → 视觉算法。 NumPy 处理数组的功夫,决定了你写视觉代码的上限。"


五、视频的本质:连续的图像帧

"咱们后面要做客流统计(视频),提前讲一下视频的本质。"老周说:

视频 = 连续的图像帧(Frame)
  视频 = 每秒 N 张图(如 25 FPS = 每秒 25 帧)
  视频处理 = 循环读帧 → 每帧做图像处理

  OpenCV 读视频:
  cap = cv2.VideoCapture("video.mp4")
  while True:
      ret, frame = cap.read()   # 读一帧
      if not ret:
          break                 # 视频结束
      # 对 frame 做图像处理
      gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
      # 显示
      cv2.imshow("video", frame)
      if cv2.waitKey(1) & 0xFF == ord("q"):
          break
  cap.release()

  摄像头(实时):
  cap = cv2.VideoCapture(0)     # 0 = 默认摄像头
  # 之后循环一样(实时流 = 一帧一帧读)

"视频处理 = '逐帧图像处理'的循环——理解了这个,'客流统计'其实就是在'每一帧里数人',再用跟踪技术把同一个人连续起来(第十一章)。"


六、章末:老周的第二章总结

第一层:图像基础与 OpenCV
├── 图像 = NumPy 数字数组(灰度二维 / 彩色三维)
├── 色彩空间:RGB(显示)/HSV(分析)/YUV(压缩)
│   OpenCV 默认 BGR(新手坑!)
├── 图像 IO:imread/imwrite + 像素/区域操作
├── 几何操作:缩放/旋转/翻转/裁剪
├── 可视化:画框、写文字(调试神器)
├── NumPy:图像底层运算(视觉基本功)
└── 视频 = 逐帧图像(VideoCapture 循环)
第三层(预告):图像处理 —— 让模糊的照片变清晰

"小陈,现在你手里有'像素'这把钥匙了。"老周说,"但你拿手机拍的图书封面,往往又暗又糊又歪——直接丢给识别程序,效果会很难看。下一章,我们学图像处理基础:灰度化、滤波、边缘检测、形态学——让'脏图'变'干净图'。这是所有视觉任务的第一道工序。"

✌ 语言