计算机视觉(OpenCV+TensorFlow)

计算机视觉(OpenCV+TensorFlow)


文章目录

  • 计算机视觉(OpenCV+TensorFlow)
  • 前言
    • 7. 图像直方图
        • 绘制直方图
          • 绘制直方图有两种方式:
        • 掩膜
    • 8. 直方图均衡化
      • 直方图均衡化的介绍
      • 直方图均衡化的步骤
      • 自适应直方图均衡化
    • 9. 图像转换
      • 傅里叶变换
      • 在频域中的图像
      • OpenCV中使用傅里叶变换
      • 高通滤波和低通滤波
  • 总结


前言

本系列文章是OpenCV系列文章的第四篇,仍然跟随上篇内容主要聚焦于图像的一些操作,到本篇为止,与图像有关的所有的基本操作我们就都总结完了


7. 图像直方图

图像直方图顾名思义就是,x轴是像素值,y是像素的数量
下图就是一个图像直方图,像素值为250的数量大概是500个
在这里插入图片描述


Opencv给我们提供的函数是cv2.calcHist(),该函数有5个参数:

  • image:输入图像,传入时应该用中括号括起来,也就是我们可以传入多张数据
  • channels:传入图像的通道,如果是灰度图像,那只有一个通道,值为0,如果是彩色图像,那么值为0,1,2中选择一个,对应着BGR各个通道,这个值也要[]传入
  • mask:掩膜图像,如果统计整幅图,那么为none,如果我们只是统计图的一部分的直方图,那就要构造相应的掩膜实现,这个之后我们再具体说
  • histSize:灰度级的个数,需要中括号,比如[256]
  • ranges:像素值的范围,通常[0,256],有的图像如果不是,需要自己调整这个值

hist是256x1的数组,每个值对应于该图像中具有相应像素值的像素数

img = cv2.imread('cat.jpg',0) #0表示灰度图
hist = cv2.calcHist([img],[0],None,[256],[0,256])

绘制直方图

绘制直方图有两种方式:
  1. 使用Matplotlib
    1. Matplotlib带有直方图绘图功能:matplotlib.pyplot.hist()

它直接找到直方图并将其绘制。无需使用 calcHist() 或 np.histogram() 函数来查找直方图

img = cv2.imread('cat.jpg',0) #0表示灰度图
hist = cv2.calcHist([img],[0],None,[256],[0,256])
plt.hist(img.ravel(),256); 
plt.show()
  1. 或者还可以使用Matplotlib的法线图
img = cv2.imread('cat.jpg') 
color = ('b','g','r')
for i,col in enumerate(color): histr = cv2.calcHist([img],[i],None,[256],[0,256]) plt.plot(histr,color = col) plt.xlim([0,256]) 
  1. 使用OpenCV,用OpenCV的话,就有点麻烦,还要对hist数组进行变化,所以就用Matplotlib就可以了。
掩膜

如果我们要查找图像某些区域的直方图,只需在要查找直方图的区域上创建白色图像,不查找的创建黑色。然后这个只有白色和黑色的图像就是一个掩膜。
掩膜其实就是用了与操作,因为要显示的区域掩膜上是255,255换算成二进制8个1,任何数跟1做与运算都是它本身,那也就是任何数跟255做与运算都是它本身,那这不就是保留了原来的值了嘛。而又因为不想保留的地方是黑色的,任何数与0做与运算都是0,所以就把不想保留的地方变成了黑色的

# 先创建一个都是0的数组,然后将部分区域变成白色
mask = np.zeros(img.shape[:2], np.uint8)
print (mask.shape)
mask[100:300, 100:400] = 255
cv_show(mask,'mask')
# 导入一张灰度图
img = cv2.imread('cat.jpg', 0)
# 相应位置做与运算
masked_img = cv2.bitwise_and(img, img, mask=mask)#与操作
# 传入mask,统计部分区域的图像直方图
hist_mask = cv2.calcHist([img], [0], mask, [256], [0, 256])

8. 直方图均衡化

https://blog.csdn.net/zaishuiyifangxym/article/details/89813977

直方图均衡化的介绍

** 直方图均衡化是一种简单有效的图像增强技术,通过改变图像的直方图来改变图像中各个像素的灰度,主要用于增强动态范围偏小的图像的对比度。原始图像由于其灰度分布可能集中在较窄的区间,造成图像不够清晰。**

例如,过曝光图像的灰度级集中在高亮度范围内,而曝光不足图像的灰度级集中在低亮度范围内。
** 通过直方图均衡化,可以把原始图像的直方图变换成均匀分布的形式,这样就增加了像素之间灰度值差别的动态范围,从而达到增强图像整体对比度的效果。**

简而言之,直方图均衡化的原理是:对在图像中像素个数多的灰度值(即对画面起主要作用的灰度值)进行展宽,而对像素个数少的灰度值(即对画面不起主要作用的灰度值)进行归并,从而增大对比度,使图像清晰。

直方图均衡化的步骤

  1. 计算累计直方图
  2. 将累计直方图进行区间转换
  3. 在累计直方图中,概率相近的原始值会被处理为相同值

具体的例子:
** 如下图所示,已知一幅图像的像素分布为 7**
在这里插入图片描述

7,根据像素值,则可以计算出统计直方图

在这里插入图片描述


根据统计直方图,可以算出归一化直方图和累计直方图,如下图所示:

在这里插入图片描述


将累计直方图进行区间转换,如下图所示:

在这里插入图片描述


我们看均衡直方图,1对应3,这个3是说明像素级<=1的共有3个,那像素级为1的就有2个
2-0,3-1,4-1,5-0,6-1,7-1,我们可以看到有两个都是0,那相比于原来不就少了两个像素级嘛
上面的灰度级是8,那灰度级转变成256,计算方法类似,如下图所示:

在这里插入图片描述

!
原始直方图和均衡直方图为

在这里插入图片描述


由上图可以看出,虽然二者相似,但右侧均衡化后的直方图分布更均匀,相邻像素级概率和与高概率近似相等。如果将两张图的灰度级放在同一区间,可以看出差别更大,如下图所示:

在这里插入图片描述

在OpenCV中,我们用 equ = cv2.equalizeHist(img) 这个函数就可以均衡化

# 均衡化之前
img = cv2.imread('clahe.jpg',0) #0表示灰度图 #clahe
plt.hist(img.ravel(),256); 
plt.show()
# 均衡化之后
equ = cv2.equalizeHist(img) 
plt.hist(equ.ravel(),256)
plt.show()

均衡化之前:

在这里插入图片描述

均衡化之后:

在这里插入图片描述

自适应直方图均衡化

下图是均衡化的前后对比,可以看到背景的对比度是增强了,但是雕像的脸却变亮了许多,我们在那里丢失了大多数的信息,这是因为均衡化是默认是对全图进行均衡化,我们也可以分模块进行均衡化,这样就可以处理的更好。
在这里插入图片描述
在这里插入图片描述


在OpenCV 中,我们用 clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) 函数来做自适应变化

  • titleGridSize 进行像素均衡化的网格大小,即在多少网格下进行直方图的均衡化操作
  • clipLimit:颜色对比度限制阈值,默认为40;
# 创建一个clear对象
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) 
# 让图像交给clear对象处理
res_clahe = clahe.apply(img)

9. 图像转换

傅里叶变换

傅里叶变换,在很多领域都有很重要的运用,那么在图像处理中也有许多的运用,如果有朋友不是很了解的话,可以看下面这篇文章

https://zhuanlan.zhihu.com/p/19763358
傅里叶变换在图像中的运用:

  1. 图像增强与图像去噪
  2. 图像分割与边缘检测
  3. 图像特征提取
  4. 图像压缩

大家看傅里叶变换在图像中的运用我们或多或少在前都提到过,比如这个图像增强,图像去噪,图像分割和边缘检测,但是那些都是在时域上的操作,如果把图像放到频域中,那这些操作会更轻松。
简单来说:傅里叶变换的目的并不是为了观察图像的频率分布(至少不是最终目的),更多情况下是为了对频率进行过滤,通过修改频率以达到图像增强、图像去噪、边缘检测、特征提取、压缩加密等目的。

在频域中的图像

下面是图像在频域中的一些概念:

  1. 图像的频率是表征图像中灰度变化剧烈程度的指标,是灰度在平面空间上的梯度
  2. 图像高频分量:图像突变部分;在某些情况下指图像边缘信息,某些情况下指噪声,更多是两者的混合;
  3. 低频分量:图像变化平缓的部分,也就是图像轮廓信息
  4. 高通滤波器:让图像使低频分量抑制,高频分量通过
  5. 低通滤波器:与高通相反,让图像使高频分量抑制,低频分量通过
  6. 带通滤波器:使图像在某一部分的频率信息通过,其他过低或过高都抑制
  7. 还有个带阻滤波器,是带通的反。

OpenCV中使用傅里叶变换

如果有朋友想要快速上手在OpenCV中使用傅里叶变换,只需要记住

  1. 傅立叶变换的物理意义是将图像的灰度分布函数变换为图像的频率分布函数、
  2. 傅立叶变换提供另外一个角度来观察图像,可以将图像从灰度分布转化到频率分布上来观察图像的特征。
  3. 对一张图像做傅里叶变换,就是将它分解为 sin 和 cos 两部分,也就是将图像从空间域转换到频域。
    在这里插入图片描述

import numpy as np
import cv2
from matplotlib import pyplot as plt
# 导入一张灰度图
img = cv2.imread('lena.jpg',0)
# 将图像转换为float32的格式
img_float32 = np.float32(img)
# OpenCV的傅里叶变换函数,输出的是图像经过傅里叶变换后的结果
dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
# 此时,图像频谱中的零频率分量位于频谱图像(频域图像)的左上角,
# 通常使用 numpy.fft.fftshift() 来将零频率成分移动到频域图像的中心位置
dft_shift = np.fft.fftshift(dft)
# 我们得到的是一个复数数组,为了显示图像,需要将他们的值调到 [0,255] 的灰度空间中
magnitude_spectrum = 20*np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()

右边的图是左边图的频谱图

在这里插入图片描述


那频谱图是什么呢?具体的解释大家可以看这篇文章:https://blog.csdn.net/u014488388/article/details/52612456?t=1496943343720&utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0-52612456-blog-94553357.pc_relevant_3mothn_strategy_and_data_recovery&spm=1001.2101.3001.4242.1&utm_relevant_index=3

那简单的解释就是:
可以将频谱的中心看做坐标原点,横轴为x轴,纵轴是y轴,建立坐标系。
频谱平面上的坐标(X,Y)的黑白,表示图像是否含有z = sin(Xw + Yw)这个正弦平面波成分,白即是有含有。
但是最后的图是我们经过对数运算后的图,原本的图看起来不是很清晰,所以我们用对数运算将对比度放大了看的就比较清晰了

未经对数运算的频谱

在这里插入图片描述

高通滤波和低通滤波

刚才我们得到了这张图片的频谱图,那下面我们就要对这个频谱图进行操作

https://blog.csdn.net/weixin_51995147/article/details/124767050?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0-124767050-blog-71699582.pc_relevant_landingrelevant&spm=1001.2101.3001.4242.1&utm_relevant_index=3

import numpy as np
import cv2
from matplotlib import pyplot as plt
# 导进一张图片
img = cv2.imread('lena.jpg',0)
# 转换为 float32的格式
img_float32 = np.float32(img)
# 傅里叶变换
dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
# 将低频移到中间
dft_shift = np.fft.fftshift(dft)
# 求图片的中心位置
rows, cols = img.shape
crow, ccol = int(rows/2) , int(cols/2)     # 中心位置# 低通滤波:图像中心的是低频,我们想要保留低频,过滤高频,就用一个掩膜,中心的是1,其他是0
mask = np.zeros((rows, cols, 2), np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1# IDFT:傅里叶的逆变换
# 用频谱图乘掩膜,那最后就中心的保留了,其他都是0
fshift = dft_shift*mask
# 将低频的再移到原来的位置
f_ishift = np.fft.ifftshift(fshift)
# 进行傅里叶的逆变换
img_back = cv2.idft(f_ishift)
# 将实部和虚部结合
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Result'), plt.xticks([]), plt.yticks([])plt.show()   

总结

那到本期,OpenCV有关的图像基本操作我们已经全部就介绍完了,但是只是草草地介绍这个一下的话,那对于学习本身是毫无意义的,所以接下来的一遍,我们将引入一个银行卡号图像检测的实战内容,帮助大家理解上述讲过的所有图像操作

我是Mayphry,从一点点到亿点点,我们下次再见

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

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

相关文章

SAP_ABAP_编程基础_数据集_创建并填充摘录数据集 / 处理摘录数据集

SAP ABAP 顾问&#xff08;开发工程师&#xff09;能力模型_Terry谈企业数字化的博客-CSDN博客文章浏览阅读494次。目标&#xff1a;基于对SAP abap 顾问能力模型的梳理&#xff0c;给一年左右经验的abaper 快速成长为三年经验提供超级燃料&#xff01;https://blog.csdn.net/j…

webshell之自建漏洞免杀

今天主要讲解&#xff0c;如何利用通用漏洞来进行命令执行&#xff0c;从而达到免杀效果 常规反序列化免杀 这种方式就相当于直接触发提供一个反序列化漏洞入口&#xff0c;但是能否被利用&#xff0c;还是在于服务端本身是否存在反序列化漏洞&#xff0c;下面给了一个例子&a…

自定义hook函数与toRef

hook 什么是hook? 本质是一个函数&#xff0c;把setup函数中使用的Composition API进行了封装。类似于 vue2 中的mixin。自定义hook的优势&#xff1a;复用代码&#xff0c;让setup中的逻辑更清除易懂。怎么用&#xff1f; hooks文件夹里面的usepoint.js&#xff08;相当于封…

基于机器学习的笔记本电脑导购系统

目 录 中英文摘要 第一章 概述 1 1.1 课题开发背景及意义 1 1.2 课题研究现状 2 1.3 课题主要研究内容 3 第二章 需求分析 4 2.1 功能需求分析 4 2.2 可行性分析 10 2.3 流程分析 11 2.4 数据流图 13 2.5 性能需求分析 15 第三章 开发技术及工具 16 3.1 系统开发模式技术 16 3…

《凤凰项目》读书笔记

文章目录 一、书名和作者二、书籍概览2.1 主要论点和结构2.2 目标读者和应用场景 三、核心观点与主题3.1 DevOps的核心原则与文化变革3.2 持续交付与自动化3.3 变更管理与风险控制3.4 关键绩效指标与持续改进 四、亮点与启发4.1 最有影响的观点4.2 对个人专业发展的启示 五、批…

【Linux--进程控制】

目录 一、进程等待1.1进程等待方法1.2获取子进程status 二、进程替换2.1单进程版本--最简单得程序替换2.2 进程替换得原理2.3 多进程版本--验证各种程序替换接口2.4 总结 一、进程等待 1.1进程等待方法 问题1&#xff1a;进程等待是什么&#xff1f; 通过系统调用wait/waitpi…

python 已知经纬度获取影像DN值或位置

基本上就是一个经纬度转影像坐标的一个操作 之前我用 xOrigin geotransform[0] #-180 yOrigin geotransform[3] #90 这两个读取出来的分别就是经度和纬度&#xff0c;但是读取极投影为3413的影像时&#xff0c;读取出来的时投影坐标&#xff0c;因此在程序中多做了一步变…

Java 定时任务

Java 定时任务 为什么需要定时任务&#xff1f; 我们来看一下几个非常常见的业务场景&#xff1a; 某系统凌晨 1 点要进行数据备份。某电商平台&#xff0c;用户下单半个小时未支付的情况下需要自动取消订单。某媒体聚合平台&#xff0c;每 10 分钟动态抓取某某网站的数据为…

【kafka实践】09|消费者位移

位移主题 前面的章节中已经多次提到消费位移了&#xff0c;本节内容就要深入了解下消费位移topic&#xff1a;__consumer_offsets&#xff08;前面是两个下划线&#xff09;&#xff0c;我们也可以称其为“位移主题” 上一节有提到老版本 Consumer 的位移管理是通过ZooKeeper…

五、关闭三台虚拟机的防火墙和Selinux

目录 1、关闭每台虚拟机的防火墙 2、关闭每台虚拟机的Selinux 2.1 什么是SELinux

MFC中updatedata(False)和Updatedata(TRUE)区别

MFC的UpdateData(FALSE)和UpdateData(TRUE)都是用来更新视图界面和数据模型之间的数据同步的。 UpdateData(TRUE)表示将视图控件的值更新到数据模型中&#xff0c;即将界面上的数据更新到与之对应的变量中。同时&#xff0c;UpdateData(TRUE)还可以强制执行控件验证。如果控件…

使用SpringBoot和ZXing实现二维码生成与解析

一、ZXing简介 ZXing是一个开源的&#xff0c;用Java实现的多种格式的1D/2D条码图像处理库。它包含了用于解析多种格式的1D/2D条形码的工具类&#xff0c;目标是能够对QR编码&#xff0c;Data Matrix, UPC的1D条形码进行解码。在二维码编制上&#xff0c;ZXing巧妙地利用构成计…

系列十四、SpringBoot的jar包可以直接运行原理分析

一、普通jar包运行 vs SpringBoot jar包运行 1.1、普通jar包运行 general-test-1.0-SNAPSHOT.jar是位于D盘的一个普通的jar包&#xff0c;是idea中一个普通的maven项目通过package打包生成&#xff0c;为了方便测试我把它拷贝到D盘了。 java -jar general-test-1.0-SNAPSHOT.j…

MySQL经验总结

RPM安装 安装官网YUM源 sudo yum install mysql80-community-release-el7-11.noarch官网安装 sudo yum install mysql80-community-release-el7-11.noarch.rpm查看默认密码 sudo grep password /var/log/mysqld.log 修改密码 sudo mysqladmin -uroot -pxxxxxx password XXxxx登…

springboot虚拟请求——测试

springboot虚拟请求 表现层测试 web环境模拟测试 虚拟请求状态匹配——执行状态的匹配 Testvoid testStatus(Autowired MockMvc mvc) throws Exception { // //http://localhost:8080/books// 创建一个虚拟请求&#xff0c;当前访问的是booksMockHttpServletRequestBui…

不会代码(零基础)学语音开发(学习工具)

学习&#xff0c;要选择适合自己的&#xff0c;好的学习工具至关重要。就像读书&#xff0c;要读好书一样。 自己不会选&#xff0c;可以参考前辈&#xff0c;找chatgpt等来帮忙。充分利用好周边的资源。 秉承着GPT和前辈们的经验之谈&#xff0c;开始选择语音开发产品&#…

localStorage 和sessionStorage

localStorage 和 sessionStorage 是浏览器提供的两种客户端存储数据的方式&#xff1a; 生命周期&#xff1a; localStorage&#xff1a; 存储在 localStorage 中的数据在浏览器关闭后仍然保留&#xff0c;直到被显式删除或浏览器清除缓存。sessionStorage&#xff1a; 存储在 …

操作系统-输入输出管理

I/O设备的基本概念和分类 I/O就是输入/输出 I/O设备就是可以将数据输入到计算机&#xff0c;或者可以接收计算机输出数据的外部设备&#xff0c;属于计算机中的硬件部件。 I/O设备按使用特性分类 人机交互类外部设备存储设备网络通信设备 I/O设备按传输速率分类 低速设备中…

uniapp-距离distance数字太长,截取保留前3为数字

1.需求 将接口返回的距离的字段&#xff0c;保留三位数显示。 2.实现效果 3.代码&#xff1a; 1.这是接口返回的数据&#xff1a; 2.调取接口&#xff0c;赋值前先处理每条数据的distance <view class"left">距你{{item.distance}}km</view>listFun() …

MySql之锁表、锁行解决方案

查询正在使用的表&#xff0c;没有跑业务&#xff0c;一般情况下是锁表了 show open tables where in_use > 0 ;查看进程&#xff0c;可以看到Command类型&#xff08;Sleep为阻塞线程&#xff09; show processlist;kill事务&#xff0c;kill 进程Id kill 8193583;其他 …