libopencv_core4130.dll.a:
核心模块,定义了基本数据结构,如多维数组Mat,还包含了其他模块常用的基本函数,为整个 OpenCV 库提供基础支持。
功能与用途
图像存储:cv::Mat 最常见的用途是存储图像数据。无论是灰度图像(单通道)、彩色图像(如 RGB 三通道或 RGBA 四通道),还是多光谱图像,都可以用 cv::Mat 来表示。例如,一幅 8 位灰度图像可以存储为一个 cv::Mat,其数据类型为 CV_8U(8 位无符号整数),每个元素对应图像中的一个像素值。
矩阵运算:除了图像数据,cv::Mat 也可用于一般的矩阵运算。它支持各种数学运算,如加法、减法、乘法、除法等,使得在处理图像或其他数据矩阵时非常方便。例如,在图像融合、滤波等操作中,经常需要对图像矩阵进行算术运算。
数据结构特点
头与数据分离:cv::Mat 采用了一种头与数据分离的设计。矩阵头(包含矩阵的尺寸、数据类型、引用计数等信息)和实际的数据存储区域是分开的。这样的设计使得矩阵的复制和传递变得高效,因为复制矩阵时只需复制矩阵头,而无需复制大量的数据,只有在真正需要修改数据时才会进行数据的深拷贝,这一机制被称为引用计数机制。
灵活的数据存储方式:cv::Mat 可以存储不同类型的数据,通过模板化的数据类型标识符来指定。常见的数据类型包括 CV_8U、CV_8S(8 位有符号整数)、CV_16U、CV_16S、CV_32S(32 位有符号整数)、CV_32F(32 位浮点数)、CV_64F(64 位浮点数)等。此外,它还支持多通道数据存储,例如,彩色图像的 RGB 三个通道可以存储在一个 cv::Mat 中,每个元素是一个包含三个值的向量,分别对应红、绿、蓝通道的值。
主要成员函数
创建与初始化:
cv::Mat::Mat(int rows, int cols, int type):通过指定行数、列数和数据类型来创建矩阵。例如,cv::Mat image(100, 100, CV_8UC3) 创建一个 100x100 的三通道 8 位无符号整数矩阵,常用于存储彩色图像。
cv::Mat::Mat(const cv::Size& size, int type):使用 cv::Size 结构体来指定矩阵的尺寸,功能与上述类似。
cv::Mat::ones(int rows, int cols, int type) 和 cv::Mat::zeros(int rows, int cols, int type):分别创建一个全为 1 或全为 0 的矩阵。
元素访问:
at<>() 模板函数:用于访问矩阵中的元素。例如,对于一个单通道 8 位无符号整数矩阵 mat,可以通过 mat.at(i, j) 来访问第 i 行第 j 列的元素;对于多通道矩阵,如 RGB 图像矩阵,可以使用 mat.atcv::Vec3b(i, j)[0] 来访问第 i 行第 j 列像素的红色通道值。
属性获取:
rows 和 cols 成员变量:分别返回矩阵的行数和列数。
type() 函数:返回矩阵的数据类型标识符,通过该标识符可以判断矩阵的数据类型和通道数。
channels() 函数:返回矩阵的通道数。
操作函数:
clone() 函数:创建一个与原矩阵完全相同的深拷贝,包括矩阵头和数据。
copyTo() 函数:将当前矩阵的数据复制到另一个矩阵中,可以选择指定感兴趣区域(ROI)进行复制。
在 OpenCV 中的应用场景
图像处理:在几乎所有的图像处理算法中都离不开 cv::Mat。例如,图像滤波算法(如高斯滤波、中值滤波)需要读取和修改 cv::Mat 中的像素值;图像变换(如仿射变换、透视变换)则是对 cv::Mat 进行几何操作;图像特征提取(如 SIFT、SURF、ORB 等)过程中,cv::Mat 用于存储图像以及提取到的特征描述符。
计算机视觉任务:在目标检测、识别、跟踪等计算机视觉任务中,cv::Mat 用于存储输入图像、处理中间结果以及输出检测或识别结果。例如,在基于 Haar 级联的人脸检测中,输入的图像首先被读取到一个 cv::Mat 中,经过一系列的处理后,检测到的人脸区域信息也可以存储在 cv::Mat 或基于 cv::Mat 的数据结构中。
bash
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <Qdebug>
#include <opencv2/opencv.hpp>
// 交换两个Mat矩阵的示例函数
void exampleSwap() {
// 创建一个3x3的单精度浮点型矩阵a,初始值全为1
cv::Mat a = cv::Mat::ones(3, 3, CV_32F);
// 创建一个3x3的单精度浮点型矩阵b,初始值全为0
cv::Mat b = cv::Mat::zeros(3, 3, CV_32F);
// 交换矩阵a和b
cv::swap(a, b);
// 判断交换后a是否全为0
bool aIsAllZeros = cv::countNonZero(a - cv::Mat::zeros(3, 3, CV_32F)) == 0;
// 判断交换后b是否全为1
bool bIsAllOnes = cv::countNonZero(b - cv::Mat::ones(3, 3, CV_32F)) == 0;
// 输出交换后a是否全为0的结果
qDebug() << "After swap, a is all zeros: " << aIsAllZeros;
// 输出交换后b是否全为1的结果
qDebug() << "After swap, b is all ones: " << bIsAllOnes;
}
// 边界插值的示例函数
void exampleBorderInterpolate() {
int p = 5; // 要插值的位置
int len = 10; // 边界长度
int borderType = cv::BORDER_CONSTANT; // 边界类型,这里是常量边界
// 进行边界插值计算
int result = cv::borderInterpolate(p, len, borderType);
// 输出边界插值的结果
qDebug() << "Border interpolate result: " << result;
}
// 复制并添加边界的示例函数
void exampleCopyMakeBorder() {
// 创建一个3x3的单精度浮点型矩阵src,初始值全为1
cv::Mat src = cv::Mat::ones(3, 3, CV_32F);
cv::Mat dst; // 用于存储添加边界后的结果矩阵
int top = 1, bottom = 1, left = 1, right = 1; // 上下左右要添加的边界宽度
int borderType = cv::BORDER_CONSTANT; // 边界类型,常量边界
cv::Scalar value(0); // 常量边界的值
// 对src矩阵进行复制并添加边界操作
cv::copyMakeBorder(src, dst, top, bottom, left, right, borderType, value);
// 输出添加边界后的矩阵大小
qDebug() << "Copied and bordered matrix size: " << dst.rows << " x " << dst.cols;
}
// 矩阵加法的示例函数
void exampleAdd() {
// 创建一个3x3的单精度浮点型矩阵src1,初始值全为1
cv::Mat src1 = cv::Mat::ones(3, 3, CV_32F);
// 创建一个3x3的单精度浮点型矩阵src2,初始值全为1
cv::Mat src2 = cv::Mat::ones(3, 3, CV_32F);
cv::Mat dst; // 用于存储加法结果的矩阵
// 对src1和src2进行矩阵加法操作
cv::add(src1, src2, dst);
// 输出加法结果的提示信息
qDebug() << "Addition result:";
// 遍历并输出结果矩阵dst的每个元素
for(int i = 0; i < dst.rows; ++i) {
for(int j = 0; j < dst.cols; ++j) {
qDebug() << dst.at<float>(i, j);
}
}
}
// 重载QDebug操作符,用于输出cv::Mat矩阵
QDebug operator<<(QDebug debug, const cv::Mat& mat) {
// 输出矩阵的基本信息,包括行数和列数
debug << "cv::Mat(" << mat.rows << ", " << mat.cols << ") {";
for(int i = 0; i < mat.rows; ++i) {
for(int j = 0; j < mat.cols; ++j) {
// 如果矩阵类型是单精度浮点型
if(mat.type() == CV_32F) {
// 输出矩阵元素
debug << mat.at<float>(i, j) << " ";
}
// 如果矩阵类型是8位无符号整型
else if(mat.type() == CV_8U) {
// 输出矩阵元素
debug << (int)mat.at<uchar>(i, j) << " ";
}
// 可根据需要添加更多数据类型的处理
}
// 换行
debug << "\n";
}
// 输出矩阵结束标志
debug << "}";
return debug;
}
// 重载QDebug操作符,用于输出cv::Scalar
QDebug operator<<(QDebug debug, const cv::Scalar& scalar) {
// 输出Scalar的开始标志
debug << "cv::Scalar(";
for(int i = 0; i < 4; ++i) {
// 输出Scalar的元素
debug << scalar.val[i];
if(i < 3) {
// 如果不是最后一个元素,输出逗号和空格
debug << ", ";
}
}
// 输出Scalar的结束标志
debug << ")";
return debug;
}
// 矩阵减法的示例函数
void exampleSubtract() {
// 创建一个3x3的单精度浮点型矩阵src1,初始值全为1
cv::Mat src1 = cv::Mat::ones(3, 3, CV_32F);
// 创建一个3x3的单精度浮点型矩阵src2,初始值全为1
cv::Mat src2 = cv::Mat::ones(3, 3, CV_32F);
cv::Mat dst; // 用于存储减法结果的矩阵
// 对src1和src2进行矩阵减法操作
cv::subtract(src1, src2, dst);
// 输出减法结果
qDebug() << "Subtraction result: " << dst;
}
// 矩阵乘法的示例函数
void exampleMultiply() {
// 创建一个3x3的单精度浮点型矩阵src1,初始值全为1
cv::Mat src1 = cv::Mat::ones(3, 3, CV_32F);
// 创建一个3x3的单精度浮点型矩阵src2,初始值全为1
cv::Mat src2 = cv::Mat::ones(3, 3, CV_32F);
cv::Mat dst; // 用于存储乘法结果的矩阵
double scale = 2; // 乘法的缩放因子
// 对src1和src2进行矩阵乘法操作,并应用缩放因子
cv::multiply(src1, src2, dst, scale);
// 输出乘法结果
qDebug() << "Multiplication result: " << dst;
}
// 矩阵除法的示例函数
void exampleDivide() {
// 创建一个3x3的单精度浮点型矩阵src1,初始值全为1
cv::Mat src1 = cv::Mat::ones(3, 3, CV_32F);
// 创建一个3x3的单精度浮点型矩阵src2,初始值全为1
cv::Mat src2 = cv::Mat::ones(3, 3, CV_32F);
cv::Mat dst; // 用于存储除法结果的矩阵
double scale = 2; // 除法的缩放因子
// 对src1和src2进行矩阵除法操作,并应用缩放因子
cv::divide(src1, src2, dst, scale);
// 输出除法结果
qDebug() << "Division result: " << dst;
}
// 缩放并加法的示例函数
void exampleScaleAdd() {
// 创建一个3x3的单精度浮点型矩阵src1,初始值全为1
cv::Mat src1 = cv::Mat::ones(3, 3, CV_32F);
// 创建一个3x3的单精度浮点型矩阵src2,初始值全为1
cv::Mat src2 = cv::Mat::ones(3, 3, CV_32F);
cv::Mat dst; // 用于存储缩放并加法结果的矩阵
double alpha = 2; // 缩放因子
// 对src1进行缩放后与src2相加
cv::scaleAdd(src1, alpha, src2, dst);
// 输出缩放并加法的结果
qDebug() << "Scale and add result: " << dst;
}
// 加权加法的示例函数
void exampleAddWeighted() {
// 创建一个3x3的单精度浮点型矩阵src1,初始值全为1
cv::Mat src1 = cv::Mat::ones(3, 3, CV_32F);
// 创建一个3x3的单精度浮点型矩阵src2,初始值全为1
cv::Mat src2 = cv::Mat::ones(3, 3, CV_32F);
cv::Mat dst; // 用于存储加权加法结果的矩阵
double alpha = 0.5, beta = 0.5, gamma = 0; // 加权系数
// 对src1和src2进行加权加法操作
cv::addWeighted(src1, alpha, src2, beta, gamma, dst);
// 输出加权加法的结果
qDebug() << "Add weighted result: " << dst;
}
// 转换、缩放并取绝对值的示例函数
void exampleConvertScaleAbs() {
// 创建一个3x3的单精度浮点型矩阵src,初始值全为0.5
cv::Mat src = cv::Mat::ones(3, 3, CV_32F) * 0.5;
cv::Mat dst; // 用于存储转换、缩放并取绝对值结果的矩阵
double alpha = 255, beta = 0; // 缩放因子和偏移量
// 对src进行转换、缩放并取绝对值操作
cv::convertScaleAbs(src, dst, alpha, beta);
// 输出转换、缩放并取绝对值的结果
qDebug() << "Convert scale and abs result: " << dst;
}
// 查找表操作的示例函数
void exampleLUT() {
// 创建一个3x3的8位无符号整型矩阵src,初始值全为128
cv::Mat src = cv::Mat::ones(3, 3, CV_8U) * 128;
// 创建一个256x1的8位无符号整型查找表lut,初始值全为0
cv::Mat lut = cv::Mat::zeros(256, 1, CV_8U);
for (int i = 0; i < 256; ++i) {
// 填充查找表,将每个值映射为255 - i
lut.at<uchar>(i) = 255 - i;
}
cv::Mat dst; // 用于存储查找表操作结果的矩阵
// 对src应用查找表lut
cv::LUT(src, lut, dst);
// 输出查找表操作的结果
qDebug() << "LUT result: " << dst;
}
// 计算矩阵元素总和的示例函数
void exampleSum() {
// 创建一个3x3的单精度浮点型矩阵src,初始值全为1
cv::Mat src = cv::Mat::ones(3, 3, CV_32F);
// 计算src矩阵元素的总和
cv::Scalar result = cv::sum(src);
// 输出矩阵元素总和
qDebug() << "Sum of elements: " << result;
}
// 判断矩阵是否有非零元素的示例函数
void exampleHasNonZero() {
// 创建一个3x3的单精度浮点型矩阵src,初始值全为1
cv::Mat src = cv::Mat::ones(3, 3, CV_32F);
// 判断src矩阵是否有非零元素
bool result = cv::hasNonZero(src);
// 输出判断结果
qDebug() << "Has non - zero elements: " << result;
}
// 统计矩阵中非零元素个数的示例函数
void exampleCountNonZero() {
// 创建一个3x3的单精度浮点型矩阵src,初始值全为1
cv::Mat src = cv::Mat::ones(3, 3, CV_32F);
// 统计src矩阵中非零元素的个数
int result = cv::countNonZero(src);
// 输出非零元素的个数
qDebug() << "Count of non - zero elements: " << result;
}
// 查找矩阵中非零元素索引的示例函数
void exampleFindNonZero() {
// 创建一个3x3的单精度浮点型矩阵src,初始值全为1
cv::Mat src = cv::Mat::ones(3, 3, CV_32F);
cv::Mat idx; // 用于存储非零元素索引的矩阵
// 查找src矩阵中非零元素的索引
cv::findNonZero(src, idx);
// 输出非零元素的索引
qDebug() << "Indices of non - zero elements: " << idx;
}
// 计算矩阵元素平均值的示例函数
void exampleMean() {
// 创建一个3x3的单精度浮点型矩阵src,初始值全为1
cv::Mat src = cv::Mat::ones(3, 3, CV_32F);
// 计算src矩阵元素的平均值
cv::Scalar result = cv::mean(src);
// 输出矩阵元素的平均值
qDebug() << "Mean of elements: " << result;
}
// 计算矩阵元素均值和标准差的示例函数
void exampleMeanStdDev() {
// 创建一个3x3的单精度浮点型矩阵src,初始值全为1
cv::Mat src = cv::Mat::ones(3, 3, CV_32F);
cv::Mat mean, stddev; // 用于存储均值和标准差的矩阵
// 计算src矩阵元素的均值和标准差
cv::meanStdDev(src, mean, stddev);
// 输出均值和标准差
qDebug() << "Mean: " << mean << " Std Dev: " << stddev;
}
// 计算矩阵范数的示例函数
void exampleNorm() {
// 创建一个3x3的单精度浮点型矩阵src1,初始值全为1
cv::Mat src1 = cv::Mat::ones(3, 3, CV_32F);
// 计算src1矩阵的范数
double result = cv::norm(src1);
// 输出矩阵的范数
qDebug() << "Norm of matrix: " << result;
}
// 计算两个矩阵峰值信噪比(PSNR)的示例函数
void examplePSNR() {
// 创建一个3x3的单精度浮点型矩阵src1,初始值全为1
cv::Mat src1 = cv::Mat::ones(3, 3, CV_32F);
// 创建一个3x3的单精度浮点型矩阵src2,初始值全为1
cv::Mat src2 = cv::Mat::ones(3, 3, CV_32F);
// 计算src1和src2矩阵的峰值信噪比
double result = cv::PSNR(src1, src2);
// 输出两个矩阵的峰值信噪比
qDebug() << "PSNR between two matrices: " << result;
}
// 矩阵归一化的示例函数
void exampleNormalize() {
// 创建一个3x3的单精度浮点型矩阵src,初始值全为1
cv::Mat src = cv::Mat::ones(3, 3, CV_32F);
cv::Mat dst; // 用于存储归一化结果的矩阵
double alpha = 0, beta = 1; // 归一化的范围
int norm_type = cv::NORM_MINMAX; // 归一化类型,这里是最小 - 最大归一化
// 对src矩阵进行归一化操作
cv::normalize(src, dst, alpha, beta, norm_type);
// 输出归一化后的矩阵
qDebug() << "Normalized matrix: " << dst;
}
int maintest() {
// 调用各个示例函数
exampleSwap();
exampleBorderInterpolate();
exampleCopyMakeBorder();
exampleAdd();
exampleSubtract();
exampleMultiply();
exampleDivide();
exampleScaleAdd();
exampleAddWeighted();
exampleConvertScaleAbs();
exampleLUT();
exampleSum();
exampleHasNonZero();
exampleCountNonZero();
exampleFindNonZero();
exampleMean();
exampleMeanStdDev();
exampleNorm();
examplePSNR();
exampleNormalize();
return 0;
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
maintest();
}
MainWindow::~MainWindow()
{
delete ui;
}