【Qt&OpenCV 图像边缘检测 Sobel/Laplace/Canny】

简介: 【Qt&OpenCV 图像边缘检测 Sobel/Laplace/Canny】

边缘检测是图像处理技术,用于确定图片中物体的边界(边缘)或者区域。边缘是图像中重要的特征。我们通过边缘来了解图像的结构信息。边缘的特征在于像素亮度的突然变化,为了检测边缘,我们需要能够寻找出存在于相邻像素之间的这种变化。

前言

越来越多的开发人员选择基于开源的Qt框架与OpenCV来实现界面和算法,其原因不单单是无版权问题,更多是两个社区的发展蓬勃,可用来学习的资料与例程特别丰富。以下是关于利用Qt构建GUI并使用OpenCV中的Sobel/Laplace/Canny函数进行图像边缘检测。

软件版本:Qt-5.12.0/OpenCV-4.5.3

平台:Windows10/11–64


一、函数介绍

1、Soble

函数原型

cv::Sobel( InputArray src, OutputArray dst, int ddepth,

int dx, int dy, int ksize = 3,

double scale = 1, double delta = 0,

int borderType = BORDER_DEFAULT );


参数解释:

src:为输入图像;

dst:目标图像,需要和源图片有一样的尺寸和类型;

ddepth::输出图像的深度,支持如下src.depth()和ddepth的组合:


若src.depth() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F

若src.depth() = CV_16U/CV_16S, 取ddepth =-1/CV_32F/CV_64F

若src.depth() = CV_32F, 取ddepth =-1/CV_32F/CV_64F

若src.depth() = CV_64F, 取ddepth = -1/CV_64F


dx:x 方向上的差分阶数;

dy:y方向上的差分阶数;

ksize:有默认值3,表示Sobel核的大小;必须取1,3,5或7。

scale:计算导数值时可选的缩放因子,默认值是1,表示默认情况下是没有应用缩放的;

delta:表示在结果存入目标图(第二个参数dst)之前可选的delta值,有默认值0;

borderType:边界模式,默认值为BORDER_DEFAULT;

2、Laplace

函数原型

cv::Laplacian( InputArray src,

OutputArray dst,

int ddepth,

int ksize = 1,

double scale = 1,

double delta = 0,

int borderType = BORDER_DEFAULT

)


参数解释:

src:待提取边缘的图像;

dst:输出图像,与输入图像src具有相同的尺寸和通道数,数据类型由第三个参数ddepth控制;

ddepth:输出图像的数据类型(深度);

ksize:表示Laplacian核的大小;

scale:对导数计算结果进行缩放的缩放因子,默认系数为1,不进行缩放;

delta:偏移值,在计算结果中加上偏移值;

borderType:边界模式,默认值为BORDER_DEFAULT;

3、Canny

函数原型

cv::Canny(InputArray src, OutputArray dst,

double threshold1, double threshold2,

int aperture_size=3);

参数解释

src:输入图像, 单通道灰度图像;

dst: 输出图像;

threshold1/threshold2:函数的两个阀值;

二、演示

1、GUI

如上图创建Operator的QComboBox控件进行函数选择,Action的功能按钮QPushButton,对当前窗口的图像进行边缘检测,并输出状态信息。

2、代码实现

edgeBtn的clicked()槽函数的实现代码:

void MainWindow::on_edgeBtn_clicked()
{
    std::size_t numView = ui->tabWidget->currentIndex() % 3;
    if (dispMat[numView]->empty())
    {
        outputInfo(2, tr("Please make sure the Mat exist!"));
        return;
    }

    if (dispMat[numView]->channels() == 3)
    {
        cv::cvtColor(*dispMat[numView], *dispMat[numView], cv::COLOR_RGB2GRAY);
    }

    tmpMat->zeros(dispMat[numView]->size(), dispMat[numView]->type());
    cv::GaussianBlur(*dispMat[numView], *dispMat[numView], cv::Size(3, 3), \  // 图像去噪
                      0, 0, cv::BORDER_DEFAULT);
    int operatorType = ui->edgeCombo->currentIndex();

    switch (operatorType)
    {
        case 0:   // Sobel
        {
            cv::Mat gradX, gradY, absGradX, absGradY;
            cv::Sobel(*dispMat[numView], gradX, CV_16S, 1, 0, 3, 1, \
                  0, cv::BORDER_DEFAULT);
            cv::convertScaleAbs(gradX, absGradX);
            cv::Sobel(*dispMat[numView], gradY, CV_16S, 0, 1, 3, 1, \
                      0, cv::BORDER_DEFAULT);

            cv::convertScaleAbs(gradY, absGradY);
            cv::addWeighted(absGradX, 0.5, absGradY, 0.5, 0, *tmpMat);

            outputInfo(1, tr("Sobel done."));

            break;
        }
        case 1:   // Laplace
        {
            cv::Laplacian(*dispMat[numView], *tmpMat, CV_16S, 3, 1, 0, \
                      cv::BORDER_DEFAULT);
            cv::convertScaleAbs(*tmpMat, *tmpMat);

            outputInfo(1, tr("Laplace done."));

            break;
        }
        case 2:   // Canny
        {
            cv::Mat cannyMat;
            int cannyThresh = ui->cannySlider->value();
            cv::Canny(*dispMat[numView], cannyMat, cannyThresh, cannyThresh * 3, \
                      3);
            *tmpMat = cv::Scalar::all(0);
            dispMat[numView]->copyTo(*tmpMat, cannyMat);
            outputInfo(1, tr("Canny done."));
            break;
        }
    }

    if (ui->edgeChkBox->isChecked())
    {
        *dispMat[numView] = tmpMat->clone();
        cvtMatPixmap(dispMat, dispPixmap, numView);
    }
    else
    {
        if (tmpMat->channels() == 3)
        {
            QImage tmpImage = QImage(tmpMat->data, tmpMat->cols,tmpMat->rows, \
                         static_cast<int>(tmpMat->step), \
                         QImage::Format_RGB888);
            dispPixmap[numView]->setPixmap(QPixmap::fromImage(tmpImage.rgbSwapped()));
        }
        else
        {
            QImage tmpImage = QImage(tmpMat->data, tmpMat->cols,tmpMat->rows, \
                         static_cast<int>(tmpMat->step), \
                         QImage::Format_Grayscale8);
            dispPixmap[numView]->setPixmap(QPixmap::fromImage(tmpImage.rgbSwapped()));
        }

    }
}

总结

以上是关于利用Qt进行GUI构建并使用OpenCV中的Sobel/Laplace/Canny函数进行图像边缘检测。

目录
相关文章
|
2月前
|
算法 计算机视觉
基于qt的opencv实时图像处理框架FastCvLearn实战
本文介绍了一个基于Qt的OpenCV实时图像处理框架FastCvLearn,通过手撕代码的方式详细讲解了如何实现实时人脸马赛克等功能,并提供了结果展示和基础知识回顾。
基于qt的opencv实时图像处理框架FastCvLearn实战
|
2月前
|
文字识别 计算机视觉 开发者
基于QT的OCR和opencv融合框架FastOCRLearn实战
本文介绍了在Qt环境下结合OpenCV库构建OCR识别系统的实战方法,通过FastOCRLearn项目,读者可以学习Tesseract OCR的编译配置和在Windows平台下的实践步骤,文章提供了技术资源链接,帮助开发者理解并实现OCR技术。
109 9
基于QT的OCR和opencv融合框架FastOCRLearn实战
|
2月前
|
计算机视觉
基于QT的opencv插件框架qtCvFrameLearn实战
这篇文章详细介绍了如何基于Qt框架开发一个名为qtCvFrameLearn的OpenCV插件,包括项目配置、插件加载、Qt与OpenCV图像转换,以及通过各个插件学习OpenCV函数的使用,如仿射变换、卡通效果、腐蚀、旋转和锐化等。
40 10
|
2月前
|
机器学习/深度学习 Java 计算机视觉
opencv4.5.5+qt5.15.2+vtk9.1+mingw81_64编译记录
本文记录了使用mingw81_64编译OpenCV 4.5.5、Qt 5.15.2、VTK 9.1的详细过程,包括编译结果截图、编译步骤、遇到的问题及其解决方案,以及相关参考链接。文中还提到了如何编译boost源码为静态库,并提供了测试代码示例。
opencv4.5.5+qt5.15.2+vtk9.1+mingw81_64编译记录
|
3月前
|
计算机视觉
使用QT显示OpenCV读取的图片
使用QT显示OpenCV读取的图片
60 1
|
4月前
|
机器学习/深度学习 人工智能 计算机视觉
好的资源-----打卡机+Arm+Qt+OpenCV嵌入式项目-基于人脸识别的考勤系统-----B站神经网络与深度学习,商城
好的资源-----打卡机+Arm+Qt+OpenCV嵌入式项目-基于人脸识别的考勤系统-----B站神经网络与深度学习,商城
|
4月前
|
数据安全/隐私保护 C++ 计算机视觉
Qt(C++)开发一款图片防盗用水印制作小工具
文本水印是一种常用的防盗用手段,可以将文本信息嵌入到图片、视频等文件中,用于识别和证明文件的版权归属。在数字化和网络化的时代,大量的原创作品容易被不法分子盗用或侵犯版权,因此加入文本水印成为了保护原创作品和维护知识产权的必要手段。 通常情况下,文本水印可以包含版权声明、制作者姓名、日期、网址等信息,以帮助识别文件的来源和版权归属。同时,为了增强防盗用效果,文本水印通常会采用字体、颜色、角度等多种组合方式,使得水印难以被删除或篡改,有效地降低了盗用意愿和风险。 开发人员可以使用图像处理技术和编程语言实现文本水印的功能,例如使用Qt的QPainter类进行文本绘制操作,将文本信息嵌入到图片中,
173 1
Qt(C++)开发一款图片防盗用水印制作小工具
|
3月前
|
监控 C++ 容器
【qt】MDI多文档界面开发
【qt】MDI多文档界面开发
74 0
|
2月前
|
开发工具 C++
qt开发技巧与三个问题点
本文介绍了三个Qt开发中的常见问题及其解决方法,并提供了一些实用的开发技巧。
|
2月前