【OpenCV实现鼠标绘图,轨迹栏做调色板,图像的基本操作】

news2024/11/18 15:49:49

文章目录

    • 鼠标绘图
    • 轨迹栏做调色板
    • 图像的基本操作

鼠标绘图

在OpenCV中操作鼠标事件
函数:cv.setMouseCallback()

目的是在鼠标双击的地方画一个圆。首先,我们需要创建一个鼠标回调函数,该函数会在鼠标事件发生时执行。鼠标事件包括左键按下、左键松开、左键双击等等。通过获取每个鼠标事件的坐标(x, y),我们就能实现画圆的功能。

import numpy as np
import cv2 as cv

# 创建一个黑色图像
img = np.zeros((512, 512, 3), np.uint8)

# 鼠标回调函数,当鼠标左键双击时,在双击的位置画一个半径为100的蓝色圆
def draw_circle(event, x, y, flags, param):
    if event == cv.EVENT_LBUTTONDBLCLK:
        # 画一个半径为100的蓝色圆,圆心坐标为(x, y),颜色为(255, 0, 0),-1表示填充整个圆
        cv.circle(img, (x, y), 100, (255, 0, 0), -1)

# 创建一个窗口,并将鼠标回调函数与窗口绑定
cv.namedWindow('image')
cv.setMouseCallback('image', draw_circle)

while True:
    # 显示图像
    cv.imshow('image', img)
    # 等待用户按键,如果按下的是'q'键,则退出循环
    if cv.waitKey(20) == ord('q'):
        break

# 关闭窗口
cv.destroyAllWindows()

结果,双击画圆:
在这里插入图片描述

这段代码创建了一个大小为512x512的黑色图像,然后定义了一个鼠标回调函数draw_circle,该函数在鼠标左键双击时,在双击的位置画一个半径为100的蓝色(BGR值为(255, 0, 0))的圆。程序将这个回调函数与窗口"image"绑定,然后进入一个无限循环,显示图像,直到用户按下键盘上的"q"键,窗口才会关闭。

当我们创建一个交互式绘图程序时,我们需要考虑两种模式:画矩形和画圆形。为了实现这个目标,我们需要在鼠标回调函数中添加逻辑,以便根据用户的选择来绘制相应的图形。


import numpy as np
import cv2 as cv

drawing = False # 当鼠标按下的时候会为True
mode = True # True画矩形,按下'm'改变模式
ix, iy = -1, -1

# 鼠标回调函数
def  draw_circle(event, x, y, flags, param):
    global ix, iy, drawing, mode
    if event == cv.EVENT_LBUTTONDOWN:
        drawing = True
        ix, iy = x, y

    elif event == cv.EVENT_MOUSEMOVE:
        if drawing == True:
            if mode == True:
                cv.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)
            else:
                cv.circle(img, (x, y), 5, (0, 0, 255), -1)

    elif event == cv.EVENT_LBUTTONUP:
        drawing = False
        if mode == True:
            cv.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)
        else:
            cv.circle(img, (x, y), 5, (0, 0, 255), -1)

img = np.zeros((512, 512, 3), np.uint8)
cv.namedWindow('image')
cv.setMouseCallback('image', draw_circle)

while 1:
    cv.imshow('image', img)
    k = cv.waitKey(1) & 0xFF

    if k == ord('m'):
        mode = not mode

    elif k == ord('q'):
        break

cv.destroyAllWindows()

二:

import numpy as np
import cv2 as cv

# 定义全局变量,初始模式为矩形
drawing = False  # 当鼠标按下时变为True
mode = True  # True表示矩形模式,False表示圆形模式
ix, iy = -1, -1  # 矩形或圆形的起始坐标

# 鼠标回调函数
def draw_shape(event, x, y, flags, param):
    global ix, iy, drawing, mode

    if event == cv.EVENT_LBUTTONDOWN:  # 当鼠标左键按下时
        drawing = True
        ix, iy = x, y

    elif event == cv.EVENT_LBUTTONUP:  # 当鼠标左键松开时
        drawing = False
        if mode:  # 如果是矩形模式
            cv.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)
        else:  # 如果是圆形模式
            radius = int(np.sqrt((x - ix) ** 2 + (y - iy) ** 2))
            cv.circle(img, (ix, iy), radius, (0, 0, 255), -1)

# 创建一个黑色图像
img = np.zeros((512, 512, 3), np.uint8)

# 创建一个窗口,并将鼠标回调函数与窗口绑定
cv.namedWindow('Drawing')
cv.setMouseCallback('Drawing', draw_shape)

while True:
    cv.imshow('Drawing', img)
    # 检测键盘按键,切换模式('r'键表示矩形模式,'c'键表示圆形模式)
    k = cv.waitKey(1) & 0xFF
    if k == ord('r'):
        mode = True
    elif k == ord('c'):
        mode = False
    elif k == 27:  # 按下ESC键退出程序
        break

cv.destroyAllWindows()

在这个程序中,我们使用了全局变量drawing来追踪鼠标是否按下,mode来追踪当前的绘制模式(矩形或圆形),以及ix和iy来保存绘制形状的起始坐标。当用户按下鼠标左键时,drawing变为True,ix和iy保存了鼠标按下的位置。当鼠标松开时,根据当前的模式(矩形或圆形)在图像上绘制相应的形状。

轨迹栏做调色板

OpenCV窗口建立轨迹栏
函数:cv.getTrackbarPos(),cv.createTrackbar()等等

使用OpenCV中的轨迹条(Trackbar)功能。这个应用将会有一个用于显示颜色的窗口,并且提供了三个轨迹条,分别用来指定红色(R)、绿色(G)和蓝色(B)的分量。通过滑动这些轨迹条,窗口的颜色会相应地变化。初始颜色为黑色。

import numpy as np
import cv2 as cv

# 回调函数,什么也不做
def nothing(x):
    pass

# 创建一个黑色图像和一个窗口
img = np.zeros((300, 512, 3), np.uint8)  # 创建一个黑色图像(300x512的RGB图像)
cv.namedWindow('image')  # 创建一个名为'image'的窗口

# 创建轨迹栏,参数分别为:轨迹条的名称、所属窗口的名称、默认值、最大值、回调函数
cv.createTrackbar('R', 'image', 0, 255, nothing)  # 创建红色分量的轨迹条
cv.createTrackbar('G', 'image', 0, 255, nothing)  # 创建绿色分量的轨迹条
cv.createTrackbar('B', 'image', 0, 255, nothing)  # 创建蓝色分量的轨迹条

# 创建开关轨迹条,用于开启或关闭窗口显示颜色
switch = '0 : OFF \n1 : ON'
cv.createTrackbar(switch, 'image', 0, 1, nothing)  # 创建开关轨迹条

while 1:
    cv.imshow('image', img)  # 在窗口中显示图像

    # 检测按键,如果按下'q'键则退出循环
    if cv.waitKey(1) & 0xFF == ord('q'):
        break

    # 获取轨迹条的当前位置
    r = cv.getTrackbarPos('R', 'image')  # 获取红色分量轨迹条的位置
    g = cv.getTrackbarPos('G', 'image')  # 获取绿色分量轨迹条的位置
    b = cv.getTrackbarPos('B', 'image')  # 获取蓝色分量轨迹条的位置
    s = cv.getTrackbarPos(switch, 'image')  # 获取开关轨迹条的位置

    # 根据轨迹条的位置设置图像颜色
    if s == 0:
        img[:] = 0  # 如果开关为关闭状态,将图像颜色设置为黑色
    else:
        img[:] = [b, g, r]  # 如果开关为开启状态,根据轨迹条位置设置图像颜色

cv.destroyAllWindows()  # 关闭所有窗口

结果:
在这里插入图片描述

在这个应用中,我们会使用cv.createTrackbar()函数来创建这些轨迹条。这个函数的第一个参数是轨迹条的名称,第二个参数是要应用的窗口的名称,第三个参数是一个默认值,第四个参数是最大值,第五个参数是一个回调函数,用于监测轨迹条值的变化。在本例中,我们不需要回调函数,所以我们将跳过这一部分。

轨迹条的另一个重要应用是作为按钮或者开关。因为OpenCV默认并没有按钮功能,所以你可以使用轨迹条来实现这个功能。在我们的应用中,我们会创建一个开关,只有当开关处于导通状态时,窗口才会显示颜色,否则窗口将一直保持黑色。通过这种方式,我们可以实现一个简单的颜色选择器应用。

图像的基本操作

访问像素值并修改他们。
当处理图像时,你可以通过像素的横纵坐标来访问和修改像素值。在OpenCV中,颜色图像通常使用BGR(蓝、绿、红)通道来表示每个像素的颜色,而灰度图像只有一个单通道,表示像素的亮度。
访问像素值:

import numpy as np
import cv2 as cv

# 加载图像
img = cv.imread('messi5.jpg')

# 访问像素值,返回BGR值
px = img[100, 100]
print(px)  # 输出:[157 166 200]


# 访问蓝色通道值
blue = img[100, 100, 0]
print(blue)  # 输出:157

在上述代码中,img[100, 100]返回了坐标为(100, 100)的像素的BGR值,img[100, 100, 0]返回了该像素的蓝色通道值。

修改像素值:

# 修改像素值为白色(255, 255, 255)
img[100, 100] = [255, 255, 255]

# 验证修改后的像素值
print(img[100, 100])  # 输出:[255 255 255]

在上述代码中,img[100, 100]的像素值被修改为白色(255, 255, 255)。

这些基本操作允许你直接访问和修改图像的像素值,为图像处理提供了灵活性。请确保在修改像素值时,坐标值在图像的范围内,以避免访问超出图像边界的像素。

警告:

在处理图像时,简单地遍历每个像素并逐个访问或修改它们通常会非常缓慢,特别是对于大型图像。Numpy是一个针对快速矩阵运算优化过的库,所以它的目标是通过矢量化操作来提高性能。对于单个像素的访问和修改,直接遍历图像的每个像素并逐个处理会效率低下。

在Numpy中,可以使用array.item()和array.itemset()来更高效地访问和修改单个像素的值。这两个方法始终返回或设置标量值。如果需要访问或修改B、G、R通道的值,可以分别使用array.item()来获取每个通道的值。

访问图像属性

图像的特征包括:

形状(Shape):图像的形状描述了它的尺寸,通常以行数、列数和通道数表示。在彩色图像中,通道数为3(表示红、绿、蓝通道),在灰度图像中,通道数为1。你可以使用img.shape获取图像的形状。
print(img.shape)  # 输出:(342, 548, 3)

像素数量(Size):图像中像素点的总数量,可以通过img.size获得。

print(img.size)  # 输出:562248

数据类型(Data Type):图像的数据类型表示像素值的存储格式。在OpenCV中,通常使用uint8(8位无符号整数)来表示像素值的范围为0到255。

  print(img.dtype)  # 输出:uint8

这些特征对于了解图像的结构和存储格式非常重要。特别是在调试时,检查图像的数据类型(img.dtype)可以帮助你避免许多与数据类型相关的错误。通过这些特征,可以确定图像的维度、通道数、像素总数以及像素值的表示范围,为图像处理和分析提供了基础信息。

设置一个感兴趣的区域(ROI)

图像处理中,通常需要对图像的特定区域进行操作。这种操作称为兴趣区域(Region of Interest,ROI)操作。通过在图像中找到特定区域,我们可以提高处理的精度和速度,因为我们只需在一个相对较小的区域上执行操作。

在Python中,使用Numpy的索引功能可以很容易地获取和操作ROI。以下是一个示例,演示了如何从图像中选择一个包含球的区域,并将该区域复制到图像的另一部分:

# 选择图像中包含球的区域(ROI)
ball = img[280:340, 330:390]

# 将球的区域复制到图像的另一部分(例如,将其粘贴到另一个位置)
img[273:333, 100:160] = ball

在上述示例中,img[280:340, 330:390]选择了图像中的一个特定区域,该区域包含球。然后,通过将这个区域赋值给ball,我们得到了一个ball变量,其中包含了球的图像区域。接着,我们将ball变量的内容复制到图像的另一个位置(例如,图像的[273:333, 100:160]区域),从而将包含球的区域粘贴到了图像的另一部分。

拆分和组合图像

在图像处理中,有时需要分开和合成图像的通道。OpenCV提供了cv.split()函数来将BGR图像分离成单独的通道,同时也提供了cv.merge()函数用于将单独的通道合成成一个BGR图像。另外,也可以通过Numpy的索引来直接访问和修改图像的特定通道。

分开图像通道:

# 使用cv.split()将BGR图像分离成单独的通道
b, g, r = cv.split(img)

在这个例子中,cv.split()函数将BGR图像分离成了三个单独的通道:蓝色(b)、绿色(g)和红色(r)。
合成图像通道:

# 使用cv.merge()将单独的通道合成为BGR图像
img = cv.merge((b, g, r))

在这个例子中,cv.merge()函数将单独的蓝色(b)、绿色(g)和红色(r)通道合成为一个BGR图像。

使用Numpy索引直接访问和修改通道

# 将所有的红色通道设置为0(即去除红色)
img[:, :, 2] = 0

在这个例子中,img[:, :, 2]直接访问并修改了图像的红色通道,将所有的红色值设置为0。
警告:

cv.split() 是一个开销很大的操作,因为它需要遍历整个图像。只有在必要的时候才使用它。否则,尽量使用Numpy的索引来直接访问和修改图像的通道,这样会更高效。

cv.copyMakeBorder()函数可以用来在图像周围添加边框。该函数有以下参数:

src:输入的图像。
top, bottom, left, right:对应方向填充的像素宽度。
borderType:想要添加的边框类型,可以是cv.BORDER_CONSTANT、cv.BORDER_REFLECT、cv.BORDER_REFLECT_101、cv.BORDER_REPLICATE 或 cv.BORDER_WRAP。
value:如果borderType是cv.BORDER_CONSTANT,需要在这里指定颜色值。

以下是一个使用cv.copyMakeBorder()函数演示的例子:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

BLUE = [255, 0, 0]
img1 = cv.imread('opencv-logo.png')

# 添加不同类型的边框
replicate = cv.copyMakeBorder(img1, 10, 10, 10, 10, cv.BORDER_REPLICATE)
reflect = cv.copyMakeBorder(img1, 10, 10, 10, 10, cv.BORDER_REFLECT)
reflect101 = cv.copyMakeBorder(img1, 10, 10, 10, 10, cv.BORDER_REFLECT_101)
wrap = cv.copyMakeBorder(img1, 10, 10, 10, 10, cv.BORDER_WRAP)
constant = cv.copyMakeBorder(img1, 10, 10, 10, 10, cv.BORDER_CONSTANT, value=BLUE)

# 显示原始图像和添加边框后的图像
plt.subplot(231), plt.imshow(img1, 'gray'), plt.title('ORIGINAL')
plt.subplot(232), plt.imshow(replicate, 'gray'), plt.title('REPLICATE')
plt.subplot(233), plt.imshow(reflect, 'gray'), plt.title('REFLECT')
plt.subplot(234), plt.imshow(reflect101, 'gray'), plt.title('REFLECT_101')
plt.subplot(235), plt.imshow(wrap, 'gray'), plt.title('WRAP')
plt.subplot(236), plt.imshow(constant, 'gray'), plt.title('CONSTANT')
plt.show()

在这个例子中,cv.copyMakeBorder()函数被用来创建原始图像和带有不同边框类型的图像。这些边框类型包括:REPLICATE、REFLECT、REFLECT_101、WRAP 和 CONSTANT。每种类型的边框都会以不同的方式填充图像的边界。通过这个例子,你可以看到不同类型的边框效果。

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

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

相关文章

PyQt学习笔记-获取Hash值的小工具

目录 一、概述1.1 版本信息:1.2 基本信息:1.2.1 软件支持的内容:1.2.2 支持的编码格式 1.3 软件界面图 二、代码实现2.1 View2.2 Controller2.3 Model 三、测试示例 一、概述 本工具居于hashlibPyQtQFileDialog写的小工具,主要是…

中国移动启动算网大脑“天穹”全网试商用

10月12日,中国移动在2023全球合作伙伴大会主论坛正式启动算网大脑“天穹”全网试商用,全面开启算力网络2.0新征程,标志着中国移动算力网络迈向“融合统一”新阶段。 为落实国家“东数西算”战略,中国移动开创性提出算力网络新理念…

操作系统【OS】微内核

基本概念 微内核结构将操作系统划分为两大部分:微内核多个服务器微内核包含: 与硬件处理紧密相关的部分一些较基本的功能客户和服务器间的通信客户与服务器之间是借助微内核提供的消息传递机制来实现交互的 基本功能 进程管理 进程的通信、切换、调度…

【算法练习Day24】递增子序列全排列全排列 II

​📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:练题 🎯长路漫漫浩浩,万事皆有期待 文章目录 递增子序列容易出错的地方 …

微信手续费2023标准

不管是微信还是支付宝,商户最低的收款手续费率可以达到0.2%费率。一般我们普通商户的收款费率一般在0.6左右,当然也有使用0.3的,也就是1万元的费率是30-60块钱,对于一些流水比较大的商家来说,确实很有必要把这个手续费…

【实用技巧】Latex写算法伪代码(格式篇)

本文主要介绍个人在编写Latex算法伪代码时所遇到的格式问题。 目录 包冲突换行与缩进算法换页 包冲突 \usepackage{algorithm} \usepackage{algorithmic} \usepackage{algorithmicx} \usepackage{algpseudocode} 网上查找算法伪代码第三方包,主要会跳出来这四…

虹科案例 | 瑞士Agroscope研究所利用压力传感器自动测量反刍动物(奶牛)的咀嚼运动

——用于动物测量研究的数据记录仪:虹科MSR145 瑞士Agroscope研究所隶属于联邦农业办公室,是农业、食品和环境领域可持续发展的推动力量,为农业和环境政策决策以及法规执行提供科学和技术基础。 作为Agroscope研究所的合作代表&…

【超详细】CentOS 7安装MySQL 5.7【安装及密码配置、字符集配置、远程连接配置】

准备工作:CentOS 7系统,并确保可以联通网络 1、获取MySQL 5.7 Community Repository软件包 注意:这里使用的是root用户身份。 wget https://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm2、安装软件包 rpm -ivh mysql5…

PyTorch入门教学——TensorBoard使用

1、TensorBoard简介 TensorBoard是Google开发的一个机器学习可视化工具。其主要用于记录机器学习过程,例如: 记录损失变化、准确率变化等记录图片变化、语音变化、文本变化等。例如在做GAN时,可以过一段时间记录一张生成的图片绘制模型 2、…

数字秒表VHDL启动暂停清零,源码和视频

名称:数字秒表VHDL启动暂停清零(代码在文末付费下载) 软件:Quartus 语言:VHDL 代码功能: 数字秒表 使用VHDL语言设置数字秒表。要求具有百分秒、秒和分钟显示,百分秒范围00-99,秒范围00-59,分钟范围0…

《java 桌面软件开发》swing 以鼠标为中心放大缩小移动图片

swing 使用Graphic2D 绘制图片,要实现对图片进行缩放和自由拖动。 1.以鼠标所在的位置为中心,滚轮控制缩放 2.缩放后再支持鼠标拖动。 基本原理: 利用scale() 函数。进行缩放。但是要注意的地方是,如果是在 public void paintCom…

Linux 下安装配置部署MySql8.0

一 . 准备工作 MySQL安装包:在官网下载需要的版本,这里我用的版本是 MySQL 8.0.34 https://dev.mysql.com/downloads/mysql/ 本次linux机器使用的是阿里云ECS实例 二 . 开始部署 1. 将安装包上传至服务器 解压到当前文件夹 tar -zxvf mysql-8.0.34…

Python 实现http server接收mutipart/form-data文件 方法1

Python 实现http server接收mutipart/form-data文件 方法1 1 Server端代码2 客户端截图3 代码说明 1 Server端代码 import os from flask import Flask, request from werkzeug.utils import secure_filenameapp Flask(__name__) app.config[UPLOAD_FOLDER] E://recv//app.ro…

玩游戏缺失“d3d11.dll丢失“的问题的五种解决方案

在我日常的计算机维护工作中,经常遇到一些用户报告他们遇到了"d3d11.dll丢失"的问题。这是一个常见的Windows系统错误,通常会导致程序无法正常运行。在这篇文章中,我将分享我找到的五种有效的解决方法,以帮助这些用户解…

开源的容器运行时项目 Podman

本心、输入输出、结果 文章目录 开源的容器运行时项目 Podman前言Podman 简介Podman 与 Docker 的区别Podman 在使用上和 Docker 有什么区别从构建者角度分析 Podman 在使用上和 Docker 有什么区别从使用者角度分析 Podman 在使用上和 Docker 有什么区别 Podman 常用命令容器镜…

Linux shell编程学习笔记14:编写和运行第一个shell脚本hello world!

* 20231020 写这篇博文断断续续花了好几天,为了说明不同shell在执行同一脚本文件时的差别,我分别在csdn提供线上Linux环境 (使用的shell是zsh)和自己的电脑上(使用的shell是bash)做测试。功夫不负有心人&am…

详解如何利用Pytest Cache Fixture实现测试结果缓存

这篇文章主要为大家详细介绍了如何利用Pytest Cache Fixture实现测试结果缓存,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起了解一下− 前言 接口自动关过程中,经常会遇到这样一些场景,“请求2需要用到请求1响应的数据”,常见的…

人脸识别顶会论文及源码合集,含2023最新

今天和大家聊聊人脸识别。 人脸识别的技术经过不断发展已经相当成熟,在门禁、监控、手机解锁、移动支付等实际场景都能看到。我们比较熟悉的识别方式是基于可见光图像的人脸识别,这种方式有个非常明显的缺点:光线限制。 在近两年的人脸识别…

如何解决NSIS 2G文件的限制

Internal compiler error #12345: error mmapping datablock to 33556079.Note: you may have one or two (large) stale temporary file(s) left in your temporary directory (Generally this only happens on Windows 9x). 最近在使用NSIS打包一个7.3GB的可执行程序时&…

【算法|动态规划No.25】leetcode LCR 020. 回文子串

个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 🍔本专栏旨在提高自己算法能力的同时,记录一下自己的学习过程,希望…