OpenCV 学习探秘之三:从图像读取到特征识别,再到机器学习等函数接口的全面实战应用与解析

发布于:2025-07-30 ⋅ 阅读:(12) ⋅ 点赞:(0)

一、引言

1.1介绍

OpenCV(Open Source Computer Vision Library)是一个功能强大的开源计算机视觉库,广泛应用于图像和视频处理、目标检测、机器学习等领域。本文将全面解析 OpenCV 中常用的函数接口,帮助读者快速掌握 OpenCV 的核心功能。
本文将按照功能模块分类,详细介绍 OpenCV 中的各类函数接口,并提供丰富的 C++ 代码示例。内容涵盖图像读取与显示、图像处理、特征提取、视频处理、机器学习等多个方面。

1.2 准备

INCLUDEPATH += "D:/opencv/opencv-4.5.4/build/include"
INCLUDEPATH += "D:/opencv/opencv-4.5.4/build/include/opencv2"
DEPENDPATH += "D:/opencv/opencv-4.5.4/build/x64/vc15/lib"
LIBS += "D:/opencv/opencv-4.5.4/build/x64/vc15/lib/opencv_world454d.lib"
  • 引入头文件
//引入opencv头文件和命名空间
#include <opencv.hpp>
using namespace cv;

附带说明:后面的特征提取如SURF算法等高阶调用,要依赖带有opencv_contrib模块的opencv库,并添加头文件

//引入头文件和命名空间,在opencv_contrib模块里
#include <opencv2/xfeatures2d.hpp>
using namespace cv::xfeatures2d;

二、OpenCV 基础:图像读取、显示与保存

2.1 图像读取:imread 函数

imread函数用于从文件中读取图像,支持多种图像格式,如 JPEG、PNG、BMP 等。

//图像读,显示,写
void MainWindow::on_bt1_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this,QString("文件对话框"),"/",QString("图片(*.jpg *.png);"));

    // 读取图像
    Mat image = imread(fileName.toStdString(), IMREAD_COLOR);

    if (image.empty()) {
        qDebug() << QString("无法读取图像!");
        return;
    }

    imshow(QString("TestSrc").toStdString(), image);
    // 修改图像(例如,转换为灰度图)
    Mat grayImage;
    cvtColor(image, grayImage, COLOR_BGR2GRAY);

    // 保存图像
    bool saved = imwrite("gray_test.jpg", grayImage);

    imshow(QString("TestDsc").toStdString(), grayImage);

    if (saved) {
        qDebug()  << QString("图像保存成功!");
    } else {
        qDebug()  << QString("图像保存失败!");
    }

    return;
}

imread函数的第二个参数是一个标志,指定图像的读取方式:

  • IMREAD_COLOR:读取彩色图像,忽略透明度(默认值);
  • IMREAD_GRAYSCALE:以灰度模式读取图像;
  • IMREAD_UNCHANGED:读取包含 Alpha 通道的图像

测试结果:
在这里插入图片描述

2.2 图像显示:imshow 和 namedWindow 函数

imshow函数用于在窗口中显示图像,而namedWindow函数用于创建一个窗口。

    QString fileName = QFileDialog::getOpenFileName(this,QString("文件对话框"),"/",QString("图片(*.jpg *.png);"));
    // 读取图像
    Mat image = imread(fileName.toStdString(), IMREAD_COLOR);

    if (image.empty()) {
        qDebug()  << QString("无法读取图像!");
        return;
    }

    // 创建窗口
    namedWindow(QString("TestSrc").toStdString(), WINDOW_AUTOSIZE); // 创建一个自动调整大小的窗口

    // 显示图像
    imshow(QString("TestSrc").toStdString(), image);

    // 等待按键事件
    waitKey(0); // 0表示无限等待,直到用户按下任意键

    return;
}

namedWindow函数的第二个参数可以是:

  • WINDOW_AUTOSIZE:窗口大小自动适应图像大小
  • WINDOW_NORMAL:窗口大小可手动调整

在这里插入图片描述

2.3 图像保存:imwrite 函数

imwrite函数用于将图像保存到文件中。

//测试写入
void MainWindow::on_bt3_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this,QString("文件对话框"),"/",QString("图片(*.jpg *.png);"));

    // 读取图像
    Mat image = imread(fileName.toStdString(), IMREAD_COLOR);

    if (image.empty()) {
        qDebug()  << QString("无法读取图像!");
        return;
    }

    // 修改图像(例如,转换为灰度图)
    Mat grayImage;
    cvtColor(image, grayImage, COLOR_BGR2GRAY);

    // 保存图像
    bool saved = imwrite("gray_test.jpg", grayImage);
    if (saved) {
        qDebug()  << QString("图像保存成功!");
    } else {
        qDebug()  << QString("图像保存失败!");
    }
    return;
}

mwrite函数的第二个参数是要保存的图像,第三个参数是一个可选的参数向量,用于指定特定格式的保存选项。
在这里插入图片描述

三、图像处理:滤波、边缘检测与形态学操作

3.1 图像滤波:平滑与降噪

图像滤波是图像处理中常用的操作,用于平滑图像、降噪或增强特定特征。

3.1.1 均值滤波:blur 函数

均值滤波是一种简单的线性滤波方法,它用邻域内像素的平均值代替中心像素的值。

//均值滤波
void MainWindow::on_bt4_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this,QString("文件对话框"),"/",QString("图片(*.jpg *.png);"));

    // 读取图像
    Mat image = imread(fileName.toStdString(), IMREAD_COLOR);

    if (image.empty()) {
        qDebug()  << QString("无法读取图像!");
        return;
    }

    // 均值滤波
    Mat blurredImage;
    blur(image, blurredImage, Size(5, 5)); // 5x5的均值滤波器

    // 显示原始图像和滤波后的图像
    namedWindow(QString("Src").toStdString(), WINDOW_AUTOSIZE);
    namedWindow(QString("Dsc").toStdString(), WINDOW_AUTOSIZE);

    imshow(QString("Src").toStdString(), image);
    imshow(QString("Dsc").toStdString(), blurredImage);

    waitKey(0);

    return;
}

在这里插入图片描述

3.1.2 高斯滤波:GaussianBlur 函数

高斯滤波是一种常用的线性滤波方法,它用高斯核来对图像进行卷积,能够有效抑制高斯噪声。

    QString fileName = QFileDialog::getOpenFileName(this,QString("文件对话框"),"/",QString("图片(*.jpg *.png);"));

    // 读取图像
    Mat image = imread(fileName.toStdString(), IMREAD_COLOR);

    if (image.empty()) {
        qDebug()  << QString("无法读取图像!");
        return;
    }

    // 高斯滤波
    Mat gaussianImage;
    GaussianBlur(image, gaussianImage, Size(5, 5), 0, 0); // 5x5的高斯滤波器

    // 显示原始图像和滤波后的图像
    namedWindow(QString("Src").toStdString(), WINDOW_AUTOSIZE);
    namedWindow(QString("Dsc").toStdString(), WINDOW_AUTOSIZE);

    imshow(QString("Src").toStdString(), image);
    imshow(QString("Dsc").toStdString(), gaussianImage);

    waitKey(0);

    return;
}

在这里插入图片描述

3.1.3 中值滤波:medianBlur 函数

中值滤波是一种非线性滤波方法,它用邻域内像素的中值代替中心像素的值,能够有效去除椒盐噪声。

//中值滤波
void MainWindow::on_bt6_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this,QString("文件对话框"),"/",QString("图片(*.jpg *.png);"));

    // 读取图像
    Mat image = imread(fileName.toStdString(), IMREAD_COLOR);

    if (image.empty()) {
        qDebug()  << QString("无法读取图像!");
        return;
    }

    // 中值滤波
    Mat medianImage;
    medianBlur(image, medianImage, 5); // 5x5的中值滤波器

    // 显示原始图像和滤波后的图像
    namedWindow(QString("Src").toStdString(), WINDOW_AUTOSIZE);
    namedWindow(QString("Dsc").toStdString(), WINDOW_AUTOSIZE);

    imshow(QString("Src").toStdString(), image);
    imshow(QString("Dsc").toStdString(), medianImage);

    waitKey(0);

    return;
}
}

在这里插入图片描述

3.2 边缘检测

边缘检测是计算机视觉中的重要任务,用于识别图像中亮度变化明显的区域。

3.2.1 Canny 边缘检测:Canny 函数

Canny 边缘检测是一种多阶段的边缘检测算法,包括高斯平滑、梯度计算、非极大值抑制和双阈值处理。

//Canny边缘检测
void MainWindow::on_bt7_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this,QString("文件对话框"),"/",QString("图片(*.jpg *.png);"));

    // 读取图像
    Mat image = imread(fileName.toStdString(), IMREAD_COLOR);

    if (image.empty()) {
        qDebug()  << QString("无法读取图像!");
        return;
    }
    // Canny边缘检测
    Mat edges;
    Canny(image, edges, 50, 150); // 低阈值50,高阈值150

    // 显示原始图像和处理后的图像
    namedWindow(QString("Src").toStdString(), WINDOW_AUTOSIZE);
    namedWindow(QString("Dsc").toStdString(), WINDOW_AUTOSIZE);

    imshow(QString("Src").toStdString(), image);
    imshow(QString("Dsc").toStdString(), edges);

    waitKey(0);

    return;
}

测试结果:
在这里插入图片描述

3.2.2 Sobel 边缘检测:Sobel 函数

Sobel 算子是一种常用的边缘检测算子,用于计算图像灰度函数的近似梯度。

// Sobel边缘检测
void MainWindow::on_bt8_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this,QString("文件对话框"),"/",QString("图片(*.jpg *.png);"));

    // 读取图像
    Mat image = imread(fileName.toStdString(), IMREAD_COLOR);

    if (image.empty()) {
        qDebug()  << QString("无法读取图像!");
        return;
    }
    // Sobel边缘检测
    Mat sobelx, sobely, sobel;

    // 计算x和y方向的梯度
    Sobel(image, sobelx, CV_64F, 1, 0, 3);
    Sobel(image, sobely, CV_64F, 0, 1, 3);

    // 合并梯度
    convertScaleAbs(sobelx, sobelx);
    convertScaleAbs(sobely, sobely);
    addWeighted(sobelx, 0.5, sobely, 0.5, 0, sobel);


    // 显示原始图像和处理后的图像
    namedWindow(QString("Src").toStdString(), WINDOW_AUTOSIZE);
    namedWindow(QString("Dsc").toStdString(), WINDOW_AUTOSIZE);

    imshow(QString("Src").toStdString(), image);
    imshow(QString("Dsc").toStdString(), sobely);

    waitKey(0);

    return;
}

测试结果:
在这里插入图片描述

3.3 形态学操作

形态学操作是基于图像形状的一系列图像处理操作,主要包括腐蚀、膨胀、开运算和闭运算。

3.3.1 腐蚀:erode 函数

腐蚀操作会减小图像中的前景区域,常用于去除小的噪声点。

//腐蚀
void MainWindow::on_bt9_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this,QString("文件对话框"),"/",QString("图片(*.jpg *.png);"));

    // 读取图像
    Mat image = imread(fileName.toStdString(), IMREAD_COLOR);

    if (image.empty()) {
        qDebug()  << QString("无法读取图像!");
        return;
    }
    // 创建结构元素
    Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));

    // 腐蚀操作
    Mat eroded;
    erode(image, eroded, element);

    // 显示原始图像和处理后的图像
    namedWindow(QString("Src").toStdString(), WINDOW_AUTOSIZE);
    namedWindow(QString("Dsc").toStdString(), WINDOW_AUTOSIZE);

    imshow(QString("Src").toStdString(), image);
    imshow(QString("Dsc").toStdString(), eroded);

    waitKey(0);

    return;
}

测试结果:
在这里插入图片描述

3.3.2 膨胀:dilate 函数

膨胀操作会增大图像中的前景区域,常用于连接断裂的物体。

//膨胀
void MainWindow::on_bt10_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this,QString("文件对话框"),"/",QString("图片(*.jpg *.png);"));
    // 读取图像
    Mat image = imread(fileName.toStdString(), IMREAD_COLOR);
    if (image.empty()) {
        qDebug()  << QString("无法读取图像!");
        return;
    }
    // 创建结构元素
    Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));

    // 膨胀操作
    Mat dilated;
    dilate(image, dilated, element);
    // 显示原始图像和处理后的图像
    namedWindow(QString("Src").toStdString(), WINDOW_AUTOSIZE);
    namedWindow(QString("Dsc").toStdString(), WINDOW_AUTOSIZE);

    imshow(QString("Src").toStdString(), image);
    imshow(QString("Dsc").toStdString(), dilated);

    waitKey(0);

    return;
}

测试结果:
在这里插入图片描述

3.3.3 开运算和闭运算:morphologyEx 函数

开运算和闭运算都是复合操作,开运算先腐蚀后膨胀,闭运算先膨胀后腐蚀。

//开闭运算
void MainWindow::on_bt12_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this,QString("文件对话框"),"/",QString("图片(*.jpg *.png);"));

    // 读取图像
    Mat image = imread(fileName.toStdString(), IMREAD_COLOR);

    if (image.empty()) {
        qDebug()  << QString("无法读取图像!");
        return;
    }
    // 创建结构元素
    Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));

    // 开运算
    Mat opened;
    morphologyEx(image, opened, MORPH_OPEN, element);

    // 闭运算
    Mat closed;
    morphologyEx(image, closed, MORPH_CLOSE, element);

    // 显示原始图像和处理后的图像
    namedWindow(QString("Src").toStdString(), WINDOW_AUTOSIZE);
    namedWindow(QString("Dsc_Open").toStdString(), WINDOW_AUTOSIZE);
    namedWindow(QString("Dsc_Close").toStdString(), WINDOW_AUTOSIZE);

    imshow(QString("Src").toStdString(), image);
    imshow(QString("Dsc_Open").toStdString(), opened);
    imshow(QString("Dsc_Close").toStdString(), closed);

    waitKey(0);

    return;
}

测试结果如下:
在这里插入图片描述

四、颜色空间转换与操作

4.1 颜色空间转换:cvtColor 函数

cvtColor函数用于在不同颜色空间之间进行转换,如 BGR 到灰度、BGR 到 HSV 等。

//颜色转换
void MainWindow::on_bt13_clicked()
{

    QString fileName = QFileDialog::getOpenFileName(this,QString("文件对话框"),"/",QString("图片(*.jpg *.png);"));

    // 读取图像
    Mat image = imread(fileName.toStdString(), IMREAD_COLOR);

    if (image.empty()) {
        qDebug()  << QString("无法读取图像!");
        return;
    }
    // BGR到灰度
        Mat gray;
        cvtColor(image, gray, COLOR_BGR2GRAY);

        // BGR到HSV
        Mat hsv;
        cvtColor(image, hsv, COLOR_BGR2HSV);

    // 显示原始图像和处理后的图像
    namedWindow(QString("Src").toStdString(), WINDOW_AUTOSIZE);
    namedWindow(QString("Dsc_Gray").toStdString(), WINDOW_AUTOSIZE);
    namedWindow(QString("Dsc_HSV").toStdString(), WINDOW_AUTOSIZE);

    imshow(QString("Src").toStdString(), image);
    imshow(QString("Dsc_Gray").toStdString(), gray);
    imshow(QString("Dsc_HSV").toStdString(), hsv);

    waitKey(0);

    return;

}

测试结果显示:
在这里插入图片描述

4.2 颜色分割:inRange 函数

inRange函数用于在图像中找到特定颜色范围的区域,常用于颜色分割。

//颜色分割
void MainWindow::on_bt14_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this,QString("文件对话框"),"E:/test/QtTest/WidgetTest/TestOpencv/bin/debug64/Out/OutImg/",QString("图片(*.jpg *.png);"));

    // 读取图像
    Mat image = imread(fileName.toStdString(), IMREAD_COLOR);

    if (image.empty()) {
        qDebug()  << QString("无法读取图像!");
        return;
    }
    // 转换到HSV颜色空间
    Mat hsv;
    cvtColor(image, hsv, COLOR_BGR2HSV);

    // 定义蓝色的HSV范围
    Scalar lower_blue = Scalar(100, 150, 0);
    Scalar upper_blue = Scalar(140, 255, 255);

    // 创建掩码
    Mat mask;
    inRange(hsv, lower_blue, upper_blue, mask);

    // 应用掩码
    Mat result;
    bitwise_and(image, image, result, mask);

    // 显示原始图像和处理后的图像
    namedWindow(QString("Src").toStdString(), WINDOW_AUTOSIZE);
    namedWindow(QString("Dsc_Mask").toStdString(), WINDOW_AUTOSIZE);
    namedWindow(QString("Dsc_Result").toStdString(), WINDOW_AUTOSIZE);

    imshow(QString("Src").toStdString(), image);
    imshow(QString("Dsc_Mask").toStdString(), mask);
    imshow(QString("Dsc_Result").toStdString(), result);

    waitKey(0);

    return;
}

运行结果如下:
在这里插入图片描述
OK,以上通过十几个示例代码展示了OpenCV图像读写及一些基本变换的应用,由于篇幅有限,下一篇,再将一些实际应用比如角点检测,特征提取,人脸检测等功能演示出来。


网站公告

今日签到

点亮在社区的每一天
去签到