学习OpenCV——Python:用OpenCV处理图像

高通滤波器(HPF)

突出一个像素跟周边像素的差异,突出一个图像

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
# coding:utf-8
import cv2
import numpy as np
from scipy import ndimage
kernel_3x3 = np.array(
[[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1]]
)
kernel_5x5 = np.array(
[[-1, -1, -1, -1, -1],
[-1, 1, 2, 1, -1],
[-1, 2, 4, 2, -1],
[-1, 1, 2, 1, -1],
[-1, -1, -1, -1, -1]]
)
# 灰度图
img = cv2.imread("0.jpg", 0)
# “convolve”大概翻译为卷积的意思吧
# 通过scipy的ndimage实现
k3 = ndimage.convolve(img, kernel_3x3)
k5 = ndimage.convolve(img, kernel_5x5)
blurred = cv2.GaussianBlur(img, (11,11), 0)
g_hpf = img - blurred
cv2.imshow("3x3", k3)
cv2.imshow("5x5", k5)
cv2.imshow("gw('img',img)_hpf", g_hpf)
cv2.waitKey()
cv2.destroyAllWindows()




可见g_hpf效果最好
### 低通滤波器(LPF)
smoothen一个像素,如果它比某个阀值低。
这在降噪跟模糊中很有用。
如高斯模糊就是一个减弱高频信号的低通滤波器
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
import cv2
import numpy as np
'''
边缘检测
OpenCV内置的边缘检测:Laplacian(), Sobel(), and Scharr()
当然,边缘检测很容易把噪声当做边缘。所以我们在进行边缘检测之前先进行降噪模糊。
OpenCV内置的模糊函数blur() (simple average), medianBlur(), and GaussianBlur()
下面我们使用medianBlur(),这对于彩色图像的降噪帮助很大。对于边缘检测,我们使用拉普拉斯算子Laplacian()
在降噪之后,我们把色彩空间从BGR转换成灰阶
'''
def strokeEdges(src, dst, blurKsize=7, edgeKsize=5):
if blurKsize >= 3:
# 7*7的模板
blurredSrc = cv2.medianBlur(src, blurKsize)
# BGR to GRAY
graySrc = cv2.cvtColor(blurredSrc, cv2.COLOR_BGR2GRAY)
else:
graySrc = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
# 边缘检测
cv2.Laplacian(graySrc, cv2.CV_8U, graySrc, ksize=edgeKsize)
# 归一化
normalizedInverseAlpha = (1.0 / 255) * (255 - graySrc)
# 分割合并
channels = cv2.split(src)
for channel in channels:
channel[:] = channel * normalizedInverseAlpha
cv2.merge(channels, dst)




自定义模板

OpenCV提供了一个filter2D()函数,供我们自定义模板
我们再来看看模板,它是一个有奇数行跟列的二维数组。

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import cv2
import numpy
'''
边缘检测
OpenCV内置的边缘检测:Laplacian(), Sobel(), and Scharr()
当然,边缘检测很容易把噪声当做边缘。所以我们在进行边缘检测之前先进行降噪模糊。
OpenCV内置的模糊函数blur() (simple average), medianBlur(), and GaussianBlur()
下面我们使用medianBlur(),这对于彩色图像的降噪帮助很大。对于边缘检测,我们使用拉普拉斯算子Laplacian()
在降噪之后,我们把色彩空间从BGR转换成灰阶
'''
def strokeEdges(src, dst, blurKsize=7, edgeKsize=5):
if blurKsize >= 3:
# 7*7的模板
blurredSrc = cv2.medianBlur(src, blurKsize)
# BGR to GRAY
graySrc = cv2.cvtColor(blurredSrc, cv2.COLOR_BGR2GRAY)
else:
graySrc = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
# 边缘检测
cv2.Laplacian(graySrc, cv2.CV_8U, graySrc, ksize=edgeKsize)
# 归一化
normalizedInverseAlpha = (1.0 / 255) * (255 - graySrc)
# 分割合并
channels = cv2.split(src)
for channel in channels:
channel[:] = channel * normalizedInverseAlpha
cv2.merge(channels, dst)
class VConvolutionFilter(object):
def __init__(self, kernel):
self._kernel = kernel
def apply(self, src, dst):
"""应用滤波器"""
# 第二个参数 -1,指的是目标图跟原图具有同样的通道深度(per-channel depth)
cv2.filter2D(src, -1, self._kernel, dst)
class SharpenFilter(VConvolutionFilter):
"""锐化"""
def __init__(self):
# 注意到模板权重总和为1。这种情况下,图像的总体亮度不变。
kernel = numpy.array(
[[-1, -1, -1],
[-1, 9, -1],
[-1, -1, -1]]
)
VConvolutionFilter.__init__(self, kernel)
class FindEdgesFilter(VConvolutionFilter):
"""边缘检测"""
def __init__(self):
# 权重总和0,边缘白色,不是边缘黑色
kernel = numpy.array(
[[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1]]
)
VConvolutionFilter.__init__(self, kernel)
class BlurFilter(VConvolutionFilter):
"""模糊"""
def __init__(self):
# 权重总和为1
kernel = numpy.array(
[[0.04, 0.04, 0.04, 0.04, 0.04],
[0.04, 0.04, 0.04, 0.04, 0.04],
[0.04, 0.04, 0.04, 0.04, 0.04],
[0.04, 0.04, 0.04, 0.04, 0.04],
[0.04, 0.04, 0.04, 0.04, 0.04]]
)
VConvolutionFilter.__init__(self, kernel)
class EmbossFilter(VConvolutionFilter):
"""浮雕"""
def __init__(self):
# 绝大多数模板都是对称的,若一边模糊(取正),一边锐化(取负),将会有奇异的效果(浮雕)
kernel = numpy.array(
[[-2, -1, 0],
[-1, 1, 1],
[0, 1, 2]]
)
VConvolutionFilter.__init__(self, kernel)

SharpenFilter



##### FindEdgesFilter



##### BlurFilter



##### EmbossFilter



### 实战
还记得我们之前的那个调用摄像头的实战吗?这次我们在前一次的基础上,加上滤波器看看。
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
filter.py
import cv2
import numpy
'''
边缘检测
OpenCV内置的边缘检测:Laplacian(), Sobel(), and Scharr()
当然,边缘检测很容易把噪声当做边缘。所以我们在进行边缘检测之前先进行降噪模糊。
OpenCV内置的模糊函数blur() (simple average), medianBlur(), and GaussianBlur()
下面我们使用medianBlur(),这对于彩色图像的降噪帮助很大。对于边缘检测,我们使用拉普拉斯算子Laplacian()
在降噪之后,我们把色彩空间从BGR转换成灰阶
'''
def strokeEdges(src, dst, blurKsize=7, edgeKsize=5):
if blurKsize >= 3:
# 7*7的模板
blurredSrc = cv2.medianBlur(src, blurKsize)
# BGR to GRAY
graySrc = cv2.cvtColor(blurredSrc, cv2.COLOR_BGR2GRAY)
else:
graySrc = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
# 边缘检测
cv2.Laplacian(graySrc, cv2.CV_8U, graySrc, ksize=edgeKsize)
# 归一化
normalizedInverseAlpha = (1.0 / 255) * (255 - graySrc)
# 分割合并
channels = cv2.split(src)
for channel in channels:
channel[:] = channel * normalizedInverseAlpha
cv2.merge(channels, dst)
class VConvolutionFilter(object):
def __init__(self, kernel):
self._kernel = kernel
def apply(self, src, dst):
"""应用滤波器"""
# 第二个参数 -1,指的是目标图跟原图具有同样的通道深度(per-channel depth)
cv2.filter2D(src, -1, self._kernel, dst)
class SharpenFilter(VConvolutionFilter):
"""锐化"""
def __init__(self):
# 注意到模板权重总和为1。这种情况下,图像的总体亮度不变。
kernel = numpy.array(
[[-1, -1, -1],
[-1, 9, -1],
[-1, -1, -1]]
)
VConvolutionFilter.__init__(self, kernel)
class FindEdgesFilter(VConvolutionFilter):
"""边缘检测"""
def __init__(self):
# 权重总和0,边缘白色,不是边缘黑色
kernel = numpy.array(
[[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1]]
)
VConvolutionFilter.__init__(self, kernel)
class BlurFilter(VConvolutionFilter):
"""模糊"""
def __init__(self):
# 权重总和为1
kernel = numpy.array(
[[0.04, 0.04, 0.04, 0.04, 0.04],
[0.04, 0.04, 0.04, 0.04, 0.04],
[0.04, 0.04, 0.04, 0.04, 0.04],
[0.04, 0.04, 0.04, 0.04, 0.04],
[0.04, 0.04, 0.04, 0.04, 0.04]]
)
VConvolutionFilter.__init__(self, kernel)
class EmbossFilter(VConvolutionFilter):
"""浮雕"""
def __init__(self):
# 绝大多数模板都是对称的,若一边模糊(取正),一边锐化(取负),将会有奇异的效果(浮雕)
kernel = numpy.array(
[[-2, -1, 0],
[-1, 1, 1],
[0, 1, 2]]
)
VConvolutionFilter.__init__(self, kernel)


#### cameo.py
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# coding:utf-8
import time
import cv2
import numpy
import filters
class CaptureManager(object):
def __init__(self, capture, previewWindowManager=None, shouldMirrorPreview=False):
# 绘制窗口,bool
self.previewWindowManager = previewWindowManager
# 镜像旋转(在窗口中问不是在文件中),bool
self.shouldMirrorPreview = shouldMirrorPreview
self._capture = capture
# 频道
self._channel = 0
self._enteredFrame = False
self._frame = None
# 写入图像
self._imageFilename = None
self._videoFilename = None
self._videoEncoding = None
self._videoWriter = None
self._startTime = None
# 从开始到现在帧数
self._framesElapsed = long(0)
# OpenCV没办法获取FPS,如果需要可以用time.time()计算
self._fpsEstimate = None
@property
def channel(self):
return self._channel
@channel.setter
def channel(self, value):
if self._channel != value:
self._channel = value
self._frame = None
@property
def frame(self):
if self._enteredFrame and self._frame is None:
_, self._frame = self._capture.retrieve()
return self._frame
@property
def isWritingImage(self):
return self._imageFilename is not None
@property
def isWritingVideo(self):
return self._videoFilename is not None
def enterFrame(self):
"""捕获下一帧,如果有的话"""
assert not self._enteredFrame, \
'previous enterFrame() had no matching exitFrame()'
if self._capture is not None:
self._enteredFrame = self._capture.grab()
def exitFrame(self):
"""绘制窗口. 写入文件. 释放."""
if self.frame is None:
self._enteredFrame = False
return
# 获取FPS
if self._framesElapsed == 0:
self._startTime = time.time()
else:
timeElapsed = time.time() - self._startTime
self._fpsEstimate = self._framesElapsed / timeElapsed
self._framesElapsed += 1
# 绘制窗口
if self.previewWindowManager is not None:
if self.shouldMirrorPreview:
mirroredFrame = numpy.fliplr(self._frame).copy()
self.previewWindowManager.show(mirroredFrame)
else:
self.previewWindowManager.show(self._frame)
# 写入图像
if self.isWritingImage:
cv2.imwrite(self._imageFilename, self._frame)
self._imageFilename = None
# 写入视频
self._writeVideoFrame()
# 释放
self._frame = None
self._enteredFrame = False
def writeImage(self, filename):
"""写入一帧到图像"""
self._imageFilename = filename
def startWritingVideo(self, filename, encoding=cv2.VideoWriter_fourcc('I', '4', '2', '0')):
"""开始准备写入视频"""
self._videoFilename = filename
self._videoEncoding = encoding
def stopWritingVideo(self):
"""停止写入视频"""
self._videoFilename = None
self._videoEncoding = None
self._videoWriter = None
def _writeVideoFrame(self):
if not self.isWritingVideo:
return
if self._videoWriter is None:
fps = self._capture.get(cv2.CAP_PROP_FPS)
if fps == 0.0:
# 不能捕获帧数就用之前自己测量的
if self._framesElapsed < 20:
# 等待帧数稳定下来
return
else:
fps = self._fpsEstimate
size = (int(self._capture.get(cv2.CAP_PROP_FRAME_WIDTH)), int(self._capture.get(cv2.CAP_PROP_FRAME_HEIGHT)))
self._videoWriter = cv2.VideoWriter(self._videoFilename, self._videoEncoding, fps, size)
self._videoWriter.write(self._frame)
class WindowManager(object):
def __init__(self, windowName, keypressCallback=None):
self.keypressCallback = keypressCallback
self._windowName = windowName
self._isWindowCreated = False
@property
def isWindowCreated(self):
return self._isWindowCreated
def createWindow(self):
cv2.namedWindow(self._windowName)
self._isWindowCreated = True
def show(self, frame):
cv2.imshow(self._windowName, frame)
def destroyWindow(self):
cv2.destroyWindow(self._windowName)
self._isWindowCreated = False
def processEvents(self):
keycode = cv2.waitKey(1)
if self.keypressCallback is not None and keycode != -1:
keycode &= 0xFF
self.keypressCallback(keycode)
class Cameo(object):
def __init__(self):
self._windowManager = WindowManager('Cameo', self.onKeypress)
self._captureManager = CaptureManager(cv2.VideoCapture(1), self._windowManager, True)
self._curveFilter = filters.EmbossFilter()
def run(self):
"""开始循环"""
self._windowManager.createWindow()
while self._windowManager.isWindowCreated:
self._captureManager.enterFrame()
frame = self._captureManager.frame
self._curveFilter.apply(frame, frame)
self._captureManager.exitFrame()
self._windowManager.processEvents()
def onKeypress(self, keycode):
"""
处理案件
space -> 截屏
tab -> 开始/停止录像
escape -> 退出
"""
if keycode == 32: # space
self._captureManager.writeImage('screenshot.png')
elif keycode == 9: # tab
if not self._captureManager.isWritingVideo:
self._captureManager.startWritingVideo('screencast.avi')
else:
self._captureManager.stopWritingVideo()
elif keycode == 27: # escape
self._windowManager.destroyWindow()
if __name__ == "__main__":
Cameo().run()




文章目录
  1. 1. 高通滤波器(HPF)
  2. 2. 自定义模板
    1. 2.0.1. SharpenFilter
|