基于QT的opencv插件框架qtCvFrameLearn实战

简介: 这篇文章详细介绍了如何基于Qt框架开发一个名为qtCvFrameLearn的OpenCV插件,包括项目配置、插件加载、Qt与OpenCV图像转换,以及通过各个插件学习OpenCV函数的使用,如仿射变换、卡通效果、腐蚀、旋转和锐化等。

0 结果展示

github项目链接: 基于QT的opencv插件框架qtCvFrameLearn.
csdn文章:基于QT的opencv插件框架qtCvFrameLearn.
基于QT的opencv插件框架qtCvFrameLearn

1 参考链接

链接: 本文微信文章,更多讲解.
链接: Qt-5-and-OpenCV-4-Computer-Vision-Projects.
链接: qt5.13配置opencv4.2环境 mscv版.

2 文件目录结构

qt插件框架qtCvFrameLearnqt插件框架qtCvFrameLearn

3 项目配置文件ImageEditor.pro

######################################################################
# Automatically generated by qmake (3.1) Sun Nov 11 20:07:20 2018
######################################################################


TEMPLATE = app
TARGET = ImageEditor
DESTDIR = ../App

QT += core gui network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

## use your own path in the following config
#unix: !mac {
   
#    INCLUDEPATH += /home/kdr2/programs/opencv/include/opencv4
#    LIBS += -L/home/kdr2/programs/opencv/lib -lopencv_core -l opencv_imgproc
#}

#unix: mac {
   
#    INCLUDEPATH += /path/to/opencv/include/opencv4
#    LIBS += -L/path/to/opencv/lib -lopencv_world
#}

#win32 {
   
##    INCLUDEPATH += c:/path/to/opencv/include/opencv4
##    LIBS += -lc:/path/to/opencv/lib/opencv_world
#    INCLUDEPATH += C:/opencv451/include/opencv2
##    LIBS += -lC:/opencv451/vc15/opencv_world
#}

# The following define makes your compiler warn you if you use any
# feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

# Input
HEADERS += mainwindow.h editor_plugin_interface.h
SOURCES += main.cpp mainwindow.cpp

# opencv config
INCLUDEPATH += C:/opencv451/include
DEPENDPATH += C:/opencv451/include

win32:CONFIG(release, debug|release): LIBS += -LC:/opencv451/vc15/lib/ \
opencv_aruco451.lib  \
opencv_bgsegm451.lib  \
opencv_bioinspired451.lib  \
opencv_ccalib451.lib  \
opencv_core451.lib  \
opencv_cudaarithm451.lib  \
opencv_cudabgsegm451.lib  \
opencv_cudacodec451.lib  \
opencv_cudafilters451.lib  \
opencv_cudaimgproc451.lib  \
opencv_cudalegacy451.lib  \
opencv_cudaobjdetect451.lib  \
opencv_cudaoptflow451.lib  \
opencv_cudastereo451.lib  \
opencv_cudawarping451.lib  \
opencv_cudev451.lib  \
opencv_cvv451.lib  \
opencv_datasets451.lib  \
opencv_dnn451.lib  \
opencv_dpm451.lib  \
opencv_face451.lib  \
opencv_flann451.lib  \
opencv_fuzzy451.lib  \
opencv_gapi451.lib  \
opencv_hfs451.lib  \
opencv_highgui451.lib  \
opencv_imgcodecs451.lib  \
opencv_imgproc451.lib  \
opencv_mcc451.lib  \
opencv_ml451.lib  \
opencv_objdetect451.lib  \
opencv_optflow451.lib  \
opencv_photo451.lib  \
opencv_plot451.lib  \
opencv_quality451.lib  \
opencv_rapid451.lib  \
opencv_reg451.lib  \
opencv_rgbd451.lib  \
opencv_saliency451.lib  \
opencv_shape451.lib  \
opencv_stereo451.lib  \
opencv_stitching451.lib  \
opencv_superres451.lib  \
opencv_text451.lib  \
opencv_tracking451.lib  \
opencv_video451.lib  \
opencv_videoio451.lib  \
opencv_videostab451.lib  \
opencv_ximgproc451.lib  \
opencv_xobjdetect451.lib  \
opencv_xphoto451.lib
else:win32:CONFIG(debug, debug|release): LIBS += -LC:/opencv451/vc15/lib/  \
opencv_aruco451d.lib  \
opencv_bgsegm451d.lib  \
opencv_bioinspired451d.lib  \
opencv_ccalib451d.lib  \
opencv_core451d.lib  \
opencv_cudaarithm451d.lib  \
opencv_cudabgsegm451d.lib  \
opencv_cudacodec451d.lib  \
opencv_cudafilters451d.lib  \
opencv_cudaimgproc451d.lib  \
opencv_cudalegacy451d.lib  \
opencv_cudaobjdetect451d.lib  \
opencv_cudaoptflow451d.lib  \
opencv_cudastereo451d.lib  \
opencv_cudawarping451d.lib  \
opencv_cudev451d.lib  \
opencv_cvv451d.lib  \
opencv_datasets451d.lib  \
opencv_dnn451d.lib  \
opencv_dpm451d.lib  \
opencv_face451d.lib  \
opencv_flann451d.lib  \
opencv_fuzzy451d.lib  \
opencv_gapi451d.lib  \
opencv_hfs451d.lib  \
opencv_highgui451d.lib  \
opencv_imgcodecs451d.lib  \
opencv_imgproc451d.lib  \
opencv_mcc451d.lib  \
opencv_ml451d.lib  \
opencv_objdetect451d.lib  \
opencv_optflow451d.lib  \
opencv_photo451d.lib  \
opencv_plot451d.lib  \
opencv_quality451d.lib  \
opencv_rapid451d.lib  \
opencv_reg451d.lib  \
opencv_rgbd451d.lib  \
opencv_saliency451d.lib  \
opencv_shape451d.lib  \
opencv_stereo451d.lib  \
opencv_stitching451d.lib  \
opencv_superres451d.lib  \
opencv_text451d.lib  \
opencv_tracking451d.lib  \
opencv_video451d.lib  \
opencv_videoio451d.lib  \
opencv_videostab451d.lib  \
opencv_ximgproc451d.lib  \
opencv_xobjdetect451d.lib  \
opencv_xphoto451d.lib
else:unix:!macx: LIBS += -LC:/opencv451/vc15/lib/ -lopencv_core451 \
-lopencv_*451

DISTFILES += \
    plugins/.gitkeep \
    plugins/AffinePlugin.dll \
    plugins/CartoonPlugin.dll \
    plugins/ErodePlugin.dll \
    plugins/RotatePlugin.dll \
    plugins/SharpenPlugin.dll

4 项目配置文件AffinePlugin.pro

######################################################################
# Automatically generated by qmake (3.1) Fri Nov 30 20:56:01 2018
######################################################################
#QT       += widgets

TARGET = AffinePlugin
TEMPLATE = lib
DESTDIR = ../App/plugins
INCLUDEPATH +=../ImageEditor


## use your own path in the following config
#unix: !mac {
   
#    INCLUDEPATH += /home/kdr2/programs/opencv/include/opencv4
#    LIBS += -L/home/kdr2/programs/opencv/lib -lopencv_core -l opencv_imgproc
#}

#unix: mac {
   
#    INCLUDEPATH += /path/to/opencv/include/opencv4
#    LIBS += -L/path/to/opencv/lib -lopencv_world
#}

#win32 {
   
#    INCLUDEPATH += C:/opencv451/include
#    LIBS += -lC:/opencv451/vc15/lib/ \
#            -lopencv_core451d
#            -lopencv_imgproc451d
#}

# The following define makes your compiler warn you if you use any
# feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

# Input
HEADERS += affine_plugin.h
SOURCES += affine_plugin.cpp


# opencv config
INCLUDEPATH += C:/opencv451/include
DEPENDPATH += C:/opencv451/include

win32:CONFIG(release, debug|release): LIBS += -LC:/opencv451/vc15/lib/ \
opencv_aruco451.lib  \
opencv_bgsegm451.lib  \
opencv_bioinspired451.lib  \
opencv_ccalib451.lib  \
opencv_core451.lib  \
opencv_cudaarithm451.lib  \
opencv_cudabgsegm451.lib  \
opencv_cudacodec451.lib  \
opencv_cudafilters451.lib  \
opencv_cudaimgproc451.lib  \
opencv_cudalegacy451.lib  \
opencv_cudaobjdetect451.lib  \
opencv_cudaoptflow451.lib  \
opencv_cudastereo451.lib  \
opencv_cudawarping451.lib  \
opencv_cudev451.lib  \
opencv_cvv451.lib  \
opencv_datasets451.lib  \
opencv_dnn451.lib  \
opencv_dpm451.lib  \
opencv_face451.lib  \
opencv_flann451.lib  \
opencv_fuzzy451.lib  \
opencv_gapi451.lib  \
opencv_hfs451.lib  \
opencv_highgui451.lib  \
opencv_imgcodecs451.lib  \
opencv_imgproc451.lib  \
opencv_mcc451.lib  \
opencv_ml451.lib  \
opencv_objdetect451.lib  \
opencv_optflow451.lib  \
opencv_photo451.lib  \
opencv_plot451.lib  \
opencv_quality451.lib  \
opencv_rapid451.lib  \
opencv_reg451.lib  \
opencv_rgbd451.lib  \
opencv_saliency451.lib  \
opencv_shape451.lib  \
opencv_stereo451.lib  \
opencv_stitching451.lib  \
opencv_superres451.lib  \
opencv_text451.lib  \
opencv_tracking451.lib  \
opencv_video451.lib  \
opencv_videoio451.lib  \
opencv_videostab451.lib  \
opencv_ximgproc451.lib  \
opencv_xobjdetect451.lib  \
opencv_xphoto451.lib
else:win32:CONFIG(debug, debug|release): LIBS += -LC:/opencv451/vc15/lib/  \
opencv_aruco451d.lib  \
opencv_bgsegm451d.lib  \
opencv_bioinspired451d.lib  \
opencv_ccalib451d.lib  \
opencv_core451d.lib  \
opencv_cudaarithm451d.lib  \
opencv_cudabgsegm451d.lib  \
opencv_cudacodec451d.lib  \
opencv_cudafilters451d.lib  \
opencv_cudaimgproc451d.lib  \
opencv_cudalegacy451d.lib  \
opencv_cudaobjdetect451d.lib  \
opencv_cudaoptflow451d.lib  \
opencv_cudastereo451d.lib  \
opencv_cudawarping451d.lib  \
opencv_cudev451d.lib  \
opencv_cvv451d.lib  \
opencv_datasets451d.lib  \
opencv_dnn451d.lib  \
opencv_dpm451d.lib  \
opencv_face451d.lib  \
opencv_flann451d.lib  \
opencv_fuzzy451d.lib  \
opencv_gapi451d.lib  \
opencv_hfs451d.lib  \
opencv_highgui451d.lib  \
opencv_imgcodecs451d.lib  \
opencv_imgproc451d.lib  \
opencv_mcc451d.lib  \
opencv_ml451d.lib  \
opencv_objdetect451d.lib  \
opencv_optflow451d.lib  \
opencv_photo451d.lib  \
opencv_plot451d.lib  \
opencv_quality451d.lib  \
opencv_rapid451d.lib  \
opencv_reg451d.lib  \
opencv_rgbd451d.lib  \
opencv_saliency451d.lib  \
opencv_shape451d.lib  \
opencv_stereo451d.lib  \
opencv_stitching451d.lib  \
opencv_superres451d.lib  \
opencv_text451d.lib  \
opencv_tracking451d.lib  \
opencv_video451d.lib  \
opencv_videoio451d.lib  \
opencv_videostab451d.lib  \
opencv_ximgproc451d.lib  \
opencv_xobjdetect451d.lib  \
opencv_xphoto451d.lib
else:unix:!macx: LIBS += -LC:/opencv451/vc15/lib/ -lopencv_core451 \
-lopencv_*451

5 代码梳理

5.1 插件加载

void MainWindow::loadPlugins()
{
   
    QDir pluginsDir(QApplication::instance()->applicationDirPath() + "/plugins");
    QStringList nameFilters;
    nameFilters << "*.so" << "*.dylib" << "*.dll";
    QFileInfoList plugins = pluginsDir.entryInfoList(
        nameFilters, QDir::NoDotAndDotDot | QDir::Files, QDir::Name);
    foreach(QFileInfo plugin, plugins) {
   
        QPluginLoader pluginLoader(plugin.absoluteFilePath(), this);
        EditorPluginInterface *plugin_ptr = dynamic_cast<EditorPluginInterface*>(pluginLoader.instance());
        if(plugin_ptr) {
   
            QAction *action = new QAction(plugin_ptr->name());
            editMenu->addAction(action);
            editToolBar->addAction(action);
            editPlugins[plugin_ptr->name()] = plugin_ptr;
            connect(action, SIGNAL(triggered(bool)), this, SLOT(pluginPerform()));
            // pluginLoader.unload();
        } else {
   
            qDebug() << "bad plugin: " << plugin.absoluteFilePath();
        }
    }
}

5.2 qt图像与opencv图像转换

void MainWindow::pluginPerform()
{
   
    if (currentImage == nullptr) {
   
        QMessageBox::information(this, "Information", "No image to edit.");
        return;
    }

    QAction *active_action = qobject_cast<QAction*>(sender());
    EditorPluginInterface *plugin_ptr = editPlugins[active_action->text()];
    if(!plugin_ptr) {
   
        QMessageBox::information(this, "Information", "No plugin is found.");
        return;
    }

    QPixmap pixmap = currentImage->pixmap();
    QImage image = pixmap.toImage();
    image = image.convertToFormat(QImage::Format_RGB888);
    cv::Mat mat = cv::Mat(
        image.height(),
        image.width(),
        CV_8UC3,
        image.bits(),
        image.bytesPerLine());

    plugin_ptr->edit(mat, mat);

    QImage image_edited(
        mat.data,
        mat.cols,
        mat.rows,
        mat.step,
        QImage::Format_RGB888);
    pixmap = QPixmap::fromImage(image_edited);
    imageScene->clear();
    imageView->resetMatrix();
    currentImage = imageScene->addPixmap(pixmap);
    imageScene->update();
    imageView->setSceneRect(pixmap.rect());
    QString status = QString("(editted image), %1x%2")
        .arg(pixmap.width()).arg(pixmap.height());
    mainStatusLabel->setText(status);
}

5.3 各个插件中的opencv函数学习

opencv中的Mat()函数

5.3.1 affine_plugin

// affine_plugin
void AffinePlugin::edit(const cv::Mat &input, cv::Mat &output)
{
   

    cv::Point2f triangleA[3];
    cv::Point2f triangleB[3];

    triangleA[0] = cv::Point2f(0 , 0);
    triangleA[1] = cv::Point2f(1 , 0);
    triangleA[2] = cv::Point2f(0 , 1);

    triangleB[0] = cv::Point2f(0, 0);
    triangleB[1] = cv::Point2f(1, 0);
    triangleB[2] = cv::Point2f(1, 1);

    cv::Mat affineMatrix = cv::getAffineTransform(triangleA, triangleB);
    cv::Mat result;
    cv::warpAffine(
        input, result,
        affineMatrix, input.size(), // output image size, same as input
        cv::INTER_CUBIC, // Interpolation method
        cv::BORDER_CONSTANT  // Extrapolation method
        //BORDER_WRAP  // Extrapolation method
    );

    output = result;
}
getAffineTransform
CV_EXPORTS_W Mat getAffineTransform( InputArray src, InputArray dst );

opencv中的getAffineTransform()函数

warpAffine
CV_EXPORTS_W void warpAffine( InputArray src, OutputArray dst,
                              InputArray M, Size dsize,
                              int flags = INTER_LINEAR,
                              int borderMode = BORDER_CONSTANT,
                              const Scalar& borderValue = Scalar());

opencv中的warpAffine()函数

5.3.2 cartoon_plugin

// cartoon_plugin
void CartoonPlugin::edit(const cv::Mat &input, cv::Mat &output)
{
   
    int num_down = 2;
    int num_bilateral = 7;

    cv::Mat copy1, copy2;
    cv::Mat image_gray, image_edge;

    copy1 = input.clone();
    for(int i = 0; i < num_down; i++) {
   
        cv::pyrDown(copy1, copy2);
        copy1 = copy2.clone();
    }

    for(int i = 0; i < num_bilateral; i++) {
   
        cv::bilateralFilter(copy1, copy2, 9, 9, 7);
        copy1 = copy2.clone();
    }

    for(int i = 0; i < num_down; i++) {
   
        cv::pyrUp(copy1, copy2);
        copy1 = copy2.clone();
    }

    if (input.cols != copy1.cols  || input.rows != copy1.rows) {
   
        cv::Rect rect(0, 0, input.cols, input.rows);
        copy1(rect).copyTo(copy2);
        copy1 = copy2;
    }

    cv::cvtColor(input, image_gray, cv::COLOR_RGB2GRAY);
    cv::medianBlur(image_gray, image_gray, 5);

    cv::adaptiveThreshold(image_gray, image_gray, 255,
        cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, 9, 2);

    cv::cvtColor(image_gray, image_edge, cv::COLOR_GRAY2RGB);

    output = copy1 & image_edge;

    /*
    cv::GaussianBlur(image_edge, image_edge, cv::Size(5, 5), 0);
    cv::Mat mask(input.rows, input.cols, CV_8UC3, cv::Scalar(90, 90, 90));
    mask = mask & (~image_edge);
    output = (copy1 & image_edge) | mask;
    */
}
pyrDown
CV_EXPORTS_W void pyrDown( InputArray src, OutputArray dst,
                           const Size& dstsize = Size(), int borderType = BORDER_DEFAULT );

opencv中的pyrDown()函数

bilateralFilter
CV_EXPORTS_W void bilateralFilter( InputArray src, OutputArray dst, int d,
                                   double sigmaColor, double sigmaSpace,
                                   int borderType = BORDER_DEFAULT );

opencv中的bilateralFilter()函数

pyrUp
CV_EXPORTS_W void pyrUp( InputArray src, OutputArray dst,
                         const Size& dstsize = Size(), int borderType = BORDER_DEFAULT );

opencv中的pyrUp()函数

medianBlur
CV_EXPORTS_W void medianBlur( InputArray src, OutputArray dst, int ksize );

opencv中的medianBlur()函数

adaptiveThreshold
CV_EXPORTS_W void adaptiveThreshold( InputArray src, OutputArray dst,
                                     double maxValue, int adaptiveMethod,
                                     int thresholdType, int blockSize, double C );

opencv中的adaptiveThreshold()函数

5.3.3 erode_plugin

void ErodePlugin::edit(const cv::Mat &input, cv::Mat &output)
{
   
    erode(input, output, cv::Mat());
}
erode
CV_EXPORTS_W void erode( InputArray src, OutputArray dst, InputArray kernel,
                         Point anchor = Point(-1,-1), int iterations = 1,
                         int borderType = BORDER_CONSTANT,
                         const Scalar& borderValue = morphologyDefaultBorderValue() );

opencv中的erode()函数

5.3.4 rotate_plugin

void RotatePlugin::edit(const cv::Mat &input, cv::Mat &output)
{
   
    double angle = 45.0;
    double scale = 1.0;
    cv::Point2f center = cv::Point(input.cols/2, input.rows/2);
    cv::Mat rotateMatrix = cv::getRotationMatrix2D(center, angle, scale);

    cv::Mat result;
    cv::warpAffine(input, result,
        rotateMatrix, input.size(),
        cv::INTER_LINEAR, cv::BORDER_CONSTANT);
    output = result;
}
getRotationMatrix2D
CV_EXPORTS Matx23d getRotationMatrix2D_(Point2f center, double angle, double scale);

inline
Mat getRotationMatrix2D(Point2f center, double angle, double scale)
{
   
    return Mat(getRotationMatrix2D_(center, angle, scale), true);
}

opencv中的getRotationMatrix2D()函数

5.3.5 sharpen_plugin

void SharpenPlugin::edit(const cv::Mat &input, cv::Mat &output)
{
   
    int intensity = 2;
    cv::Mat smoothed;
    cv::GaussianBlur(input, smoothed, cv::Size(9, 9), 0);
    output = input + (input - smoothed) * intensity;
}
GaussianBlur
CV_EXPORTS_W void GaussianBlur( InputArray src, OutputArray dst, Size ksize,
                                double sigmaX, double sigmaY = 0,
                                int borderType = BORDER_DEFAULT );

opencv中的GaussianBlur()函数

相关文章
|
2月前
|
算法 计算机视觉
基于qt的opencv实时图像处理框架FastCvLearn实战
本文介绍了一个基于Qt的OpenCV实时图像处理框架FastCvLearn,通过手撕代码的方式详细讲解了如何实现实时人脸马赛克等功能,并提供了结果展示和基础知识回顾。
104 7
基于qt的opencv实时图像处理框架FastCvLearn实战
|
2月前
|
文字识别 计算机视觉 开发者
基于QT的OCR和opencv融合框架FastOCRLearn实战
本文介绍了在Qt环境下结合OpenCV库构建OCR识别系统的实战方法,通过FastOCRLearn项目,读者可以学习Tesseract OCR的编译配置和在Windows平台下的实践步骤,文章提供了技术资源链接,帮助开发者理解并实现OCR技术。
127 9
基于QT的OCR和opencv融合框架FastOCRLearn实战
WK
|
8天前
|
开发框架 开发工具 C++
C++跨平台框架Qt
Qt是一个功能强大的C++跨平台应用程序开发框架,支持Windows、macOS、Linux、Android和iOS等操作系统。它提供了250多个C++类,涵盖GUI设计、数据库操作、网络编程等功能。Qt的核心特点是跨平台性、丰富的类库、信号与槽机制,以及良好的文档和社区支持。Qt Creator是其官方IDE,提供了一整套开发工具,方便创建、编译、调试和运行应用程序。Qt适用于桌面、嵌入式和移动应用开发。
WK
28 5
|
1月前
|
机器学习/深度学习 算法 计算机视觉
【Python篇】Python + OpenCV 全面实战:解锁图像处理与视觉智能的核心技能
【Python篇】Python + OpenCV 全面实战:解锁图像处理与视觉智能的核心技能
66 2
|
2月前
|
C语言 C++ Windows
QT多插件通信框架CTK编译记录
本文记录了编译QT多插件通信框架CTK的过程,包括编译结果截图、部署配置、Log4Qt编译配置、参考链接和拓展资料。文中提供了详细的编译步骤和配置文件示例,以及相关的资源链接。
QT多插件通信框架CTK编译记录
|
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编译记录
|
4月前
|
数据安全/隐私保护 C++ 计算机视觉
Qt(C++)开发一款图片防盗用水印制作小工具
文本水印是一种常用的防盗用手段,可以将文本信息嵌入到图片、视频等文件中,用于识别和证明文件的版权归属。在数字化和网络化的时代,大量的原创作品容易被不法分子盗用或侵犯版权,因此加入文本水印成为了保护原创作品和维护知识产权的必要手段。 通常情况下,文本水印可以包含版权声明、制作者姓名、日期、网址等信息,以帮助识别文件的来源和版权归属。同时,为了增强防盗用效果,文本水印通常会采用字体、颜色、角度等多种组合方式,使得水印难以被删除或篡改,有效地降低了盗用意愿和风险。 开发人员可以使用图像处理技术和编程语言实现文本水印的功能,例如使用Qt的QPainter类进行文本绘制操作,将文本信息嵌入到图片中,
180 1
Qt(C++)开发一款图片防盗用水印制作小工具
|
3月前
|
监控 C++ 容器
【qt】MDI多文档界面开发
【qt】MDI多文档界面开发
88 0
|
2月前
|
开发工具 C++
qt开发技巧与三个问题点
本文介绍了三个Qt开发中的常见问题及其解决方法,并提供了一些实用的开发技巧。
|
2月前