【OpenCV学习笔记08】- 图像基本操作

关于 OpenCV 官方文档的 GUI功能告一段落,接下来开始核心操作的学习。学习笔记中会记录官方给出的例子,也会给出自己根据官方的例子完成的更改代码,同样彩蛋的实现也会结合多个知识点一起实现一些小功能,来帮助我们对学会的知识点进行结合应用。
如果有喜欢我笔记的请麻烦帮我关注、点赞、评论。谢谢诸位。

学习笔记:
学习笔记目录里面会收录我关于OpenCV系列学习笔记博文,大家如果有什么不懂的可以通过阅读我的学习笔记进行学习。
【OpenCV学习笔记】- 学习笔记目录

内容

  • 访问像素值并修改它们
  • 访问像素属性
  • 设置感兴趣区域(ROI)
  • 分割和合并图像

本节中的几乎所有操作都主要与 Numpy 有关而非 OpenCV。熟悉 Numpy 后才能使用 OpenCV 编写更好的优化后代码。

访问和修改像素值

先来理解图像与一般的矩阵或张量的不同之处(不考虑图像的格式,元数据等信息)。
首先,一张图像有自己的属性:宽,高,通道数。
其中宽和高是我们肉眼可见的属性,而通道数则是图像能呈现色彩的属性。
我们都知道,光学三原色是红色,绿色和蓝色,这三种颜色的混合可以形成任意的颜色。
常见的图像的像素通道也是对应的R,G,B三个通道,在OpenCV中,每个通道的取值范围为0~255。(注:还有RGBA,YCrCb,HSV等其他图像通道表示方法)。即,一般彩色图像读进内存之后是一个h * w * c的矩阵,其中h为图像高(相当于矩阵的行),w为图像宽(相当于矩阵列),c为通道数。

下面我们先加载一副彩色图像,更准确地说,是一副黄色图像。
示例代码:

import numpy as np
import cv2

file_path = '../image/2.1.png'
img = cv2.imread(file_path)
cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyWindow("image")
h, w, c = img.shape
# 图像大小
print(h, w, c)

效果图:
在这里插入图片描述
控制台/命令行输出:

512 512 3

从下面的代码中可以看到,您可以通过行和列坐标访问像素值。注意,对于常见的RGB 图像,OpenCV的imread函数返回的是一个蓝色(Blue)值、绿色(Green)值、红色(Red)值的数组,维度大小为3。而对于灰度图像,仅返回相应的灰度值。

示例代码:

import numpy as np
import cv2

file_path = '../image/2.1.png'
img = cv2.imread(file_path)
cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyWindow("image")
h, w, c = img.shape
# 图像大小
print(h, w, c)

print(img[100, 100])
# OpenCV的读取顺序为B,G,R,由于图像所有像素为黄色,因此,G=255,R=255
# [  0 255 255]

控制台/命令行输出:

512 512 3
[  0 255 255]

访问三个通道的像素:

示例代码:

import numpy as np
import cv2

file_path = '../image/2.1.png'
img = cv2.imread(file_path)
cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyWindow("image")
h, w, c = img.shape
# 图像大小
print(h, w, c)

print(img[100, 100])
# OpenCV的读取顺序为B,G,R,由于图像所有像素为黄色,因此,G=255,R=255
# [  0 255 255]
# 仅访问蓝色通道的像素
blue = img[0, 0, 0]
print(blue)
# 仅访问绿色通道的像素
green = img[0, 0, 1]
print(green)
# 仅访问红通道的像素
red = img[0, 0, 2]
print(red)

控制台/命令行输出:

512 512 3
[  0 255 255]
0
255
255

在这里我们会发现img[0, 0]和img[100, 100]输出是一样的,因为这是一张纯色图。

更改像素点

我们可以通过相同方式给对应位置的像素赋值不同颜色。
在这里我通过修改一个小的九宫格像素,我们可以在效果图中很明显有一个黑点出现。
示例代码:

import numpy as np
import cv2

file_path = '../image/2.1.png'
img = cv2.imread(file_path)
cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyWindow("image")
h, w, c = img.shape
# 图像大小
print(h, w, c)

print(img[100, 100])
# OpenCV的读取顺序为B,G,R,由于图像所有像素为黄色,因此,G=255,R=255
# [  0 255 255]
# 仅访问蓝色通道的像素
blue = img[0, 0, 0]
print(blue)
# 仅访问绿色通道的像素
green = img[0, 0, 1]
print(green)
# 仅访问红通道的像素
red = img[0, 0, 2]
print(red)

# 更改像素点颜色
img[99, 99] = [0, 0, 0]
img[99, 100] = [0, 0, 0]
img[99, 101] = [0, 0, 0]
img[100, 99] = [0, 0, 0]
img[100, 100] = [0, 0, 0]
img[100, 101] = [0, 0, 0]
img[101, 99] = [0, 0, 0]
img[101, 100] = [0, 0, 0]
img[101, 101] = [0, 0, 0]

cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyWindow("image")

原图:
在这里插入图片描述

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

通过 Numpy 数组方法进行更改像素点

Numpy 是一个用于快速阵列计算的优化库。因此,简单地访问每个像素值并修改其值将非常缓慢,并不鼓励这样做。

注意: 上述方法通常用于选择数组的某个区域,比如前 5 行和后 3 列。对于单个像素的访问,可以选择使用 Numpy 数组方法中的 array.item()和 array.itemset(),注意它们的返回值是一个标量。如果需要访问所有的 G、R、B 的值,则需要所有像素分别调用 array.item()

更好访问和编辑像素的方法:
示例代码:

import numpy as np
import cv2

file_path = '../image/2.1.png'
img = cv2.imread(file_path)
cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyWindow("image")
h, w, c = img.shape

# 仅访问蓝色通道的像素
blue = img.item(0, 0, 0)
print(blue)
# 仅访问绿色通道的像素
green = img.item(0, 0, 1)
print(green)
# 仅访问红通道的像素
red = img.item(0, 0, 2)
print(red)

# # 更改像素点颜色
img.itemset((99, 99, 0), 0)
img.itemset((99, 99, 1), 0)
img.itemset((99, 99, 2), 0)
img.itemset((99, 100, 0), 0)
img.itemset((99, 100, 1), 0)
img.itemset((99, 100, 2), 0)
img.itemset((99, 101, 0), 0)
img.itemset((99, 101, 1), 0)
img.itemset((99, 101, 2), 0)
img.itemset((100, 99, 0), 0)
img.itemset((100, 99, 1), 0)
img.itemset((100, 99, 2), 0)
img.itemset((100, 100, 0), 0)
img.itemset((100, 100, 1), 0)
img.itemset((100, 100, 2), 0)
img.itemset((100, 101, 0), 0)
img.itemset((100, 101, 1), 0)
img.itemset((100, 101, 2), 0)
img.itemset((101, 99, 0), 0)
img.itemset((101, 99, 1), 0)
img.itemset((101, 99, 2), 0)
img.itemset((101, 100, 0), 0)
img.itemset((101, 100, 1), 0)
img.itemset((101, 100, 2), 0)
img.itemset((101, 101, 0), 0)
img.itemset((101, 101, 1), 0)
img.itemset((101, 101, 2), 0)


cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyWindow("image")

原图:
在这里插入图片描述

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

访问图像属性

图像属性包括行数,列数和通道数,图像数据类型,像素数等。

与一般的numpy.array一样,可以通过 img.shape 访问图像的形状。它返回一组由图像的行、列和通道组成的元组(如果图像是彩色的):
示例代码:

print(img.shape)
(512, 512, 3)

注意: 如果图像是灰度图像,则返回的元组仅包含行数和列数,因此它是检查加载的图像是灰度图还是彩色图的一种很好的方法。

通过 img.size 访问图像的总像素数:
示例代码:

print(img.size)
786432

图像数据类型可以由 img.dtype 获得:
示例代码:

print(img.dtype)
uint8

注意: img.dtype 在调试时非常重要,因为 OpenCV-Python 代码中的大量错误由无效的数据类型引起。

图像中的感兴趣区域

有时您将不得不处理某些图像区域。对于图像中的眼部检测,在整个图像上进行第一次面部检测。当获得面部后,我们单独选择面部区域并在其内部搜索眼部而不是搜索整个原始图像。它提高了准确性(因为眼睛总是在脸上:D)和性能(因为我们在一个小区域搜索)。

使用 Numpy 索引再次获得 ROI(感兴趣区域)。在这里,我选择球并将其复制到图像中的另一个区域:
示例代码:

import numpy as np
import cv2

file_path = '../image/1.jpg'
img = cv2.imread(file_path)

# 复制区域的像素
cow = img[1126:1295, 1800:1991]
# 在指定区域覆盖像素
img[600: 769, 1100:1291] = cow

cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyWindow("image")

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

拆分和合并图像通道

有时您需要在 B,G,R 通道图像上单独工作。在这种情况下,您需要将 BGR 图像分割为单个通道。在其他情况下,您可能需要将这些单独的通道合并至 BGR 图像。您可以通过以下方式完成:
示例代码:

# 得到 B、G、R通道
b, g, r = cv2.split(img)
# 合并通道
img = cv2.merge((b, g, r))

或者使用numpy.array的切片方法
示例代码:

# 得到 B 通道
b = img[:,:,0]

假设您要将所有红色像素设置为零,则无需先拆分通道。Numpy 索引更快:
示例代码:

# 修改 R 通道像素为0
img[:,:,2] = 0

警告:
cv2.spilt()是一项代价高昂的操作(就时间而言)。所以只在你需要时再这样做,否则使用 Numpy 索引。

制作图像边界(填充)

如果要在图像周围创建边框,比如相框,可以使用 cv2.copyMakeBorder()。但它有更多卷积运算,零填充等应用。该函数采用以下参数:

  • src:输入的图像

  • top,bottom,left,right:上下左右四个方向上的边界拓宽的值

  • borderType:定义要添加的边框类型的标志。它可以是以下类型:

    • cv2.BORDER_CONSTANT:添加一个恒定的彩色边框。该值应作为下一个参数value给出。
    • cv2.BORDER_REFLECT:边框将是边框元素的镜像反射,如下所示:fedcba|abcdefgh|hgfedcb
    • cv2.BORDER_REFLECT_101 或者 cv2.BORDER_DEFAULT:与上面相同,但略有改动,如下所示: gfedcb | abcdefgh | gfedcba
    • cv2.BORDER_REPLICATE:最后一个元素被复制,如下所示: aaaaaa | abcdefgh | hhhhhhh
    • cv2.BORDER_WRAP:不好解释,它看起来像这样: cdefgh | abcdefgh | abcdefg
  • value:如果边框类型为 cv2.BORDER_CONSTANT,则这个值即为要设置的边框颜色

下面是一个示例代码,演示了上述所有边框类型,以便更好地理解:
示例代码:

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

BLUE = [255, 255, 0]
img1 = cv2.imread('../image/OpenCV.jpg')
replicate = cv2.copyMakeBorder(img1, 30, 30, 30, 30, cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img1, 30, 30, 30, 30, cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img1, 30, 30, 30, 30, cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img1, 30, 30, 30, 30, cv2.BORDER_WRAP)
constant = cv2.copyMakeBorder(img1, 30, 30, 30, 30, cv2.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()

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

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

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

相关文章

leetcode:LCR 159. 库存管理 III(python3解法)

难度:简单 仓库管理员以数组 stock 形式记录商品库存表,其中 stock[i] 表示对应商品库存余量。请返回库存余量最少的 cnt 个商品余量,返回 顺序不限。 示例 1: 输入:stock [2,5,7,4], cnt 1 输出:[2]示例…

通过wireshark抓取的流量还原文件(以zip为例)

wireshark打开流量包,通过zip关键字查找 追踪流可查看详细信息 选中media Type右键, 点击导出分组字节流选项 将生成的文件进行命名,需要时什么格式就以什么格式后缀

uniapp 字母索引列表插件(组件版) Ba-SortList

简介(下载地址) Ba-SortList 是一款字母索引列表组件版插件,可自定义样式,支持首字母字母检索、首字检索、搜索等等;支持点击事件。 支持首字母字母检索支持首字检索支持搜索支持点击事件支持长按事件支持在uniapp界…

代币中的decimal精度代表了什么

精度的意义在于允许发送小数的代币。举例,一个CAT代币合约的精度为6。那么 你拥有1个CAT就意味着合约中的balance 1 * 10^6 , 转账 0.1CAT出去的话,就需要输入 0.1*10^6 10^5。 也就时在涉及代币时,查询到的余额、转账的代币数量 都和 代币…

扫描错题用什么软件?分享4个好用的工具!

在学习的道路上,我们难免会遇到错题。有些时候,手抄的笔记或是纸质错题集不易携带、查找不方便,还容易丢失。为了解决这些问题,现在有许多软件可以帮助我们快速、准确地扫描错题,并进行整理和纠正。本文将为你介绍几款…

满足ITOM需求的网络监控工具

IT 运营管理(ITOM)可以定义为监督 IT 基础架构的各种物理和虚拟组件的过程;确保其性能、运行状况和可用性;并使它们能够与基础架构的其他组件无缝协作。IT 运营管理(ITOM)在大型 IT 管理模型中也发挥着积极作用,包括 I…

使用GraphQL实现简单的增删改查

使用GraphQL实现简单的增删改查 GraphQL官网:https://graphql.cn/ Altair Graphql 调试工具:https://saltair.sirmuel.design/#download 或者添加扩展使用网页版:https://chrome.google.com/webstore/detail/altair-graphql-client/flnheeel…

在线图表编辑工具Draw.io本地部署并结合内网穿透实现远程协作办公

前言 提到流程图,大家第一时间可能会想到Visio,不可否认,VIsio确实是功能强大,但是软件为收费,并且因为其功能强大,导致安装需要很多的系统内存,并且是不可跨平台使用。所以,今天给…

怎么处理网站的一些安全风险

随时互联网的持续发展,数字化转型步伐不断加快,社会各行业都走进了信息化、数字化。但与此同时,网络发展带来了许多风险,各行业面临着日益复杂的数据安全和网络安全威胁。其中,网站的安全风险持续增长,是各…

R语言生物群落(生态)数据统计分析与绘图教程

详情点击链接:R语言生物群落(生态)数据统计分析与绘图教程 前沿 R 语言作的开源、自由、免费等特点使其广泛应用于生物群落数据统计分析。生物群落数据多样而复杂,涉及众多统计分析方法。 一:R和Rstudio及入门和作…

零基础学习数学建模——(一)什么是数学建模

本篇博客将详细介绍什么是数学建模。 文章目录 个人简介什么是数学建模(一)引例:高中数学里的简单线性规划问题数学建模的定义及用途数学建模的定义数学建模的用途 正确认识数学建模 个人简介 ​ 本人在本科阶段获得过国赛省一、mathorcup数…

【算法】基础算法001之双指针

👀樊梓慕:个人主页 🎥个人专栏:《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》《算法》 🌝每一个不曾起舞的日子,都是对生命的辜负 目录 前言 1.数组分块&#xf…

UTONMOS:探索元宇宙,开启未来游戏新篇章

在元宇宙的世界里,游戏不再只是消遣,而是一个全新的互动世界,等待你来探索! 逼真的虚拟现实技术,让你沉浸在充满想象力的游戏世界中,体验前所未有的刺激和乐趣。 与来自全球的玩家互动交流,结…

vue3+ts+vite中封装axios,使用方法从0到1

一、安装axios npm install axios types/axios --save二、配置代理vite.config.ts,如果没有需要新建该文件 module.exports {server: {proxy: {/api: {target: http://localhost:5000, // 设置代理目标changeOrigin: true, // 是否改变请求源地址rewrite: (path)…

【算法每日一练]-动态规划 (保姆级教程 篇16) #纸带 #围栏木桩 #四柱河内塔

目录 今日知识点: 计算最长子序列的方案个数,类似最短路径个数问题 四柱河内塔问题:dp[i]min{ (p[i-k]f[k])dp[i-k] } 纸带 围栏木桩 四柱河内塔 纸带 思路: 我们先设置dp[i]表示从i到n的方案数。 那么减法操作中&#xff…

Kafka消息存储

一、层次结构 具体到某个broker上则是, 数据目录/分区名/日志相关文件集合。其中日志文件集合内包括.log文件, index索引文件和.timeindex时间戳索引文件。 二、.log 结构 .log中记录具体的消息。一般消息由header和body组成, 这点儿在Kafka消息中也同样适用。 message MES…

视角与焦距

视角与焦距关系 视角与焦距之间存在密切的关系。在摄影和摄像领域,这两个概念都非常重要。 视角是指相机镜头所能覆盖的视野范围,通常以度数来表示。焦距则是从镜头到成像平面的距离,决定了拍摄的物体在成像平面上的大小。 焦距越短,视角就越大,拍到的画面就越宽广;焦距…

雪王IP +出海,是蜜雪冰城登陆港交所想讲的“新故事”?

霸屏互联网的“雪王”,如今身影出现在港交所。这一次,“雪王”除了出街的气派,也给市场打开了更多的想象空间。 据招股书数据,2023年前三个季度,蜜雪冰城营收同比增加近50%。如今看来,无论是品牌影响力&am…

【数据库学习】ClickHouse(ck)

1,ClickHouse(CK) 是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS)。 1)特性 按列存储,列越多速度越慢; 按列存储,数据更容易压缩(类型相同、区分度)&#xff1b…

Flink/Doris生产环境方案选型的一些思考

各位总监,技术负责人,架构师们大家好。今天的文章有点短,是一些个人思考,仅做记录。 以Flink为主的计算组件和以Doris为代表的存储计算一体的方案选择问题是我们在技术选型过程中最常见的问题之一。也是很多公司和业务支持过程中会…