基於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;
    }
 
這個時候已經有以下界面,能夠打開顯示圖片了
 
 
打開圖片,顯示圖片
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM