【OpenCV】Mat詳解

在OpenCV中,cv::Mat是用于存儲圖像、矩陣等多維數據的核心數據結構,替代了早期的IplImage(需手動管理內存),其設計的核心目標是自動內存管理高效數據操作。下面詳細介紹其組成原理及使用方法。

一、cv::Mat的組成原理

cv::Mat的結構由兩部分組成:矩陣頭(Matrix Header)數據指針(Data Pointer),二者分離的設計使其既能高效傳遞,又能避免冗余內存占用。

1. 矩陣頭(Matrix Header)

矩陣頭是一個輕量級結構體,存儲了數據的元信息,不直接存儲像素數據。核心成員包括:

  • rows:行數(圖像的高度,單位為像素)。
  • cols:列數(圖像的寬度,單位為像素)。
  • size():返回cv::Size(cols, rows),便捷表示尺寸。
  • type():數據類型,由位深度通道數組成(如CV_8UC3表示8位無符號整數,3通道)。
    • 位深度:如8U(8位無符號)、16S(16位有符號)、32F(32位浮點)等。
    • 通道數:單通道(灰度圖)、3通道(RGB/BGR)、4通道(帶Alpha通道)等。
  • channels():返回通道數(由type()推導,如CV_8UC3的通道數為3)。
  • step:行步長(每行數據的總字節數,包括像素數據和可能的填充字節,用于快速定位某一行的起始地址)。
  • refcount:引用計數器(用于內存自動釋放,記錄當前有多少個Mat對象共享同一塊數據)。
2. 數據指針(Data Pointer)

數據指針(uchar* data)指向存儲實際像素數據的內存區域。數據在內存中的排列方式由通道數決定:

  • 單通道(灰度圖):按行存儲,每行像素依次排列(如[p0, p1, p2, ..., p_cols-1])。
  • 多通道:每個像素的通道數據連續存儲(如3通道圖像的一個像素為[B, G, R],按B0, G0, R0, B1, G1, R1, ...排列,OpenCV默認通道順序為BGR而非RGB)。
3. 內存管理機制:引用計數

cv::Mat通過引用計數實現高效內存管理:

  • 當復制Mat對象(如Mat B = A)時,僅復制矩陣頭,數據指針指向同一塊內存,引用計數refcount加1。
  • Mat對象銷毀時,引用計數減1;當refcount為0時,自動釋放數據內存,避免內存泄漏。
  • 若需深拷貝(獨立數據),需使用clone()copyTo()方法(如Mat C = A.clone())。

二、cv::Mat的使用方法

1. 創建cv::Mat對象

常用創建方式包括:

(1)通過構造函數創建

指定行數、列數、數據類型:

// 創建3行2列的8位無符號單通道矩陣(初始值隨機)
cv::Mat mat1(3, 2, CV_8UC1);// 創建3行2列的32位浮點3通道矩陣(初始值隨機)
cv::Mat mat2(3, 2, CV_32FC3);// 用cv::Size指定尺寸(寬x高)
cv::Mat mat3(cv::Size(200, 100), CV_8UC3); // 寬200,高100(rows=100, cols=200)
(2)創建并初始化特殊矩陣

使用zeros()ones()eye()(單位矩陣):

// 創建3x3的8位無符號單通道零矩陣
cv::Mat zeros_mat = cv::Mat::zeros(3, 3, CV_8UC1);// 創建2x4的32位浮點3通道全1矩陣
cv::Mat ones_mat = cv::Mat::ones(2, 4, CV_32FC3);// 創建5x5的64位浮點單通道單位矩陣
cv::Mat eye_mat = cv::Mat::eye(5, 5, CV_64FC1);
(3)從已有數據創建

將外部數組數據包裝為Mat(不復制數據,僅共享內存):

float data[] = {1.0f, 2.0f, 3.0f, 4.0f};
// 創建2行2列的32位浮點單通道矩陣,數據指向data數組
cv::Mat mat_from_data(2, 2, CV_32FC1, data);
(4)從圖像文件讀取

使用cv::imread讀取圖像,返回Mat對象:

// 讀取彩色圖像(默認3通道BGR)
cv::Mat img_color = cv::imread("image.jpg");// 讀取灰度圖(單通道)
cv::Mat img_gray = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
2. 訪問cv::Mat的屬性

通過成員函數或成員變量獲取元信息:

cv::Mat img = cv::imread("image.jpg");
int rows = img.rows;         // 圖像高度(行數)
int cols = img.cols;         // 圖像寬度(列數)
cv::Size size = img.size();  // 尺寸(cols, rows)
int channels = img.channels(); // 通道數(如3)
int type = img.type();       // 數據類型(如CV_8UC3)
size_t step = img.step;      // 行步長(每行字節數)
3. 訪問像素數據

根據場景選擇不同方法(效率和便捷性權衡):

(1)at<T>()方法(便捷,適合單像素訪問)

需指定數據類型T(與type()匹配),語法:mat.at<T>(row, col)(單通道)或mat.at<T>(row, col)[channel](多通道)。

cv::Mat img = cv::imread("image.jpg"); // CV_8UC3類型// 訪問(10, 20)處的像素(行10,列20)
cv::Vec3b pixel = img.at<cv::Vec3b>(10, 20); // Vec3b對應8UC3(3個uchar)
uchar blue = pixel[0];   // B通道
uchar green = pixel[1]; // G通道
uchar red = pixel[2];    // R通道// 修改像素值
img.at<cv::Vec3b>(10, 20) = cv::Vec3b(255, 0, 0); // 改為藍色
  • 常用類型對應:CV_8UC1ucharCV_32FC1floatCV_8UC3cv::Vec3bCV_32FC3cv::Vec3f
(2)行指針ptr<T>()(高效,適合遍歷行)

獲取某一行的起始指針,通過指針遍歷像素(效率高于at<T>()):

cv::Mat img = cv::imread("image.jpg"); // 8UC3
for (int i = 0; i < img.rows; ++i) {// 獲取第i行的指針(uchar*,因8UC3每個像素3字節)uchar* row_ptr = img.ptr<uchar>(i);for (int j = 0; j < img.cols; ++j) {// 計算當前像素的起始位置(每行j列的像素:j*通道數)int pos = j * 3;uchar b = row_ptr[pos];     // Buchar g = row_ptr[pos + 1]; // Guchar r = row_ptr[pos + 2]; // R// 修改為灰度(簡單平均)row_ptr[pos] = row_ptr[pos + 1] = row_ptr[pos + 2] = (b + g + r) / 3;}
}
(3)迭代器(安全,適合復雜遍歷)

使用cv::MatIterator_<T>遍歷,自動處理邊界:

cv::Mat img = cv::imread("image.jpg");
// 3通道迭代器
cv::MatIterator_<cv::Vec3b> it = img.begin<cv::Vec3b>();
cv::MatIterator_<cv::Vec3b> it_end = img.end<cv::Vec3b>();
for (; it != it_end; ++it) {// 每個迭代器指向一個像素(Vec3b)(*it)[0] = 0; // 將B通道置0
}
4. 常用操作
  • 通道分離與合并:用split()merge()處理多通道圖像:

    cv::Mat img = cv::imread("image.jpg"); // BGR
    std::vector<cv::Mat> channels;
    cv::split(img, channels); // 分離為3個單通道(B, G, R)
    channels[2] = cv::Mat::zeros(img.size(), CV_8UC1); // 將R通道置0
    cv::Mat img_no_red;
    cv::merge(channels, img_no_red); // 合并回3通道
    
  • ROI(感興趣區域):提取子矩陣(共享原數據,需深拷貝時用clone()):

    cv::Mat img = cv::imread("image.jpg");
    // 提取從(10, 20)開始,寬100、高50的區域(行范圍[10,10+50),列范圍[20,20+100))
    cv::Mat roi = img(cv::Rect(20, 10, 100, 50)); // Rect(x, y, width, height)
    roi.setTo(cv::Scalar(0, 255, 0)); // 直接修改ROI,原圖像也會變化
    
  • 保存圖像:用cv::imwrite

    cv::Mat img = cv::imread("image.jpg");
    cv::imwrite("output.jpg", img); // 保存為JPG
    

三、注意事項

  1. 數據類型匹配:訪問像素時,at<T>()ptr<T>()T必須與Mat::type()匹配(如CV_8UC3對應cv::Vec3b),否則會導致內存訪問錯誤。
  2. 引用計數與深拷貝:默認復制為淺拷貝(共享數據),需獨立數據時用clone()copyTo()
  3. 通道順序:OpenCV默認圖像通道為BGR(而非RGB),處理時需注意轉換(可通過cv::cvtColor(img, img_rgb, cv::COLOR_BGR2RGB)轉換)。

通過理解cv::Mat的組成和使用方法,可高效處理圖像數據,避免內存問題并優化操作性能。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/93302.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/93302.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/93302.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

疏老師-python訓練營-Day45Tensorboard使用介紹

浙大疏錦行知識點回顧&#xff1a; tensorboard的發展歷史和原理tensorboard的常見操作tensorboard在cifar上的實戰&#xff1a;MLP和CNN模型 效果展示如下&#xff0c;很適合拿去組會匯報撐頁數&#xff1a; 作業&#xff1a;對resnet18在cifar10上采用微調策略下&#xff0c;…

算法詳細講解:基礎算法 - 離散化/區間合并

離散化 講解 這里的離散化特指整數有序離散化。整個值域跨度很大&#xff0c;但是值非常稀疏的情況。 問題背景 我們有一個無限長的數軸&#xff0c;初始時每個位置上的值都是0。我們需要進行兩種操作&#xff1a; 修改操作&#xff1a;在某個位置 x 上增加一個值 c。查詢…

SpringBoot 實現在線查看內存對象拓撲圖 —— 給 JVM 裝上“透視眼”

0. 你將獲得什么 一個可嵌入任何 Spring Boot 應用的內存對象拓撲服務&#xff1a;訪問 /memviz.html 就能在瀏覽器看見對象圖。 支持按類/包名過濾、按對象大小高亮、點擊節點看詳情。 線上可用&#xff1a;默認只在你點擊“生成快照”時才工作&#xff1b;日常零開銷。 1.…

STM32 HAL驅動MPU6050傳感器

STM32 HAL驅動MPU6050傳感器 項目概述 本項目實現了基于STM32 HAL庫的MPU6050傳感器驅動&#xff0c;可以讀取加速度計和陀螺儀數據。項目使用I2C接口與MPU6050通信&#xff0c;并通過UART接口輸出數據。 項目倉庫地址&#xff1a;STM32_Sensor_Drives 硬件連接 MPU6050 I2…

flex-wrap子元素是否換行

flex-wrap設置子元素是否換行&#xff0c;默認情況下&#xff0c;項目都排在一條線&#xff08;又稱”軸線”&#xff09;上。flex-wrap屬性定義&#xff0c;flex布局中默認是不換行的。1、div的寬度是600px&#xff0c;每個span的寬度是150px&#xff0c;總共有5個&#xff0c…

RabbitMQ面試精講 Day 21:Spring AMQP核心組件詳解

【RabbitMQ面試精講 Day 21】Spring AMQP核心組件詳解 開篇 歡迎來到"RabbitMQ面試精講"系列第21天&#xff01;今天我們將深入探討Spring AMQP的核心組件&#xff0c;這是Java開發者集成RabbitMQ最常用的框架。掌握Spring AMQP不僅能提升開發效率&#xff0c;更是…

Flink TableAPI 按分鐘統計數據量

一、環境版本環境版本Flink1.17.0Kafka2.12MySQL5.7.33二、MySQL建表腳本 create table user_log (id int auto_increment comment 主鍵primary key,uid int not null comment 用戶id,event int not null comment 用戶行為,logtime bigint null comment 日志時…

18.13 《3倍效率提升!Hugging Face datasets.map高級技巧實戰指南》

3倍效率提升!Hugging Face datasets.map高級技巧實戰指南 實戰項目:使用 datasets.map 進行高級數據處理 在大模型訓練過程中,數據預處理的質量直接決定了模型最終的表現。Hugging Face Datasets 庫提供的 datasets.map 方法是處理復雜數據場景的瑞士軍刀,本章將深入解析…

實體店獲客新引擎:數據大集網如何破解傳統門店引流難題

在商業競爭日益激烈的當下&#xff0c;實體店的生存與發展正面臨前所未有的挑戰。無論是街邊的小型便利店&#xff0c;還是大型購物中心的連鎖品牌&#xff0c;都在為"如何吸引顧客進店"而絞盡腦汁。傳統廣告投放效果不佳、線下流量持續萎縮、客戶轉化率難以提升………

LeetCode 分類刷題:2302. 統計得分小于 K 的子數組數目

題目一個數組的 分數 定義為數組之和 乘以 數組的長度。比方說&#xff0c;[1, 2, 3, 4, 5] 的分數為 (1 2 3 4 5) * 5 75 。給你一個正整數數組 nums 和一個整數 k &#xff0c;請你返回 nums 中分數 嚴格小于 k 的 非空整數子數組數目。子數組 是數組中的一個連續元素序…

TDengine IDMP 基本功能(1.界面布局和操作)

UI 布局和操作說明 TDengine IDMP 的用戶界面&#xff08;UI&#xff09;設計旨在提供直觀、易用的操作體驗。下面介紹 UI 的主要區域和典型操作&#xff1a; 主要區域 IDMP 的用戶界面是完全基于瀏覽器的。登錄后的典型 UI 界面具有幾個區域&#xff1a; 主菜單&#xff1a;AI…

QT(概述、基礎函數、界面類、信號和槽)

一、概述1、QTQT是一個c的第三方庫&#xff0c;是專門用來進行界面編程的一個庫 1. QT本身實現了多種軟件&#xff1a; 2. ubuntu系統中所有界面都是QT做的 3. 最新版本的QQ也是QT做的 4. 嵌入式編程中&#xff0c;幾乎所有的上位機&#xff0c;都可以使用QT來做 QT本身除了實現…

【從零開始java學習|第六篇】運算符的使用與注意事項

目錄 一、算術運算符 1. 基本算術運算符&#xff08;二元&#xff09; 2. 自增 / 自減運算符&#xff08;一元&#xff09; 二、類型轉換&#xff08;隱式與強制&#xff09; 1. 隱式轉換&#xff08;自動類型轉換&#xff09; ?編輯 2. 強制轉換&#xff08;顯式類型轉…

shellgpt

一、介紹 官網&#xff1a;https://github.com/TheR1D/shell_gpt ShellGPT&#xff08;shell_gpt&#xff09; 是一款把 GPT 系列大模型能力直接搬到終端 的開源命令行生產力工具。用日常英語或中文描述需求&#xff0c;就能幫你 生成、解釋甚至自動執行 Shell 命令&#xff…

geoserver sql視圖調用Postgis自定義函數問題記錄

一、問題描述&#xff1a;geoserver sql視圖調用Postgis自定義函數對點圖層增加一條記錄時&#xff0c;返回結果主鍵自增ID加了2&#xff0c;但表中數據只增加一條記錄。 但在pgAdmin中直接寫SQL調用Postgis自定義函數對點圖層增加一條記錄時&#xff0c;返回結果主鍵自增ID只加…

#T1224. 最大子矩陣

題目傳送 題目描述 已知矩陣的大小定義為矩陣中所有元素的和。給定一個矩陣&#xff0c;你的任務是找到最大的非空(大小至少是11)子矩陣。 比如&#xff0c;如下44的矩陣 0 -2 -7 09 2 -6 2 -4 1 -4 1-1 8 0 -2的最大子矩陣是 9 2-4 1-1 8這…

2025年大模型安全崗的面試匯總(題目+回答)

安全領域各種資源&#xff0c;學習文檔&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各種好玩的項目及好用的工具&#xff0c;歡迎關注。 目錄 1. Transformer核心機制及其對LLM突破的基石作用 2. LLM能力邊界評估框架設計 3. 模型層級安全風險分析 …

《關于省級政務云服務費支出預算標準的規定》豫財預〔2024〕106號解讀

《關于省級政務云服務費支出預算標準的規定》豫財預〔2024〕106號文件由河南省財政廳編制經省政府同意后于2024年12月3日印發執行&#xff0c;規定作為省級政務云服務費支出預算編制和審核的依據&#xff0c;旨在加強省級部門預算管理&#xff0c;規范政務云服務費支出預算編制…

使用HalconDotNet實現異步多相機采集與實時處理

文章目錄 一、核心功能與原理 功能目標: 工作原理: 關鍵機制: 二、完整C#實現代碼 三、關鍵實現解析 1. 零拷貝圖像傳輸 2. 動態幀率控制 3. HALCON并行優化 4. 異常隔離機制 四、高級優化策略 1. 硬件加速配置 2. 內存池管理 3. 實時性保障 一、核心功能與原理 功能目標:…

《瘋狂Java講義(第3版)》學習筆記ch4

ch4流程控制與數組1.switch語句后的expression表達式的數據類型只能是byte、short、char、int四種證書類型。2.建議不要在循環體內修改循環變量&#xff08;也叫循環計數器&#xff09;的值&#xff0c;否則會增加程序出錯的可能性。3.定義數組推薦語法格式&#xff1a;type[] …