当前位置: 首页 > news >正文

OpenCV(十二):Mat

数据结构概述

在 C++ 中,cv::Mat 是 OpenCV 的核心数据结构,用于存储图像和矩阵。它由两部分组成:

  1. 矩阵头(Matrix Header):包含矩阵的尺寸(行、列)、数据类型、存储地址(指向数据的指针)等元信息。
  2. 数据块(Data Block):实际存储像素值或矩阵元素的内存块。

在 Python 中,cv2.imread() 等函数返回的图像对象是一个 numpy.ndarray。NumPy 数组同样包含元数据(Metadata)(如形状 shape、数据类型 dtype 等)和实际的数据缓冲区(Data Buffer)

无论是 cv::Mat 还是 numpy.ndarray,它们的深拷贝浅拷贝主要区别就在于是否创建新的数据块

浅拷贝(Shallow Copy)

浅拷贝创建了一个新的对象,但它只复制了原始对象的顶层结构,即元数据/头部信息。对于复杂对象(如包含其他对象的对象),浅拷贝只会复制其中包含的对象的引用(指针),而不会复制实际的数据内容

Python 中 NumPy 的浅拷贝机制:

在 NumPy/OpenCV 中,主要的浅拷贝方式包括:

  1. 简单的变量赋值(Assignment)

    import cv2
    import numpy as npimg_original = cv2.imread("image.jpg")
    img_shallow_assign = img_original
    
    • 行为:这并不是真正的拷贝,而是引用传递img_shallow_assignimg_original 指向内存中的同一个对象(同一个 ndarray),共享头部和数据块
    • 后果:修改 img_shallow_assign 直接影响 img_original,反之亦然。
  2. 视图/切片(View/Slice)

    # 浅拷贝示例:切片操作
    img_shallow_slice = img_original[100:200, 100:200]
    
    • 行为:切片操作通常会创建一个新的 ndarray 对象(新的头部),但其数据指针仍指向原始数组的数据块。这个新对象被称为原始数组的视图(View)
    • 后果:虽然是不同的变量名和头部,但它们共享底层数据。修改 img_shallow_slice 的像素值影响 img_original 中对应区域的像素值。
  3. ndarray.view() 方法

    # 浅拷贝示例:view() 方法
    img_shallow_view = img_original.view()
    
    • 行为:明确地创建一个新的 ndarray 头部,但与原始数组共享数据缓冲区。
    • 后果:修改 img_shallow_view 影响 img_original

浅拷贝总结

特点描述
头部新对象有自己的头部信息(形状、数据类型等)。 (赋值除外,赋值连头部都共享)
数据共享原始对象的底层数据块。
独立性不独立。修改其中任何一个对象的数据,另一个对象的数据也会随之改变。
速度/内存快,内存占用少,因为没有复制数据。
适用场景当你希望在不改变内存中实际数据的前提下,以不同的方式(如不同的数据类型、形状)来查看或操作同一块数据时。

深拷贝(Deep Copy)

深拷贝创建了一个完全独立的新对象。它不仅复制了原始对象的顶层结构(头部),还会递归地复制原始对象中的所有数据块。这意味着,深拷贝的结果对象拥有全新的、独立的内存数据

Python 中 NumPy 的深拷贝机制

在 OpenCV/NumPy 中,实现深拷贝的主要方法是:

  1. ndarray.copy() 方法

    # 深拷贝示例:.copy() 方法
    img_deep_copy = img_original.copy()
    
    • 行为:创建了一个新的 ndarray 头部,并为图像数据分配了全新的内存空间,然后将原始数据内容复制到新内存中。
    • 后果img_deep_copy 是一个完全独立的副本。修改 img_deep_copy 的像素值不会影响 img_original,反之亦然。
  2. cv2.clone() (C++ 中常用,Python 对应 copy()):

    虽然在 C++ 中有 Mat::clone() 方法,但在 Python 的 NumPy 环境下,ndarray.copy() 是最常用的深拷贝方法,效果等同于 C++ 中的 clone()。

  3. cv2.copyTo() (功能等价于 copy()):

    在 C++ 中 Mat::copyTo() 也是常用的深拷贝方法,在 Python 中也可以用于深拷贝,但不如 img.copy() 直接和常用。

  4. copy.deepcopy() 函数

    import copy
    # 深拷贝示例:copy 模块
    img_deep_copy_module = copy.deepcopy(img_original)
    
    • 行为copy 模块是 Python 内置的,deepcopy() 适用于任何复杂的 Python 对象,它会进行递归复制。对于 NumPy 数组,其效果与 ndarray.copy() 相同,但通常**ndarray.copy() 效率更高**,因为它是 NumPy 库内部优化的 C 语言实现。

深拷贝总结

特点描述
头部新对象有自己的头部信息(形状、数据类型等)。
数据拥有独立分配的新数据块。
独立性完全独立。修改一个对象不会影响另一个对象。
速度/内存慢,内存占用大,因为它需要分配新内存并复制所有数据。
适用场景当你需要在保留原始数据的同时,对副本进行修改或处理,且不希望相互影响时(例如图像滤波、目标检测后的标注绘制等)。

示例

import cv2
import numpy as np# 1. 准备原始图像 (假设我们有一张 100x100 的三通道 BGR 图像)
# 实际操作中,请替换为 cv2.imread("your_image.jpg")
img_original = np.zeros((100, 100, 3), dtype=np.uint8) 
# 将左上角像素设为白色 (255, 255, 255)
img_original[0, 0] = [255, 255, 255] 
print(f"原始图像 [0, 0] 像素: {img_original[0, 0]}")# ----------------- 浅拷贝 (视图/切片) -----------------
# 切片操作创建一个视图,共享数据
img_shallow_slice = img_original[50:80, 50:80] # 修改浅拷贝(切片)的左上角像素 (即原始图像的 [50, 50] 像素)
img_shallow_slice[0, 0] = [0, 0, 255] # 改为蓝色print("\n--- 浅拷贝操作 ---")
print(f"浅拷贝 [0, 0] 像素 (修改后): {img_shallow_slice[0, 0]}")
# 检查原始图像中对应的像素
print(f"原始图像 [50, 50] 像素 (被影响): {img_original[50, 50]}") # 结果是 [0, 0, 255]# ----------------- 深拷贝 (copy()) -----------------
# 使用 .copy() 方法创建深拷贝
img_deep_copy = img_original.copy()# 将深拷贝的 [0, 0] 像素修改为绿色 (0, 255, 0)
img_deep_copy[0, 0] = [0, 255, 0] print("\n--- 深拷贝操作 ---")
print(f"深拷贝 [0, 0] 像素 (修改后): {img_deep_copy[0, 0]}")
# 检查原始图像中对应的像素
print(f"原始图像 [0, 0] 像素 (未被影响): {img_original[0, 0]}") # 结果是 [255, 255, 255]# ----------------- 赋值 (最浅的拷贝/引用) -----------------
img_assign = img_original 
img_assign[1, 1] = [255, 0, 0] # 修改为红色print("\n--- 赋值操作 ---")
print(f"赋值 [1, 1] 像素: {img_assign[1, 1]}")
print(f"原始图像 [1, 1] 像素 (被影响): {img_original[1, 1]}") # 结果是 [255, 0, 0]# --- 结论 ---
# 1. 浅拷贝/切片:修改 img_shallow_slice[0, 0] 影响了 img_original[50, 50]。
# 2. 深拷贝:修改 img_deep_copy[0, 0] 没有影响 img_original[0, 0]。
# 3. 赋值:修改 img_assign[1, 1] 影响了 img_original[1, 1]。

总结

在 OpenCV 的 Python 实践中,选择正确的拷贝方式是高效和安全编程的关键:

  1. 何时使用深拷贝 (img.copy())?
    • 当你需要对图像进行修改(如绘图、阈值处理、颜色转换、滤波等),但又希望保留原始图像不变时。
    • 这是最安全的选择,确保操作的隔离性。
  2. 何时使用浅拷贝(切片 img[y:y+h, x:x+w])?
    • 当你需要提取图像的某个区域进行操作,并且希望修改能够反映回原图时。
    • 当你需要仅查看图像的某个区域,而不想复制数据以节省内存和时间时。
    • 当你需要创建一个临时变量,仅用于引用原图,并且知道不会进行修改操作时。
  3. 避免使用简单赋值
    • 对于 NumPy/OpenCV 数组,简单赋值 = 只是创建了一个新的引用,它甚至都不是一个新对象(它共享头部和数据)。这极易导致意外的副作用,通常只有当你确定两个变量必须共享所有状态时才使用。
http://www.dtcms.com/a/506817.html

相关文章:

  • iOS 智能应用开发实践:从模型集成到场景化交互
  • 更好的网站制作系统平台
  • 佛山市手机网站建设网站建设管理工作情况的通报
  • ThinkPad 安装 Ubuntu 系统教程
  • 《未来的 AI 操作系统(四)——AgentOS 的内核设计:调度、记忆与自我反思机制》
  • Platform Health Management 与 EXM/STM 的集成实现方式
  • lambda怎么遍历集合
  • 国外客户推广网站做羞羞事的网站
  • 安装好PySide6后如何找到Qt Designer(pyside6-designer.exe)可执行文件
  • EIT/ERT技术在机器人触觉传感的硬件及电路实现
  • h5游戏免费下载:公园停车
  • FPGA 49 ,Xilinx Vivado 软件术语解析(Vivado 界面常用英文字段详解,以及实际应用场景和注意事项 )
  • 自动化漏洞利用技术颠覆传统:微软生态暴露的攻防新变局
  • Annals of Neurology | EEG‘藏宝图’:用于脑电分类、聚类与预测的语义化低维流形
  • 中小学网站建设有什么好处管理系统软件开发
  • uniapp canvas实现手写签字功能(包括重签,撤回等按钮)
  • 大语言模型如何精准调用函数—— Function Calling 系统笔记
  • 商业智能BI 浅谈数据孤岛和数据分析的发展
  • Chrome 浏览器扩展图片 提取大师
  • Uniapp微信小程序开发:修改了数据,返回父页面时,父页面数据重新加载
  • etcd-问题-调优-监控
  • 【国内电子数据取证厂商龙信科技】手机版Chrome调试方法
  • 做企业网站要怎么设计方案信产部网站备案
  • 成都爱站网seo站长查询工具上海跨境电商网站制作
  • Linux网络编程:Socket编程TCP
  • 库周报 | 25亿融资!天兵科技冲刺IPO;双十一3D打印机价格战打响;拓竹、爱乐酷等发新品
  • 替代传统电脑的共享云服务器如何实现1拖8SolidWorks设计办公
  • Python趣味算法:三色球问题:Python暴力枚举法的完美实践
  • Amazon Bedrock AgentCore Memory:亚马逊云科技的托管记忆解决方案
  • 赋能智慧城市:EasyGBS如何构筑智慧城市视觉中枢?