1. 卷积核
卷积核就是一个小数字矩阵 ,在图像上滑动,小数字矩阵和对应位置的像素做运算,实现模糊、锐化、边缘检测。
blur、GaussianBlur、medianBlur、filter2D全部底层都是卷积运算
假设 3×3 卷积核,滑动到图像某一块:
图像像素 卷积核kernel [10 20 30] [a b c] [40 50 60] [d e f] [70 80 90] [g h i]输出中心像素 =
10*a + 20*b +30*c +40*d +50*e +60*f +70*g +80*h +90*i核窗口逐像素向右、向下滑动,遍历整张图,生成输出图像。
2. 均值滤波
void blur(
InputArray src,
InputArray dst,
Size ksize,
Point point = Point(-1, -1),
int borderType = BORDER_DEFAULT
);
原理:在图像上滑动一个矩形窗口(卷积核),把窗口内所有像素求算术平均值,赋值给窗口中心输出像素。
cv::Mat src,dst; src = imread("test.jpg"); cv::blur(src,dst,cv::Size(5,5));cv::Size(3,3) 卷积核大小,必须奇数, size越大越模糊
2. 高斯模糊
void GaussianBlur(
InputArray src,
InputArray dst,
Size ksize,
double sigmaX,
double sigmaY = 0,
int borderType = BORDER_DEFAULT
);
Size 设置卷积核的大小,必须是奇数 Size(0,0) 核大小有sigmaX自动计算
sigmaX:X方向高斯标准差;数值越大,模糊越强 sigmaX = 0 ,sigmaX由Size()自动计算
sigmaY: Y方向高斯标准差;sigmaY传0就自动等于sigmaX
Mat src,dst; GaussianBlur(src,dst,Size(5,5),0); // sigmaX由size自动计算 GaussianBlue(src,dst,Size(0,0),4); // Size(0,0) 核大小由sigmaX 自动计算3. 中值滤波
void medianBlur(InputArray src, InputArray dst, int ksize);
原理:取卷积窗口内像素中位数,不是平均值。
ksize 窗口大小,取像素值,必须是奇数
cv::Mat src,dst; medianBlure(src, dst, 5);4. 双边滤波
void bilateral(
InputArray src,
InputArray dst,
int d,
double sigmaColor,
double sigmaSpace,
int borderType = BORDER_DEAFAULT
);
双边滤波:保边缘的模糊,美颜算法底层。
❗不是固定卷积核,权重是动态计算,每一个位置的权重都不一样,计算开销大。
- d:滤波邻域直径。
d = 0:程序自动根据sigmaSpace计算邻域大小(推荐写 0)- sigmaColor:颜色域标准差
- 值越大:允许相差更大的颜色参与平滑;越大模糊越强。
- 一般取值:
25 ~ 100- sigmaSpace:空间域标准差,单位像素
- 值越大:参与计算的像素范围越大。
- 一般取值:
25 ~ 100borderType:边界填充,默认即可,不用修改
实例代码:
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QDebug> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { qDebug() << __func__ << __LINE__; ui->setupUi(this); initMainWindow(); } MainWindow::~MainWindow() { delete ui; } void MainWindow::initMainWindow() { qDebug() << __func__ << __LINE__; ui->blurViewLabel->setFixedSize(723,399); ui->gaussianViewLabel->setFixedSize(723,399); ui->medianViewLabel->setFixedSize(723,399); ui->bilateralViewLabel->setFixedSize(723,399); QString imgPath = R"(D:\new_share\016_opencv\OpenCVFilter\1.jpg)"; Mat imgData = imread(imgPath.toStdString()); // BGR 格式 cvtColor(imgData, imgData , COLOR_BGR2RGB); // 转为 RGB 格式 myImg = imgData; blurImg = QImage((const unsigned char*)imgData.data, imgData.cols, imgData.rows, static_cast<int>(imgData.step),QImage::Format_RGB888).copy(); gaussianImg = blurImg; medianImg = blurImg; bilateralImg = blurImg; imgShow(); } void MainWindow::imgShow() { qDebug() << __func__ << __LINE__; ui->blurViewLabel->setPixmap(QPixmap::fromImage(blurImg.scaled(ui->blurViewLabel->size()))); ui->gaussianViewLabel->setPixmap(QPixmap::fromImage(gaussianImg.scaled(ui->gaussianViewLabel->size()))); ui->medianViewLabel->setPixmap(QPixmap::fromImage(medianImg.scaled(ui->medianViewLabel->size()))); ui->bilateralViewLabel->setPixmap(QPixmap::fromImage(bilateralImg.scaled(ui->bilateralViewLabel->size()))); } void MainWindow::imgProc(int kernel) { qDebug() << __func__ << __LINE__; Mat imgSrc = myImg; Mat imgBlurDst = imgSrc.clone(); Mat imgGaussianDst = imgSrc.clone(); Mat imgMedianDst = imgSrc.clone(); Mat imgBilateralDst = imgSrc.clone(); int value = 1; value = value + kernel*2; blur(imgSrc,imgBlurDst,Size(value,value),Point(-1,-1)); GaussianBlur(imgSrc, imgGaussianDst, Size(value,value),0); medianBlur(imgSrc,imgMedianDst,value); bilateralFilter(imgSrc, imgBilateralDst, value, value*2.0, value/2.0); blurImg = QImage((const unsigned char*)imgBlurDst.data, imgBlurDst.cols, imgBlurDst.rows, static_cast<int>(imgBlurDst.step),QImage::Format_RGB888).copy(); gaussianImg = QImage((const unsigned char*)imgGaussianDst.data, imgGaussianDst.cols, imgGaussianDst.rows, static_cast<int>(imgGaussianDst.step), QImage::Format_RGB888).copy(); medianImg = QImage((const unsigned char*)imgMedianDst.data, imgMedianDst.cols, imgMedianDst.rows, static_cast<int>(imgMedianDst.step), QImage::Format_RGB888).copy(); bilateralImg = QImage((const unsigned char*)imgBilateralDst.data, imgBilateralDst.cols, imgBilateralDst.rows, static_cast<int>(imgBilateralDst.step), QImage::Format_RGB888).copy(); imgShow(); } void MainWindow::on_verticalSlider_valueChanged(int value) { qDebug() << __func__ << __LINE__; imgProc(value); }mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <opencv2/opencv.hpp> QT_BEGIN_NAMESPACE using namespace cv; namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); void initMainWindow(); void imgShow(); void imgProc(int kernel); private slots: void on_verticalSlider_valueChanged(int value); private: Ui::MainWindow *ui; Mat myImg; QImage blurImg; QImage gaussianImg; QImage medianImg; QImage bilateralImg; }; #endif // MAINWINDOW_H