当前位置: 首页 > 编程日记 > 正文

基于qml创建最简单的图像处理程序(1)-基于qml创建界面

 《基于qml创建最简单的图像处理程序》系列课程及配套代码
基于qml创建最简单的图像处理程序(1)-基于qml创建界面
http://www.cnblogs.com/jsxyhelu/p/8343310.html
课程1附件
https://files.cnblogs.com/files/jsxyhelu/%E9%98%B6%E6%AE%B5%E4%BB%A3%E7%A0%811.zip
基于qml创建最简单的图像处理程序(2)-使用c++&qml进行图像处理
http://www.cnblogs.com/jsxyhelu/p/8361441.html
课程2附件
https://files.cnblogs.com/files/jsxyhelu/%E9%98%B6%E6%AE%B5%E4%BB%A3%E7%A0%812.zip
基于qml创建最简单的图像处理程序(3)-使用opencv&qml进行图像处理
http://www.cnblogs.com/jsxyhelu/p/8361443.html
课程3附件
https://files.cnblogs.com/files/jsxyhelu/%E9%98%B6%E6%AE%B5%E4%BB%A3%E7%A0%813.zip

  为什么使用QT,包括进一步使用QML?两个主要原因,一是因为我是一个c++程序员,有语言使用惯性;二是我主要做图像处理方面工作,使用什么平台对于我来说不重要,我只需要在不同平台上面能够运行我的图像处理程序(而主要是和OpenCV有关系的)。所以选择QT,它能够在win/linux/android,包括PI上面都提供不错的GUI支持;而如果我想在Android上编写图像处理程序,又主要遇到两个问题,一是相机的获取。OpenCV的videocapture在Android上支持不好,在最新版本的OpenCV里面已经把这个部分相关内容去掉了,同时QCamera(基于widget的camera)支持也不好,Qml是目前对Android支持最好的。这个地方QML提供的camera功能就类似windows中的dshow一样,是一个基础类库;二是界面的创建,在windows下面,基于ribbon等,我能够创建还说的过去的界面,但是在Android中,目前没有很好的工具。特别是在手机这个小小界面中,如果界面有问很影响使用。

       我需要的是一个界面说的过去(有官方控件),对相机支持好,能够支持各种平台的这么一个工具,不求最好,但是要能用。在不多的选择中,QML(qtquick)是最合适的。当然如果要掌握QML也要跨越一些学习曲线,但是付出是值得的。
        本文中参考了一些资料(主要是《qtquick核心编程》),我们基于qml创建最简单的图像处理程序。两个主要内容,一个是直接使用qml自己的能力进行图像处理;二个是引用并且使用OpenCV。只求实现主要功能,很多细节还需打磨,但我相信瑕不掩瑜。
 
新建工程,最新默认的界面main.qml代码为
import QtQuick 2.9
import QtQuick.Window 2.2

Window {
visible: true
width: 640
height: 480
}

我就直接在这个QML上进行修改
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 1.1
import QtQuick.Dialogs 1.1
import QtQuick.Controls.Styles 1.1
Window {
    visible: true
    width: 640
    height: 480
    //RGB
    color: "#0000FF";

    //忙等控件,包含在QtQuick.Controls中
    BusyIndicator {
        id: busy;
        running: false;
        anchors.centerIn: parent;
        z: 2;
    }
    //状态显示Label
    Label {
        id: stateLabel;
        visible: false;
        anchors.centerIn: parent;
    }
    //主要界面
    Image {
        objectName: "imageViewer";
        id: imageViewer;
        asynchronous: true;
        anchors.fill: parent;
        fillMode: Image.PreserveAspectFit;
        //根据imageviewer状态判断,控制控件表现出不同状态
        onStatusChanged: {
            if (imageViewer.status === Image.Loading) {
                busy.running = true;
                stateLabel.visible = false;
            }
            else if(imageViewer.status === Image.Ready){
                busy.running = false;
            }
            else if(imageViewer.status === Image.Error){
                busy.running = false;
                stateLabel.visible = true;
                stateLabel.text = "ERROR";
            }
        }
    }

    //打开文件界面,包含在 QtQuick.Dialogs 中。固然在Android中使用这个方法打开图片不是最佳方法,但是可用方法
    FileDialog {
        id: fileDialog;
        title: "Please choose a file";
        nameFilters: ["Image Files (*.jpg *.png *.gif)"];
        onAccepted: {
            console.log(fileDialog.fileUrl);
            imageViewer.source = fileDialog.fileUrl;
        }
    }

    //以下用于创建button,其中ButtonStyle来自QtQuick.Controls.Styles
    //其中所谓Component就是可重用构建的意思,这个用于Button的Componet是可以复用的
    Component{
        id: btnStyle;
        ButtonStyle {
            background: Rectangle {
                implicitWidth: 140;
                implicitHeight: 50;
                border.width: control.pressed ? 2 : 1;
                border.color: (control.pressed || control.hovered) ? "#00A060" : "#888888";
                radius: 12;
                gradient: Gradient {
                    GradientStop { position: 0 ; color: control.pressed ? "#cccccc" : "#e0e0e0"; }
                    GradientStop { position: 1 ; color: control.pressed ? "#aaa" : "#ccc"; }
                }
            }
        }
    }
    //就是做了个黑色的框子,用于放button的
    Rectangle {
        anchors.left: parent.left;
        anchors.top: parent.top;
        anchors.bottom: openFile.bottom;
        anchors.bottomMargin: -6;
        anchors.right: quit.right;
        anchors.rightMargin: -6;
        color: "#404040";
        opacity: 0.7;
    }

    //打开按钮
    Button {
        id: openFile;
        text: "打开";
        anchors.left:  parent.left;
        anchors.leftMargin: 6;
        anchors.top: parent.top;
        anchors.topMargin: 6;
        onClicked: {
            fileDialog.visible = true;
        }
        //直接使用了btnStyle
        style: btnStyle;
        z: 1;
    }
    //退出就是退出
    Button {
        id: quit;
        text: "退出";
        anchors.left: openFile.right;
        anchors.leftMargin: 4;
        anchors.bottom: openFile.bottom;
        onClicked: {
            Qt.quit()
        }
        style: btnStyle;
        z: 1;
    }

    //另外一个黑色框子,注意用到了op,也就是上面的4个按钮

    Rectangle {
        anchors.left: parent.left;
        anchors.top: op.top;
        anchors.topMargin: -4;
        anchors.bottom: parent.bottom;
        anchors.right: op.right;
        anchors.rightMargin: -4;
        color: "#404040";
        opacity: 0.7;
    }

    //以另一种方式将几个按钮连在一起
    //我们实现4个比较简单的效果
    Grid {
        id: op;
        anchors.left: parent.left;
        anchors.leftMargin: 4;
        anchors.bottom: parent.bottom;
        anchors.bottomMargin: 4;
        rows: 2;
        columns: 2;
        rowSpacing: 4;
        columnSpacing: 4;
        z: 1;
        //柔化效果
        Button {
            text: "柔化";
            style: btnStyle;
            onClicked: {
                //busy.running = true;
                //processor.process(fileDialog.fileUrl, ImageProcessor.Soften);
            }
        }
        //灰度效果
        Button {
            text: "灰度";
            style: btnStyle;
            onClicked: {
                //busy.running = true;
                //processor.process(fileDialog.fileUrl, ImageProcessor.Gray);
            }
        }
        //浮雕效果
        Button {
            text: "浮雕";
            style: btnStyle;
            onClicked: {
                //busy.running = true;
                //processor.process(fileDialog.fileUrl, ImageProcessor.Emboss);
            }
        }
        //黑白效果
        Button {
            text: "黑白";
            style: btnStyle;
            onClicked: {
                //busy.running = true;
                //processor.process(fileDialog.fileUrl, ImageProcessor.Binarize);
            }
        }
    }

}
 
虽然代码代码看上去有点多,但是好在还算有结构。
1、头文件,不多说。用在哪里的看注释;
2、全部的界面都包含在Windos{}中的
Window {
    visible: true
    width: 640
    height: 480
    //RGB
    color: "#0000FF";
……
在这段代码中width和height已经没有什么实际价值了。需要注意的是color为背景色,而qml是按照RGB来定义的。
3、控件控件,全部都是控件的定义。我们使用QML就要习惯直接使用代码定义的方式精确地进行界面定位,包含以下:

 //忙等控件,包含在QtQuick.Controls中
    BusyIndicator {
        id: busy;
        running: false;
        anchors.centerIn: parent;
        z: 2;
    }

 //状态显示Label
    Label {
        id: stateLabel;
        visible: false;
        anchors.centerIn: parent;
    }

    //主要图片显示
    Image {
        objectName: "imageViewer";
        id: imageViewer;
        asynchronous: true;
        anchors.fill: parent;
        fillMode: Image.PreserveAspectFit;
        //根据imageviewer状态判断,控制控件表现出不同状态
        onStatusChanged: {
            if (imageViewer.status === Image.Loading) {
                busy.running = true;
                stateLabel.visible = false;
            }
            else if(imageViewer.status === Image.Ready){
                busy.running = false;
            }
            else if(imageViewer.status === Image.Error){
                busy.running = false;
                stateLabel.visible = true;
                stateLabel.text = "ERROR";
            }
        }
    }

 //打开文件界面,包含在 QtQuick.Dialogs 中。固然在Android中使用这个方法打开图片不是最佳方法,但是可用方法
    FileDialog {
        id: fileDialog;
        title: "Please choose a file";
        nameFilters: ["Image Files (*.jpg *.png *.gif)"];
        onAccepted: {
            console.log(fileDialog.fileUrl);
            imageViewer.source = fileDialog.fileUrl;
        }
    }
4、按钮控件,但是使用了一些可重用思想

//以下用于创建button,其中ButtonStyle来自QtQuick.Controls.Styles
    //其中所谓Component就是可重用构建的意思,这个用于Button的Componet是可以复用的
    Component{
        id: btnStyle;
        ButtonStyle {
            background: Rectangle {
                implicitWidth: 140;
                implicitHeight: 50;
                border.width: control.pressed ? 2 : 1;
                border.color: (control.pressed || control.hovered) ? "#00A060" : "#888888";
                radius: 12;
                gradient: Gradient {
                    GradientStop { position: 0 ; color: control.pressed ? "#cccccc" : "#e0e0e0"; }
                    GradientStop { position: 1 ; color: control.pressed ? "#aaa" : "#ccc"; }
                }
            }
        }
    }


 //打开按钮
    Button {
        id: openFile;
        text: "打开";
        anchors.left:  parent.left;
        anchors.leftMargin: 6;
        anchors.top: parent.top;
        anchors.topMargin: 6;
        onClicked: {
            fileDialog.visible = true;
        }
        //直接使用了btnStyle
        style: btnStyle;
        z: 1;
    }
    //退出就是退出
    Button {
        id: quit;
        text: "退出";
        anchors.left: openFile.right;
        anchors.leftMargin: 4;
        anchors.bottom: openFile.bottom;
        onClicked: {
            Qt.quit()
        }
        style: btnStyle;
        z: 1;
    }
5、将按钮放在一起,我们使用grid
//以另一种方式将几个按钮连在一起
    //我们实现4个比较简单的效果
    Grid {
        id: op;
        anchors.left: parent.left;
        anchors.leftMargin: 4;
        anchors.bottom: parent.bottom;
        anchors.bottomMargin: 4;
        rows: 2;
        columns: 2;
        rowSpacing: 4;
        columnSpacing: 4;
        z: 1;
        //柔化效果
        Button {
            text: "柔化";
            style: btnStyle;
            onClicked: {
                //busy.running = true;
                //processor.process(fileDialog.fileUrl, ImageProcessor.Soften);
            }
        }
        //灰度效果
        Button {
            text: "灰度";
            style: btnStyle;
            onClicked: {
                //busy.running = true;
                //processor.process(fileDialog.fileUrl, ImageProcessor.Gray);
            }
        }
        //浮雕效果
        Button {
            text: "浮雕";
            style: btnStyle;
            onClicked: {
                //busy.running = true;
                //processor.process(fileDialog.fileUrl, ImageProcessor.Emboss);
            }
        }
        //黑白效果
        Button {
            text: "黑白";
            style: btnStyle;
            onClicked: {
                //busy.running = true;
                //processor.process(fileDialog.fileUrl, ImageProcessor.Binarize);
            }
        }
    }


6、两个黑色框子,没有其它用途,就是美观
//就是做了个黑色的框子,用于放button的
    Rectangle {
        anchors.left: parent.left;
        anchors.top: parent.top;
        anchors.bottom: openFile.bottom;
        anchors.bottomMargin: -6;
        anchors.right: quit.right;
        anchors.rightMargin: -6;
        color: "#404040";
        opacity: 0.7;
    }
 
//另外一个黑色框子,注意用到了op,也就是上面的4个按钮
    Rectangle {
        anchors.left: parent.left;
        anchors.top: op.top;
        anchors.topMargin: -4;
        anchors.bottom: parent.bottom;
        anchors.right: op.right;
        anchors.rightMargin: -4;
        color: "#404040";
        opacity: 0.7;
    }
 
这个时候已经有以下界面,能够打开显示图片了
 
打开图片,显示图片

相关文章:

存储方式与介质对性能的影响

摘要 数据的存储方式对应用程序的整体性能有着极大的影响。对数据的存取,是顺利读写还是随机读写?将数据放磁盘上还将数据放flash卡上?多线程读写对性能影响?面对着多种数据存储方式,我们如何选择?本文给大…

struts配置文件没有标签提示

2019独角兽企业重金招聘Python工程师标准>>> struts配置文件没有标签提示 原因:" http://struts.apache.org/dtds/struts-2.0.dtd"是通过网络的形式帮你下载对应的dtd文件, 如果机器没有联网,就不会有提示 解决办法&…

iPhone 隐私新规下的“大地震”:四大平台损失近百亿美元,“连用户是男是女都分不清……”

整理 | 郑丽媛 出品 | CSDN(ID:CSDNnews) 大家有这样的经历吗?前一秒刚在聊天软件上跟朋友分享了一款产品,下一秒就能在其他 App 中看到这款产品的广告推送,不了解内情的人说不定还会感慨一句:“…

Python 判断类型

类型判断:isinstance(obj, type) 方法 : isinstance(obj, type) print (isinstance(3, int)) # True print (isinstance(3, str)) # False print (isinstance(3, list)) # False print (isinstance([1,2,3], list)) …

php打印warning日志引发的core追查

内容 春节期间线上出了两个php-cgi的core,具体追查过程如下: 一、 Core信息 file core.xxx bug.php-cgi.3611.1296586902: ELF 64-bit LSB core file AMD x86-64, version 1 (SYSV), SVR4-style, from ‘php-cgi’ gdb ~/php5/bin/php-cgi core.xx…

BIZTALK项目中WEB引用WEBSERVICES服务时候报错

近期工作中须要完毕通过BIZTALK完毕调用WEBLOGIC公布的WebServices服务,环境搭建好后,打开VS开发工具新建一个BIZTALK项目,加入WEB引用将对方公布的地址拷贝上去,能够正常浏览到,然后点击加入引用button,这…

百度“知识增强的跨模态语义理解技术”获国家技术发明奖

11月3日,2020年度国家科学技术奖励大会在京举行,百度“知识增强的跨模态语义理解关键技术及应用”获国家技术发明二等奖。 该技术旨在通过构建大规模知识图谱,关联跨模态信息,通过知识增强的自然语言语义表示方法,解决…

Objective C浅拷贝和深拷贝

##浅拷贝 浅拷贝就是对内存地址的复制,让目标对象指针和源对象指向同一片内存空间。如: char* str (char*)malloc(100); char* str2 str; 复制代码浅拷贝只是对对象的简单拷贝,让几个对象共用一片内存,当内存销毁的时候&#xf…

我常用的那些linux命令

我常用的那些linux命令 用linux也有些年头了,说来也忏愧,说是有些年头了,其实也还是个不长进的主。记得第一次接触linux是boss跟我说的怎么操作,什么编辑模式,按i,a,o进入编辑模式。在一个黑乎乎…

2021腾讯数字生态大会:腾讯安全聚焦安全共建,护航数字经济发展

11月3日,以“数实融合 绽放新机”为主题的2021腾讯数字生态大会在武汉开幕。在首日的主峰会上,多位腾讯高管及行业领袖、企业家对数字时代如何建设安全底座,发表了看法。 腾讯高级执行副总裁、云与智慧产业事业群CEO汤道生指出,没…

Oauth认证协议

原文地址腾讯QQ第三方登录的实现原理? Oauth当中的角色: 1.Service Provider(服务提供方): 服务提供方通常是网站,在这些网站当中存储着一些受限制的资源,如照片、视频、联系人列表等。这些网站…

“分布式哈希”和“一致性哈希”的概念与算法实现

分布式哈希和一致性哈希是分布式存储和p2p网络中说的比较多的两个概念了。介绍的论文很多,这里做一个入门性质的介绍。 分布式哈希(DHT)   两个key point:每个节点只维护一部分路由;每个节点只存储一部分数据。从而实现整个网络中的寻址和存…

7000 字 23 张图,Pandas一键生成炫酷的动态交互式图表

作者 | 俊欣来源 | 关于数据分析与可视化今天小编来演示一下如何用pandas一行代码来绘制可以动态交互的图表,并且将绘制的图表组合到一起,组成可视化大屏,本次小编将要绘制的图表有折线图散点图直方图柱状图饼图面积图地图组合图准备工作我们…

手把手教你使用zabbix监控nginx

zabbix监控nginx,多亏了容哥(杨容)的帮忙,为了感谢容哥的帮助,写了这篇文章。环境介绍:服务器系统版本:CentOSrelease 6.6 (Final)内核版本:Linux hk_nginx2.6.32-504.3.3.el6.x86_64ZabbixServer版本&…

理解多线程设计模式

多线程设计模式:1.Single Threaded Execution Pattern [同一时刻只允许一个线程操作] 比喻:三个挑水的和尚,只能同一时间一个人过桥,不然都掉河里喂鱼了。 总结:在多个线程同时要访问的方法上加上synchronized关键…

Linux内核之旅

内核模块是Linux内核向外部提供的一个插口,其全称为动态可加载内核模块(Loadable Kernel Module,LKM),我们简称为模块。Linux内核之所以提供模块机制,是因为它本身是一个单内核(monolithic kern…

qq腾讯第三方登陆

html页面&#xff1a;<html> <head> <meta charset"utf-8" /> <title>第三方登录</title> <meta property"qc:admins" content"1541324001721762700063671645060454" /> </h…

如何利用 Python 爬取 LOL 高清精美壁纸?

作者 | 阿拉斯加 来源 | 杰哥的IT之旅 一、背景介绍 随着移动端的普及出现了很多的移动 APP&#xff0c;应用软件也随之流行起来。最近看到英雄联盟的手游上线了&#xff0c;感觉还行&#xff0c;PC 端英雄联盟可谓是爆火的游戏&#xff0c;不知道移动端的英雄联盟前途如何&…

生产环境主从数据同步不了?

生产环境主从数据同步不了&#xff1f;经历过程&#xff1a; 一般我们常常在做主从复制的时候&#xff0c;可能是很少遇到到错误&#xff0c;那都是因为&#xff0c;你做主从基本用的是&#xff0c;本地虚拟机做&#xff0c;或者一些测试环境做。但是当我们把主从复制部署…

用 YOLOv5模型识别出表情!

作者 | 闫永强来源 | Datawhale本文利用YOLOV5对手势进行训练识别&#xff0c;并识别显示出对应的emoji&#xff0c;如同下图&#xff1a;本文整体思路如下。提示&#xff1a;本文含完整实践代码&#xff0c;代码较长&#xff0c;建议先看文字部分的实践思路&#xff0c;代码先…

Linux操作系统中内存buffer和cache的区别

我们一开始&#xff0c;先从Free命令说起。 free 命令相对于top 提供了更简洁的查看系统内存使用情况&#xff1a; $ freetotal used free shared buffers cachedMem: 255268 238332 16936 0 85540 126384-/ buffers/cache: 26408 228860Swap: 265000 …

sort cut 命令的常用用法

sort命令介绍&#xff1a;sort是在Linux里非常常用的一个命令&#xff0c;管排序的&#xff0c;集中精力&#xff0c;五分钟搞定sort&#xff0c;现在开始&#xff01;1 sort的工作原理sort将文件的每一行作为一个单位&#xff0c;相互比较&#xff0c;比较原则是从首字符向后&…

使用 dockerfile 创建镜像

dockerfile 是一个文本格式的配置文件&#xff0c;可以使用 dockerfile 快速创建自定义的镜像。 dockerfile 一般包含4部分信息&#xff1a;基础镜像信息、维护者信息、镜像操作指令、容器启动时执行指令 创建镜像命令&#xff1a;docker build [选项] 路径&#xff0c;会读取指…

wireshark的使用教程--用实践的方式帮助我们理解TCP/IP中的各个协议是如何工作的

wireshark的使用教程 --用实践的方式帮助我们理解TCP/IP中的各个协议是如何工作的 wireshark是一款抓包软件&#xff0c;比较易用&#xff0c;在平常可以利用它抓包&#xff0c;分析协议或者监控网络&#xff0c;是一个比较好的工具&#xff0c;因为最近在研究这个&#xff0c;…

设计师你们还坐的住吗?2021 PS 进入人工智能 P 图时代

与每年一样&#xff0c;Adobe 的 Max 2021 活动顺利开展。本次活动主要是以产品展示以及其他创新产品。 这个活动最有趣的特点之一是&#xff0c;Adobe 不断将人工智能集成到其产品或是功能中。在过去的几年里&#xff0c;人工智能一直是这家公司不断探索的领域。 与许多其他公…

图像处理之噪声---椒盐,白噪声,高斯噪声三种不同噪声的区别

白噪声是指功率谱密度在整个频域内均匀分布的噪声。 所有频率具有相同能量的随机噪声称为白噪声。白噪声或白杂讯&#xff0c;是一种功率频谱密度为常数的随机信号或随机过程。换句话说&#xff0c;此信号在各个频段上的功率是一样的&#xff0c;由于白光是由各种频率&#xff…

发现一个“佛系记账本”

因为这是一款微信小程序&#xff0c;张小龙大力推崇的“用完即走”完美地适合记账应用。 不用下载、不用安装、不用注册、不用各种授权&#xff0c;只要从微信进入&#xff0c;就能记账&#xff0c;账本只与微信关联。 换手机、换PAD都无所谓&#xff0c;只要登录微信&#xff…

YSLOW法则中,为什么yahoo推荐用GET代替POST?

原文&#xff1a;http://www.cnxct.com/use-get-for-ajax-requests-why/ 背景&#xff1a;上上周五&#xff0c;公司前端工程师培训&#xff0c;提到前端优化的一些技巧&#xff0c;当然不能少了yahoo yslow的优化法则。其中有这么一条“Use GET for AJAX Requests”&#xff0…

Python 多进程、协程异步抓取英雄联盟皮肤并保存在本地

作者 | 俊欣来源 | 关于数据分析与可视化就在11月7日晚间&#xff0c;《英雄联盟》S11赛季全球总决赛决斗&#xff0c;在冰岛拉开“帷幕”&#xff0c;同时面向全球直播。在经过了5个小时的鏖战&#xff0c;EDG战队最终以3:2战胜来自韩国LCK赛区的DK战队&#xff0c;获得俱乐部…

QT 5.4.1 for Android Ubuntu QtWebView Demo

QT 5.4.1 for Android Ubuntu QtWebView Demo 2015-5-15 目录 一、说明&#xff1a; 二、参考文章&#xff1a; 三、QtWebView Demo在哪里&#xff1f; 四、Qt Creator 3.4.0能打开QtWebView Demo&#xff1f; 五、Qt Creator如何生成AndroidManifest.xml&#xff1f; 一、…