Hello,大家好我叫是Dream呀,一个有趣的Python博主,小白一枚,多多关照
CSDN Python领域新星创作者,大二在读,欢迎大家找我合作学习
入门须知:这片乐园从不缺乏天才,努力才是你的最终入场券!
最后,愿我们都能在看不到的地方闪闪发光,一起加油进步
“一万次悲伤,依然会有Dream,我一直在最温暖的地方等你”,唱的就是我!哈哈哈~
✨✨✨
侵蚀的基本思想就像土壤侵蚀一样,它侵蚀前景物体的边界(尽量使前景保持白色)。它是做什么的呢?内核滑动通过图像(在2D卷积中)。原始图像中的一个像素(无论是1还是0)只有当内核下的所有像素都是1时才被认为是1,否则它就会被侵蚀(变成0)。
结果是,根据内核的大小,边界附近的所有像素都会被丢弃。因此,前景物体的厚度或大小减小,或只是图像中的白色区域减小。它有助于去除小的白色噪声(正如我们在颜色空间章节中看到的),分离两个连接的对象等。
腐蚀主要就是调用
cv2.erode(img,kernel,iterations)
,这个函数的参数是:
第一个参数:img指需要腐蚀的图第二个参数:kernel指腐蚀操作的内核,默认是一个简单的3X3矩阵,我们也可以利用getStructuringElement()函数指明它的形状
第三个参数:iterations指的是腐蚀次数,省略是默认为1
代码:
import cv2 as cv
import numpy as np
img = cv.imread('yuanxing.png',0)
kernel = np.ones((5,5),np.uint8)
erosion = cv.erode(img,kernel,iterations=2)
cv.imshow('xuxux',erosion)
cv.waitKey(0)
它与侵蚀正好相反。如果内核下的至少一个像素为“ 1”,则像素元素为“ 1”。因此,它会增加图像中的白色区域或增加前景对象的大小。通常,在消除噪音的情况下,腐蚀后会膨胀。因为腐蚀会消除白噪声,但也会缩小物体。因此,我们对其进行了扩展。由于噪音消失了,它们不会回来,但是我们的目标区域增加了。在连接对象的损坏部分时也很有用。
代码:
import cv2 as cv
import numpy as np
img = cv.imread('yuanxing.png',1)
kernel = np.ones((5,5),np.uint8)
# erosion=cv.erode(img,kernel,iterations = 1)
erosion=cv.dilate(img,kernel,iterations=1)
cv.imshow('erosion',erosion)
cv.waitKey(0)
这是图像扩张和侵蚀之间的区别。结果将看起来像对象的轮廓:
代码:
import cv2 as cv
import numpy as np
img = cv.imread('yuanxing.png',1)
kernel = np.ones((5,5),np.uint8)
gradient = cv.morphologyEx(img, cv.MORPH_GRADIENT, kernel)
cv.imshow('erosion',gradient)
cv.waitKey(0)
前言:
在本章中,我们将学习: - 查找图像梯度,边缘等 - 我们将看到以下函数:cv.Sobel(),cv.Scharr(),cv.Laplacian()等
OpenCV提供三种类型的梯度滤波器或高通滤波器,即Sobel,Scharr和Laplacian。我们将看到他们每一种。
Sobel算子
是高斯平滑加微分运算的联合运算,因此它更抗噪声。逆可以指定要采用的导数方向,垂直或水平(分别通过参数yorder和xorder)。逆还可以通过参数ksize指定内核的大小。如果ksize = -1,则使用3x3 Scharr滤波器,比3x3 Sobel滤波器具有更好的结果。
# -*-coding:utf-8 -*-
# @Author:到点了,心疼徐哥哥
# 奥利给干!!!
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('qipan.jpg',0)
# 其中,0表示将图片以灰度读出来。
laplacian = cv.Laplacian(img,cv.CV_64F)
# 图像边缘处理sobel细节
# 利用Sobel方法可以进行sobel边缘检测
# img表示源图像,即进行边缘检测的图像
# cv2.CV_64F表示64位浮点数即64float。
# 这里不使用numpy.float64,因为可能会发生溢出现象。用cv的数据则会自动
# 第三和第四个参数分别是对X和Y方向的导数(即dx,dy),对于图像来说就是差分,这里1表示对X求偏导(差分),0表示不对Y求导(差分)。其中,X还可以求2次导。
# 注意:对X求导就是检测X方向上是否有边缘。
# 第五个参数ksize是指核的大小。
# 这里说明一下,这个参数的前四个参数都没有给谁赋值,而ksize则是被赋值的对象
# 实际上,这时可省略的参数,而前四个是不可省的参数。注意其中的不同点
sobelx = cv.Sobel(img,cv.CV_64F,1,0,ksize=5)
sobely = cv.Sobel(img,cv.CV_64F,0,1,ksize=5)
plt.subplot(2,2,1),plt.imshow(img,cmap = 'gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,2),plt.imshow(laplacian,cmap = 'gray')
plt.title('Laplacian'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,3),plt.imshow(sobelx,cmap = 'gray')
plt.title('Sobel X'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,4),plt.imshow(sobely,cmap = 'gray')
plt.title('Sobel Y'), plt.xticks([]), plt.yticks([])
plt.show()
在我们的最后一个示例中,输出数据类型为cv.CV_8U或np.uint8。但这有一个小问题。黑色到白色的过渡被视为正斜率(具有正值),而白色到黑色的过渡被视为负斜率(具有负值)。因此,当您将数据转换为np.uint8时,所有负斜率均设为零。简而言之,您会错过这一边缘信息。
如果要检测两个边缘,更好的选择是将输出数据类型保留为更高的形式,例如cv.CV_16S,cv.CV_64F等,取其绝对值,然后转换回cv.CV_8U。
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('box.png',0)
# Output dtype = cv.CV_8U
sobelx8u = cv.Sobel(img,cv.CV_8U,1,0,ksize=5)
# Output dtype = cv.CV_64F. Then take its absolute and convert to cv.CV_8U
sobelx64f = cv.Sobel(img,cv.CV_64F,1,0,ksize=5)
abs_sobel64f = np.absolute(sobelx64f)
sobel_8u = np.uint8(abs_sobel64f)
plt.subplot(1,3,1),plt.imshow(img,cmap = 'gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(1,3,2),plt.imshow(sobelx8u,cmap = 'gray')
plt.title('Sobel CV_8U'), plt.xticks([]), plt.yticks([])
plt.subplot(1,3,3),plt.imshow(sobel_8u,cmap = 'gray')
plt.title('Sobel abs(CV_64F)'), plt.xticks([]), plt.yticks([])
plt.show()
目标
在本章中,我们将学习 - Canny边缘检测的概念 - OpenCV函数: cv.Canny()
理论: Canny Edge Detection是一种流行的边缘检测算法。它由John F. Canny发明
这是一个多阶段算法,我们将经历每个阶段。
降噪:
由于边缘检测容易受到图像中噪声的影响,因此第一步是
使用5x5高斯滤波器消除图像中的噪声。我们已经在前面的章节中看到了这一点。
然后使用Sobel核在水平和垂直方向上对平滑的图像进行滤波,以在水平方向(Gx)和垂直方向(Gy)上获得一阶导数。从这两张图片中,我们可以找到每个像素的边缘渐变和方向,如下所示:
在获得梯度大小和方向后,将对图像进行全面扫描,以去除可能不构成边缘的所有不需要的像素。为此,在每个像素处,检查像素是否是其在梯度方向上附近的局部最大值。查看下面的图片:
点A在边缘(垂直方向)上。渐变方向垂直于边缘。点B和C在梯度方向上。因此,将A点与B点和C点进行检查,看是否形成局部最大值。如果是这样,则考虑将其用于下一阶段,否则将其抑制(置为零)。 简而言之,你得到的结果是带有“细边”的二进制图像。
该阶段确定哪些边缘全部是真正的边缘,哪些不是。为此,我们需要两个阈值minVal和maxVal。强度梯度大于maxVal的任何边缘必定是边缘,而小于minVal的那些边缘必定是非边缘,因此将其丢弃。介于这两个阈值之间的对象根据其连通性被分类为边缘或非边缘。如果将它们连接到“边缘”像素,则将它们视为边缘的一部分。
OpenCV将以上所有内容放在单个函数 cv.Canny() 中。我们将看到如何使用它。第一个参数是我们的输入图像。第二个和第三个参数分别是我们的minVal和maxVal。第三个参数是perture_size。它是用于查找图像渐变的Sobel内核的大小。默认情况下为3。最后一个参数是L2gradient,它指定用于查找梯度幅度的方程式。如果为True,则使用上面提到的更精确的公式,否则使用以下函数:默认情况下,它为False。
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('haojin.jpg',0)
# img1 = cv.GaussianBlur(img, (1,1),0)
edges = cv.Canny(img,50,100)
plt.subplot(121),plt.imshow(img,cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(edges,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
plt.show()
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('haojin.jpg',0)
img1 = cv.GaussianBlur(img, (5,5),0)
edges = cv.Canny(img1,50,100)
plt.subplot(121),plt.imshow(img1,cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(edges,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
plt.show()
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('haojin.jpg',0)
img1 = cv.GaussianBlur(img, (1,1),0)
edges = cv.Canny(img1,50,100)
plt.subplot(121),plt.imshow(img1,cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(edges,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
plt.show()
目标
在本章中, - 我们将学习图像金字塔 - 我们将使用图像金字塔创建一个新的水果“Orapple” - 我们将看到以下功能:cv.pyrUp(),cv.pyrDown()
以多个分辨率来表示图像的一种有效且概念简单的结构是图像金字塔
。图像金字塔最初用于机器视觉和图像压缩,一个图像金字是一系列以金字塔形状排列的、分辨率逐步降低的图像集合。
如图下图所示,它包括了四层图像,将这一层一层的图像比喻成金字塔。图像金字塔可以通过梯次向下采样获得,直到达到某个终止条件才停止采样,在向下采样中,层级越高,则图像越小
,分辨率越低。
生成图像金字塔主要包括两种方式:向下取样 和 向上取样。
如下图所示:
向下取样:将图像从G0转换为G1、G2、G3,图像分辨率不断降低的过程;
向上取样:将图像从G3转换为G2、G1、G0,图像分辨率不断增大的过程。
在图像向下取样中,一般分两步:
其中,高斯核卷积运算(高斯滤波) 就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值(权重不同)经过加权平均后得到。常见的 33 和 55 高斯核如下:
注:由于每次向下取样会删除偶数行和列,所以它会不停地丢失图像的信息。
在OpenCV中,向下取样使用的函数为pyrDown(),其函数用法如下所示:
dst = pyrDown(src[, dst[, dstsize[, borderType]]])
其中,参数:
src 表示输入图像;
dst 表示输出图像,和输入图像具有一样的尺寸和类型;
dstsize 表示输出图像的大小,默认值为Size();
borderType 表示像素外推方法,详见cv::bordertypes 。
取一次样:
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取原始图像
img = cv2.imread('juzi.png')
# 图像向下取样
r = cv2.pyrDown(img)
# 显示图像
cv2.imshow('original', img)
cv2.imshow('PyrDown', r)
cv2.waitKey()
cv2.destroyAllWindows()
# -*-coding:utf-8 -*-
# @Author:到点了,心疼徐哥哥
# 奥利给干!!!
# -*- coding: utf-8 -*-
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# 读取原始图像
img=cv.imread('pinguo.png')
# 图像向下取样
r1=cv.pyrDown(img)
r2=cv.pyrDown(r1)
r3=cv.pyrDown(r2)
# 显示图像
cv.imshow('original',img)
cv.imshow('pyrDown1',r1)
cv.imshow('pyrDown2',r2)
cv.imshow('pyrDown3',r3)
cv.waitKey()
cv.destroyWindow()
在图像向上取样是由小图像不断放图像的过程。它将图像在每个方向上扩大为原图像的2倍,新增的行和列均用0来填充,并使用与“向下取样”相同的卷积核乘以4,再与放大后的图像进行卷积运算,以获得“新增像素”的新值。
注:向上取样和向下取样无法互逆的。
和上文中的向下取样其时并无大异。
在OpenCV中,向上取样使用 pyrUp() 函数,其函数用法如下所示:
dst = pyrUp(src[, dst[, dstsize[, borderType]]])
其中,参数:
src 表示输入图像;
dst 表示输出图像,和输入图像具有一样的尺寸和类型;
dstsize 表示输出图像的大小,默认值为Size();
borderType 表示像素外推方法,详见cv::bordertypes 。
取一次样:
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取原始图像
img = cv2.imread('juzi.png')
# 图像向下取样
r = cv2.pyrUp(img)
# 显示图像
cv2.imshow('original', img)
cv2.imshow('PyrDown', r)
cv2.waitKey()
cv2.destroyAllWindows()
# -*-coding:utf-8 -*-
# @Author:到点了,心疼徐哥哥
# 奥利给干!!!
# -*- coding: utf-8 -*-
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# 读取原始图像
img=cv.imread('pinguo.png')
# 图像向下取样
r1=cv.pyrUp(img)
r2=cv.pyrUp(r1)
r3=cv.pyrUp(r2)
# 显示图像
cv.imshow('original',img)
cv.imshow('pyrDown1',r1)
cv.imshow('pyrDown2',r2)
cv.imshow('pyrDown3',r3)
cv.waitKey()
cv.destroyWindow()
# -*-coding:utf-8 -*-
# @Author:到点了,心疼徐哥哥
# 奥利给干!!!
# -*- coding: utf-8 -*-
from cv2 import cv2
import numpy as np
A = cv2.imread('pinguo.png')
# 注意:为了使后面可以逐渐减半,这里的尺寸必须为2的次幂
A = cv2.resize(A, (256, 256), interpolation=cv2.INTER_CUBIC)
B = cv2.imread('juzi.png')
B = cv2.resize(B, (256, 256), interpolation=cv2.INTER_CUBIC)
# 生成高斯金字塔
G = A.copy()
gpA = [G]
for i in range(5):
G = cv2.pyrDown(G)
gpA.append(G)
G = B.copy()
gpB = [G]
for i in range(5):
G = cv2.pyrDown(G)
gpB.append(G)
# 产生Laplacian金字塔
lpA = [gpA[5]]
for i in range(5, 0, -1):
GE = cv2.pyrUp(gpA[i])
L = cv2.subtract(gpA[i - 1], GE)
lpA.append(L)
lpB = [gpB[5]]
for i in range(5, 0, -1):
GE = cv2.pyrUp(gpB[i])
L = cv2.subtract(gpB[i - 1], GE)
lpB.append(L)
# 合并
LS = []
for la, lb in zip(lpA, lpB):
rows, cols, dpt = la.shape
ls = np.hstack((la[:, 0:cols // 2], lb[:, cols // 2:]))
LS.append(ls)
# 重新构建图像
ls_ = LS[0]
for i in range(1, 6):
ls_ = cv2.pyrUp(ls_)
ls_ = cv2.add(ls_, LS[i])
# 连接
real = np.hstack((A[:, :cols // 2], B[:, cols // 2:]))
cv2.imshow("LS", ls_)
cv2.imshow("Real", real)
cv2.waitKey()
cv2.destroyAllWindows()
往期文章推荐:
还看不懂Python OpenCV?不,我不允许!隔壁大爷都说看得懂!❤️环境配置+问题分析+视频图像入门❤️万字只为你~
Python OpenCV实战画图——这次一定能行!爆肝万字,建议点赞收藏~❤️❤️❤️
❤️大家中秋节快乐❤️接下来请欣赏Python Opencv实战之图像阈值和模糊处理,万字实战,收藏起来吧~
Python OpenCV ❤️超级有趣❤️ 颜色转换 + 几何变换,一网打尽⚡⚡⚡~
好啦,这就是今天要分享给大家的全部内容了
❤️❤️❤️如果你喜欢的话,就不要吝惜你的一键三连了~