深度学习系列实验-计算机视觉基础

机器视觉基础实验:图像处理与特征分析

一、实验目的

通过本实验,掌握视频流接入、图像预处理、降噪与边缘增强、纹理特征提取和光照变换等核心图像处理技术,为后续智能感知算法开发奠定基础。

1.1 知识目标

  • 理解视频流的基本概念(帧率、分辨率、编码格式)及其在智能感知中的应用
  • 掌握图像噪声的类型(高斯噪声、椒盐噪声)及常用滤波方法的原理(均值、高斯、中值、双边滤波)
  • 理解图像边缘的物理意义及边缘检测算子(Sobel、Laplacian、Canny)的数学原理
  • 掌握纹理特征的概念及局部二值模式(LBP)、灰度共生矩阵(GLCM)的统计原理
  • 理解光照变换(直方图均衡化、CLAHE、伽马校正)对图像对比度和亮度的影响机制

1.2 技能目标

  • 能够使用OpenCV完成摄像头视频流捕获、视频文件读取及视频分帧与图像提取
  • 能够对图像进行灰度转换、尺寸调整、保存等基本操作
  • 能够模拟图像噪声并应用均值滤波、高斯滤波、中值滤波、双边滤波进行降噪
  • 能够使用Sobel、Laplacian、Canny算子完成边缘检测,并实现边缘增强
  • 能够提取图像的LBP特征直方图和GLCM统计特征(对比度、能量、同质性等)
  • 能够应用直方图均衡化、CLAHE和伽马校正进行光照归一化处理
  • 能够将光照变换与纹理特征提取结合,完成综合性的图像分析任务

1.3 素养目标

  • 培养参数调优与结果对比分析的实验习惯
  • 建立图像预处理与特征提取在智能感知系统中的重要地位认知
  • 提升实验记录、可视化展示和报告撰写的规范能力

二、实验内容

本实验包含四大模块:

模块一:视频流接入与图像基本操作

  1. 安装OpenCV库并验证环境
  2. 从摄像头实时捕获视频流并显示
  3. 从本地视频文件读取并逐帧处理
  4. 按帧间隔或时间间隔提取视频帧并保存为图片
  5. 图像的读取、灰度转换、尺寸调整、保存等基本操作

模块二:图像降噪与边缘增强

  1. 人为添加高斯噪声和椒盐噪声,观察噪声影响
  2. 使用均值滤波、高斯滤波、中值滤波、双边滤波进行降噪处理,对比效果
  3. 使用Sobel、Laplacian、Canny算子检测图像边缘
  4. 将边缘信息叠加到原图实现边缘增强
  5. 整合为实时视频流降噪与边缘检测演示程序

模块三:图像纹理特征提取

  1. 理解纹理特征的概念及LBP和GLCM的基本原理
  2. 使用skimage库计算图像的LBP编码图及归一化直方图
  3. 使用均匀模式LBP(Uniform LBP)降维并比较
  4. 构建灰度共生矩阵(GLCM)并提取对比度、能量、同质性、相关性等统计特征
  5. 对比不同纹理图像(如砖墙、草地、砾石)的LBP直方图和GLCM特征差异

模块四:图像光照变换

  1. 计算并绘制灰度图像的直方图,分析亮度分布
  2. 应用全局直方图均衡化(HE)提升对比度
  3. 应用自适应直方图均衡化(CLAHE),调整clipLimit参数观察效果
  4. 应用伽马校正(Gamma Correction)模拟不同光照条件
  5. 分析光照变换对LBP纹理特征的影响(鲁棒性测试)

三、实验步骤

3.1 环境准备与OpenCV安装

  1. 安装OpenCV及相关库

    打开Anaconda Prompt,激活前序实验创建的dl_env环境:

    bash

    复制代码
    conda activate dl_env
    pip install opencv-python opencv-contrib-python
    pip install numpy matplotlib scikit-image scipy
  2. 验证安装

    创建测试文件test_opencv.py

    python

    复制代码
    import cv2
    import numpy as np
    import skimage
    print("OpenCV版本:", cv2.__version__)
    print("scikit-image版本:", skimage.__version__)
    print("NumPy版本:", np.__version__)

    运行无误即表示环境准备完成。

3.2 视频流接入与图像基本操作

步骤1:摄像头视频流捕获

创建video_capture.py,实现从默认摄像头读取并显示实时画面:

python

复制代码
import cv2

cap = cv2.VideoCapture(0)  # 0表示默认摄像头
if not cap.isOpened():
    print("无法打开摄像头")
    exit()

# 设置分辨率
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

print("按 'q' 键退出")
while True:
    ret, frame = cap.read()
    if not ret:
        break
    cv2.imshow("Camera Stream", frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()
步骤2:从视频文件读取与分帧提取

创建video_to_frames.py,实现对本地视频文件的读取和按帧保存:

python

复制代码
import cv2
import os

def extract_frames(video_path, output_dir, frame_interval=30):
    os.makedirs(output_dir, exist_ok=True)
    cap = cv2.VideoCapture(video_path)
    if not cap.isOpened():
        print("无法打开视频")
        return
    total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    fps = cap.get(cv2.CAP_PROP_FPS)
    print(f"总帧数: {total_frames}, 帧率: {fps:.2f}")

    count = 0
    saved = 0
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        if count % frame_interval == 0:
            filename = os.path.join(output_dir, f"frame_{saved:06d}.jpg")
            cv2.imwrite(filename, frame)
            saved += 1
            if saved % 10 == 0:
                print(f"已保存 {saved} 张")
        count += 1
    cap.release()
    print(f"完成,共保存 {saved} 张图片")

if __name__ == "__main__":
    extract_frames("./test_video.mp4", "./extracted_frames", frame_interval=30)
步骤3:图像基本操作

创建image_basic_ops.py,演示图像的读取、灰度转换、尺寸调整与保存:

python

复制代码
import cv2
import matplotlib.pyplot as plt

img = cv2.imread("./test_image.jpg")
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_resized = cv2.resize(img, (256, 256))

plt.figure(figsize=(12,4))
plt.subplot(1,3,1); plt.imshow(img_rgb); plt.title("原始"); plt.axis('off')
plt.subplot(1,3,2); plt.imshow(img_gray, cmap='gray'); plt.title("灰度"); plt.axis('off')
plt.subplot(1,3,3); plt.imshow(cv2.cvtColor(img_resized, cv2.COLOR_BGR2RGB)); plt.title("调整尺寸"); plt.axis('off')
plt.show()

3.3 图像降噪与边缘增强

步骤4:噪声模拟与滤波对比

创建denoise_demo.py,添加噪声并应用四种滤波方法:

python

复制代码
import cv2
import numpy as np
import matplotlib.pyplot as plt

def add_gaussian_noise(img, sigma=25):
    noise = np.random.normal(0, sigma, img.shape).astype(np.uint8)
    return cv2.add(img, noise)

def add_salt_pepper_noise(img, prob=0.02):
    noisy = img.copy()
    salt = np.random.random(img.shape[:2]) < prob/2
    pepper = np.random.random(img.shape[:2]) < prob/2
    noisy[salt] = 255
    noisy[pepper] = 0
    return noisy

img = cv2.imread("./test_image.jpg", cv2.IMREAD_GRAYSCALE)
img_gauss = add_gaussian_noise(img, 30)
img_sp = add_salt_pepper_noise(img, 0.03)

# 滤波
blur_mean = cv2.blur(img_gauss, (5,5))
blur_gaussian = cv2.GaussianBlur(img_gauss, (5,5), 1.5)
blur_median = cv2.medianBlur(img_sp, 5)
blur_bilateral = cv2.bilateralFilter(img_gauss, 9, 75, 75)

# 显示对比
titles = ['原始', '高斯噪声', '均值滤波', '高斯滤波', '椒盐噪声', '中值滤波', '双边滤波']
images = [img, img_gauss, blur_mean, blur_gaussian, img_sp, blur_median, blur_bilateral]
plt.figure(figsize=(15,10))
for i in range(7):
    plt.subplot(2,4,i+1); plt.imshow(images[i], cmap='gray'); plt.title(titles[i]); plt.axis('off')
plt.tight_layout()
plt.savefig('./results/denoise_comparison.png', dpi=150)
plt.show()
步骤5:边缘检测与增强

创建edge_detection.py

python

复制代码
import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread("./test_image.jpg", cv2.IMREAD_GRAYSCALE)

# Sobel
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)
sobel_mag = np.uint8(np.sqrt(sobelx**2 + sobely**2))

# Laplacian
laplacian = np.uint8(np.abs(cv2.Laplacian(img, cv2.CV_64F, ksize=3)))

# Canny (先高斯滤波)
img_blur = cv2.GaussianBlur(img, (5,5), 1.5)
canny = cv2.Canny(img_blur, 50, 150)

# 边缘增强(叠加Laplacian)
enhanced = cv2.addWeighted(img, 1.0, laplacian, 0.5, 0)

plt.figure(figsize=(15,10))
titles = ['原图', 'Sobel X', 'Sobel Y', 'Sobel幅值', 'Laplacian', 'Canny', '边缘增强']
images = [img, np.abs(sobelx), np.abs(sobely), sobel_mag, laplacian, canny, enhanced]
for i in range(7):
    plt.subplot(2,4,i+1); plt.imshow(images[i], cmap='gray'); plt.title(titles[i]); plt.axis('off')
plt.tight_layout()
plt.savefig('./results/edge_detection.png', dpi=150)
plt.show()
步骤6:实时视频流处理综合程序

创建realtime_process.py,整合降噪和边缘检测,按键盘切换模式:

python

复制代码
import cv2

cap = cv2.VideoCapture(0)
denoise = True
edge = False

while True:
    ret, frame = cap.read()
    if not ret:
        break
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    processed = gray
    if denoise:
        processed = cv2.GaussianBlur(processed, (5,5), 1.5)
    if edge:
        edges = cv2.Canny(processed, 50, 150)
        processed = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR)
    else:
        processed = cv2.cvtColor(processed, cv2.COLOR_GRAY2BGR)
    
    cv2.putText(processed, f"Denoise:{denoise} Edge:{edge}", (10,30), 
                cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0,255,0), 2)
    cv2.imshow("Real-time", processed)
    key = cv2.waitKey(1) & 0xFF
    if key == ord('q'):
        break
    elif key == ord('d'):
        denoise = not denoise
    elif key == ord('e'):
        edge = not edge

cap.release()
cv2.destroyAllWindows()

3.4 纹理特征提取

步骤7:LBP特征提取与直方图对比

创建texture_lbp.py,使用skimage加载纹理图片并提取LBP:

python

复制代码
import numpy as np
import matplotlib.pyplot as plt
from skimage.feature import local_binary_pattern
from skimage import data

# 加载三种纹理
brick = data.load('brick')
grass = data.load('grass')
gravel = data.load('gravel')

P, R = 8, 1
def compute_lbp_hist(img):
    lbp = local_binary_pattern(img, P, R, method='uniform')
    hist, _ = np.histogram(lbp.ravel(), bins=59, range=[0, 59])
    hist = hist / hist.sum()
    return hist, lbp

fig, axes = plt.subplots(3, 3, figsize=(12, 12))
for i, (img, name) in enumerate([(brick, '砖墙'), (grass, '草地'), (gravel, '砾石')]):
    hist, lbp = compute_lbp_hist(img)
    axes[i,0].imshow(img, cmap='gray'); axes[i,0].set_title(name); axes[i,0].axis('off')
    axes[i,1].imshow(lbp, cmap='gray'); axes[i,1].set_title('LBP编码'); axes[i,1].axis('off')
    axes[i,2].bar(range(59), hist, width=1.0); axes[i,2].set_xlabel('模式'); axes[i,2].set_ylabel('频率')
plt.tight_layout()
plt.savefig('./results/lbp_comparison.png', dpi=150)
plt.show()
步骤8:GLCM特征提取

创建texture_glcm.py

python

复制代码
import cv2
import numpy as np
from skimage.feature import graycomatrix, graycoprops

def reduce_gray_levels(img, levels=64):
    factor = 256 // levels
    return (img // factor).astype(np.uint8)

img = cv2.imread("./test_texture.jpg", cv2.IMREAD_GRAYSCALE)
img_comp = reduce_gray_levels(img, 64)

glcm = graycomatrix(img_comp, distances=[1, 2, 3], angles=[0, np.pi/4, np.pi/2, 3*np.pi/4],
                    levels=64, symmetric=True, normed=True)

contrast = graycoprops(glcm, 'contrast')
correlation = graycoprops(glcm, 'correlation')
energy = graycoprops(glcm, 'energy')
homogeneity = graycoprops(glcm, 'homogeneity')

print("GLCM特征(距离=1,方向0°)")
print(f"对比度: {contrast[0,0]:.4f}, 相关性: {correlation[0,0]:.4f}, "
      f"能量: {energy[0,0]:.4f}, 同质性: {homogeneity[0,0]:.4f}")

3.5 光照变换

步骤9:直方图均衡化与CLAHE

创建illumination_transform.py

python

复制代码
import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread("./test_image.jpg", cv2.IMREAD_GRAYSCALE)

# 直方图均衡化
img_he = cv2.equalizeHist(img)

# CLAHE
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
img_clahe = clahe.apply(img)

# 伽马校正
def gamma_correction(img, gamma):
    inv_gamma = 1.0 / gamma
    table = np.array([((i / 255.0) ** inv_gamma) * 255 for i in range(256)]).astype(np.uint8)
    return cv2.LUT(img, table)

img_gamma_05 = gamma_correction(img, 0.5)   # 变亮
img_gamma_20 = gamma_correction(img, 2.0)   # 变暗

# 显示
plt.figure(figsize=(15,10))
titles = ['原始', 'HE', 'CLAHE', 'Gamma=0.5', 'Gamma=2.0']
images = [img, img_he, img_clahe, img_gamma_05, img_gamma_20]
for i in range(5):
    plt.subplot(2,3,i+1); plt.imshow(images[i], cmap='gray'); plt.title(titles[i]); plt.axis('off')
    # 绘制直方图
    plt.subplot(2,3,i+6); plt.hist(images[i].ravel(), bins=256, range=[0,256], color='black')
    plt.xlim([0,256])
plt.tight_layout()
plt.savefig('./results/illumination_transform.png', dpi=150)
plt.show()
步骤10:光照变换对LBP特征的影响分析

创建texture_illumination_robustness.py,对比不同光照变换后的LBP直方图差异:

python

复制代码
import cv2
import numpy as np
import matplotlib.pyplot as plt
from skimage.feature import local_binary_pattern

img = cv2.imread("./test_texture.jpg", cv2.IMREAD_GRAYSCALE)
img_he = cv2.equalizeHist(img)
clahe = cv2.createCLAHE(clipLimit=2.0).apply(img)
img_gamma = gamma_correction(img, 0.5)   # 使用上面定义的函数

def get_lbp_hist(img):
    lbp = local_binary_pattern(img, 8, 1, method='uniform')
    hist, _ = np.histogram(lbp.ravel(), bins=59, range=[0,59])
    return hist / hist.sum()

hists = [get_lbp_hist(i) for i in [img, img_he, img_clahe, img_gamma]]
labels = ['原始', 'HE', 'CLAHE', 'Gamma=0.5']

plt.figure(figsize=(12,8))
for i, (hist, label) in enumerate(zip(hists, labels)):
    plt.subplot(2,2,i+1); plt.bar(range(59), hist, width=1.0)
    plt.title(f'{label} LBP直方图'); plt.xlabel('模式'); plt.ylabel('频率')
plt.tight_layout()
plt.savefig('./results/lbp_illumination_effect.png', dpi=150)
plt.show()

四、实验验收标准

4.1 环境与工具验收

  • OpenCV、scikit-image等库正确安装并能导入
  • 摄像头或视频文件正常读取

4.2 功能模块验收

  • 视频流接入:能成功捕获摄像头或读取视频文件,并能按指定间隔提取帧保存为图片
  • 图像基本操作:能完成灰度转换、尺寸调整、保存等操作
  • 降噪与边缘增强:能展示四种滤波方法的对比结果,能展示Sobel、Laplacian、Canny边缘检测结果,并能实现边缘增强
  • 纹理特征提取:能生成LBP编码图和直方图,能计算GLCM的对比度、能量、同质性等特征
  • 光照变换:能展示HE、CLAHE、伽马校正的效果及直方图变化,能分析光照变换对LBP特征的影响

4.3 代码与报告质量

  • 代码结构清晰,关键步骤有注释
  • 实验结果图片保存完整(建议保存至./results/目录)
  • 实验报告包含各模块的核心代码、结果截图和分析讨论

五、常见问题与解决方案

问题 可能原因 解决方案
cv2.VideoCapture(0)无法打开 摄像头被占用或驱动问题 关闭其他使用摄像头的程序;检查设备管理器
视频文件读取失败 路径错误或编码不支持 使用绝对路径;转换为H.264编码的MP4
SIFT不可用(若使用) OpenCV版本低于4.5.0 本实验未使用SIFT,无需担心
skimage.data.load('brick')报错 网络问题或数据未缓存 使用本地图片替代,或安装pooch
GLCM计算内存不足 灰度级别过高(256) 使用reduce_gray_levels压缩至64或32级
CLAHE处理后对比度过强 clipLimit值过大 降低clipLimit(如0.5~2.0)
实时处理帧率低 图像尺寸大或算法复杂 缩小处理尺寸;减少滤波核大小

六、实验总结与思考

  1. 记录结果 :记录各模块的最优参数配置(如滤波核大小、Canny阈值、CLAHE的clipLimit值)及处理效果。对比不同滤波方法对高斯噪声和椒盐噪声的适用性,分析哪种方法更适合边缘保持。
  2. 问题思考
    • 在视频分帧提取中,帧间隔过大或过小分别会带来什么影响?如何根据应用场景选择合适的间隔?
    • 中值滤波为什么对椒盐噪声抑制效果显著,而对高斯噪声效果一般?
    • Canny边缘检测中的双阈值(低阈值和高阈值)对检测结果有何影响?如何选择合理的阈值?
    • LBP的均匀模式(Uniform LBP)相比原始LBP有什么优势?在什么情况下应该使用均匀模式?
    • 直方图均衡化和CLAHE的主要区别是什么?CLAHE中的tileGridSize参数如何影响输出?
    • 光照变换对LBP特征的鲁棒性有何影响?哪种光照变换方法更有利于保持纹理特征的稳定性?
  3. 实验报告要求
    • 提交PDF格式实验报告,包含每个模块的关键代码、处理前后对比图、参数分析及对思考题的回答。
    • 同时提交完整代码压缩包,确保代码可重复运行。

提交格式 :PDF文档 + 代码压缩包

提交时间 :实验完成后一周内

评分标准:环境配置(10%) + 各模块功能实现(50%) + 结果分析与可视化(20%) + 实验报告质量(20%)

相关推荐
yyk33324几秒前
计算机识别中的人脸检测
人工智能·计算机视觉
PFFstronger1 分钟前
基于 Dify 知识库 + Ollama 大模型,自动生成测试用例并导出 XMind 的完整方案
人工智能·python·测试用例·xmind
文心快码BaiduComate5 分钟前
从“代码补全”到“自主交付”:文心快码全私有化部署落地中信百信银行核心研发链路
人工智能·程序员·文心快码
__如果15 分钟前
Medical Benchmark
人工智能
β添砖java17 分钟前
深度学习32Transformer、BERT、
人工智能·深度学习
2601_9623878222 分钟前
学习笔记DAY1:Python编程从0开始学起,从自学入门到精通
人工智能·网络爬虫·学习笔记·网页开发·python编程
TechEdu20260631 分钟前
[人工智能]AI芯片家族:英伟达、AMD、英特尔、高通与华为
人工智能·ai
具身AGI36 分钟前
物理AI人类学习路线的答案
人工智能·学习
johnsong38 分钟前
AI前沿日报 2026-09-06
人工智能
海鸥8144 分钟前
AIOps(智能运维)理解
运维·人工智能