PySide(PyQt)实现鼠标画框局部放大

news2024/11/25 12:40:54

 按住鼠标左键画框,裁切画面并局部放大,可以用来生成ROI

 1、在QtDesigner中创建ui文件,命名为crop.ui:

2、自定义脚本ImageLabel.py :

from PySide6.QtCore import Qt, QRect, Signal, QPoint
from PySide6.QtGui import QPixmap, QPainter, QPen, QColor
from PySide6.QtWidgets import QLabel


class ImageLabel(QLabel):
    src_info = Signal(str)
    crop_info = Signal(str)
    show_info = Signal(str)

    def __init__(self, parent=None):
        super().__init__(parent)

        self.scale = 1.0  # 显示比例,其含义为当前的显示窗口的每个像素代表原始图几个像素
        self.src_width = 1
        self.src_height = 1
        self.showing_pixmap = QPixmap()  # 当前显示的图像内容(从原图原比例裁切而来)
        self.scaled_image = QPixmap()  # 当前显示的图像内容(经过缩放适应窗口的)
        self.scaled_image_x0 = 0  # 显示内容的x起点
        self.scaled_image_y0 = 0  # 显示内容的y起点
        self.erase = False  # 擦除已有的方框

        self.start_pos = QPoint()  # 鼠标起始点
        self.end_pos = QPoint()  # 鼠标结束点

        self.show_rect = QRect(0, 0, 1, 1)  # 显示窗口维度的方框
        self.crop_rect = QRect(0, 0, 1, 1)  # 实际像素维度的方框

    # 重新定义鼠标按下事件
    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.start_pos = event.position().toPoint()
            self.erase = False

    # 重新定义鼠标移动事件
    def mouseMoveEvent(self, event):
        if self.start_pos:
            self.end_pos = event.position().toPoint()
            self.show_rect = QRect(self.start_pos, self.end_pos)
            self.update()

    # 重新定义鼠标松开事件
    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.end_pos = event.position().toPoint()
            self.show_rect = QRect(self.start_pos, self.end_pos)
            self.erase = True  # 这一行决定了松开鼠标后方框是否擦除
            self.normalize_rect()  # 将方框参数转成正数
            self.update()

            self.crop_image(self.showing_pixmap, self.show_rect)  # 裁切图像

    # 重新定义绘画事件
    def paintEvent(self, event):
        super().paintEvent(event)
        painter = QPainter(self)
        if not self.erase:  # 不擦除
            painter.setPen(QPen(QColor(255, 0, 0, 255), 1, Qt.SolidLine))

        else:  # 擦除(用透明色画一遍)
            painter.setPen(QPen(QColor(0, 0, 0, 0), 2, Qt.SolidLine))

        painter.drawRect(self.show_rect)

    # 将得到的方框的长宽尺寸转换成正数
    def normalize_rect(self):
        x = self.show_rect.x()
        y = self.show_rect.y()
        width = self.show_rect.width()
        height = self.show_rect.height()

        if width < 0:
            x += width
            width = abs(width)
        if height < 0:
            y += height
            height = abs(height)

        # 最小方框
        self.show_rect = QRect(x, y, max(width, 3), max(height, 3))

        # 裁切并显示画面

    def crop_image(self, real_pixmap, showing_rect):  # 注意:pixmap是需要显示的真实像素维度的图像,rect是鼠标在屏幕显示维度上的方框
        # 将需要显示的图像进行满幅不变形缩放,并存储为显示图像
        self.scaled_image = real_pixmap.scaled(self.width(), self.height(), Qt.KeepAspectRatio,
                                               Qt.SmoothTransformation)
        # 显示倍率,含义为显示的窗口中,每像素相当于几个实际的像素
        self.scale = float(real_pixmap.width() / self.scaled_image.width())
        # 坐标变换,当在像素窗口中画方框,映射到显示图像中的相对坐标
        self.scaled_image_x0 = (self.width() - self.scaled_image.width()) / 2
        self.scaled_image_y0 = (self.height() - self.scaled_image.height()) / 2

        # 用以在实际像素的原图中裁切的方框
        self.crop_rect = QRect((showing_rect.x() - self.scaled_image_x0) * self.scale,
                               (showing_rect.y() - self.scaled_image_y0) * self.scale,
                               (showing_rect.width()) * self.scale,
                               (showing_rect.height()) * self.scale
                               )
        # 裁切到的用以显示的图像
        self.showing_pixmap = self.showing_pixmap.copy(self.crop_rect)
        # 再次缩放裁切到的的图像
        self.scaled_image = self.showing_pixmap.scaled(self.width(), self.height(), Qt.KeepAspectRatio,
                                                       Qt.SmoothTransformation)  # 将需要显示的图像进行满幅不变形缩放,并存储为显示图像
        self.setPixmap(self.scaled_image)  # 显示图像
        self.setAlignment(Qt.AlignCenter)  # 居中显示

        # 再次计算显示倍率
        self.scale = self.showing_pixmap.height() / self.scaled_image.height()
        self.crop_info.emit(f'裁切到的尺寸:{str(self.showing_pixmap.width())} * {str(self.showing_pixmap.height())}')
        self.show_info.emit(
            f'显示像素:{str(self.scaled_image.width())} * {str(self.scaled_image.height())},显示倍率:{self.scale}')

    # 初始化,设置原图像
    def set_src(self, pixmap):
        self.src_width = pixmap.width()
        self.src_height = pixmap.height()
        self.showing_pixmap = pixmap.copy()
        # 满幅裁切
        self.crop_rect = QRect(0, 0, self.width(), self.height())
        self.crop_image(self.showing_pixmap, self.crop_rect)
        self.src_info.emit(f'原图尺寸:{str(self.src_width)} * {str(self.src_height)}')

3、在QtDesigner中添加“提升为”的自定义脚本,并且将显示用的窗口提升:

4、用pyui工具将ui文件生成py文件,并编写主程序:

# encoding: utf-8

from PySide6.QtCore import QObject
from PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtGui import QPixmap, Qt
import sys

import crop_rc  # 导入需要显示的画面


# 定义需要显示的画面类
class MainWindow(QMainWindow, crop_rc.Ui_MainWindow):
    def __init__(self):
        super().__init__()


# 系统的初始化
def start_todo():
    pass


# #############################主程序##################################
if __name__ == '__main__':
    app = QApplication(sys.argv)

    # #######################项目级别的定义#############################
    class UI(QObject):  # 将项目定义为QObject,用来管理项目级别的信号和变量
        # ###########__init__###############
        def __init__(self):
            super().__init__()


    # ########################本项目的实例化############################
    ui = UI()  # 项目实例化

    # ########################实例化画面###############################
    window1 = MainWindow()  # 画面实例化

    window1.show()  # 显示画面
    window1.setupUi(window1)  # 画面初始化

    # ###########################信号的连接和槽函数#####################
    # “保存文件”按钮点击的槽函数
    def window1_btn_save_clicked():
        pass

    # “保存文件”按钮点击的连接
    window1.btn_save.clicked.connect(window1_btn_save_clicked)

    # “恢复原图”按钮点击的槽函数
    def window1_btn_refresh_clicked():
        window1.label_show.set_src(ui.src_img)    # 设置并显示原始图像

    # “恢复原图”按钮点击的连接
    window1.btn_refresh.clicked.connect(window1_btn_refresh_clicked)

    # 几个信息显示标签的文字更新槽和连接
    def src_info_changed(txt):
        window1.src_info.setText(txt)

    def crop_info_changed(txt):
        window1.crop_info.setText(txt)

    def show_info_changed(txt):
        window1.show_info.setText(txt)

    window1.label_show.src_info.connect(src_info_changed)
    window1.label_show.crop_info.connect(crop_info_changed)
    window1.label_show.show_info.connect(show_info_changed)

    # ###########################系统的初始化#######################
    start_todo()
    ui.src_img = QPixmap('../PYS/9.png')  # 读取和定义原图像文件
    window1.label_show.set_src(ui.src_img)  # 设置并显示原图像

    sys.exit(app.exec())

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1827667.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

cmake构建Qt项目

cmake构建Qt项目 项目结构 一、添加头文件 # 添加头文件目录&#xff0c;还需要在add_executable中添加头文件&#xff01;&#xff01;&#xff01; include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) add_executable(landlardsinclude/test.h)二、添加源文件 aux…

如何从印刷体的图片中把手写体部分统统去掉?--免费途径

AI图像处理技术 我是从国外某个网站上找到在线AI免费credit的处理方式的。国内的基本没有全功能试用、或者即使收费也不好用。 国内的差距主要是&#xff1a;1、对图片分辨率和大小有更多限制&#xff0c;即使收费用户也是&#xff1b;2、需要安装app之类&#xff0c;然后连线…

深入探讨限流算法:固定窗口、滑动窗口、漏桶与令牌桶原理及应用场景

固定窗口算法 简单粗暴&#xff0c;但有临界问题&#xff1a; 滑动窗口算法 滑动窗口通俗来讲是一种流量控制技术&#xff0c;描述接收方TCP数据报缓冲区大小的数据。发送方根据这个数据计算最大可发送的数据量。滑动窗口协议是TCP使用的一种流量控制方法&#xff0c;允许发送…

英语学习笔记37——Making a bookcase

Making a bookcase 做书架 词汇 Vocabulary work v. 工作 ing形式&#xff1a;working 搭配&#xff1a;work on 工作 做……工作    work for 人 为……而工作 例句&#xff1a;我正在做我的家庭作业。    I am working on my homework.    我正在为Bobby工作。 …

解决Qt的multimedia库在clion中依赖库补全的问题

解决Qt的multimedia库在clion中使用报错的问题 在clion中&#xff0c;使用Qt的multimedia库时会报如下错误&#xff1a; defaultServiceProvider::requestService(): no service found for - "org.qt-project.qt.mediaplayer" 我猜测出现这个错误的原因很可能是因为…

监控异地组网的方法?

监控异地组网是一项关键的技术&#xff0c;能够实现远程连接和访问。在复杂的网络环境中&#xff0c;使用传统的方法可能会遭遇网络限制和访问速度较慢的问题。而采用新兴的监控异地组网方法&#xff0c;如【天联】组网技术&#xff0c;可以克服这些问题并提供更好的用户体验。…

4.8.2 利用Spark SQL计算总分与平均分

姓名语文数学英语物理化学陈燕文8998807665张晓峰9078928456李太白8793677892洪小琳9867879076 1. 准备数据 创建本地成绩文件&#xff1a;scores.txt&#xff0c;包含学生成绩数据。上传到 HDFS&#xff1a; 创建目录&#xff1a;hdfs dfs -mkdir -p /scoresumavg/input上传文…

如何通过在线封装APP快速上线?小猪APP分发帮你解决难题

你是否曾经为了上线一款APP而头疼不已&#xff1f;开发完成后&#xff0c;封装、测试、分发&#xff0c;这些繁琐的步骤让人望而却步。别担心&#xff0c;小猪APP分发来了&#xff01;这篇文章将带你了解如何通过在线封装APP快速上线&#xff0c;并且告诉你为什么选择小猪APP分…

海底管缆先敷后埋与边敷边埋有什么区别?

海缆铺设有两种方式&#xff1a;“边敷边埋”和“先敷后埋”。 “边敷边埋”冲埋式埋设犁施工法———通过埋设犁(水力开沟机)泵送高压水&#xff0c;在海底冲出一条沟槽的同时&#xff0c;将海缆平铺下去,然后利用在潮汐作用下海床面自行回填(必要时采取压盖保护施工)。主要施…

MATLAB直方图中bin中心与bin边界之间的转换

要将 bin 中心转换为 bin 边界&#xff0c;请计算 centers 中各连续值之间的中点。 d diff(centers)/2; edges [centers(1)-d(1), centers(1:end-1)d, centers(end)d(end)];要将 bin 边界转换为bin 中心 bincenters binedges(1:end-1)diff(binedges)/2;

1832javaERP管理系统之能力物料管理Myeclipse开发mysql数据库servlet结构java编程计算机网页项目

一、源码特点 java erp管理系统之能力物料管理是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助采用了serlvet设计&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统采用web模式&#xff0c;系统主要采用 B/S模式开发。开发环境为TOMCAT7.0,My…

special characters are not allowed

处理域名连接nacos读取配置异常 1 项目启动报错2 问题处理3 刷新依赖重启问题解决 1 项目启动报错 使用ip可以正在启动&#xff0c;但是使用域名报下面的错误 2024-06-15 17:37:22.981 ERROR 29268 --- [ main] c.a.c.n.c.NacosPropertySourceBuilder : parse …

等级考试3-2021年3月题

作业&#xff1a; #include <iostream> using namespace std; int chonghe(int,int,int,int); int main(){int a[1000],b[1000];int n,ma0;cin>>n;for(int i0;i<n;i){cin>>a[i]>>b[i];}for(int i0;i<n;i){for(int ji1;j<n;j){mamax(ma,chongh…

Nginx - 反向代理、负载均衡、动静分离(案例实战分析)

目录 Nginx 开始 概述 安装&#xff08;非 Docker&#xff09; 配置环境变量 常用命令 配置文件概述 location 路径匹配方式 配置反向代理 实现效果 准备工作 具体配置 效果演示 配置负载均衡 实现效果 准备工作 具体配置 实现效果 其他负载均衡策略 配置动…

C语言的结构体与联合体

引言 C语言提供了结构体和联合体两种聚合数据类型&#xff0c;使得程序员可以创建包括多个数据类型的复杂数据结构。结构体用于将不同类型的数据组合成一个单元&#xff0c;而联合体用于在同一存储空间中存储不同类型的数据。本篇文章将详细介绍C语言中的结构体和联合体&#x…

C语言 | Leetcode C语言题解之第151题反转字符串中的单词

题目&#xff1a; 题解&#xff1a; void myResverse(char* s,int start,int end){while(start<end){char temp s[start];s[start] s[end];s[end] temp;start;end--;} } char* reverseWords(char* s) {int start 0;int end strlen(s)-1;myResverse(s,start,end);if(s[…

Linux时间子系统5:timekeeper、timecountercyclecounter

1. 前言 前面我们介绍了用户态获取时间的接口clock_gettime&#xff0c;时钟的种类posix_clocks以及时钟源clocksource。那么我们思考这样一个问题&#xff0c;无论clock_gettime或者posix_clock定义的时间都是相对于某个起始点的时间&#xff0c;即相对于Linux Epoch的秒数&am…

Centos7系统下Docker的安装与配置

文章目录 前言下载Docker安装yum库安装Docker启动和校验配置Docker镜像加速卸载Docker 前言 此博客的内容的为自己的学习笔记&#xff0c;如果需要更具体的内容&#xff0c;可查看Docker官网文档内容 注意&#xff1a;以下命令在root管理员用户下运行&#xff0c;如果在普通用…

2024年了,苹果可以通话录音了

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 6月11日凌晨&#xff0c;苹果在WWDC24大会上&#xff0c;密集输出了酝酿多时的AI应用更新。苹果对通话、对话、图…

使用Ventoy 替代Win_To_Go更好的随身系统

Ventoy支持在物理机上直接启动安装了 Linux/Windows 系统的 磁盘映像文件 。 系统是在真实物理机上运行&#xff0c;并不是在虚拟机里运行&#xff0c;没有性能损失。支持 Legacy BIOS 和 UEFI 模式。支持从任意磁盘启动磁盘映像。 Windows 支持固定大小以及动态扩展类型的 VH…