十七、OpenCV中HighGUI模块的介绍和使用

文章目录

一、使用cv::namedWindow()创建一个窗口

cv::namedWindow() 是 OpenCV 中用于创建一个显示窗口的函数,它通常与 cv::imshow() 一起使用,用于显示图像或视频帧。它属于 HighGUI 模块,是 OpenCV 提供的最基本 GUI 接口之一。

函数原型:

cpp 复制代码
void cv::namedWindow(const std::string& winname, int flags = cv::WINDOW_AUTOSIZE);

参数说明:

窗口模式(flags):

注意:只有在 WINDOW_NORMAL 模式下,用户才能手动改变窗口大小。其他模式如 AUTOSIZE 下,窗口会随图像大小自动变化。

使用示例

示例 1:创建并显示图像窗口

cpp 复制代码
#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    Mat img = imread("test.jpg");
    if (img.empty()) {
        printf("图片加载失败!\n");
        return -1;
    }

    // 创建一个自动适应图像大小的窗口
    namedWindow("My Window", WINDOW_AUTOSIZE);

    // 在窗口中显示图像
    imshow("My Window", img);

    // 等待按键
    waitKey(0);

    return 0;
}

示例 2:创建一个可调整大小的窗口

cpp 复制代码
#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    Mat img = imread("test.jpg");
    if (img.empty()) return -1;

    // 创建一个可缩放的窗口
    namedWindow("Resizable Window", WINDOW_NORMAL);
    imshow("Resizable Window", img);

    waitKey(0);
    return 0;
}

此时你可以拖动窗口边缘改变大小。

示例 3:与滑动条结合使用

cpp 复制代码
#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    Mat img = imread("test.jpg");
    if (img.empty()) return -1;

    namedWindow("Brightness Control", WINDOW_NORMAL);

    int alpha = 50;
    createTrackbar("Brightness", "Brightness Control", &alpha, 100);

    while (true)
    {
        Mat adjusted;
        img.convertTo(adjusted, -1, 1, alpha - 50);
        imshow("Brightness Control", adjusted);

        if (waitKey(30) == 27) break; // 按下 ESC 退出
    }

    return 0;
}

二、通过cv::imshow()显示图像

cv::imshow() 是 OpenCV 中最常用的图像显示函数之一,用于在一个窗口中显示图像。

它通常与 cv::namedWindow() 和 cv::waitKey() 搭配使用。

在语言模型中,编码器和解码器都是由一个个的 Transformer 组件拼接在一起形成的。

函数原型:

cpp 复制代码
void cv::imshow(const std::string& winname, cv::InputArray mat);

参数说明:

函数作用:

  • 在指定名称的窗口中显示一张图像。
  • 如果窗口不存在,OpenCV 会自动创建一个 WINDOW_AUTOSIZE 类型的窗口。
  • 显示内容会一直保留,直到:显示新的内容(再次调用 imshow()),或者窗口被关闭(cv::destroyWindow())。

基本使用示例

示例 1:显示一张图片

cpp 复制代码
#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    Mat img = imread("test.jpg"); // 读取图片
    if (img.empty()) {
        printf("无法读取图像!\n");
        return -1;
    }

    imshow("显示窗口", img);  // 显示图像
    waitKey(0);               // 等待按键(0 表示无限等待)

    return 0;
}

waitKey() 是必须的,否则窗口会一闪而过。waitKey() 会触发窗口事件处理(刷新显示、响应鼠标等)。

示例 2:手动创建可缩放窗口

cpp 复制代码
#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    Mat img = imread("test.jpg");
    if (img.empty()) return -1;

    namedWindow("可调整大小窗口", WINDOW_NORMAL); // 可缩放窗口
    imshow("可调整大小窗口", img);

    waitKey(0);
    return 0;
}

示例 3:显示灰度图

cpp 复制代码
#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    Mat gray = imread("test.jpg", IMREAD_GRAYSCALE); // 灰度读取
    imshow("灰度图", gray);
    waitKey(0);
    return 0;
}

示例 4:显示处理过程中的多张图像

cpp 复制代码
#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    Mat img = imread("test.jpg");
    if (img.empty()) return -1;

    Mat gray, edges;
    cvtColor(img, gray, COLOR_BGR2GRAY);
    Canny(gray, edges, 100, 200);

    imshow("原图", img);
    imshow("灰度图", gray);
    imshow("边缘检测", edges);

    waitKey(0);
    return 0;
}

示例 5:实时显示视频帧(如摄像头)

cpp 复制代码
#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    VideoCapture cap(0); // 打开摄像头
    if (!cap.isOpened()) {
        printf("无法打开摄像头!\n");
        return -1;
    }

    while (true)
    {
        Mat frame;
        cap >> frame;
        if (frame.empty()) break;

        imshow("摄像头实时画面", frame);

        // 按下 ESC 键退出
        if (waitKey(30) == 27) break;
    }

    return 0;
}

示例6:在窗口上实时更新图像

cpp 复制代码
#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    Mat img = imread("test.jpg");
    if (img.empty()) return -1;

    namedWindow("动态显示", WINDOW_AUTOSIZE);

    for (int i = 0; i < 100; i++)
    {
        Mat bright;
        img.convertTo(bright, -1, 1, i - 50); // 动态调节亮度
        imshow("动态显示", bright);

        if (waitKey(30) == 27) break; // ESC 退出
    }

    return 0;
}

三、鼠标事件的使用

OpenCV 的鼠标事件(Mouse Events)是图像交互中非常实用的一部分。通过它,你可以在显示窗口中响应鼠标点击、拖拽、移动等操作,从而实现图像标注、ROI选区、目标跟踪等功能。

函数原型:

cpp 复制代码
void cv::setMouseCallback(
    const std::string& winname,
    cv::MouseCallback onMouse,
    void* userdata = nullptr
);

参数说明:

回调函数类型定义:

cpp 复制代码
typedef void (*MouseCallback)(
    int event,        // 鼠标事件类型
    int x,            // 鼠标x坐标
    int y,            // 鼠标y坐标
    int flags,        // 组合键标志(如Ctrl/Shift等)
    void* userdata    // 用户数据指针
);

常用鼠标事件类型(event):

组合键标志(flags):

示例代码

打印鼠标坐标:

cpp 复制代码
#include <opencv2/opencv.hpp>
using namespace cv;

// 鼠标回调函数
void onMouse(int event, int x, int y, int flags, void* userdata)
{
    if (event == EVENT_MOUSEMOVE)
    {
        printf("鼠标移动到 (%d, %d)\n", x, y);
    }
    else if (event == EVENT_LBUTTONDOWN)
    {
        printf("左键按下: (%d, %d)\n", x, y);
    }
    else if (event == EVENT_RBUTTONDOWN)
    {
        printf("右键按下: (%d, %d)\n", x, y);
    }
}

int main()
{
    Mat img = Mat::zeros(400, 600, CV_8UC3);
    namedWindow("鼠标演示", WINDOW_AUTOSIZE);

    // 绑定鼠标事件
    setMouseCallback("鼠标演示", onMouse, nullptr);

    imshow("鼠标演示", img);
    waitKey(0);
    return 0;
}

鼠标绘制矩形(ROI选择):

cpp 复制代码
#include <opencv2/opencv.hpp>
using namespace cv;

struct RectData {
    Point start, end;
    bool drawing = false;
};

void onMouse(int event, int x, int y, int flags, void* userdata)
{
    RectData* data = reinterpret_cast<RectData*>(userdata);

    if (event == EVENT_LBUTTONDOWN) {
        data->drawing = true;
        data->start = Point(x, y);
    }
    else if (event == EVENT_MOUSEMOVE && data->drawing) {
        data->end = Point(x, y);
    }
    else if (event == EVENT_LBUTTONUP) {
        data->drawing = false;
        data->end = Point(x, y);
        printf("选取区域:(%d,%d) - (%d,%d)\n", data->start.x, data->start.y, data->end.x, data->end.y);
    }
}

int main()
{
    Mat img = Mat::zeros(400, 600, CV_8UC3);
    Mat temp;
    RectData data;

    namedWindow("ROI绘制", WINDOW_AUTOSIZE);
    setMouseCallback("ROI绘制", onMouse, &data);

    while (true)
    {
        img.copyTo(temp);
        if (data.drawing)
            rectangle(temp, data.start, data.end, Scalar(0, 255, 0), 2);

        imshow("ROI绘制", temp);
        if (waitKey(30) == 27) break; // 按ESC退出
    }

    return 0;
}

四、键盘事件的使用

在 OpenCV 中确实有按键事件(Keyboard Events),不过它不像鼠标事件那样需要回调函数,而是通过函数 cv::waitKey() 实现的。

核心函数:cv::waitKey()

函数原型:

cpp 复制代码
int cv::waitKey(int delay = 0);

参数说明:

返回值:

  • 如果用户按下某个键,则 waitKey() 返回该键的 ASCII 码值。
  • 如果在 delay 毫秒内未检测到按键,则返回 -1。

原理说明

cv::waitKey() 其实有两个功能:

  1. 处理窗口刷新事件(否则 imshow() 的内容不会更新)
  2. 监听键盘输入事件

也就是说,不调用 waitKey(),图像窗口不会响应任何事件,包括显示更新和鼠标交互!

基本使用示例

示例 1:等待按键退出

cpp 复制代码
#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    Mat img = imread("test.jpg");
    imshow("图像窗口", img);

    // 等待任意按键
    waitKey(0);
    return 0;
}

当你按任意键时,程序才会退出。

示例 2:定时刷新 + 检测按键

cpp 复制代码
#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    VideoCapture cap(0);
    if (!cap.isOpened()) return -1;

    while (true)
    {
        Mat frame;
        cap >> frame;
        imshow("摄像头", frame);

        int key = waitKey(30);  // 等待30ms
        if (key == 27) break;   // ESC退出
    }
    return 0;
}

每隔 30ms 刷新一次图像,并检查用户是否按下 ESC 键。这是典型的 OpenCV 实时显示循环写法。

常见按键值(ASCII码)

示例:按键控制显示行为

cpp 复制代码
#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    Mat img = imread("test.jpg");
    if (img.empty()) return -1;

    imshow("按键控制", img);

    while (true)
    {
        int key = waitKey(0);

        if (key == 27) // ESC
            break;
        else if (key == 's' || key == 'S')
        {
            imwrite("output.jpg", img);
            printf("图片已保存!\n");
        }
        else if (key == 'g' || key == 'G')
        {
            Mat gray;
            cvtColor(img, gray, COLOR_BGR2GRAY);
            imshow("按键控制", gray);
            printf("切换为灰度图\n");
        }
    }
    return 0;
}

五、滑动条的使用

在 OpenCV 中,滑动条其实就是一个 GUI 控件,可以用来实时调节参数(例如阈值、亮度、对比度、滤波半径等),而"滚动条"和"开关"在 OpenCV 中是通过滑动条或按钮模拟实现的。
函数原型:

cpp 复制代码
int cv::createTrackbar(
    const std::string &trackbarname,
    const std::string &winname,
    int *value,
    int count,
    TrackbarCallback onChange = 0,
    void *userdata = 0
);

参数说明:

回调函数类型:

cpp 复制代码
typedef void (*TrackbarCallback)(int pos, void* userdata);
  • pos:当前滑动条位置
  • userdata:用户自定义数据

滑动条基本示例:

cpp 复制代码
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

void onTrack(int pos, void* userdata)
{
    Mat* img = reinterpret_cast<Mat*>(userdata);
    Mat dst;
    img->convertTo(dst, -1, 1, pos - 50); // 调整亮度
    imshow("滑动条示例", dst);
}

int main()
{
    Mat img = imread("test.jpg");
    if (img.empty()) return -1;

    namedWindow("滑动条示例", WINDOW_AUTOSIZE);

    int slider = 50; // 初始值
    createTrackbar("Brightness", "滑动条示例", &slider, 100, onTrack, &img);

    imshow("滑动条示例", img);
    waitKey(0);

    return 0;
}
相关推荐
疯笔码良4 小时前
【IOS开发】SwiftUI + OpenCV实现图片的简单处理(一)
opencv·ios·swiftui
864记忆4 小时前
opencv图像预处理函数的功能与作用
人工智能·opencv·计算机视觉
Antonio9151 天前
【图像处理】灰度图像与二值化
图像处理·opencv
Mrliu__1 天前
Opencv(一): 用Opencv了解图像
人工智能·opencv·计算机视觉
yanxing.D1 天前
penCV轻松入门_面向python(第七章 图像平滑处理)
图像处理·人工智能·opencv·计算机视觉
宇宙浪子1 天前
在 UOS(统信操作系统,基于 Debian/Ubuntu 体系)上编译 OpenCV 4.10.0
opencv·ubuntu·debian
柳鲲鹏2 天前
多种方法:OpenCV中修改像素RGB值
前端·javascript·opencv·1024程序员节
weixin_582985182 天前
OpenCV cv::Mat.type() 以及类型数据转换
c++·opencv·计算机视觉
Antonio9152 天前
【图像处理】图像形态学操作
图像处理·人工智能·opencv