图像阈值

ret, dst = cv2.threshold(src, thresh, maxval, type)

  • src: 输入图,只能输入单通道图像,通常来说为灰度图
  • dst: 输出图
  • ret: 阈值
  • thresh: 阈值
  • maxval: 当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值
  • type:二值化操作的类型,包含以下5种类型: cv2.THRESH_BINARY; cv2.THRESH_BINARY_INV; cv2.THRESH_TRUNC; cv2.THRESH_TOZERO;cv2.THRESH_TOZERO_INV
  • cv2.THRESH_BINARY 超过阈值部分取maxval(最大值),否则取0
  • cv2.THRESH_BINARY_INV THRESH_BINARY的反转
  • cv2.THRESH_TRUNC 大于阈值部分设为阈值,否则不变
  • cv2.THRESH_TOZERO 大于阈值部分不改变,否则设为0
  • cv2.THRESH_TOZERO_INV THRESH_TOZERO的反转 ```python ret, thresh1 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY) ret, thresh2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV) ret, thresh3 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TRUNC) ret, thresh4 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO) ret, thresh5 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO_INV)

titles = [‘Original Image’, ‘BINARY’, ‘BINARY_INV’, ‘TRUNC’, ‘TOZERO’, ‘TOZERO_INV’] images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]

for i in range(6): plt.subplot(2, 3, i + 1) # subplot(nrows, ncols, index, kwargs) = subplot(pos, kwargs) 3位整数或三个单独的整数描述子图的位置。如果三个整数依次为nrows,ncols 和index,则 子图将在具有nrows 行和ncols列的网格上取得索引位置。索引从 左上角的1开始并向右增加。 plt.imshow(images[i], ‘gray’) #留疑,为何这里要加一个把参数表明输出是灰度图 plt.title(titles[i]) plt.xticks([]), plt.yticks([]) plt.show()

  1. ![image.png](https://cdn.nlark.com/yuque/0/2020/png/639303/1589705987071-507261bc-3a12-457f-ae5b-e61a5e97fb9c.png#align=left&display=inline&height=235&margin=%5Bobject%20Object%5D&name=image.png&originHeight=371&originWidth=591&size=116287&status=done&style=none&width=375)
  2. <a name="a8IwQ"></a>
  3. # 图像平滑
  4. ```python
  5. # 均值滤波
  6. # 简单的平均卷积操作
  7. blur = cv2.blur(img, (3, 3))
  8. # 方框滤波
  9. # 基本和均值一样,可以选择归一化
  10. box = cv2.boxFilter(img,-1,(3,3), normalize=True)
  11. box = cv2.boxFilter(img,-1,(3,3), normalize=False)
  12. # 高斯滤波
  13. # 高斯模糊的卷积核里的数值是满足高斯分布,相当于更重视中间的
  14. aussian = cv2.GaussianBlur(img, (5, 5), 1)
  15. # 中值滤波
  16. # 相当于用中值代替
  17. median = cv2.medianBlur(img, 5) # 中值滤波

形态学-腐蚀操作

img = cv2.imread('dige.png')

kernel = np.ones((3,3),np.uint8) 

# kernel=array([[1, 1, 1],
#               [1, 1, 1],
#               [1, 1, 1]], dtype=uint8)
erosion = cv2.erode(img,kernel,iterations = 1) # iterations表示迭代次数
pie = cv2.imread('pie.png') # 这里的pie是一个圆

kernel = np.ones((30,30),np.uint8) 
erosion_1 = cv2.erode(pie,kernel,iterations = 1)
erosion_2 = cv2.erode(pie,kernel,iterations = 2)
erosion_3 = cv2.erode(pie,kernel,iterations = 3)
res = np.hstack((erosion_1,erosion_2,erosion_3)) #np.hstack():在水平方向上平铺
res = cv2.resize(res, (0, 0), fx=0.4, fy=0.4,  
                  interpolation=cv2.INTER_CUBIC)

QQ截图20200517173601.png

形态学-膨胀操作

跟腐蚀类似
dige_dilate = cv2.dilate(dige_erosion,kernel,iterations = 1)

开运算与闭运算

# 开:先腐蚀,再膨胀
img = cv2.imread('dige.png')

kernel = np.ones((5,5),np.uint8) 
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)

# 闭:先膨胀,再腐蚀
img = cv2.imread('dige.png')

kernel = np.ones((5,5),np.uint8) 
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)

梯度运算

# 梯度=膨胀-腐蚀
pie = cv2.imread('pie.png')
kernel = np.ones((7,7),np.uint8) 
gradient = cv2.morphologyEx(pie, cv2.MORPH_GRADIENT, kernel)

礼帽与黑帽

  • 礼帽 = 原始输入-开运算结果
  • 黑帽 = 闭运算-原始输入 ```python

    礼帽

    img = cv2.imread(‘dige.png’) tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)

黑帽

img = cv2.imread(‘dige.png’) blackhat = cv2.morphologyEx(img,cv2.MORPH_BLACKHAT, kernel)


<a name="bNve6"></a>
# 图像梯度
梯度简单来说就是求导。<br />OpenCV 提供了三种不同的梯度滤波器,或者说高通滤波器:Sobel,Scharr 和 Laplacian。我们会意义介绍他们。<br />Sobel,Scharr 其实就是求一阶或二阶导数。Scharr 是对 Sobel(使用小的卷积核求解求解梯度角度时)的优化。Laplacian 是求二阶导数。
<a name="NpggP"></a>
## Sobel算子
原理:[链接:Sobel算子](https://baike.baidu.com/item/%E7%B4%A2%E8%B4%9D%E5%B0%94%E7%AE%97%E5%AD%90/15805328?fromtitle=Sobel%E7%AE%97%E5%AD%90&fromid=11000092&fr=aladdin)<br />![1.png](https://cdn.nlark.com/yuque/0/2020/png/639303/1589803394965-54c71060-01bd-4f0b-b684-d2c7199ca013.png#align=left&display=inline&height=91&margin=%5Bobject%20Object%5D&name=1.png&originHeight=258&originWidth=1307&size=32965&status=done&style=none&width=461)<br />dst = cv2.Sobel(src, ddepth, dx, dy, ksize)

- ddepth:图像的深度
- dx和dy分别表示水平和竖直方向
- ksize是Sobel算子的大小,一般是3*3也就是上面的。
```python
#分别计算x和y方向
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
#白到黑是负数,黑到白就是正数了,所有的负数会被截断成0,所以要取绝对值
sobelx = cv2.convertScaleAbs(sobelx)

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

#再求和
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)

#不建议直接计算
sobelxy=cv2.Sobel(img,cv2.CV_64F,1,1,ksize=3)
sobelxy = cv2.convertScaleAbs(sobelxy)

关于参数中的图像深度:参数ddepth = -1 表示设定输出图像的深度(数据类型)与原图像保持一致,但是我们在代码中使用的却是 cv2.CV_64F。因为一个从黑(灰度值为0)到白(灰度值为255)的边界的导数是整数,而一个从白到黑的边界点导数却是负数。如果原图像的深度是np.int8 时,所有的负值都会被截断变成 0,换句话说就是把把边界丢失掉。所以如果这两种边界你都想检测到,最好的的办法就是将输出的数据类型设置的更高,比如 cv2.CV_16S,cv2.CV_64F等。取绝对值然后再把它转回cv2.CV_8U。
链接:通道和位深的理解含义整理(CV_8UC1,CV_8SC1,CV_32FC1)

Scharr算子

Scharr 是对 Sobel(使用小的卷积核求解求解梯度角度时)的优化,Sobel 算子是高斯平滑与微分操作的结合体,所以它的抗噪声能力很好,如果 ksize=-1,会使用 3x3 的 Scharr 滤波器,它的的效果要比 3x3 的 Sobel 滤波器好(而且速度相同,所以在使用 3x3 滤波器时应该尽量使用 Scharr 滤波器)。
2.png

laplacian算子

如果邻域系统是4 邻域,Laplacian 算子的模板为: 如果邻域系统是8 邻域,Laplacian 算子的模板为:
2.png 3.png

和sobelx、sobely的对比(openCV官方文档):
1.png
sobelxy,scharrxy,laplacian对比(唐宇迪课件):
1.png

Canny边缘检测

  • 1) 使用高斯滤波器,以平滑图像,滤除噪声。
  • 2) 计算图像中每个像素点的梯度强度和方向。
  • 3) 应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。
  • 4) 应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘。
  • 5) 通过抑制孤立的弱边缘最终完成边缘检测。

    1:高斯滤波器

    canny_1.png

    2:梯度和方向

    canny_2.png

    3:非极大值抑制

    canny_3.png
    canny_6.png

    4:双阈值检测

    canny_5.png ```python img=cv2.imread(“lena.jpg”,cv2.IMREAD_GRAYSCALE)

v1=cv2.Canny(img,80,150) # 第2个参数80表示minVal,第3个参数150表示maxval v2=cv2.Canny(img,50,100)

res = np.hstack((v1,v2)) cv_show(res,’res’)

img=cv2.imread(“car.png”,cv2.IMREAD_GRAYSCALE)

v1=cv2.Canny(img,120,250) v2=cv2.Canny(img,50,100)

res = np.hstack((v1,v2)) cv_show(res,’res’)

<a name="7i7vD"></a>
# 图像金字塔

- 高斯金字塔
- 拉普拉斯金字塔

![Pyramid_1.png](https://cdn.nlark.com/yuque/0/2020/png/639303/1590218145405-9e427047-5f70-4bc5-b889-dec11e5dbd16.png#align=left&display=inline&height=396&margin=%5Bobject%20Object%5D&name=Pyramid_1.png&originHeight=396&originWidth=1132&size=260942&status=done&style=none&width=1132)
<a name="7cveP"></a>
## 高斯金字塔:向下采样方法(缩小)
![Pyramid_2.png](https://cdn.nlark.com/yuque/0/2020/png/639303/1590218169247-30d95ba9-7185-49c5-a8b4-b833c04dc1db.png#align=left&display=inline&height=194&margin=%5Bobject%20Object%5D&name=Pyramid_2.png&originHeight=194&originWidth=666&size=30003&status=done&style=none&width=666)
<a name="yFIZh"></a>
## 高斯金字塔:向上采样方法(放大)
![Pyramid_3.png](https://cdn.nlark.com/yuque/0/2020/png/639303/1590218193819-60aba76a-925e-445c-825c-ace7d94ef0d2.png#align=left&display=inline&height=287&margin=%5Bobject%20Object%5D&name=Pyramid_3.png&originHeight=287&originWidth=670&size=17050&status=done&style=none&width=670)
```python
up=cv2.pyrUp(img)

down=cv2.pyrDown(img)

拉普拉斯金字塔

Pyramid_4.png

down=cv2.pyrDown(img)
down_up=cv2.pyrUp(down)
l_1=img-down_up
cv_show(l_1,'l_1')

图像轮廓

轮廓可以简单认为成将连续的点(连着边界)连在一起的曲线,具有相同的颜色或者灰度。轮廓在形状分析和物体的检测和识别中很有用。
• 为了更加准确,要使用二值化图像。在寻找轮廓之前,要进行阈值化处理或者 Canny 边界检测。
• 查找轮廓的函数会修改原始图像。如果你在找到轮廓之后还想使用原始图像的话,你应该将原始图像存储到其他变量中。
• 在 OpenCV 中,查找轮廓就像在黑色背景中超白色物体。你应该记住,要找的物体应该是白色而背景应该是黑色。

cv2.findContours(img,mode,method)
mode:轮廓检索模式

  • RETR_EXTERNAL :只检索最外面的轮廓;
  • RETR_LIST:检索所有的轮廓,并将其保存到一条链表当中;
  • RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;
  • RETR_TREE:(最常用)检索所有的轮廓,并重构嵌套轮廓的整个层次;

method:轮廓逼近方法

  • CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。
  • CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。

返回值有三个:第一个是二值图像,第二个是轮廓,第三个是(轮廓的)层析结构。轮廓(第二个返回值)是一个 Pytho列表,其中存储这图像中的所有轮廓。每一个轮廓都是一个 Numpy 数组,包含对象边界点(x,y)的坐标。
chain.png
为了更高的准确率,使用二值图像。

img = cv2.imread('contours.png')
gray = cv2.cvtColor(img, cv2.COLOR
                    _BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
cv_show(thresh,'thresh')

binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

# 绘制轮廓
#传入绘制图像,轮廓,轮廓索引(第三个参数是轮廓的索引(在绘制单个轮廓时有用。要绘制所有轮廓(包括外轮廓和内轮廓),请传递-1)),颜色模式,线条厚度
# 注意需要copy,要不原图会变。。。
draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)
cv_show(res,'res')

draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, 0, (0, 0, 255), 2)
cv_show(res,'res')

轮廓特征

#需要将轮廓取出来才能用其他函数处理
cnt = contours[0] #每个单独的轮廓是一个(x,y)坐标的Numpy数组的边界点的对象

#面积
cv2.contourArea(cnt)

#周长,True表示闭合的
cv2.arcLength(cnt,True)

轮廓近似

contours3.png

img = cv2.imread('contours2.png')

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = contours[0]

draw_img = img.copy()
res = cv2.drawContours(draw_img, [cnt], -1, (0, 0, 255), 2)
cv_show(res,'res')


epsilon = 0.15*cv2.arcLength(cnt,True) 
approx = cv2.approxPolyDP(cnt,epsilon,True)

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

# 边界矩形

img = cv2.imread('contours.png')

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(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 = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
cv_show(img,'img')

area = cv2.contourArea(cnt)
x, y, w, h = cv2.boundingRect(cnt)
rect_area = w * h
extent = float(area) / rect_area
print ('轮廓面积与边界矩形比',extent)

# 外接圆

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

模板匹配

模板匹配和卷积原理很像,模板在原图像上从原点开始滑动,计算模板与(图像被模板覆盖的地方)的差别程度,这个差别程度的计算方法在opencv里有6种(建议使用归一化方法),然后将每次计算的结果放入一个矩阵里,作为结果输出。假如原图形是AxB大小,而模板是axb大小,则输出结果的矩阵是(A-a+1)x(B-b+1)
TM_SQDIFF:计算平方不同,计算出来的值越小,越相关
TM_CCORR:计算相关性,计算出来的值越大,越相关
TM_CCOEFF:计算相关系数,计算出来的值越大,越相关
TM_SQDIFF_NORMED:计算归一化平方不同,计算出来的值越接近0,越相关
TM_CCORR_NORMED:计算归一化相关性,计算出来的值越接近1,越相关
TM_CCOEFF_NORMED:计算归一化相关系数,计算出来的值越接近1,越相关
公式:https://docs.opencv.org/3.3.1/df/dfb/groupimgprocobject.html#ga3a7850640f1fe1f58fe91a2d7583695d

# 模板匹配
img = cv2.imread('lena.jpg', 0)
template = cv2.imread('face.jpg', 0)
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']
res = cv2.matchTemplate(img, template, cv2.TM_SQDIFF)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

#使用不同方法进行匹配
for meth in methods:
    img2 = img.copy()

    # 匹配方法的真值
    method = eval(meth) # eval() 函数用来执行一个字符串表达式,并返回表达式的值。
    print (method)
    res = cv2.matchTemplate(img, template, method)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

    # 如果是平方差匹配TM_SQDIFF或归一化平方差匹配TM_SQDIFF_NORMED,取最小值
    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, cmap='gray')
    plt.xticks([]), plt.yticks([])  # 隐藏坐标轴
    plt.subplot(122), plt.imshow(img2, cmap='gray')
    plt.xticks([]), plt.yticks([])
    plt.suptitle(meth)
    plt.show()

#匹配多个对象  
img_rgb = cv2.imread('mario.jpg')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('mario_coin.jpg', 0)
h, w = template.shape[:2]

res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
threshold = 0.8
# 取匹配程度大于%80的坐标y,x
loc = np.where(res >= threshold)# 输出满足条件的所有元素的坐标
for pt in zip(*loc[::-1]):  # *号表示可选参数
    bottom_right = (pt[0] + w, pt[1] + h)
    cv2.rectangle(img_rgb, pt, bottom_right, (0, 0, 255), 2)

cv2.imshow('img_rgb', img_rgb)
cv2.waitKey(0)

最后一步有几个Python/Numpy的重要知识,来大致看下:

x = np.arange(9.).reshape(3, 3)
print(np.where(x > 5))
# 结果(先y坐标(行号,也算是矩阵的高h),再x坐标(列号,相当于矩阵的款w),这也是矩阵索引的正常顺序):
# (array([2, 2, 2]), array([0, 1, 2]))
loc[::-1]
# 倒序 (array([0, 1, 2], array([2, 2, 2])
*loc
# 依次取出两个一维数组的同一个位置的数

zip函数,功能很强大到难以解释,举个简单例子就知道了:

x = [1, 2, 3]
y = [4, 5, 6]
print(list(zip(x, y)))  # [(1, 4), (2, 5), (3, 6)]

这样大家就能理解前面代码的用法了吧:因为loc是先y坐标再x坐标,所以用loc[::-1]Python 中的 [:-1] 和 [::-1]翻转一下,然后再用zip函数拼接在一起。
*号常用在list变量前。表示解析出list中可迭代的元素,传递到函数中。
fruits = [‘lemon’, ‘pear’, ‘watermelon’, ‘tomato’]
print(fruits[0], fruits[1], fruits[2], fruits[3]) = print(fruits) [python中的号和** 号如何使用](https://jingyan.baidu.com/article/219f4bf75b480ade442d389a.html)

直方图

hist_1.png

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

  • images: 原图像图像格式为 uint8 或 float32。当传入函数时应 用中括号 [] 括来例如[img]
  • channels: 同样用中括号括来它会告函数我们统幅图 像的直方图。如果入图像是灰度图它的值就是 [0]如果是彩色图像 的传入的参数可以是 [0][1][2] 它们分别对应着 BGR。
  • mask: 掩模图像。统整幅图像的直方图就把它为 None。但是如 果你想统图像某一分的直方图的你就制作一个掩模图像并 使用它。
  • histSize:BIN (柱子的数目)的数目。也应用中括号括来
  • ranges: 像素值范围常为 [0,256] ```python import cv2 #opencv读取的格式是BGR import numpy as np import matplotlib.pyplot as plt#Matplotlib是RGB %matplotlib inline

def cv_show(img,name): cv2.imshow(name,img) cv2.waitKey() cv2.destroyAllWindows()

img = cv2.imread(‘cat.jpg’,0) #0表示灰度图 hist = cv2.calcHist([img],[0],None,[256],[0,256]) hist.shape #输出为256*1维数组

<a name="fmeE4"></a>
# 
<a name="oAdyO"></a>
# 傅里叶变换
我们生活在时间的世界中,早上7:00起来吃早饭,8:00去挤地铁,9:00开始上班。。。以时间为参照就是时域分析。<br />但是在频域中一切都是静止的!<br />[https://zhuanlan.zhihu.com/p/19763358](https://zhuanlan.zhihu.com/p/19763358)
<a name="g8CRC"></a>
## 傅里叶变换的作用

- 高频:变化剧烈的灰度分量,例如边界<br />
- 低频:变化缓慢的灰度分量,例如一片大海<br />
<a name="La8nS"></a>
## 滤波

- 低通滤波器:只保留低频,会使得图像模糊<br />
- 高通滤波器:只保留高频,会使得图像细节增强<br />
- opencv中主要就是cv2.dft()和cv2.idft(),输入图像需要先转换成np.float32 格式。
- 得到的结果中频率为0的部分会在左上角,通常要转换到中心位置,可以通过shift变换来实现。
- cv2.dft()返回的结果是双通道的(实部,虚部),通常还需要转换成图像格式才能展示(0,255)。
```python
img = cv2.imread('lena.jpg',0)

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, 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()

下载.png

img = cv2.imread('lena.jpg',0)

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

# IDFT
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()

下载 (1).png

img = cv2.imread('lena.jpg',0)

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

# IDFT
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()

下载 (2).png