Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/samples/python/deconvolution.py
16337 views
1
#!/usr/bin/env python
2
3
'''
4
Wiener deconvolution.
5
6
Sample shows how DFT can be used to perform Weiner deconvolution [1]
7
of an image with user-defined point spread function (PSF)
8
9
Usage:
10
deconvolution.py [--circle]
11
[--angle <degrees>]
12
[--d <diameter>]
13
[--snr <signal/noise ratio in db>]
14
[<input image>]
15
16
Use sliders to adjust PSF paramitiers.
17
Keys:
18
SPACE - switch btw linear/cirular PSF
19
ESC - exit
20
21
Examples:
22
deconvolution.py --angle 135 --d 22 ../data/licenseplate_motion.jpg
23
(image source: http://www.topazlabs.com/infocus/_images/licenseplate_compare.jpg)
24
25
deconvolution.py --angle 86 --d 31 ../data/text_motion.jpg
26
deconvolution.py --circle --d 19 ../data/text_defocus.jpg
27
(image source: compact digital photo camera, no artificial distortion)
28
29
30
[1] http://en.wikipedia.org/wiki/Wiener_deconvolution
31
'''
32
33
# Python 2/3 compatibility
34
from __future__ import print_function
35
36
import numpy as np
37
import cv2 as cv
38
39
# local module
40
from common import nothing
41
42
43
def blur_edge(img, d=31):
44
h, w = img.shape[:2]
45
img_pad = cv.copyMakeBorder(img, d, d, d, d, cv.BORDER_WRAP)
46
img_blur = cv.GaussianBlur(img_pad, (2*d+1, 2*d+1), -1)[d:-d,d:-d]
47
y, x = np.indices((h, w))
48
dist = np.dstack([x, w-x-1, y, h-y-1]).min(-1)
49
w = np.minimum(np.float32(dist)/d, 1.0)
50
return img*w + img_blur*(1-w)
51
52
def motion_kernel(angle, d, sz=65):
53
kern = np.ones((1, d), np.float32)
54
c, s = np.cos(angle), np.sin(angle)
55
A = np.float32([[c, -s, 0], [s, c, 0]])
56
sz2 = sz // 2
57
A[:,2] = (sz2, sz2) - np.dot(A[:,:2], ((d-1)*0.5, 0))
58
kern = cv.warpAffine(kern, A, (sz, sz), flags=cv.INTER_CUBIC)
59
return kern
60
61
def defocus_kernel(d, sz=65):
62
kern = np.zeros((sz, sz), np.uint8)
63
cv.circle(kern, (sz, sz), d, 255, -1, cv.LINE_AA, shift=1)
64
kern = np.float32(kern) / 255.0
65
return kern
66
67
68
if __name__ == '__main__':
69
print(__doc__)
70
import sys, getopt
71
opts, args = getopt.getopt(sys.argv[1:], '', ['circle', 'angle=', 'd=', 'snr='])
72
opts = dict(opts)
73
try:
74
fn = args[0]
75
except:
76
fn = '../data/licenseplate_motion.jpg'
77
78
win = 'deconvolution'
79
80
img = cv.imread(fn, 0)
81
if img is None:
82
print('Failed to load file:', fn)
83
sys.exit(1)
84
85
img = np.float32(img)/255.0
86
cv.imshow('input', img)
87
88
img = blur_edge(img)
89
IMG = cv.dft(img, flags=cv.DFT_COMPLEX_OUTPUT)
90
91
defocus = '--circle' in opts
92
93
def update(_):
94
ang = np.deg2rad( cv.getTrackbarPos('angle', win) )
95
d = cv.getTrackbarPos('d', win)
96
noise = 10**(-0.1*cv.getTrackbarPos('SNR (db)', win))
97
98
if defocus:
99
psf = defocus_kernel(d)
100
else:
101
psf = motion_kernel(ang, d)
102
cv.imshow('psf', psf)
103
104
psf /= psf.sum()
105
psf_pad = np.zeros_like(img)
106
kh, kw = psf.shape
107
psf_pad[:kh, :kw] = psf
108
PSF = cv.dft(psf_pad, flags=cv.DFT_COMPLEX_OUTPUT, nonzeroRows = kh)
109
PSF2 = (PSF**2).sum(-1)
110
iPSF = PSF / (PSF2 + noise)[...,np.newaxis]
111
RES = cv.mulSpectrums(IMG, iPSF, 0)
112
res = cv.idft(RES, flags=cv.DFT_SCALE | cv.DFT_REAL_OUTPUT )
113
res = np.roll(res, -kh//2, 0)
114
res = np.roll(res, -kw//2, 1)
115
cv.imshow(win, res)
116
117
cv.namedWindow(win)
118
cv.namedWindow('psf', 0)
119
cv.createTrackbar('angle', win, int(opts.get('--angle', 135)), 180, update)
120
cv.createTrackbar('d', win, int(opts.get('--d', 22)), 50, update)
121
cv.createTrackbar('SNR (db)', win, int(opts.get('--snr', 25)), 50, update)
122
update(None)
123
124
while True:
125
ch = cv.waitKey()
126
if ch == 27:
127
break
128
if ch == ord(' '):
129
defocus = not defocus
130
update(None)
131
132