1. Mat --> QImage
cpp
QImage mat2QImage(const cv::Mat &mat)
{
if(mat.empty()) return QImage();
if(mat.type == CV_8UC3)
{
// BGR -> RGB
cv::Mat rgb;
cv::cvtColor(mat, rgb, cv::COLOR_BGR2RGB);
return QImage(rgb.data, rgb.cols, rgb.rows, rgb.step, QImage::Format_RGB888).copy();
}
else if(mat.type == CV_8UC1)
{
// BGR -> GRAY
cv::Mat gray;
cv::cvtColor(mat, gray, cv::COLOR_BGR2GRAY);
return QImage(gray.data, gray.cols, gray.rows, gray.step, QImage::Fomat_RGB888).copy();
}
return QImage();
}
2. QImage ---> Mat
cpp
cv::Mat qImage2Mat(const QImage &img)
{
if(img.isNull()) return cv::Mat();
if(img.format() == QImage::Format_RGB888)
{
cv::Mat mat(img.height(), img.width(), CV_8UC3, (void*)img.bits(), img.bytesPerLine());
cv::Mat bgr;
cv::cvtColor(mat, bgr, cv::COLOR_RGB2BGR);
return bgr;
}
if(img.format() == QImage::Format_Grayscale8)
{
cv::Mat mat(img.height(), img.width(), CV_8UC1, (void *)img.bits(),img.byesPerLine());
return mat;
}
return cv::Mat();
}
3. 在label显示Mat
cpp
void MainWindow::showMat(const cv::Mat& mat)
{
QImage img = mat2QImage(mat);
ui->label->setPixmap(QPixmap::fromQImage(img).scaled(ui->label->size(), Qt::KeepAspectRatio, Qt::SmoothTransFormation));
}
3. 读写与显示
cpp
// 读取图像
cv::Mat matBgr = cv::imread("test.jpg");
// 灰度读取
cv::Mat gray = cv::imread("test.jpg", cv::IMREAD_GRAYSCALE);
//显示窗口
cv::imshow("matbgr", matBgr);
cv::waitKey(0); // 等待按键
cv::destoryAllwindows() // 销毁所有窗口
//保存
cv::imwrite("out.jpg", img);
4. 滤波(均值、高斯、中植、双边)
cpp
//均值滤波 cv::Size() 必须奇数, size越大越模糊
void onblur()
{
cv::blur(srcMat, srcMat, cv::Size(5, 5));
showMat(srcMat);
}
void blur(InputArray src, OutputArray dst, Size ksize, Point anchor = Point(-1,-1), int borderType = BORDER_DEFAULT)
srcMat:输入图像;第二个srcMat:输出图像(原地覆盖)
cv::Size(5,5):5×5 的卷积核普通均匀噪声
cpp
// 高斯滤波
void onGaussian()
{
cv::GaussianBlur(srcMat, srcMat, cv::Size(5,5), 1.2);
showMat(srcMat);
}
void GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY = 0, int borderType = BORDER_DEFAULT)
Size(5,5):高斯核大小,必须是奇数(3,5,7...)
1.2:sigmaX,X 方向高斯标准差;sigmaY=0默认和 sigmaX 相等重点:如果
ksize填 Size (0,0),OpenCV 会自动根据 sigma 计算核大小。高斯噪声(图像里淡淡的均匀噪点)
cpp
//中值滤波
void onMedian()
{
cv::MedianBlur(srcMat, srcMat, 5);
showMat(srcMat);
}
void medianBlur(InputArray src, OutputArray dst, int ksize)
5:核尺寸,必须是奇数,这里是 5×5 窗口适合:图像里随机的黑白噪点(椒盐噪声)
cpp
// 双边滤波
void onBilateral()
{
cv::bilateralFilter(srcMat, srcMat, 9, 75, 75);
showMat(srcMat);
}
void bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType = BORDER_DEFAULT)
参数解释:
d=9:滤波时使用的邻域直径;d≤0 时由 sigmaSpace 自动计算sigmaColor=75:颜色空间标准差。值越大,颜色差异大的像素也会被一起平均sigmaSpace=75:坐标空间标准差。值越大,更远的像素参与计算适合:需要保留轮廓、边缘的场景(人像、物体轮廓)
缺点:速度很慢,计算量大;对椒盐噪声效果差
| 滤波 | 核心 | 擅长噪声 | 边缘 | 速度 |
|---|---|---|---|---|
| 均值 blur | 窗口平均值 | 均匀噪声 | 严重模糊 | 快 |
| 高斯 GaussianBlur | 高斯加权平均 | 高斯噪声 | 轻微模糊 | 较快 |
| 中值 medianBlur | 窗口中位数 | 椒盐噪声(黑白噪点) | 模糊 | 中等 |
| 双边 bilateralFilter | 空间 + 灰度双重高斯 | 平缓区域噪声 | ✅ 保留边缘 | 很慢 |
- 几何变换(缩放、平移、旋转、翻转)
cpp
//缩放
cv::resize(srcMat, dstMat, cv::Size(), 0.6, 0.6, cv::INTER_LINEAR);
void cv::resize(
cv::InputArray src, // 输入图
cv::OutputArray dst, // 输出图
cv::Size dsize, // 目标尺寸 (宽,高)
double fx = 0, // x方向缩放系数
double fy = 0, // y方向缩放系数
int interpolation = cv::INTER_LINEAR // 插值方式
);
重点:dsize 和 fx/fy 二选一
- 写了 dsize,fx、fy 自动忽略
- dsize 填
cv::Size(0,0),才会使用 fx、fy 计算大小OpenCV
cpp
//翻转
cv::flip(srcMat, dstMat, 1); // 1 水平翻转 0 垂直翻转 -1 同时翻转
// 旋转
void onRotate()
{
cv::Point2f center(srcMat.cols/2.of, srcMat.rows/2.0f);
// 以center为中心,旋转30度,缩放0.8 得到旋转矩阵
cv::Mat rotMat = cv::getRotationMatrix2D(center, 30, 0.8);
cv::warpAffine(srcMat, ddstMat, rotMat, srMat.size());
showMat(dstMat);
}
// 平移
void onShift()
{
cv::Mat transMat = (cv::Mat_<float>(2,3) << 1,0,20, 0,1,20);
cv::warpAffine(srcMat, dstMat, transMat, srcMat.size());
showMat(srcMat);
}
仿射变换:可以实现平移、旋转、缩放、斜切(错切);特点:直线保持直线、平行线依旧平行;矩形可以变成平行四边形
void cv::warpAffine(
cv::InputArray src, // 输入图
cv::OutputArray dst, // 输出图
cv::InputArray M, // 【2行3列 float矩阵】仿射矩阵
cv::Size dsize, // 输出图尺寸 (宽,高)
int flags = cv::INTER_LINEAR, // 插值,和resize一样
int borderMode = cv::BORDER_CONSTANT,
const cv::Scalar &borderValue = cv::Scalar(0,0,0) // 填充边界颜色,默认黑色
);
生成旋转矩阵(最常用)
Mat getRotationMatrix2D(Point2f center, double angle, double scale);
