【OpenCV实现图像的算数运算,性能测试和优化,改变颜色空间】

文章目录

    • OpenCV功能概要
    • 图像的算数运算
    • 性能测试和优化
    • 改变颜色空间
    • 对象追踪

OpenCV功能概要

OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习库,提供了丰富的图像处理和计算机视觉算法。它支持多种编程语言,包括Python、C++和Java。以下是OpenCV的主要功能概要:

  1. 图像的算数运算:
    OpenCV提供了多种算数运算函数,包括加法、减法、位运算等,可以用来处理图像。这些函数能够执行图像间的像素级别操作,例如图像加法和减法,以及与常数的算数运算。

  2. 性能测试和优化:
    OpenCV提供了丰富的性能测试工具和优化技术,可以帮助开发者评估和提高图像处理算法的性能。使用OpenCV的性能测试功能,可以度量不同操作的执行时间,从而找出性能瓶颈。优化技术包括使用OpenCV的内置函数,以及利用硬件加速(如CUDA和OpenCL)来加速图像处理任务。

  3. 改变颜色空间:
    OpenCV支持多种颜色空间的转换,例如RGB到灰度、RGB到HSV等。这些转换可以帮助开发者在不同颜色空间中进行图像处理,从而更好地理解和操作图像的颜色信息。

图像的算数运算

一些图像上的运算操作,就像加法,减法,位操作等等
函数:cv.add()、cv.addWeighted()等等

1.图像添加
图像的添加是图像处理中常见的操作之一,用于将两幅图像叠加在一起。在OpenCV中,你可以使用cv2.add()函数来实现图像的添加。另外,你也可以使用NumPy进行相似的操作,但需要注意OpenCV和NumPy在处理饱和运算方面的差异。

使用OpenCV的cv2.add()函数时,它会执行饱和运算(saturate operation),即当像素值超过255时,会被截断到255,不会溢出。这是因为图像的像素值通常是8位无符号整数(0到255之间的值),超出这个范围的值会被截断。

import cv2
import numpy as np

# 读取两幅图像
img1 = cv2.imread('img.png')
img2 = cv2.imread('img_1.png')

# 调整第二幅图像的尺寸与第一幅图像相同
img2_resized = cv2.resize(img2, (img1.shape[1], img1.shape[0]))

# 使用NumPy进行图像相加(饱和运算)
added_image_numpy = np.clip(img1.astype(int) + img2_resized.astype(int), 0, 255).astype(np.uint8)

# 输出结果
print("NumPy添加结果(饱和运算):", added_image_numpy)
cv2.imshow('Blended Image', added_image_numpy)
cv2.waitKey(0)
cv2.destroyAllWindows()

cv2.add()函数执行了饱和运算,确保了结果图像的像素值不会超出255。而使用NumPy进行图像相加时,需要使用np.clip()函数来进行饱和运算,确保结果在合理范围内。
在这里插入图片描述

2.图片混合
这种图像叠加操作是通过赋予不同权重给两幅图像,从而实现混合或透明效果的一种方法。具体地,通过以下的线性组合公式:

g(x)=(1−α)f0(x)+αf1(x)g(x)=(1−α)f0​(x)+αf1​(x)

其中,f0(x)f0​(x)和f1(x)f1​(x)分别代表两幅输入图像的像素值,αα表示权重,可以调整从0到1,实现不同程度的混合。在OpenCV中,这种混合效果可以通过cv2.addWeighted()函数实现,其公式如下:

dst=α⋅img1+β⋅img2+γdst=α⋅img1+β⋅img2+γ

在这个公式中,img1和img2分别是两幅输入图像,αα和ββ是相应图像的权重,而γγ通常被设置为0。

以下是一个使用OpenCV进行两幅图像混合的例子:

import cv2

# 读取两幅图像
img1 = cv2.imread('img.png')
img2 = cv2.imread('img_1.png')

# 调整第二幅图像的尺寸与第一幅图像相同
img2_resized = cv2.resize(img2, (img1.shape[1], img1.shape[0]))

# 设置权重
alpha = 0.7
beta = 0.3

# 图像混合
blended_img = cv2.addWeighted(img1, alpha, img2_resized, beta, 0)

# 显示混合结果
cv2.imshow('Blended Image', blended_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

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

3.位操作
我想把OpenCV的图标放到一个图片上面。如果我直接相加两个图像,图标的颜色就会被改变。如果是选择混合他们,那么透明度就会受影响。但我希望它是不透明的。如果这是一个规则的区域,我就可以用上一个章节使用的ROI来操作。但是OpenCV图标并不是一个规则的形状。所以你可以通过下面的例子进行位运算。

使用位运算来处理两幅图像,将OpenCV的图标放置在另一幅图像的特定区域上,并确保它是不透明的。以下是代码的详细解释:

  1. 加载图片:
img1 = cv.imread('messi5.jpg')
img2 = cv.imread('opencv-logo-white.png')

2.创建ROI区域:
我们希望将img2(OpenCV的图标)放在img1的左上角。因此,我们创建一个ROI区域,其大小与img2相同。

rows, cols, channels = img2.shape
roi = img1[0:rows, 0:cols]

3.创建徽标蒙版和反向蒙版:
我们将img2转换为灰度图像,然后使用阈值将其二值化(变为黑白图像)。接着,我们通过cv.bitwise_not()函数创建反向蒙版。

img2gray = cv.cvtColor(img2, cv.COLOR_BGR2GRAY)
ret, mask = cv.threshold(img2gray, 10, 255, cv.THRESH_BINARY)
mask_inv = cv.bitwise_not(mask)

4.背景提取和前景提取:
使用cv.bitwise_and()函数,我们将ROI区域中的徽标区域涂黑,得到背景提取的图像(img1_bg)。然后,我们从徽标图像中提取徽标区域,得到前景提取的图像(img2_fg)。

img1_bg = cv.bitwise_and(roi, roi, mask=mask_inv)
img2_fg = cv.bitwise_and(img2, img2, mask=mask)

5.合并前景和背景:
将前景和背景图像相加,得到最终的结果图像。

dst = cv.add(img1_bg, img2_fg)
img1[0:rows, 0:cols] = dst

6.显示结果:
最终,通过cv.imshow()函数显示结果图像,你也可以在代码中插入其他步骤来查看中间结果。

  cv.imshow('res', img1)
    cv.waitKey(0)
    cv.destroyAllWindows()

这个例子中使用位运算,将OpenCV的图标合并到了另一幅图像的特定区域上,同时确保了不透明度。

性能测试和优化

函数:cv.getTickCount,cv.getTickFrequency 等等
在OpenCV中,你可以使用cv.getTickCount()函数来获取一个时间戳,该时间戳表示自系统启动以来的时钟周期数。你还可以使用cv.getTickFrequency()函数来获取时钟周期的频率,即每秒的时钟周期数。通过这两个函数,你可以计算函数的运行时间。

具体步骤如下:

使用cv.getTickCount()获取函数开始时的时间戳。
e1 = cv.getTickCount()
在你的代码执行完毕后,再次调用cv.getTickCount()获取函数结束时的时间戳。
  # 你的代码
e2 = cv.getTickCount()

计算函数的运行时间(以秒为单位)。

time = (e2 - e1) / cv.getTickFrequency()

这样,time变量将包含函数的运行时间(以秒为单位)。

OpenCV中默认的优化方法

OpenCV中的许多函数都利用了现代处理器的特殊指令集(如SSE2、AVX等)进行优化,以提高性能。OpenCV同时也包含了未经过优化的代码。因此,如果系统支持这些特殊指令集(几乎所有现代处理器都支持),应该充分利用它们。
在编译时,OpenCV默认会启用这些优化,因此在运行时,OpenCV会尽量使用经过优化的代码。只有在不支持这些指令集的情况下,OpenCV才会使用未优化的代码。可以使用cv.useOptimized()函数来检查优化是否启用,以及使用cv.setUseOptimized()函数来手动启用或禁用优化。

# 检查是否启用优化
print(cv.useOptimized())  # 输出: True

# 使用优化进行中值滤波,循环10次,计算平均每次循环的时间
%timeit res = cv.medianBlur(img, 49)

# 禁用优化
cv.setUseOptimized(False)

# 检查是否禁用了优化
print(cv.useOptimized())  # 输出: False

# 禁用优化后进行中值滤波,循环10次,计算平均每次循环的时间
%timeit res = cv.medianBlur(img, 49)

在IPython中的测量方法
在IPython中,你可以使用神奇的timeit命令来完成这个任务。timeit通过多次运行代码获取准确的结果,同样也适用于单行代码。

比如,你想知道以下几种操作哪个更快:x = 5; y = x**2,x = 5; y = x * x,x = np.uint8([5]); y = x * x,或者是 y = np.square(x)。我们可以在IPython中找到答案。

x = 5

%timeit y = x**2
# 输出结果:10000000 loops, best of 3: 73 ns per loop

%timeit y = x * x
# 输出结果:10000000 loops, best of 3: 58.3 ns per loop

z = np.uint8([5])

%timeit y = z * z
# 输出结果:1000000 loops, best of 3: 1.25 us per loop

%timeit y = np.square(z)
# 输出结果:1000000 loops, best of 3: 1.16 us per loop

你会发现,x = 5; y = x * x 的速度要比Numpy的快20倍。如果考虑到创建一个数组,这个差距可能会更大,这真的很酷(实际上,Numpy就是用来解决这类问题的)。

需要注意的是,Python的标量运算远比Numpy的快。所以,如果你只是对一两个元素进行操作,可能没有必要使用Numpy。Numpy的真正优势体现在大量数据的矩阵运算上。

接下来,我们尝试比较cv.countNonZero()和np.count_nonzero()函数在操作同一张图片时的性能表现。

%timeit z = cv.countNonZero(img)
# 输出结果:100000 loops, best of 3: 15.8 us per loop

%timeit z = np.count_nonzero(img)
# 输出结果:1000 loops, best of 3: 370 us per loop

可以看到,OpenCV的函数比Numpy的快了大约25倍。

需要注意的是,通常情况下,OpenCV的函数比Numpy的函数更快。因此,在进行相同操作时,OpenCV的性能会更好。不过,也有一些例外情况,具体取决于操作的性质,特别是当Numpy使用视图而不是副本时。

改变颜色空间

图像从一个颜色空间转换到另外一个,就像 BGR ↔ Gray, BGR ↔ HSV ,等等。
创建一个应用程序来提取视频中的色彩对象。
函数:cv.cvtColor(),cv.inRange()等等。
注意:Note 对于 HSV,色调范围为 [0,179],饱和度范围为 [0,255],值范围为 [0,255]。不同的软件使用不同的尺度。因此,如果您将 OpenCV 值与它们进行比较,则需要对这些范围进行归一化。

改变颜色空间

在OpenCV中,有超过150种颜色空间转换方法,但我们通常关注其中两种最常用的:BGR到灰度(BGR ↔ Gray)和BGR到HSV(BGR ↔ HSV)的转换。

在颜色转换中,我们使用cv.cvtColor(input_img, flag)函数,其中flag参数用于确定转换的类型。

对于BGR到灰度的转换,我们将cv.COLOR_BGR2GRAY传递给flag参数。类似地,对于BGR到HSV的转换,我们将cv.COLOR_BGR2HSV传递给flag参数。可以在Python中运行以下代码:

import cv2 as cv

flags = [i for i in dir(cv) if i.startswith('COLOR_')]

print(flags)

需要注意的是,在HSV颜色空间中,色调范围是0,1790,179,饱和度范围是0,2550,255,值范围是0,2550,255。不同的软件使用不同的尺度。因此,如果你想将OpenCV中的值与其他软件进行比较,你需要对这些范围进行归一化处理。

对象追踪

现在,我们已经学会如何将一幅BGR图像转换成HSV颜色空间。接下来,我们可以利用这个知识来提取特定颜色的对象。在这个例子中,我们将尝试提取蓝色对象的图像。

以下是具体的步骤:

获取每一帧图像: 从视频中捕获每一帧图像。

颜色空间转换: 将BGR图像转换为HSV颜色空间,这样更容易提取特定颜色的对象。

颜色阈值处理: 在HSV颜色空间中,指定蓝色的阈值范围(lower_blue和upper_blue)。这样,我们可以定位在该范围内的蓝色像素。

创建掩码: 使用cv.inRange()函数创建一个掩码,该掩码仅包含在指定蓝色范围内的像素。

提取蓝色对象: 将掩码应用到原始图像上,使用cv.bitwise_and()函数,这样就可以提取出蓝色对象的图像。

显示图像: 分别显示原始图像、掩码和提取出的蓝色对象的图像。

等待用户操作: 等待用户按下键盘上的ESC键(ASCII码为27)来退出循环。

释放资源: 当用户按下ESC键后,释放所有窗口资源。
import cv2 as cv
import numpy as np

cap = cv.VideoCapture(0)

while True:
    # 获取每一帧
    _, frame = cap.read()

    # 从BGR转换到HSV
    hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)

    # 在HSV中定位蓝色范围
    lower_blue = np.array([110, 50, 50])
    upper_blue = np.array([130, 255, 255])

    # 设置HSV图像仅获得蓝色图像
    mask = cv.inRange(hsv, lower_blue, upper_blue)

    # 按位与掩码和原始图像
    res = cv.bitwise_and(frame, frame, mask=mask)

    # 显示图像
    cv.imshow('Original', frame)
    cv.imshow('Mask', mask)
    cv.imshow('Blue Object', res)

    # 等待用户按下ESC键退出
    k = cv.waitKey(5) & 0xFF
    if k == 27:
        break

# 释放资源
cap.release()
cv.destroyAllWindows()

在这里插入图片描述

Note 图像中有些噪声。我们将在后面演示如何去除它。这个是一个简单的项目追踪方法。一旦你学会了轮廓的函数,你就可以做一系列事情,就像是找到一个物体的质心并用它去跟踪物体,或者是只需要在相机前移动你的手就可以画出图表,或者其他有趣的事情。

要找到需要跟踪的颜色的HSV值,可以使用OpenCV中的cv.cvtColor()函数。不需要传递整个图像,只需传递所需的BGR值即可。以下是一个示例,假设想找到绿色的HSV值:

import numpy as np
import cv2 as cv

# 定义一个绿色的BGR值
green = np.uint8([[[0, 255, 0]]])

# 将BGR转换为HSV
hsv_green = cv.cvtColor(green, cv.COLOR_BGR2HSV)

print(hsv_green)

运行这段代码,会得到绿色的HSV值:[[[60 255 255]]]。现在,可以将这个HSV值作为跟踪绿色的下限(Lower Bound):[H-10, 100, 100],和上限(Upper Bound):[H+10, 255, 255]。在这个例子中,绿色的H值为60,所以下限为50,上限为70。这个范围可以根据实际情况微调。

另外,除了使用代码计算HSV值外,也可以使用图像编辑工具(如GIMP)或在线颜色转换器来找到这些值。但是请记住,确保在使用这些工具时调整HSV范围,因为不同的工具可能使用不同的HSV标准。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【计算机网络】HTTP协议

文章目录 1. HTTP介绍认识URL 2. HTTP消息结构请求request响应response 3. HTTP请求方法4. HTTP报头5. HTTP响应状态码6. Cookie和Session 1. HTTP介绍 HTTP(hypertext transfer protocol)是一种常用的应用层协议,用于在计算机之间传输超文本…

Linux常用命令——cksum命令

在线Linux命令查询工具 cksum 检查文件的CRC是否正确 补充说明 cksum命令是检查文件的CRC是否正确,确保文件从一个系统传输到另一个系统的过程中不被损坏。这种方法要求校验和在源系统中被计算出来,在目的系统中又被计算一次,两个数字进行…

Postman的简单使用

Postman简介 官网 Postman是Google公司开发的一款功能强大的网页调试与发送HTTP请求,并能运行测试用例的Chrome插件 使用Postman进行简单接口测试 新建测试 → 选择请求方式 → 请求URL,下面用百度作为例子: 参考文档 [1] Postman使用教程…

香港科技大学广州|可持续能源与环境学域博士招生宣讲会—广州大学城专场!!!(暨全额奖学金政策)

香港科技大学广州|可持续能源与环境学域博士招生宣讲会—广州大学城专场!!!(暨全额奖学金政策) “面向未来改变游戏规则的——可持续能源与环境学域” ���专注于能源环…

Mysql视图特性用户管理

目录 一、视图基本使用 二、用户管理 2.1 用户 ①用户信息 ②创建用户 tips:(解决无法创建用户) ③删除用户 ④修改用户密码 2.2数据库的权限 ①给用户授权 ②回收权限 视图:视图是一种虚拟表。视图是基于一个或多个基础表中的数据所创建的一个查询结果…

OTA: Optimal Transport Assignment for Object Detection 论文和代码学习

OTA 原因步骤什么是最优传输策略标签分配的OT正标签分配负标签分配损失计算中心点距离保持稳定动态k的选取 整体流程代码使用 论文连接: 原因 1、全部按照一个策略如IOU来分配GT和Anchors不能得到全局最优,可能只能得到局部最优。 2、目前提出的ATSS和P…

16结构型模式-组合模式

我们很容易将“组合模式”和“组合关系”搞混。组合模式最初只是用于解决树形结构的场景,更多的是处理对象组织结构之间的问题。而组合关系则是通过将不同对象封装起来完成一个统一功能. 1 组合模式介绍 将对象组合成树形结构以表示整个部分的层次结构.组合模式可…

深度学习 anaconda 安装问题

配置anaconda 在官网下载匹配版本的anaconda(官网下载可能时间比较长),可以选择清华镜像。 安装过程默认即可,或者根据情况进行修改。 旧版本是可以在安装的时候勾选添加路径到环境变量中的,但是我安装的是2023.9月…

分布式微服务技术栈-SpringCloud<Eureka,Ribbon,nacos>

微服务技术栈 一、微服务 介绍了解1 架构结构案例与 springboot 兼容关系拆分案例拆分服务拆分-服务远程调用 2 eureka注册中心Eureka-提供者与消费者Eureka-eureka原理分析Eureka-搭建eureka服务Eureka-服务注册Eureka-服务发现 3 Ribbon组件 负载均衡Ribbon-负载均衡原理Ribb…

Linux搭建Redis环境

1. 基础环境 名称说明CentOS 7.6Linux操作系统版本redis-5.0.0.tar.gzRedis二进制安装包 2. 服务安装 服务端路径:usr/loacl/redis/redis-server客户端路径:usr/loacl/redis/redis-cli # 解压二进制包 [rootzhouwei resource]# tar -zxvf redis-5.0.…

MySQL3:MySQL中一条更新SQL是如何执行的?

MySQL3:MySQL中一条更新SQL是如何执行的? MySQL中一条更新SQL是如何执行的?1.Buffer Pool缓冲池2.Redo logredo log作用Redo log文件位置redo log为什么是2个? 3.Undo log4.更新过程5.InnoDB官网架构InnoDB架构-内存结构①Buffer …

java类的动态加载

java类的动态加载 java动态加载的机制: ClassLoader->SecureClassloader–>URLClassLoader–>AppClassLoader loadClass–>findClass(重写方法)–>defineClass(从字节码加载类) 初始化的时候会加载静态代码块 实例化的时候会加载构造代码块、无参构…

S32K324 UDS Bootloader开发-需求篇

文章目录 前言内存分配UDS诊断协议需求CAN ID及时间参数UDS诊断服务Bootloader诊断服务APP诊断服务 DID22服务的DID:2E服务的DID:Routine Control DID: 刷写流程预编程主编程后编程 总结 前言 之前做过一个STM32的UDS Bootloader,协议栈主要是NXP官网下…

单片机矩阵键盘

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、什么是矩阵键盘?1.独立键盘2.矩阵键盘变化1变化2变化3 3. 通过变型,举一反三,就可以实现4*4的矩阵键盘扫描 二、使用步骤…

app开发者提升第四季度广告收入的方法

第四季度将迎来双十一、双十二、圣诞、元旦为主的电商购物季,这是一年中利用线上消费为全新年度和全新预算做好准备的最佳时机,从过往的变现成功案例中汇总了优化要点,帮助开发者在第四季度和未来一年获取更多广告收益。 https://www.shensh…

CSS - 常用属性和布局方式

目录 前言 一、常用属性 1.1、字体相关 1.2、文本相关 1.3、背景相关 1.3.1、背景颜色 1.3.2、背景图片 1.4、圆角边框 二、常用布局相关 2.1、display 2.2、盒子模型 2.2.1、基本概念 2.2.2、border 边框 2.2.3、padding 内边距 2.2.4、margin 外边距 2.3、弹…

sql server2014如何添加多个实例 | 以及如何删除多个实例中的单个实例

标题sql server2014如何添加多个实例 前提(已安装sql server2014 且已有默认实例MSSQLSERVER) 添加新的实例 其实就是根据安装步骤再安装一次(区别在过程中说明) 双击安装 选择“全新独立安装或添加现有功能” 然后下一步下一…

【Spring Cloud】如何确定微服务项目的Spring Boot、Spring Cloud、Spring Cloud Alibaba的版本

文章目录 1. 版本选择2. 用脚手架快速生成微服务的pom.xml3. 创建一个父工程4. 代码地址 本文描述如何确定微服务项目的Spring Boot、Spring Cloud、Spring Cloud Alibaba的版本。 1. 版本选择 我们知道Spring Boot、Spring Cloud、Spring Cloud Alibaba的版本选择一致性非常重…

小主机折腾记18

这个月冲动消费了小两千块钱…… 1.880g5twr 由于四根2400t的内存条没有用出去,我又把它们装回了惠普的800g5twr; 看到pdd有400块钱的9350K,于是想着给他上一个9350k 在参考了pdd、咸鱼以及淘宝的价格后,我发现400块钱的9350k都…

【JAVA学习笔记】41 - 接口

项目代码 https://github.com/yinhai1114/Java_Learning_Code/tree/main/IDEA_Chapter10/src/com/yinhai/interface_ 一、快速入门 usb插槽就是现实中的接口。你可以把手机,相机,u盘都插在usb插槽上,而不用担心那个插槽是专门插哪个的&#x…