【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 loopz = 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 cvflags = [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 npcap = cv.VideoCapture(0)while True:# 获取每一帧_, frame = cap.read()# 从BGR转换到HSVhsv = 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) & 0xFFif 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标准。

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

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

相关文章

Java中的volatile关键字

volatile是什么? "volatile"是一个关键字,用于修饰变量。它的作用是告诉编译器该变量可能会在意料之外的时候被修改,因此编译器在对该变量进行优化时需要特别小心。 具体来说,当一个变量被声明为"volatile"…

算法通过村第十七关-贪心|白银笔记|贪心高频问题

文章目录 前言区间问题判断区间是否重复合并区间插入区间 字符串分割加油站问题总结 前言 提示:如果生活把你的门关上了,那你就再打开,这就是门,门就是这样的。 --佚名 贪婪的思想不一定要理解的很透彻,但是贪婪的问题…

Cookie技术

Cookie中文名称为小型文本文件,指某些网站为了辨别用户身份、进行会话跟踪而储存在用户本地终端上的数据。 Cookie是由服务器端生成,发送给User-Agent(—般是浏览器),浏览器会将Cookie的key/value保存到某个目录下的文…

软考系列(系统架构师)- 2013年系统架构师软考案例分析考点

试题一 软件架构(根据描述填表、ESB 定义和功能) 【问题1】(10分) 服务建模是对Ramp Coordination信息系统进行集成的首要工作,公司的架构师首先对Ramp Coordination信息系统进行服务建模,识别出系统中的两…

从Mysql架构看一条查询sql的执行过程

1. 通信协议 我们的程序或者工具要操作数据库,第一步要做什么事情? 跟数据库建立连接。 首先,MySQL必须要运行一个服务,监听默认的3306端口。在我们开发系统跟第三方对接的时候,必须要弄清楚的有两件事。 第一个就是通…

uniapp开发小程序 小米手机真机bottom:0无效 底部间隙 设备安全区域处理办法

uniApp自定义导航 CSS设置 bottom:0竟然无效,而iphone和开发模拟器没有问题 height: 150rpx;position: fixed;left: 0;right: 0;bottom: calc(var(--window-bottom,0)); 网上查了各种方法,包括设置bottom:-20啊以及 padding-bottom: constant(safe-are…

静电模型PIC方法的Matlab仿真设计

任务要求: 采用PIC模拟方法的静电模型来模拟多环形电子注在圆柱系统中的运动轨迹。模拟电子枪阴极表面发射电子注,电子在静态场的作用下运动直至稳定的运动过程。其中 系统长:0.01m 系统半径:0.005m 入射的每个宏电子电流&#x…

业界中说的快速原型法是什么

快速原型法是一种软件开发过程,其核心思想是在开发初期快速构建一个系统的原型,即一个工作模型,以便用户和开发者能够更好地理解系统的需求和功能。这种方法强调快速迭代和用户参与,目的是更早地发现和修正问题,从而提…

Ubuntu中查看电脑有多少个核——lscpu

1. 使用lscpu命令: 打开终端并输入以下命令: lscpu你会看到与CPU相关的详细信息。查找"CPU(s)"这一行来看总的核心数。另外,“Core(s) per socket”表示每个插槽或每个物理CPU的核数,“Socket(s)”表示物理CPU的数量。将这两个值相乘即得到总…

IO流框架,缓冲流

一.缓冲流有什么优点 Java中的缓冲流(Buffered Stream)具有以下优势: 提高效率:缓冲流通过在内存中缓存一部分数据,减少了直接从内存到磁盘或从磁盘到内存的频繁IO操作,从而提高了读写效率。缓冲区大小调整…

蓝桥杯双周赛算法心得——通关(哈希+小根堆)

大家好,我是晴天学长,这是很重要的贪心思维题,哈希的存法和小根堆的表示很重要。 1) .通关 2) .算法思路 通关 用hash(int[])存点的子节点并按输入顺序存关卡的号码(输入顺序就是) 列如&#…

RabbitMQ-死信交换机和死信队列

1. 简介 1.1 DLX简介 DLX: Dead-Letter-Exchange 死信交换器,死信邮箱 当消息成为Dead message后,可以被重新发送到另一个交换机,这个交换机就是DLX。 如下图所示: 其实死信队列就是一个普通的交换机,有些队列的消息…

初步认识 Web Components 并实现一个按钮

目录 1.Web Components 基本概念 1.1 三个场景 1.2 是什么 2.使用 Custom Elements 实现一个按钮 2.1 概念介绍 2.1.1 Shadow DOM 2.1.2 Element.attachShadow() 2.1.3 在组件中 使用 Shadow DOM 基本步骤 2.1.4 attributeChangedCallback 2.1.5 get observedAttribu…

Spring Security漏洞防护—HttpFirewall和 HTTPS

一、HttpFirewall Spring Security有几个领域,你所定义的 pattern 会针对传入的请求进行测试,以决定应该如何处理请求。这发生在 FilterChainProxy 决定请求应该通过哪个过滤链时,以及 FilterSecurityInterceptor 决定哪些安全约束适用于请求…

计算机毕设 flink大数据淘宝用户行为数据实时分析与可视化

文章目录 0 前言1、环境准备1.1 flink 下载相关 jar 包1.2 生成 kafka 数据1.3 开发前的三个小 tip 2、flink-sql 客户端编写运行 sql2.1 创建 kafka 数据源表2.2 指标统计:每小时成交量2.2.1 创建 es 结果表, 存放每小时的成交量2.2.2 执行 sql &#x…

Servlet 与Spring对比!

前言: Spring相关的框架知识,算是目前公司在用的前沿知识了,很重要!! 那么以Spring为基础的框架有几个? 以Spring为基础的框架包括若干模块,其中主要的有Spring Framework、Spring Boot、Spring…

Mybatis基础

文章目录 Mybatis基础XML语言概述使用Mybatis配置Mybatis增删改查复杂查询事务操作动态 SQLifchoose、when、otherwise 缓存机制注解开发 Mybatis基础 虽然我们能够通过JDBC来连接和操作数据库,但是哪怕只是完成一个SQL语句的执行,都需要编写大量的代码…

Tensorflow2 中模型训练标签顺序和预测结果标签顺序不一致问题解决办法

本篇文章将详细介绍Tensorflow2.x中模型训练标签顺序和预测结果标签顺序不一致问题,这个问题如果考虑不周,或者标签顺序没有控制好的情况下会出现预测结果精度极其不准确的情况。 训练数据集的结构:数据集有超过10的类别数,这里包…

【Java 进阶篇】Java HTTP 请求消息详解

HTTP(Hypertext Transfer Protocol)是一种用于传输超文本的应用层协议,广泛用于构建互联网应用。在Java中,我们经常需要发送HTTP请求来与远程服务器进行通信。本文将详细介绍Java中HTTP请求消息的各个部分,包括请求行、…

shouldComponentUpdate 是做什么的?

目录 前言 生命周期函数 shouldComponentUpdate 的写法和用法 代码 事件和API 优缺点 方法 总结 理论 结论 shouldComponentUpdate 是 React 类组件中的一个生命周期方法,用于决定一个组件的 props 或 state 发生变化时是否应该重新渲染。默认情况下&…