import Qt.labs.platform import QtQuick import QtQuick.Controls import QtQuick.Controls.Material import QtQuick.Layouts import QtQuick.Dialogs import "Components" import Util 1.0 ApplicationWindow { visibility: "Maximized" visible: true title: qsTr("图像处理工具") Material.theme: Material.Dark Material.accent: Material.LightBlue menuBar: MenuBar { FileDialog { id: openDialog title: qsTr("打开图片") nameFilters: ["图片文件 (*.jpg *.png)"] onAccepted: { imageItem.readFile(selectedFile) } } FileDialog { id: saveDialog title: qsTr("保存图片") fileMode: FileDialog.SaveFile nameFilters: ["图片文件 (*.jpg *.png)"] onAccepted: { imageItem.saveFile(selectedFile) } } Menu { title: qsTr("文件") Action { text: qsTr("打开") onTriggered: { openDialog.open() } } Action { text: qsTr("保存") onTriggered: { saveDialog.open() } } } Menu { title: qsTr("操作") Action { text: qsTr("撤销") onTriggered: { imageItem.withdraw() } } } } Pane { anchors.fill: parent RowLayout { anchors.fill: parent spacing: 25 ListView { id: tab Layout.fillHeight: true Layout.preferredWidth: contentItem.childrenRect.width currentIndex: 0 spacing: 10 model: ["图像变换", "图形绘制", "灰度变换", "边缘检测", "图像平滑", "形态处理", "噪声添加", "风格迁移"] delegate: TabButton { text: qsTr(modelData) checked: tab.currentIndex === index onClicked: { tab.currentIndex = index } } Pane { z: -1 anchors.fill: parent Material.elevation: 8 } } ImageItem { id: imageItem Layout.fillHeight: true Layout.fillWidth: true Pane { z: -1 anchors.fill: parent Material.elevation: 8 } MouseArea { id: imageItemArea anchors.fill: parent property int ix property int iy property bool isSelecting: false signal select(point point) onPressed: { if (isSelecting) { return } cursorShape = Qt.ClosedHandCursor ix = mouseX iy = mouseY } onReleased: { if (isSelecting) { return } cursorShape = Qt.ArrowCursor } onPositionChanged: { if (isSelecting) { return } if (pressed) { parent.moveBy(ix - mouseX, iy - mouseY) } ix = mouseX iy = mouseY } onClicked: { if (isSelecting) { const point = imageItem.getPoint(mouseX, mouseY) select(point) } imageItemArea.isSelecting = false } } } Pane { Material.elevation: 8 Layout.fillHeight: true Layout.preferredWidth: 250 StackLayout { anchors.fill: parent currentIndex: tab.currentIndex Section { Operation { title: qsTr("消除通道") Labelrow { text: qsTr("通道") ComboBox { id: removeChannel_channel model: ["r", "g", "b"] } } onSubmitted: { imageItem.removeChannel( removeChannel_channel.currentIndex) } } Operation { title: qsTr("平移") Labelrow { text: qsTr("左右") Floatspin { id: translation_dx from: -1000 to: 1000 decimals: 0 stepSize: 1 defaultValue: 0 } } Labelrow { text: qsTr("上下") Floatspin { id: translation_dy from: -1000 to: 1000 decimals: 0 stepSize: 1 defaultValue: 0 } } Labelrow { text: qsTr("填充") Selectcolor { id: translation_border } } onSubmitted: { imageItem.translation(translation_dx.value, translation_dy.value, translation_border.color) } } Operation { title: qsTr("旋转") Labelrow { text: qsTr("模式") ComboBox { id: rotation_combobox model: ["中心旋转", "直角旋转"] } } StackLayout { Layout.fillWidth: true currentIndex: rotation_combobox.currentIndex Labelrow { text: qsTr("角度") Floatspin { Layout.fillWidth: true id: centralRotation_theta from: 0 to: 360 decimals: 0 stepSize: 1 } } Labelrow { text: qsTr("方式") ComboBox { id: rightAngleRotation_theta model: ["不旋转", "顺时针90°", "180°", "逆时针90°"] } } } onSubmitted: { switch (rotation_combobox.currentIndex) { case 0: imageItem.centralRotation( centralRotation_theta.value) break case 1: imageItem.rightAngleRotation( rightAngleRotation_theta.currentIndex) break } } } Operation { title: qsTr("翻转") Labelrow { text: qsTr("模式") ComboBox { id: flip_combobox model: ["不翻转", "垂直翻转", "水平翻转", "水平垂直翻转"] } } onSubmitted: { imageItem.flip(flip_combobox.currentIndex) } } Operation { title: qsTr("缩放") Labelrow { text: qsTr("宽度") Floatspin { id: resize_width_size from: 0.01 to: 3.00 decimals: 2 } } Labelrow { text: qsTr("高度") Floatspin { id: resize_height_size from: 0.01 to: 3.00 decimals: 2 } } onSubmitted: { imageItem.resize(resize_width_size.value, resize_height_size.value) } } Operation { title: qsTr("仿射变换") onSubmitted: { imageItem.affine() } } Operation { title: qsTr("错切") onSubmitted: { imageItem.shear() } } Operation { title: qsTr("投影变换") onSubmitted: { imageItem.projective() } } } Section { Operation { title: qsTr("直线") Labelrow { text: qsTr("起点") Selectpoint { id: line_start area: imageItemArea } } Labelrow { text: qsTr("终点") Selectpoint { id: line_end area: imageItemArea } } Labelrow { text: qsTr("颜色") Selectcolor { id: line_color } } Labelrow { text: qsTr("线宽") Floatspin { id: line_width from: 1 to: 10 decimals: 0 } } onSubmitted: { imageItem.line(line_start.point, line_end.point, line_color.color, line_width.value) } } Operation { title: qsTr("矩形") Labelrow { text: qsTr("顶点") Selectpoint { id: rectangle_start area: imageItemArea } } Labelrow { text: qsTr("对顶点") Selectpoint { id: rectangle_end area: imageItemArea } } Labelrow { text: qsTr("颜色") Selectcolor { id: rectangle_color } } Labelrow { text: qsTr("线宽") Floatspin { id: rectangle_width from: 1 to: 10 decimals: 0 } } onSubmitted: { imageItem.rectangle(rectangle_start.point, rectangle_end.point, rectangle_color.color, rectangle_width.value) } } Operation { title: qsTr("圆形") Labelrow { text: qsTr("圆心") Selectpoint { id: circle_center area: imageItemArea } } Labelrow { text: qsTr("圆上一点") Selectpoint { id: circle_side area: imageItemArea } } Labelrow { text: qsTr("颜色") Selectcolor { id: circle_color } } Labelrow { text: qsTr("线宽") Floatspin { id: circle_width from: 1 to: 10 decimals: 0 } } onSubmitted: { imageItem.circle(circle_center.point, circle_side.point, circle_color.color, circle_width.value) } } Operation { title: qsTr("文字") Labelrow { text: qsTr("左下角") Selectpoint { id: text_start area: imageItemArea } } Labelrow { text: qsTr("颜色") Selectcolor { id: text_color } } Labelrow { text: qsTr("字号") Floatspin { id: text_fontsize from: 1 to: 10 decimals: 0 defaultValue: 4 } } Labelrow { text: qsTr("线宽") Floatspin { id: text_width from: 1 to: 10 decimals: 0 } } Labelrow { text: qsTr("内容") TextField { id: text_text validator: RegularExpressionValidator { regularExpression: /[0-9A-Za-z]+/ } } } onSubmitted: { imageItem.text(text_start.point, text_color.color, text_fontsize.value, text_width.value, text_text.text) } } } Section { Operation { title: qsTr("二值化") Labelrow { text: qsTr("阈值") Floatspin { id: binaryTransformation_thresh from: 0 to: 255 decimals: 0 defaultValue: 100 } } onSubmitted: { imageItem.binaryTransformation( binaryTransformation_thresh.value) } } Operation { title: qsTr("分段线性变换") onSubmitted: { imageItem.linearGrayscaleTransformation() } } Operation { title: qsTr("灰度级分层") Labelrow { text: qsTr("下界") Floatspin { id: grayLayered_low_thresh from: 0 to: 255 decimals: 0 defaultValue: 45 } } Labelrow { text: qsTr("上界") Floatspin { id: grayLayered_high_thresh from: grayLayered_low_thresh.value to: 255 decimals: 0 defaultValue: 155 } } onSubmitted: { imageItem.grayLayered( grayLayered_low_thresh.value, grayLayered_high_thresh.value) } } Operation { title: qsTr("对数变换") onSubmitted: { imageItem.logTrans() } } Operation { title: qsTr("幂律变换") Labelrow { text: qsTr("γ") Floatspin { id: gammaTrans_gamma from: 0.01 to: 25 decimals: 2 defaultValue: 2 } } onSubmitted: { imageItem.gammaTrans(gammaTrans_gamma.value) } } Operation { title: qsTr("灰度直方图") onSubmitted: { imageItem.grayHistogram() } } } Section { Operation { title: qsTr("基本算子") Labelrow { text: qsTr("算子") ComboBox { id: edgeProcessing_operator model: ["Roberts", "Sobel", "Prewitt", "Laplacian"] } } onSubmitted: { switch (edgeProcessing_operator.currentIndex) { case 0: imageItem.roberts() break case 1: imageItem.sobel() break case 2: imageItem.prewitt() break case 3: imageItem.laplacian() break } } } Operation { title: qsTr("LoG算子") Labelrow { text: qsTr("卷积核") Floatspin { id: loG_size from: 3 to: 7 decimals: 0 } } Labelrow { text: qsTr("σ") Floatspin { id: loG_sigma from: 0.01 to: 25 decimals: 2 defaultValue: 0.8 } } onSubmitted: { imageItem.loG(loG_size.value, loG_sigma.value) } } Operation { title: "Canny算子" Labelrow { text: qsTr("卷积核") Floatspin { id: canny_size from: 3 to: 7 decimals: 0 defaultValue: 5 } } Labelrow { text: qsTr("下界") Floatspin { id: canny_low_thresh from: 0 to: 255 decimals: 0 defaultValue: 50 } } Labelrow { text: qsTr("上界") Floatspin { id: canny_high_thresh from: canny_low_thresh.value to: 255 decimals: 0 defaultValue: 150 } } onSubmitted: { imageItem.canny(canny_size.value, canny_low_thresh.value, canny_high_thresh.value) } } } Section { Operation { title: qsTr("空域平滑") Labelrow { text: qsTr("算法") ComboBox { id: smoothSpace model: ["均值滤波", "中值滤波"] } } StackLayout { Layout.fillWidth: true currentIndex: smoothSpace.currentIndex Labelrow { text: qsTr("卷积核") Floatspin { id: blur_size from: 3 to: 7 decimals: 0 } } Labelrow { text: qsTr("卷积核") Floatspin { id: medianBlur_size from: 3 to: 7 decimals: 0 } } } onSubmitted: { switch (smoothSpace.currentIndex) { case 0: imageItem.blur(blur_size.value) break case 1: imageItem.medianBlur(medianBlur_size.value) break } } } Operation { title: qsTr("频域平滑") Labelrow { text: qsTr("算法") ComboBox { id: smoothFrequency model: ["理想低通滤波", "巴特沃斯滤波", "高斯滤波"] } } StackLayout { currentIndex: smoothFrequency.currentIndex Layout.fillWidth: true Layout.preferredHeight: children[currentIndex].height Labelrow { Layout.fillHeight: false text: qsTr("D0") Floatspin { id: lowPassIdealBlur_d0 from: 1 to: 2000 decimals: 0 defaultValue: 20 } } ColumnLayout { Layout.fillHeight: false Labelrow { text: qsTr("D0") Floatspin { id: lowPassButterworthBlur_d0 from: 1 to: 200 decimals: 0 defaultValue: 20 } } Labelrow { text: qsTr("n") Floatspin { id: lowPassButterworthBlur_n from: 1 to: 10 decimals: 0 defaultValue: 2 } } } Labelrow { Layout.fillHeight: false text: qsTr("D0") Floatspin { id: lowPassGaussianBlur_d0 from: 1 to: 200 decimals: 0 defaultValue: 20 } } } onSubmitted: { switch (smoothFrequency.currentIndex) { case 0: imageItem.lowPassIdealBlur( lowPassIdealBlur_d0.value) break case 1: imageItem.lowPassButterworthBlur( lowPassButterworthBlur_d0.value, lowPassButterworthBlur_n.value) break case 2: imageItem.lowPassGaussianBlur( lowPassGaussianBlur_d0.value) break } } } } Section { Operation { title: qsTr("腐蚀") Labelrow { text: qsTr("形状") ComboBox { id: erode_shape model: ["矩形", "十字", "椭圆"] } } Labelrow { text: qsTr("大小") Floatspin { id: erode_size from: 3 to: 7 decimals: 0 defaultValue: 5 } } onSubmitted: { imageItem.erode(erode_shape.currentIndex, erode_size.value) } } Operation { title: qsTr("膨胀") Labelrow { text: qsTr("形状") ComboBox { id: dilate_shape model: ["矩形", "十字", "椭圆"] } } Labelrow { text: qsTr("大小") Floatspin { id: dilate_size from: 3 to: 7 decimals: 0 defaultValue: 5 } } onSubmitted: { imageItem.dilate(dilate_shape.currentIndex, dilate_size.value) } } Operation { title: qsTr("开运算") Labelrow { text: qsTr("形状") ComboBox { id: open_shape model: ["矩形", "十字", "椭圆"] } } Labelrow { text: qsTr("大小") Floatspin { id: open_size from: 3 to: 7 decimals: 0 defaultValue: 5 } } onSubmitted: { imageItem.open(open_shape.currentIndex, open_size.value) } } Operation { title: qsTr("闭运算") Labelrow { text: qsTr("形状") ComboBox { id: close_shape model: ["矩形", "十字", "椭圆"] } } Labelrow { text: qsTr("大小") Floatspin { id: close_size from: 3 to: 7 decimals: 0 defaultValue: 5 } } onSubmitted: { imageItem.close(close_shape.currentIndex, close_size.value) } } } Section { Operation { title: qsTr("高斯噪声") Labelrow { text: qsTr("μ") Floatspin { id: gaussNoise_mu from: 0.0 to: 10.0 decimals: 1 } } Labelrow { text: qsTr("σ") Floatspin { id: gaussNoise_sigma from: 0.0 to: 25.0 decimals: 1 defaultValue: 20.0 } } onSubmitted: { imageItem.gaussNoise(gaussNoise_mu.value, gaussNoise_sigma.value) } } Operation { title: qsTr("指数噪声") Labelrow { text: qsTr("a") Floatspin { id: expNoise_a from: 0.0 to: 25.0 decimals: 1 defaultValue: 10.0 } } onSubmitted: { imageItem.expNoise(expNoise_a.value) } } Operation { title: qsTr("平均噪声") Labelrow { text: qsTr("均值") Floatspin { id: uniformNoise_mean from: 0 to: 20 decimals: 0 defaultValue: 10 } } Labelrow { text: qsTr("σ") Floatspin { id: uniformNoise_sigma from: 0 to: 500 decimals: 0 defaultValue: 100 } } onSubmitted: { imageItem.uniformNoise(uniformNoise_mean.value, uniformNoise_sigma.value) } } Operation { title: qsTr("椒盐噪声") Labelrow { text: qsTr("盐概率") Floatspin { id: pepperSaltNoise_ps from: 0.00 to: 1.00 decimals: 2 defaultValue: 0.05 } } Labelrow { text: qsTr("椒概率") Floatspin { id: pepperSaltNoise_pp from: 0.00 to: 1.00 - pepperSaltNoise_ps.value decimals: 2 defaultValue: 0.02 } } onSubmitted: { imageItem.pepperSaltNoise( pepperSaltNoise_ps.value, pepperSaltNoise_pp.value) } } } Section { Operation { title: qsTr("风格迁移") Labelrow { text: qsTr("选择风格") ComboBox { id: styleTransfer_style textRole: "key" valueRole: "value" model: ListModel { ListElement { key: "星月夜" value: "starrynew" } ListElement { key: "电路" value: "circuit" } ListElement { key: "海洋" value: "ocean" } ListElement { key: "宇宙" value: "stars" } } } } onSubmitted: { imageItem.styleTransfer( styleTransfer_style.currentValue) } } } } } } } }