【opencv】图像处理(二)

news2024/11/25 14:33:07

前文指引

一、使用到的图片

一、梯度计算

原始图片

img = cv2.imread('circle.jpg')

plt.imshow(img)
plt.show()

sobel算子

使用两个核 Gx = [[-1,0,1], [-2,0,2], [-1,0,1]] Gy = [[-1,-2,-1], [0,0,0], [1,2,1]]

dst = cv2.Sobel(src, ddepth, dx, dy, ksize)

  • ddepth 深度 -1
  • dx,dy 水平和竖直的方向
  • ksize 核大小

x方向上计算梯度

# CV_64F带负数
sobelx = cv2.Sobel(img, cv2.CV_64F,1,0,ksize = 3)
# 取绝对值,否则左边是白-黑大于0, 右边是黑-白小于0
sobelx = cv2.convertScaleAbs(sobelx)

plt.imshow(sobelx)
plt.show()

opencv梯度计算x方向.png

y方向上计算梯度

sobely = cv2.Sobel(img, cv2.CV_64F,0,1,ksize = 3)
sobely = cv2.convertScaleAbs(sobely)

plt.imshow(sobely)
plt.show()

opencv梯度计算y方向.png

猫图像计算梯度获得边缘

cat = cv2.imread('cat.jpg', cv2.IMREAD_GRAYSCALE)
sobelx = cv2.convertScaleAbs(cv2.Sobel(cat, cv2.CV_64F,1,0,ksize = 3))
sobely = cv2.convertScaleAbs(cv2.Sobel(cat, cv2.CV_64F,0, 1,ksize = 3))
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5, 0)

plt.figure(figsize=(20,15))
plt.subplot(121)
plt.imshow(cat, cmap='gray')
plt.subplot(122)
plt.imshow(sobelxy, cmap='gray')
plt.show()

opencv梯度计算.png

二、边缘检测

Canny边缘检测

  1. 使用高斯滤波器,平滑图像,消除噪点
  2. 计算图像每个像素点的梯度强度和方向
  3. 应用非极大值抑制,消除边缘检测带来的杂散效应
  • 线性插值法,计算M(Q)点为w * M(g1) + (1 - w) * M(g2)
  • 简化计算,把像素点的梯度方向离散为8个方向
  1. 应用双阈值检测来确定真是的和潜在的边缘
  • 大于上边界,处理为边界
  • 在上下边界之间,如果连有边界,则保留
  • 小于下边界,舍弃
  1. 通过抑制鼓励的弱边缘完成边缘检测
img = cv2.imread('car.jpg', cv2.IMREAD_GRAYSCALE)

# minval 和 maxval
v1 = cv2.Canny(img, 30, 100)
v2 = cv2.Canny(img, 50, 150)

plt.figure(figsize=(20,25))

plt.subplot(121)
plt.imshow(v1, cmap='gray')

plt.subplot(122)
plt.imshow(v2, cmap='gray')

plt.show()

opencv边缘检测.png

三、图像金字塔

高斯金字塔

  1. 向下采样,缩小

    将Gi与高斯内核卷积

    去除偶数行和列

  2. 向上采样,放大

    图像在每个方向扩大为原来的两倍,新增的行列0填充

    使用高斯内核与放大后的图像卷积,获得近似值

img = cv2.imread('jerry.jpg')
up = cv2.pyrUp(img)
down = cv2.pyrDown(img)

plt.figure(figsize=(20,15))

plt.subplot(131)
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))

plt.subplot(132)
plt.imshow(cv2.cvtColor(up, cv2.COLOR_BGR2RGB))

plt.subplot(133)
plt.imshow(cv2.cvtColor(down, cv2.COLOR_BGR2RGB))

plt.show()

虽然看着图片大小一样,看坐标轴上可以看出来实际大小是不一样的,清晰的也略有差异

opencv高斯金字塔.png

拉普拉斯金字塔

每一层都是Li+1 = Gi - pyrUp(pyrDown(Gi))

down_up = cv2.resize(cv2.pyrUp(cv2.pyrDown(img)),(500, 635))
res = img - down_up

plt.imshow(cv2.cvtColor(res, cv2.COLOR_BGR2RGB))
plt.show()

opencv拉普拉斯金字塔.png

四、轮廓检测

轮廓检测函数

cv2.findContours(img,mode,method)

mode:轮廓检索模式

  • RETR_EXTERNAL:只检索最外面的轮廓
  • RETR_LIST:检索所有轮廓,保存到一条链表
  • RETR_CCOMP:检索所有轮廓,组织为两层,定策是各部分的外部边界,第二层是空洞的边界
  • RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次

method:轮廓逼近方法

  • CHAINAPPROXNONE:以Freeman链码的方式输出轮廓,所有其它方法输出多边形
  • CHAINAPPROXSIMPLE:压缩水平的、垂直的和斜的部分,只保留终点

转换图片为二值图像

# 二值图像准确率更高
img = cv2.imread('contours.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 转为二值图像
ret,thresh = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)

plt.imshow(thresh,'gray')
plt.show()

opencv轮廓检测二值图像.png

绘制轮廓

# 二值图像,轮廓信息,层级
binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 使用原图会导致原图改变
img_copy = img.copy()
# 绘制全部轮廓,BGR,线宽
res = cv2.drawContours(img_copy, contours, -1, (0,0,255),2)

plt.imshow(cv2.cvtColor(res, cv2.COLOR_BGR2RGB))
plt.show()

opencv绘制轮廓.png

轮廓特征

# 拿出星形的外圈轮廓
cnt = contours[0]

print('星形外圈包围的面积为',cv2.contourArea(cnt))
print('星形外圈周长为',cv2.arcLength(cnt,True))

轮廓近似

原轮廓

img = cv2.imread('irregular.jpg')
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(img_gray, 127,255,cv2.THRESH_BINARY)

binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = contours[0]
img_copy = img.copy()
res = cv2.drawContours(img_copy, [cnt], 0, (0,0,255),2)

plt.imshow(cv2.cvtColor(res, cv2.COLOR_BGR2RGB))
plt.show()

opencv不规则轮廓.png

有时我们不需要这么精准的轮廓

# 0.1倍的周长作为阈值
epsilon = 0.1 * cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)

img_copy = img.copy()
res = cv2.drawContours(img_copy, [approx], -1, (0,0,255),2)

plt.imshow(cv2.cvtColor(res, cv2.COLOR_BGR2RGB))
plt.show()

opencv近似轮廓.png

轮廓外接图形

外接矩形

img = cv2.imread('contours.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)

binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = contours[0]
# 得到四条边
x,y,w,h = cv2.boundingRect(cnt)
img_copy = img.copy()
res = cv2.rectangle(img_copy, (x, y), (x + w, y + h), (0,255,0), 2)

plt.imshow(cv2.cvtColor(res, cv2.COLOR_BGR2RGB))
plt.show()

opencv外接矩形.png

外接圆

(x, y), radius = cv2.minEnclosingCircle(cnt)
center = (int(x), int(y))
radius = int(radius)
res = cv2.circle(img, center, radius, (0,255,0),2)

plt.imshow(cv2.cvtColor(res, cv2.COLOR_BGR2RGB))
plt.show()

opencv外接圆.png

五、模板匹配

就是从大图像中找出匹配的目标图像

img = cv2.imread('car.jpg')
template = cv2.imread('wheel.jpg')
h,w = template.shape[:2]
# 常用方法
methods={'cv2.TM_CCOEFF','cv2.TM_CCOEFF_NORMED','cv2.TM_CCORR',
        'cv2.TM_CCORR_NORMED','cv2.TM_SQDIFF','cv2.TM_SQDIFF_NORMED'}

for m in methods:
    img2 = img.copy()
    # 获得匹配方法的真值
    method = eval(m)
    # 进行匹配
    res = cv2.matchTemplate(img,template, method)
    # 获得匹配的最高最低得分值及其位置
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

    # 如果是平方差匹配或者归一化平方差匹配,取最小值
    if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
        top_left = min_loc
    else: 
        top_left = max_loc
    bottom_right = (top_left[0] + w, top_left[1] + h)

    # 绘制矩形
    cv2.rectangle(img2, top_left, bottom_right, 255, 2)

    plt.subplot(121)
    plt.imshow(res, 'gray')
    plt.xticks([])
    plt.yticks([])
    plt.subplot(122)
    plt.imshow(img2, 'gray')
    plt.xticks([])
    plt.yticks([])
    plt.suptitle(m)
    plt.show()

图片太长了,这里只展示一部分,从结果中可以看出, 带归一化的方法比不带归一化的方法要更加精准

opencv模板匹配.png

六、图像直方图

直方图直观的表示图片中某个(或某组)像素值的像素点个数

直方图函数

cv2.calcHist(images,channels,mask,histSize,ranges)

  • images:输入图像
  • channels:012对应BGR
  • mask:掩模图像,统计整幅图像就设为None。
  • histSize:BIN的数量(一个柱表示的像素范围)
  • ranges:像素值范围
img = cv2.imread('cat.jpg',cv2.IMREAD_GRAYSCALE)
hist = cv2.calcHist([img],[0],None,[256],[0,256])

plt.hist(img.ravel(),256)
plt.show()

opencv直方图.png

三通道直方图

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])
plt.show()

opencv三通道直方图.png

直方图均衡化

img = cv2.imread('cat.jpg',cv2.IMREAD_GRAYSCALE)
equ = cv2.equalizeHist(img)
plt.hist(equ.ravel(), 256)
plt.show()

plt.subplot(121)
plt.imshow(img, 'gray')
plt.subplot(122)
plt.imshow(equ, 'gray')
plt.show()

opencv直方图均衡化.png

opencv均衡化对比.png

自适应均衡化

clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
res_clahe = clahe.apply(img)

plt.subplot(121)
plt.imshow(img, 'gray')

plt.subplot(122)
plt.imshow(res_clahe, 'gray')

plt.show()

opencv自适应均衡化.png

七、傅里叶变换

img = cv2.imread('cat.jpg', cv2.IMREAD_GRAYSCALE)
img_float32 = np.float32(img)

dft = cv2.dft(img_float32, flags=cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)

# 转为灰度图表示形式
magnitude_spectrum = 20 * np.log(cv2.magnitude(dft_shift[:,:,0], dft_shift[:,:,1]))

plt.subplot(121)
plt.imshow(img, 'gray')
plt.title('input')

plt.subplot(122)
plt.imshow(magnitude_spectrum, 'gray')
plt.title('output')

plt.show()

opencv傅里叶变换特征图.png

拿到特征图后可以使用低通滤波使图像边缘模糊,或者使用高通滤波加强图像边缘

img = cv2.imread('cat.jpg', cv2.IMREAD_GRAYSCALE)
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)

# 低通滤波
mask = np.zeros((rows,cols,2), np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1
fshift = dft_shift * mask

# idft
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, 'gray')
plt.title('input')

plt.subplot(122)
plt.imshow(img_back, 'gray')
plt.title('output')

plt.show()




img = cv2.imread('cat.jpg', cv2.IMREAD_GRAYSCALE)
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)

# 高通滤波
mask = np.ones((rows,cols,2), np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 0
fshift = dft_shift * mask
# idft
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, 'gray')
plt.title('input')

plt.subplot(122)
plt.imshow(img_back, 'gray')
plt.title('output')

plt.show()

opencv滤波.png

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

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

相关文章

添砖Java之路(其四)——面向对象的编程,类和对象

目录 前言: 面向对象的编程: this关键字: 构造方法: 前言: 其实中间我还有很多地方没有去讲,因为我觉得里面的很多东西和c/c差不太多,就比如逻辑运算,方法重载,以及数…

庙算兵棋推演AI开发初探(4-调用AI模型)

前面讲了如何开展编写规则脚本型Agent(智能体)的方法,现在探究一下如何调用知识型(一般而言的训练出的模型)智能体的方法。 这次调用的是庙算平台的demo(网址见图) 下载了“知识强化学习型”…

详解依赖注入的三种方法以及遇到问题的解决

各位大佬光临寒舍,希望各位能赏脸给个三连,谢谢各位大佬了!!! 目录 1.三种依赖注入的方法 1.属性注入 优点 缺点 2.构造方法注入 优点 缺点 3.Setter注入 优点 缺点 4.小结 2.依赖注入常见问题的解决 1…

全国防灾减灾日主题活动投稿我可算找对了投稿方法

作为一名社区公众人员,我深知对外信息宣传的重要性。特别是在全国防灾减灾日这样的特殊时刻,我们不仅要向居民普及防灾减灾知识,还要通过媒体将社区的活动和成果展示给更多人。然而,在投稿的过程中,我最初却遭遇了诸多挑战。 起初,我采用传统的邮箱投稿方式,将精心撰写的稿件发…

网页如何集成各社区征文活动

Helllo , 我是小恒 由于我需要腾讯云社区,稀土掘金以及CSDN的征文活动RSS,找了一下没发现,所以使用GET 请求接口对网页定时进行拉取清洗,甚至无意间做了一个简单的json格式API 最终网址:hub.liheng.work API:http://hub.liheng.wo…

ubuntu server 22.04.4 系统安装详细教程

本教程使用vmware workstation 17创建虚拟机进行安装演示,安装方式和真机安装没有区别。 1、下载镜像 下载ubuntu server版本系统镜像,官网下载地址:https://cn.ubuntu.com/download/server/step1 注意:自己下载时需要确认是否是…

向银行家应用程序添加日期

● 首先我们将下面图片上的时间更换成现在的时间 const now new Date(); const day now.getDate(); const month now.getMonth() 1; const year now.getFullYear(); const hour now.getHours(); const min now.getMinutes();labelDate.textContent ${day}/${month}/$…

从头开始学Spring—01Spring介绍和IOC容器思想

目录 1.Spring介绍 1.1Spring概述 1.2特性 1.3五大功能模块 2.IOC容器 2.1IOC思想 ①获取资源的传统方式 ②反转控制方式获取资源 ③DI 2.2IOC容器在Spring中的实现 ①BeanFactory ②ApplicationContext ③ApplicationContext的主要实现类 1.Spring介绍 1.1Sprin…

ASP.NET Web Api 如何使用 Swagger 管理 API

前言 Swagger 是一个开源的框架,支持 OpenAPI 规范,可以根据 API 规范自动生成美观的、易于浏览的 API 文档页面,包括请求参数、响应示例等信息,并且,Swagger UI 提供了一个交互式的界面,可以帮助我们快速…

本来还挺喜欢……

前阵子买了个天空星开发板,到手之后发觉不对劲。 之前我们玩玩开发板都是用的面包板的,就算是ESP那种比较宽的板子用两个面包板拼一下也勉强可以用。 但是天空星它的引脚是分为两组,每组有两排,如果我们还是直接使用面包板的话&a…

Pencils Protocol 提供层次化的 Staking,品牌升级不断

Pencils Protocol 是一个 Scroll 生态中的一个综合应用平台,在全新的品牌升级后(原为 Penpad),其在原有的 LaunchPad 的基础上,进一步向收益聚合器、RWA 等板块进行全新的拓展。目前,Pencils Protocol 生态的整体功能板块包括 Lau…

Kubernetes——两万字超细致集群搭建平台规划

目录 前言——常见的K8S安装部署方式 一、Kubernetes平台规划 1.单Master集群架构 2.多Master集群架构 二、集群规划 1.服务器硬件配置推荐 2.操作系统初始化 2.1关闭防火墙 2.2关闭SElinux 2.3关闭Swap 2.4添加Hosts 2.5调整内核参数 2.5同步时间 三、集群搭建…

【每日刷题】Day39

【每日刷题】Day39 🥕个人主页:开敲🍉 🔥所属专栏:每日刷题🍍 🌼文章目录🌼 1. 622. 设计循环队列 - 力扣(LeetCode) 2. 387. 字符串中的第一个唯一字符 - …

C++类细节,反汇编,面试题02

文章目录 2. 虚函数vs纯虚函数3. 重写vs重载vs隐藏3.1. 为什么C可以重载? 4. struct vs union4.1. 为什么要内存对齐? 5. static作用6. 空类vs空结构体6.1. 八个默认函数:6.2. 为什么空类占用1字节 7. const作用7.1 指针常量vs常量指针vs常量…

k8s v1.20二进制部署

目录 一、环境准备 二、操作系统初始化配置 2.1.关闭防火墙 ​编辑 2.2.关闭selinux 2.3.关闭swap 2.4.根据规划设置主机名 2.5在master添加hosts 2.6.调整内核参数 2.7.时间同步 三、部署 docker引擎 3.1.所有 node 节点部署docker引擎 四、部署 etcd 集群 4.1.…

【云计算小知识】云管理的作用是什么?

云计算已经成为推动企业数字化转型,提升运营效率的重要力量。而在这个过程中,云管理作为确保云计算环境稳定、高效运行的关键环节,其作用愈发凸显。今天我们小编就给大家详细介绍一下云管理的作用是什么? 云管理的作用是什么&…

找不到mfc140.dll是什么意思?四种高效率方法修复mfc140.dll文件

软件运行过程中的错误和问题偶尔会发生,这可能导致不便和工作效率的降低。其中一个常见的问题是“找不到 mfc140.dll”错误消息,这会阻止某些基于 Microsoft Visual Studio 2015 编写的应用程序运行。mfc140.dll 是一个重要的系统文件,今天我…

Whistle Web Debugging Proxy介绍及使用

大家好,今天继续给大家分享一款抓包工具,这款抓包工具是网页的形式,方便多人访问同时维护。Whistle Web Debugging Proxy是一个用于HTTP、HTTPS、WebSocket等网络协议的跨平台调试工具。它可以帮助开发者对网络请求进行捕捉、分析、修改和重定…

Spring Boot项目怎么集成Gitee登录

一、背景 现在的越来越多的项目,需要集成第三方系统进行登录。今天我们以Spring Boot项目集成Gitee为例,演示一下怎么使用Oauth2协议,集成第三方系统登录。 不了解oauth2的,可以看我之前的文章。Ouath2是怎么实现在第三方应用认…

Java入门基础学习笔记21——Scanner

在程序中接收用户通过键盘输入的数据: 需求: 请在程序中,提示用户通过键盘输入自己的姓名、年龄、并能在程序中收到这些信息,怎么解决? Java已经写好了实现程序,我们调用即可。 API:Applicat…