目录

OpenCV Chapter5 直方图,均衡化与傅里叶变换


OpenCV

直方图

统计每一个像素值出现的次数

1
cv2.calcHist(images, channels, mask, histSize, ranges)
  • images:原图像图像格式为uint8或float32.当传入函数时应用中括号[]括起来,例如[img],通常使用二值图

  • channels:同样用中括号,如果图像是灰度图则传入[0],如果是彩色图,则可以传入$[0]\ or\ [1]\ or\ [2]$,它们分别对应着$BGR\newline$

  • mask:掩模图像。统计整幅图像的直方图就将其设为None。但是如果想要统计图像的某一分的直方图你就制作一个掩模图像并且使用它

  • histSize:BIN数目,也应该用中括号括来(横轴取值范围,通常用[0,256])

  • ranges:像素值范围为[0,256]

二值图

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import cv2
import matplotlib.pyplot as plt


def show(image):
    cv2.imshow('result', image)
    cv2.waitKey()
    cv2.destroyAllWindows()


img = cv2.imread("img path", 0)
show(img)

hist = cv2.calcHist([img], [0], None, [256], [0, 256])
print(hist.shape)  # -> [256, 1]

plt.hist(img.ravel(), 256)
plt.show()
/img/Opencv/chapter5-1.png
OpenCV(直方图)

三通道

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import cv2
import matplotlib.pyplot as plt


def show(image):
    cv2.imshow('result', image)
    cv2.waitKey()
    cv2.destroyAllWindows()


img = cv2.imread("img path")
show(img)
color = ('b', 'g', 'r')
for i, col in enumerate(color):
    hist = cv2.calcHist([img], [i], None, [256], [0, 256])
    plt.plot(hist, color=col)
    plt.xlim([0, 256])

plt.show()
/img/Opencv/chapter5-2.png
OpenCV(直方图)

mask操作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import cv2
import matplotlib.pyplot as plt
import numpy as np


def show(image):
    cv2.imshow('result', image)
    cv2.waitKey()
    cv2.destroyAllWindows()


img = cv2.imread("img path", 0)
show(img)

# 创建mask
mask = np.zeros(img.shape[:2], np.uint8)
mask[100:300, 100:400] = 255
show(mask)
masked_img = cv2.bitwise_and(img, img, mask=mask)
show(masked_img)
hist_full = cv2.calcHist([img], [0], None, [256], [0, 256])
hist_mask = cv2.calcHist([img], [0], mask, [256], [0, 256])

plt.subplot(221), plt.imshow(img, 'gray')
plt.subplot(222), plt.imshow(mask, 'gray')
plt.subplot(223), plt.imshow(masked_img, 'gray')
plt.subplot(224), plt.plot(hist_full), plt.plot(hist_mask)
plt.xlim([0, 256])
plt.show()
/img/Opencv/chapter5-3.png
OpenCV(mask操作)

均衡化原理

直方图均衡化

将概率转化为累积概率

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import cv2
import matplotlib.pyplot as plt


def show(image):
    cv2.imshow('result', image)
    cv2.waitKey()
    cv2.destroyAllWindows()


img = cv2.imread("img path", 0)
show(img)

plt.subplot(211)
plt.hist(img.ravel(), 256)

plt.subplot(212)
equ = cv2.equalizeHist(img)
plt.hist(equ.ravel(), 256)
plt.show()
/img/Opencv/chapter5-4.png
OpenCV(直方图均值化)

如果均衡化效果更好$\rightarrow$分块均衡,但是此时要注意局部噪音点的影响

自适应直方图均值化

OpenCV在分块进行均值化操作的时候会对各模块边界进行一些线性插值处理,防止均值化之后各模块边界过于明显

1
cv2.createCLAHE([, clipLimit[, tileGridSize]])  retval
  • clipLimit:颜色对比度的阈值,可选项,默认值 8
  • titleGridSize:局部直方图均衡化的模板(邻域)大小,可选项,默认值 (8,8)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import cv2
import numpy as np


def show(image):
    cv2.imshow('result', image)
    cv2.waitKey()
    cv2.destroyAllWindows()


img = cv2.imread("img path", 0)
show(img)

clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
res_clahe = clahe.apply(img)
res = np.hstack((img, res_clahe))
show(res)
/img/Opencv/chapter5-5.png
OpenCV(自适应直方图均值化)

傅里叶变换

傅里叶分析之掐死教程(完整版)更新于2014.06.06(引用Heinrich的知乎文章,侵删)

傅里叶变换的作用

  • 高频:变化剧烈的灰度分量,例如边界
  • 低频:变化缓慢的灰度分量,例如一片大海

滤波

  • 低通滤波器:只保留低频,会使得图像模糊
  • 高通滤波器:只保留高频,会使得图像细节增强

代码

低通滤波器

  • opencv中主要就是$\rightarrow (执行傅里叶变换)$cv2.dft()和$\rightarrow (执行傅里叶逆变换)$cv2.idft(),输入图像需要先转换成np.float32格式

  • 得到的结果中得频率为0得部分会在左上角,通常要转换到中心位置,可以通过shift变换来实现

  • cv2.dft()返回的结果是双通道的(实部,虚部),通常还需要转换成图像格式才能展示(0, 255)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread("img path", 0)
img_float32 = np.float32(img)  # 格式转换

dft = cv2.dft(img_float32, flags=cv2.DFT_COMPLEX_OUTPUT)  # 执行傅里叶变换
dft_shift = np.fft.fftshift(dft)  # 进行shift变换
magnitude_spectrum = 20 * np.log(cv2.magnitude(dft_shift[:, :, 0], dft_shift[:, :, 1]))  # 得到灰度图能表示的形式
# 由于结果非常小,所以需要借助 20 * np.log进行映射
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()
/img/Opencv/chapter5-6.png
傅里叶变换(前后对比)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread("img path", 0)
img_float32 = np.float32(img)  # 格式转换

dft = cv2.dft(img_float32, flags=cv2.DFT_COMPLEX_OUTPUT)  # 执行傅里叶变换
dft_shift = np.fft.fftshift(dft)  # 进行shift变换

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  # 是1的保留下来,其余归零
f_ishift = np.fft.ifftshift(fshift)  # ishift(shift变换的逆运算)
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()
/img/Opencv/chapter5-7.png
傅里叶变换(低通滤波器)

高通滤波器

将原来的mask0部分改为1,1部分改为0即可

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread("img path", 0)
img_float32 = np.float32(img)  # 格式转换

dft = cv2.dft(img_float32, flags=cv2.DFT_COMPLEX_OUTPUT)  # 执行傅里叶变换
dft_shift = np.fft.fftshift(dft)  # 进行shift变换

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  # 是1的保留下来,其余归零
f_ishift = np.fft.ifftshift(fshift)  # ishift(shift变换的逆运算)
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()
/img/Opencv/chapter5-8.png
傅里叶变换(高通滤波器)