OpenCV的“画笔”功能

类似于画图软件的自由笔刷功能,当按住鼠标左键,在屏幕上画出连续的线条。

定义函数:

import cv2
import numpy as np# 初始化参数
drawing = False  # 鼠标左键按下时为True
ix, iy = -1, -1  # 鼠标初始位置# 鼠标回调函数
def mouse_paint(event, x, y, flags, param):global ix, iy, drawing# 左键按下事件if event == cv2.EVENT_LBUTTONDOWN:drawing = Trueix, iy = x, y# 鼠标移动事件elif event == cv2.EVENT_MOUSEMOVE:if drawing:cv2.line(img, (ix, iy), (x, y), (0, 255, 0), 2)ix, iy = x, ycv2.imshow('image', img)# 左键松开事件elif event == cv2.EVENT_LBUTTONUP:drawing = False# cv2.line(img, (ix, iy), (x, y), (0, 255, 0), 2)# cv2.imshow('image', img)cv2.waitKey(0)# 创建空白图像或读取现有图像
img = np.zeros((500, 500, 3), np.uint8)    # 创建空白图像
# img = cv2.imread('d:\\mask1\\3.png', cv2.IMREAD_COLOR)   # 读取现有图像# 创建一个窗口并将回调函数与窗口绑定
cv2.namedWindow('image')
cv2.setMouseCallback('image', mouse_paint)# 保存绘制轨迹后的图像
cv2.imshow('image', img)
cv2.waitKey(0)
cv2.imwrite('output_image.jpg', img)
cv2.destroyAllWindows()

 这里用到了OpenCV的鼠标回调函数cv2.setMouseCallback():

cv2.setMouseCallback() 是 OpenCV 库中用于设置鼠标事件回调函数的函数。该函数用于与图像窗口交互,通过在图像窗口中进行鼠标操作来获取像素点的坐标或执行一些特定操作。

函数原型为:

cv2.setMouseCallback(windowName, onMouse, param=None)
  • windowName 是要操作的图像窗口的名称。
  • onMouse 是回调函数,用于处理鼠标事件。该函数通常包含四个参数: event(事件类型,如 cv2.EVENT_MOUSEMOVEcv2.EVENT_LBUTTONDOWN 等)、x(鼠标点击的 x 坐标)、y(鼠标点击的 y 坐标)、flags(附加参数,如 cv2.EVENT_FLAG_CTRLKEYcv2.EVENT_FLAG_SHIFTKEY 等)。
  • param 是传递给回调函数的可选参数。

 封装为类:

import cv2
import numpy as npclass Painter:def __init__(self):self.drawing = Falseself.ix, self.iy = -1, -1self.img = np.zeros((500, 500, 3), np.uint8)def mouse_paint(self, event, x, y, flags, param):if event == cv2.EVENT_LBUTTONDOWN:self.drawing = Trueself.ix, self.iy = x, yelif event == cv2.EVENT_MOUSEMOVE:if self.drawing:cv2.line(self.img, (self.ix, self.iy), (x, y), (0, 255, 0), 1)self.ix, self.iy = x, ycv2.imshow('image', self.img)elif event == cv2.EVENT_LBUTTONUP:self.drawing = Falsecv2.waitKey(0)def run(self):cv2.setMouseCallback('image', self.mouse_paint)cv2.imshow('image', self.img)cv2.waitKey(0)cv2.imwrite('output_image.jpg', self.img)cv2.destroyAllWindows()if __name__ == "__main__":cv2.namedWindow('image')painter = Painter()painter.run()

使用PySide6和OpenCV实现:

 目前阶段我的PySide6熟悉程度要强于OpenCV

import sys
from PySide6.QtWidgets import QApplication, QLabel, QVBoxLayout, QWidget, QPushButton
from PySide6.QtGui import QPainter, QPixmap, QMouseEvent, QColor, QPen, QImage
from PySide6.QtCore import Qt, QPoint
import cv2
import numpy as npclass PaintLabel(QLabel):def __init__(self, parent=None):super(PaintLabel, self).__init__(parent)self.image = QImage()self.drawing = Falseself.last_point = QPoint()def set_image(self, image_file):self.image = QImage(image_file)self.setPixmap(QPixmap.fromImage(self.image))def mousePressEvent(self, event: QMouseEvent):if event.button() == Qt.LeftButton:self.drawing = Trueself.last_point = event.position()def mouseMoveEvent(self, event: QMouseEvent):if event.buttons() & Qt.LeftButton and self.drawing:painter = QPainter(self.image)pen = QPen(QColor('red'))pen.setWidth(3)painter.setPen(pen)painter.drawLine(self.last_point, event.position())self.last_point = event.position()self.setPixmap(QPixmap.fromImage(self.image))def mouseReleaseEvent(self, event: QMouseEvent):if event.button() == Qt.LeftButton:self.drawing = Falsedef save_image(self, file_path):self.image.save(file_path)class MainWindow(QWidget):def __init__(self):super().__init__()self.label = PaintLabel()# Load an image (you can change the file path)img = np.zeros((500, 500, 3), np.uint8)  # 创建空白图像q_img = cv2side(img)self.label.set_image(q_img)save_button = QPushButton('Save Image')save_button.clicked.connect(self.save_image)layout = QVBoxLayout()layout.addWidget(self.label)layout.addWidget(save_button)self.setLayout(layout)def save_image(self):self.label.save_image('output_image.png')# 将OpenCV格式的图像转换为PySide格式
def cv2side(img):img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # 转换 BGR 到 RGB# 转换图像到QT的QImage格式height, width, channels = img_rgb.shape  # 获取形状bytes_per_line = channels * width  # 每行字节数q_img = QImage(img_rgb.data, width, height, bytes_per_line, QImage.Format_RGB888)  # 转换成QImage格return q_imgif __name__ == "__main__":app = QApplication(sys.argv)main_window = MainWindow()main_window.show()sys.exit(app.exec())

运行截图:

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

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

相关文章

五个超实用的 ChatGPT-4o 提示词

GPT-4o 是 OpenAI 最近推出的最新人工智能模型,不仅具备大语言模型的能力,而且拥有多模态模型的看、读、说等能力,而且速度比 GPT-4 更快。下面我们就来介绍几个超实用的 GPT-4o 提示词,帮助大家更好地了解 GPT-4o 的功能和应用场…

Android 动态修改APP图标

文章目录 Android 动态修改APP图标定义activity-alias修改图标和App名监听APP前后台状态切换进入后台时切换修改图标和名字缺点 Android 动态修改APP图标 修改前: 修改后: 定义activity-alias 在 AndroidManifest.xml 中设置 activity-alias&#xff1…

RTA_OS基础功能讲解 2.8-Tick计数器

RTA_OS基础功能讲解 2.8-Tick计数器 文章目录 RTA_OS基础功能讲解 2.8-Tick计数器一、计数器简介二、计数器配置三、计数器驱动3.1 软件计数器驱动3.1.1 递增软件计数器3.1.2 静态计数器接口3.2 硬件计数器驱动3.2.1 Advancing硬件计数器3.2.2 回调函数四、在运行时访问计数器属…

JVM之【类的生命周期】

首先,请区分Bean的声明周期和类的声明周期。此处讲的是类的声明周期 可以同步观看另一篇文章JVM之【类加载机制】 概述 在Java中数据类型分为基本数据类型和引用数据类型 基本数据类型由虚拟机预先定义,引用数据类型则需要进行类的加载 按照]ava虚拟机…

AI大模型日报#0606:智谱AI开源GLM-4-9B、Pika再融5.8亿

导读:AI大模型日报,爬虫LLM自动生成,一文览尽每日AI大模型要点资讯!目前采用“文心一言”(ERNIE 4.0)、“零一万物”(Yi-Large)生成了今日要点以及每条资讯的摘要。欢迎阅读&#xf…

C++构造器设计模式

构造器模式可以简化复杂对象或一系列对象的构造过程,从而单独定义构成该复杂对象的各个组件的构建方法。 这篇文章只讲解较为简单的构造器的创建。创建一个构造器我们得了解如何实现流式调用以及如何关闭外界的访问权对构造函数的访问权限。 流式调用 所谓流式调…

【Linux】进程切换环境变量

目录 一.进程切换 1.进程特性 2.进程切换 1.进程切换的现象 2.如何实现 3.现实例子 2.环境变量 一.基本概念 二.常见环境变量 三.查询常见环境变量的方法 四.和环境变量相关的命令 五.环境变量表的组织方式 六.使用系统调用接口方式查询环境变量 1.getenv 2.反思 …

【简单讲解下TalkingData】

🌈个人主页: 程序员不想敲代码啊 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共…

Signac|成年小鼠大脑 单细胞ATAC分析(1)

引言 在本教程中,我们将探讨由10x Genomics公司提供的成年小鼠大脑细胞的单细胞ATAC-seq数据集。本教程中使用的所有相关文件均可在10x Genomics官方网站上获取。 本教程复现了之前在人类外周血单核细胞(PBMC)的Signac入门教程中执行的命令。…

100道大模型面试八股文

算法暑期实习机会快结束了,校招大考即将来袭。 当前就业环境已不再是那个双向奔赴时代了。求职者在变多,岗位在变少,要求还更高了。 最近,我们陆续整理了很多大厂的面试题,帮助球友解惑答疑和职业规划,分…

【Python报错】已解决ModuleNotFoundError: No Module Named ‘openyxl’

成功解决“ModuleNotFoundError: No Module Named ‘openyxl’”错误的全面指南 在Python编程中,遇到ModuleNotFoundError: No Module Named openyxl这样的错误通常意味着Python解释器无法找到名为openyxl的模块。然而,这里存在一个常见的拼写错误&#…

javascript中的flat和faltmap的区别

JavaScript 中的 flat 和 flatMap 是数组方法,它们用于处理嵌套数组(即数组中的元素也是数组)。下面是它们的区别: flat 方法: flat 方法用于将嵌套数组“展平”成一个新数组,但不会改变原始数组。它接受一个可选的深…

Anaconda 环境管理的一些特殊操作

在指定位置创建虚拟环境 第一步:在现有/your/paht/目录创建env_name的环境变量 conda create -p /your/paht/env_name python3.x第二步:通过一下命令发现环境变量没有名字: conda env list第三步:将/your/paht/ 加入到conda 的en…

资源描述框架的用途及实际应用解析

什么是RDF? RDF代表 资源描述框架 RDF是用于描述网络资源的框架 RDF旨在被计算机阅读和理解 RDF并非设计用于供人阅读 RDF以 XML 编写 示例 描述购物商品的属性,如价格和可用性描述网络活动的时间表描述网页的信息(内容,作者&a…

使用 Nacos 在 C# (.NET Core) 应用程序中实现高效配置管理和服务发现

在分布式系统架构日益流行的今天,服务配置管理和发现成为了开发和运维团队面临的重大挑战。Nacos,作为阿里巴巴开源的一款强大的动态配置管理与服务发现平台,为解决这一难题提供了有效方案。本文将介绍如何在C# (.NET Core)应用程序中集成Nac…

springboot,配置类加载过程

加载过程 首先来看启动类,启动类上包含了SpringBootApplication注解 SpringBootApplication MapperScan("com.cskaoyan.mapper") public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);…

后端开发面经系列 --中望C++面经

中望C面经,全部内容! 公众号:阿Q技术站 文章目录 中望C面经,全部内容!一面 8.15 时长45min1、介绍项目相关2、gdb怎么调试的?打断点用什么指令?3、gcc的编译过程4、cmake添加头文件搜索路径用…

Werkzeug的Response

Werkzeug的Response Werkzeug是一个WSGI工具包,提供了一组工具用于开发基于WSGI的Python Web应用。它不仅仅是一个简单的库,还提供了许多方便的工具来处理HTTP请求和响应。本文将深入探讨Werkzeug中Response类的讲解。 官方文档链接 Werkzeug Respons…

大语言模型 (LLM) 窥探未来

随着2023年的岁月渐渐走向尾声,我们站在人工智能的前沿,回望大语言模型(Large Language Models, LLM)所走过的道路,同时也不禁展望未来。从初步尝试到成为人工智能领域的万千宠爱,一种又一种的技术突破&…

搜维尔科技:「案例」Faceware电影中面部动画的演变历程

面部动画是电影中角色表演的一个重要方面,尤其是在严重依赖电子动画、化妆效果和动作捕捉系统的奇幻电影中。在《龙与地下城:盗贼荣誉》电影中,龙裔角色的面部动画是一个复杂的系统,使该生物在大屏幕上栩栩如生。该系统依赖于一种…