入门OpenCV(Python版)(上) opencv-python-tutorial
bigegpt 2024-10-12 06:57 8 浏览
引言
在本系列文章中,我将使用 Python 的 OpenCV 库展示一些计算机视觉初学者级别问题的解决方案。
OpenCV 库是最著名的开源计算机视觉库,可以用于许多编程语言中。利用它,我们可以对数字图像进行几何变换、滤波、摄像机标定、特征提取、目标检测等修改。
像素处理
对于第一个问题,作为“ hello world”类型的问题,我们将访问一个图像并操作其像素。
首先导入库。
import cv2
要加载图像,我们使用 imread 函数作为参数传递要读取的文件的名称以及我们希望如何读取它: 0-Black and White,1-Color,-1-changed。对于这个问题,我们只能解读为黑白和彩色。为了显示与读取类似的图像,我们调用一个函数作为参数传递要显示的窗口的名称及其内容,通常是通过调用 imread 创建的图像对象。
因此,让我们读取一个黑白图像,访问它的像素,改变一些,并显示结果。图像加载为一个矩阵(每个元素一个像素) ,如果灰度矩阵有两个维度,每个元素代表灰度的强度。如果是彩色的,则是一组三个矩阵表示的颜色通道 RGB。
image = cv2.imread("lenna.png", 0)
for i in range(200, 210):
for j in range(10, 200):
image[i][j] = 0
cv2.imshow("image", image)
重要提示: 在 OpenCV 中,矩阵的坐标是不同的。水平坐标为 y,垂直坐标为 x。此外,左上角是(0,0)原点的位置。所以坐标从左上角向右下方向增长。为了更容易理解,当使用称为 x 和 y 的变量在坐标上循环时,我们只会在访问位置时更改 OpenCV 符号。
读取之后,我们可以做一些简单的矩阵访问和改变像素颜色我们想要的。在修改了一些之后,我们用一种方法制作了一个矩形,把结果显示为黑色。
这里需要一个非常有用的命令,这样我们就可以使用相同的代码对图像进行多个操作。waitKey 等待用户按下一个键继续执行代码(这样我们就可以看到平静地显示的结果)。参数0等待要按的任何键在代码上继续。经过这个处理之后,我们再次读取 Lenna 的图像,但是这一次着色并绘制一个红色矩形,就像我们之前所做的那样。
cv2.waitKey(0)
image = cv2.imread("lenna.png", 1)
for i in range (200,210):
for j in range(10,200):
image[i, j] = [0, 0, 255]
cv2.imshow("janela", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
对于有颜色的图像,像素访问的方式是不同的,我们传递给像素的数组以 BGR 顺序表示颜色通道(由于某种“历史”原因被翻转过来)。作为输出,我们有一个最大的亮红色矩形,创建在同一点。
最后,为了破坏为显示图像而创建的窗口,我们调用了 destroyAllWindows 函数,因此在程序停止运行后什么也不显示。
现在,让我们用黑白图像的底片做一个矩形。矩形的位置由用户表示,负面效果是从像素的最大可能值减去像素(这里是8 bit:255)。
import cv2, sys
image = cv2.imread("lenna.png", 0)
for i in range(int(sys.argv[1]),int(sys.argv[2])):
for j in range(int(sys.argv[3]),int(sys.argv[4])):
image[i][j] = 255 - image[i][j]
cv2.imshow("janela", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
坐标100,200,30,150
进一步探索像素操作,让我们重新排列图像的四个象限。四分之一象限表示正方形格式的图像的1/4,就好像图像是在垂直和水平方向上被切成两半。
对于这个挑战,我们将使用 Numpy 库来简化使用矩阵的操作。Numpy 函数将矩阵分割为给定位置和给定方向。在分割图像之后,我们必须将这些部分以翻转的顺序连接起来。
import cv2
import numpy as np
image = cv2.imread("lenna.png", 0)
height, width = image.shape
#position to be splitted in half of the vertical and 0 for horizontal
[h,w] = np.split(image, [int(height/2)], 0)
#concatenate flipped in horizontal
image = np.concatenate((w,h))
#position to be splitted in half of the hoizontal and 1 for vertical
[h,w] = np.split(image,[int(width/2)], 1)
#concatenate flipped in vertical
image = np.concatenate((w,h),1)
cv2.imshow("image",image)
cv2.waitKey(0)
cv2.destroyAllWindows()
填充区域
在计算机视觉中,一个非常常见的任务是计算被检测场景中的目标。感知对象是检测属于每个对象的像素聚集的必要条件。为了更好地处理这个问题,我们将使用一个二进制图片(只有灰度像素0和255)意味着0黑色背景和1个对象像素。
这里我们假设每个白色像素的聚合都是一个单独的对象。所以,一个可能的做法是贴标签。通常标记算法以二值图像作为输入,并返回多尺度灰度图像。为此,我们将使用一种内置的算法来填充被称为“洪水填充”的区域。该算法实质上是以种子像素作为参考,搜索具有相同颜色的邻居。如果我们给出一个颜色作为参数的函数使所有的像素搜索找到的颜色。
Opencv 中的 floodFill 请求获得图像、掩码(not used = None)、种子像素以及为种子和类似邻居着色的颜色。有了这个,我们只需要逐个像素检查它的颜色,如果是白色,我们改变一些灰色,然后增加灰色,这样下一个对象将有一个不同的灰度。随着这个过程的进行,我们可以计算 floodFill 应用了多少次,并假设这是场景中对象的数量。
import cv2
image = cv2.imread("bolhas.png",0)
height, width = image.shape
cv2.imshow("image", image)
cv2.waitKey(0)
nelem = 0
for x in range(height):
for y in range(width):
if image[x,y] == 255:
nelem += 1
cv2.floodFill(image, None, (y,x), nelem)
print("Number of elements: ", nelem)
cv2.imshow("image", image)
cv2.waitKey(0)
结果,我们看不到一些物体,因为使用的灰色缩放是同样的变量用来计数对象的数量,所以使它成为一个非常深灰色。
由于我们使用灰度来计算对象的数量,因此在一个场景中进行8位处理时,我们会受到场景中255个对象数量的限制。您可以想出不同的方法来解决这个问题,我建议创建另一个变量,当元素数量达到256时(从0开始)跟踪这个变量。当这种情况发生时,这个变量将递增,nelem 将为零,以便重新开始。在标签的最后,我们会得到同样灰色的物体,但是与 nelem 一起跟踪的变量可以计算出超过极限后检测到的物体的数量。
现在再次看到原始的二进制图片,我们可以认识到有两种不同类型的对象,有一个洞和没有它。我们怎么能把它们分开计算呢?
首先,我们不知道那些被边界切开的是否有洞,所以我们忽略它们(以某种方式)。有了场景中的所有对象,解决这个问题的一个方法是在图像的背景中应用 floodFill 为 white 255(如果场景中有超过255个对象,我们必须编辑代码来保护最大白色不被使用) ,所以现在我们有了对象灰色缩放,背景白色和黑洞(旧背景) ,因为洪水填充背景白色不会击中洞。
for x in range(height):
if image[x,0] != 0:
cv2.floodFill(image, None, (0, x),0)
if image[x, width-1] != 0:
cv2.floodFill(image, None, (width-1, x),0)
for y in range(width):
if image[0,y] != 0:
cv2.floodFill(image, None, (y,0),0)
if image[height-1, y] != 0:
cv2.floodFill(image, None, (y, height-1), 0)
cv2.imshow("image", image)
cv2.waitKey(0)
有了这个,我们就解决了这个问题,让黑洞变成黑色,就是在整个图像中搜索黑色像素,每找到一个黑色像素,我们就增加黑洞的数量,然后用洪水填充,这样我们就不会错误地得到和。对于这个例子,我们使用相同的背景颜色,所以我们有洞的感觉。
cv2.floodFill(image, None, (0,0), 255)
nHoles = 0
for x in range(height):
for y in range(width):
if image[x,y] == 0:
cv2.floodFill(image, None, (y,x), 255)
nHoles += 1
print("Number of holes: ", nHoles)
cv2.imshow("image", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
· END ·
相关推荐
- 当Frida来“敲”门(frida是什么)
-
0x1渗透测试瓶颈目前,碰到越来越多的大客户都会将核心资产业务集中在统一的APP上,或者对自己比较重要的APP,如自己的主业务,办公APP进行加壳,流量加密,投入了很多精力在移动端的防护上。而现在挖...
- 服务端性能测试实战3-性能测试脚本开发
-
前言在前面的两篇文章中,我们分别介绍了性能测试的理论知识以及性能测试计划制定,本篇文章将重点介绍性能测试脚本开发。脚本开发将分为两个阶段:阶段一:了解各个接口的入参、出参,使用Python代码模拟前端...
- Springboot整合Apache Ftpserver拓展功能及业务讲解(三)
-
今日分享每天分享技术实战干货,技术在于积累和收藏,希望可以帮助到您,同时也希望获得您的支持和关注。架构开源地址:https://gitee.com/msxyspringboot整合Ftpserver参...
- Linux和Windows下:Python Crypto模块安装方式区别
-
一、Linux环境下:fromCrypto.SignatureimportPKCS1_v1_5如果导包报错:ImportError:Nomodulenamed'Crypt...
- Python 3 加密简介(python des加密解密)
-
Python3的标准库中是没多少用来解决加密的,不过却有用于处理哈希的库。在这里我们会对其进行一个简单的介绍,但重点会放在两个第三方的软件包:PyCrypto和cryptography上,我...
- 怎样从零开始编译一个魔兽世界开源服务端Windows
-
第二章:编译和安装我是艾西,上期我们讲述到编译一个魔兽世界开源服务端环境准备,那么今天跟大家聊聊怎么编译和安装我们直接进入正题(上一章没有看到的小伙伴可以点我主页查看)编译服务端:在D盘新建一个文件夹...
- 附1-Conda部署安装及基本使用(conda安装教程)
-
Windows环境安装安装介质下载下载地址:https://www.anaconda.com/products/individual安装Anaconda安装时,选择自定义安装,选择自定义安装路径:配置...
- 如何配置全世界最小的 MySQL 服务器
-
配置全世界最小的MySQL服务器——如何在一块IntelEdison为控制板上安装一个MySQL服务器。介绍在我最近的一篇博文中,物联网,消息以及MySQL,我展示了如果Partic...
- 如何使用Github Action来自动化编译PolarDB-PG数据库
-
随着PolarDB在国产数据库领域荣膺桂冠并持续获得广泛认可,越来越多的学生和技术爱好者开始关注并涉足这款由阿里巴巴集团倾力打造且性能卓越的关系型云原生数据库。有很多同学想要上手尝试,却卡在了编译数据...
- 面向NDK开发者的Android 7.0变更(ndk android.mk)
-
订阅Google官方微信公众号:谷歌开发者。与谷歌一起创造未来!受Android平台其他改进的影响,为了方便加载本机代码,AndroidM和N中的动态链接器对编写整洁且跨平台兼容的本机...
- 信创改造--人大金仓(Kingbase)数据库安装、备份恢复的问题纪要
-
问题一:在安装KingbaseES时,安装用户对于安装路径需有“读”、“写”、“执行”的权限。在Linux系统中,需要以非root用户执行安装程序,且该用户要有标准的home目录,您可...
- OpenSSH 安全漏洞,修补操作一手掌握
-
1.漏洞概述近日,国家信息安全漏洞库(CNNVD)收到关于OpenSSH安全漏洞(CNNVD-202407-017、CVE-2024-6387)情况的报送。攻击者可以利用该漏洞在无需认证的情况下,通...
- Linux:lsof命令详解(linux lsof命令详解)
-
介绍欢迎来到这篇博客。在这篇博客中,我们将学习Unix/Linux系统上的lsof命令行工具。命令行工具是您使用CLI(命令行界面)而不是GUI(图形用户界面)运行的程序或工具。lsoflsof代表&...
- 幻隐说固态第一期:固态硬盘接口类别
-
前排声明所有信息来源于网络收集,如有错误请评论区指出更正。废话不多说,目前固态硬盘接口按速度由慢到快分有这几类:SATA、mSATA、SATAExpress、PCI-E、m.2、u.2。下面我们来...
- 新品轰炸 影驰SSD多款产品登Computex
-
分享泡泡网SSD固态硬盘频道6月6日台北电脑展作为全球第二、亚洲最大的3C/IT产业链专业展,吸引了众多IT厂商和全球各地媒体的热烈关注,全球存储新势力—影驰,也积极参与其中,为广大玩家朋友带来了...
- 一周热门
- 最近发表
-
- 当Frida来“敲”门(frida是什么)
- 服务端性能测试实战3-性能测试脚本开发
- Springboot整合Apache Ftpserver拓展功能及业务讲解(三)
- Linux和Windows下:Python Crypto模块安装方式区别
- Python 3 加密简介(python des加密解密)
- 怎样从零开始编译一个魔兽世界开源服务端Windows
- 附1-Conda部署安装及基本使用(conda安装教程)
- 如何配置全世界最小的 MySQL 服务器
- 如何使用Github Action来自动化编译PolarDB-PG数据库
- 面向NDK开发者的Android 7.0变更(ndk android.mk)
- 标签列表
-
- mybatiscollection (79)
- mqtt服务器 (88)
- keyerror (78)
- c#map (65)
- resize函数 (64)
- xftp6 (83)
- bt搜索 (75)
- c#var (76)
- mybatis大于等于 (64)
- xcode-select (66)
- mysql授权 (74)
- 下载测试 (70)
- linuxlink (65)
- pythonwget (67)
- androidinclude (65)
- libcrypto.so (74)
- logstashinput (65)
- hadoop端口 (65)
- vue阻止冒泡 (67)
- jquery跨域 (68)
- php写入文件 (73)
- kafkatools (66)
- mysql导出数据库 (66)
- jquery鼠标移入移出 (71)
- 取小数点后两位的函数 (73)