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
'''
Wiener deconvolution.
Sample shows how DFT can be used to perform Weiner deconvolution [1]
of an image with user-defined point spread function (PSF)
Usage:
deconvolution.py [--circle]
[--angle <degrees>]
[--d <diameter>]
[--snr <signal/noise ratio in db>]
[<input image>]
Use sliders to adjust PSF paramitiers.
Keys:
SPACE - switch btw linear/cirular PSF
ESC - exit
Examples:
deconvolution.py --angle 135 --d 22 data/licenseplate_motion.jpg
(image source: http://www.topazlabs.com/infocus/_images/licenseplate_compare.jpg)
deconvolution.py --angle 86 --d 31 data/text_motion.jpg
deconvolution.py --circle --d 19 data/text_defocus.jpg
(image source: compact digital photo camera, no artificial distortion)
[1] http://en.wikipedia.org/wiki/Wiener_deconvolution
'''
import numpy as np
import cv2
from common import nothing
def blur_edge(img, d=31):
h, w = img.shape[:2]
img_pad = cv2.copyMakeBorder(img, d, d, d, d, cv2.BORDER_WRAP)
img_blur = cv2.GaussianBlur(img_pad, (2*d+1, 2*d+1), -1)[d:-d,d:-d]
y, x = np.indices((h, w))
dist = np.dstack([x, w-x-1, y, h-y-1]).min(-1)
w = np.minimum(np.float32(dist)/d, 1.0)
return img*w + img_blur*(1-w)
def motion_kernel(angle, d, sz=65):
kern = np.ones((1, d), np.float32)
c, s = np.cos(angle), np.sin(angle)
A = np.float32([[c, -s, 0], [s, c, 0]])
sz2 = sz // 2
A[:,2] = (sz2, sz2) - np.dot(A[:,:2], ((d-1)*0.5, 0))
kern = cv2.warpAffine(kern, A, (sz, sz), flags=cv2.INTER_CUBIC)
return kern
def defocus_kernel(d, sz=65):
kern = np.zeros((sz, sz), np.uint8)
cv2.circle(kern, (sz, sz), d, 255, -1, cv2.CV_AA, shift=1)
kern = np.float32(kern) / 255.0
return kern
if __name__ == '__main__':
print __doc__
import sys, getopt
opts, args = getopt.getopt(sys.argv[1:], '', ['circle', 'angle=', 'd=', 'snr='])
opts = dict(opts)
try: fn = args[0]
except: fn = 'data/licenseplate_motion.jpg'
win = 'deconvolution'
img = cv2.imread(fn, 0)
img = np.float32(img)/255.0
cv2.imshow('input', img)
img = blur_edge(img)
IMG = cv2.dft(img, flags=cv2.DFT_COMPLEX_OUTPUT)
defocus = '--circle' in opts
def update(_):
ang = np.deg2rad( cv2.getTrackbarPos('angle', win) )
d = cv2.getTrackbarPos('d', win)
noise = 10**(-0.1*cv2.getTrackbarPos('SNR (db)', win))
if defocus:
psf = defocus_kernel(d)
else:
psf = motion_kernel(ang, d)
cv2.imshow('psf', psf)
psf /= psf.sum()
psf_pad = np.zeros_like(img)
kh, kw = psf.shape
psf_pad[:kh, :kw] = psf
PSF = cv2.dft(psf_pad, flags=cv2.DFT_COMPLEX_OUTPUT, nonzeroRows = kh)
PSF2 = (PSF**2).sum(-1)
iPSF = PSF / (PSF2 + noise)[...,np.newaxis]
RES = cv2.mulSpectrums(IMG, iPSF, 0)
res = cv2.idft(RES, flags=cv2.DFT_SCALE | cv2.DFT_REAL_OUTPUT )
res = np.roll(res, -kh//2, 0)
res = np.roll(res, -kw//2, 1)
cv2.imshow(win, res)
cv2.namedWindow(win)
cv2.namedWindow('psf', 0)
cv2.createTrackbar('angle', win, int(opts.get('--angle', 135)), 180, update)
cv2.createTrackbar('d', win, int(opts.get('--d', 22)), 50, update)
cv2.createTrackbar('SNR (db)', win, int(opts.get('--snr', 25)), 50, update)
update(None)
while True:
ch = cv2.waitKey()
if ch == 27:
break
if ch == ord(' '):
defocus = not defocus
update(None)