quant1x 0.2.5__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {quant1x-0.2.5 → quant1x-0.3.0}/PKG-INFO +1 -1
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x/__init__.py +1 -1
- quant1x-0.3.0/quant1x/data/futu-basicinfo.py +27 -0
- quant1x-0.3.0/quant1x/findpeaks/__init__.py +13 -0
- quant1x-0.3.0/quant1x/findpeaks/filters/__init__.py +0 -0
- quant1x-0.3.0/quant1x/findpeaks/filters/frost.py +168 -0
- quant1x-0.3.0/quant1x/findpeaks/filters/kuan.py +139 -0
- quant1x-0.3.0/quant1x/findpeaks/filters/lee.py +147 -0
- quant1x-0.3.0/quant1x/findpeaks/filters/lee_enhanced.py +163 -0
- quant1x-0.3.0/quant1x/findpeaks/filters/mean.py +122 -0
- quant1x-0.3.0/quant1x/findpeaks/filters/median.py +103 -0
- quant1x-0.3.0/quant1x/findpeaks/findpeaks.py +1253 -0
- quant1x-0.3.0/quant1x/findpeaks/interpolate.py +194 -0
- quant1x-0.3.0/quant1x/findpeaks/stats.py +593 -0
- quant1x-0.3.0/quant1x/findpeaks/union_find.py +73 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x.egg-info/PKG-INFO +1 -1
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x.egg-info/SOURCES.txt +13 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/LICENSE +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/README.rst +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x/base/__init__.py +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x/base/basic.py +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x/base/formula.py +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x/base/formula_plus.py +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x/base/series.py +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x/data/__init__.py +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x/data/quotes.py +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x/formula/__init__.py +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x/indicator/__init__.py +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x/indicator/ma1x.py +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x/strategy/__init__.py +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x/strategy/bad_base.py +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x/strategy/linear_regression.py +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x/util/__init__.py +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x/util/font.py +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x.egg-info/dependency_links.txt +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x.egg-info/entry_points.txt +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x.egg-info/not-zip-safe +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x.egg-info/requires.txt +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/quant1x.egg-info/top_level.txt +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/setup.cfg +0 -0
- {quant1x-0.2.5 → quant1x-0.3.0}/setup.py +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: UTF-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
证券基本信息
|
|
5
|
+
"""
|
|
6
|
+
from futu import *
|
|
7
|
+
|
|
8
|
+
quote_ctx = OpenQuoteContext(host='127.0.0.1', port=11111)
|
|
9
|
+
print('******************************************')
|
|
10
|
+
ret, data = quote_ctx.get_stock_basicinfo(Market.SH, SecurityType.STOCK)
|
|
11
|
+
if ret == RET_OK:
|
|
12
|
+
data.to_csv('sh.csv', index=False)
|
|
13
|
+
else:
|
|
14
|
+
print('error:', data)
|
|
15
|
+
print('******************************************')
|
|
16
|
+
ret, data = quote_ctx.get_stock_basicinfo(Market.SZ, SecurityType.STOCK)
|
|
17
|
+
if ret == RET_OK:
|
|
18
|
+
data.to_csv('sz.csv', index=False)
|
|
19
|
+
else:
|
|
20
|
+
print('error:', data)
|
|
21
|
+
ret, data = quote_ctx.get_stock_basicinfo(Market.HK, SecurityType.STOCK)
|
|
22
|
+
if ret == RET_OK:
|
|
23
|
+
data.to_csv('hk.csv', index=False)
|
|
24
|
+
else:
|
|
25
|
+
print('error:', data)
|
|
26
|
+
|
|
27
|
+
quote_ctx.close() # 结束后记得关闭当条连接,防止连接条数用尽
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from quant1x.findpeaks.filters.frost import frost_filter
|
|
2
|
+
from quant1x.findpeaks.filters.kuan import kuan_filter
|
|
3
|
+
# Import the denosing filters
|
|
4
|
+
from quant1x.findpeaks.filters.lee import lee_filter
|
|
5
|
+
from quant1x.findpeaks.filters.lee_enhanced import lee_enhanced_filter
|
|
6
|
+
from quant1x.findpeaks.filters.mean import mean_filter
|
|
7
|
+
from quant1x.findpeaks.filters.median import median_filter
|
|
8
|
+
from quant1x.findpeaks.findpeaks import findpeaks
|
|
9
|
+
from quant1x.findpeaks.findpeaks import (
|
|
10
|
+
import_example,
|
|
11
|
+
stats,
|
|
12
|
+
interpolate,
|
|
13
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
# Copyright 2012 - 2013
|
|
5
|
+
# Matías Herranz <matiasherranz@gmail.com>
|
|
6
|
+
# Joaquín Tita <joaquintita@gmail.com>
|
|
7
|
+
# https://github.com/PyRadar/pyradar
|
|
8
|
+
#
|
|
9
|
+
# 2020: Erdogan Taskesen: <erdogant@gmail.com> Converted to python3.
|
|
10
|
+
#
|
|
11
|
+
# This library is free software; you can redistribute it and/or
|
|
12
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
13
|
+
# License as published by the Free Software Foundation; either
|
|
14
|
+
# version 3 of the License, or (at your option) any later version.
|
|
15
|
+
#
|
|
16
|
+
# This library is distributed in the hope that it will be useful,
|
|
17
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
18
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
19
|
+
# Lesser General Public License for more details.
|
|
20
|
+
#
|
|
21
|
+
# You should have received a copy of the GNU Lesser General Public
|
|
22
|
+
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
import numpy as np
|
|
26
|
+
from scipy.stats import variation
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def compute_coef_var(image, x_start, x_end, y_start, y_end):
|
|
30
|
+
"""
|
|
31
|
+
Compute coefficient of variation in a window of [x_start: x_end] and
|
|
32
|
+
[y_start:y_end] within the image.
|
|
33
|
+
"""
|
|
34
|
+
if x_start < 0: raise Exception('ERROR: x_start must be >= 0.')
|
|
35
|
+
if y_start < 0: raise Exception('ERROR: y_start must be >= 0.')
|
|
36
|
+
|
|
37
|
+
x_size, y_size = image.shape
|
|
38
|
+
x_overflow = x_end > x_size
|
|
39
|
+
y_overflow = y_end > y_size
|
|
40
|
+
|
|
41
|
+
if x_overflow: raise Exception('ERROR: invalid parameters cause x window overflow.')
|
|
42
|
+
if y_overflow: raise Exception('ERROR: invalid parameters cause y window overflow.')
|
|
43
|
+
|
|
44
|
+
window = image[x_start:x_end, y_start:y_end]
|
|
45
|
+
|
|
46
|
+
coef_var = variation(window, None)
|
|
47
|
+
|
|
48
|
+
if not coef_var: # dirty patch
|
|
49
|
+
coef_var = 0.01
|
|
50
|
+
# print "squared_coef was equal zero but replaced by %s" % coef_var
|
|
51
|
+
if coef_var <= 0: raise Exception('ERROR: coeffient of variation cannot be zero.')
|
|
52
|
+
|
|
53
|
+
return coef_var
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def calculate_all_Mi(window_flat, factor_A, window):
|
|
57
|
+
"""
|
|
58
|
+
Compute all the weights of pixels in the window.
|
|
59
|
+
"""
|
|
60
|
+
N, M = window.shape
|
|
61
|
+
center_pixel = np.float64(window[int(N / 2), int(M / 2)])
|
|
62
|
+
window_flat = np.float64(window_flat)
|
|
63
|
+
|
|
64
|
+
distances = np.abs(window_flat - center_pixel)
|
|
65
|
+
|
|
66
|
+
weights = np.exp(-factor_A * distances)
|
|
67
|
+
|
|
68
|
+
return weights
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def calculate_local_weight_matrix(window, factor_A):
|
|
72
|
+
"""
|
|
73
|
+
Returns an array with the weights for the pixels in the given window.
|
|
74
|
+
"""
|
|
75
|
+
weights_array = np.zeros(window.size)
|
|
76
|
+
window_flat = window.flatten()
|
|
77
|
+
|
|
78
|
+
weights_array = calculate_all_Mi(window_flat, factor_A, window)
|
|
79
|
+
|
|
80
|
+
return weights_array
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def frost_filter(img, damping_factor=2.0, win_size=3):
|
|
84
|
+
"""Frost filter.
|
|
85
|
+
|
|
86
|
+
Description
|
|
87
|
+
-----------
|
|
88
|
+
Apply frost filter to a numpy matrix containing the image, with a window of win_size x win_size. By default, the window size is 3x3.
|
|
89
|
+
|
|
90
|
+
Parameters
|
|
91
|
+
----------
|
|
92
|
+
img : array-like
|
|
93
|
+
Input image.
|
|
94
|
+
damping_factor : float (default: 2.0)
|
|
95
|
+
Damping factor.
|
|
96
|
+
win_size : int, int (default: 3)
|
|
97
|
+
Window size.
|
|
98
|
+
|
|
99
|
+
Returns
|
|
100
|
+
-------
|
|
101
|
+
img_filtered : array-like
|
|
102
|
+
Filtered image.
|
|
103
|
+
|
|
104
|
+
Examples
|
|
105
|
+
--------
|
|
106
|
+
>>> import findpeaks
|
|
107
|
+
>>> import matplotlib.pyplot as plt
|
|
108
|
+
>>> img = findpeaks.import_example('2dpeaks_image')
|
|
109
|
+
>>> # Resize
|
|
110
|
+
>>> img = findpeaks.stats.resize(img, size=(300,300))
|
|
111
|
+
>>> # Make grey image
|
|
112
|
+
>>> img = findpeaks.stats.togray(img)
|
|
113
|
+
>>> # Scale between [0-255]
|
|
114
|
+
>>> img = findpeaks.stats.scale(img)
|
|
115
|
+
>>> # frost filter
|
|
116
|
+
>>> img_filtered = findpeaks.stats.frost_filter(img.copy(), damping_factor=2, win_size=15)
|
|
117
|
+
>>>
|
|
118
|
+
>>> plt.figure()
|
|
119
|
+
>>> fig, axs = plt.subplots(1,2)
|
|
120
|
+
>>> axs[0].imshow(img, cmap='gray'); axs[0].set_title('Input')
|
|
121
|
+
>>> axs[1].imshow(img_filtered, cmap='gray'); axs[1].set_title('Frost filter')
|
|
122
|
+
|
|
123
|
+
"""
|
|
124
|
+
if win_size < 3: raise Exception('[findpeaks] >ERROR: win size must be at least 3')
|
|
125
|
+
if len(img.shape) > 2: raise Exception(
|
|
126
|
+
'[findpeaks] >ERROR: Image should be 2D. Hint: set the parameter: togray=True')
|
|
127
|
+
if ((win_size % 2) == 0): print(
|
|
128
|
+
'[findpeaks] >It is highly recommended to user odd window sizes. You provided %s, an even number.' % (win_size))
|
|
129
|
+
|
|
130
|
+
img_filtered = np.zeros_like(img)
|
|
131
|
+
N, M = img.shape
|
|
132
|
+
win_offset = int(win_size / 2)
|
|
133
|
+
|
|
134
|
+
for i in np.arange(0, N):
|
|
135
|
+
xleft = i - win_offset
|
|
136
|
+
xright = i + win_offset
|
|
137
|
+
if xleft < 0:
|
|
138
|
+
xleft = 0
|
|
139
|
+
if xright >= N:
|
|
140
|
+
xright = N - 1
|
|
141
|
+
for j in np.arange(0, M):
|
|
142
|
+
yup = j - win_offset
|
|
143
|
+
ydown = j + win_offset
|
|
144
|
+
if yup < 0:
|
|
145
|
+
yup = 0
|
|
146
|
+
if ydown >= M:
|
|
147
|
+
ydown = M - 1
|
|
148
|
+
|
|
149
|
+
# inspired by http://www.pcigeomatics.com/cgi-bin/pcihlp/FFROST
|
|
150
|
+
variation_coef = compute_coef_var(img, xleft, xright, yup, ydown)
|
|
151
|
+
window = img[xleft:xright, yup:ydown]
|
|
152
|
+
window_mean = window.mean()
|
|
153
|
+
sigma_zero = variation_coef / window_mean # var / u^2
|
|
154
|
+
factor_A = damping_factor * sigma_zero
|
|
155
|
+
|
|
156
|
+
weights_array = calculate_local_weight_matrix(window, factor_A)
|
|
157
|
+
pixels_array = window.flatten()
|
|
158
|
+
|
|
159
|
+
weighted_values = weights_array * pixels_array
|
|
160
|
+
|
|
161
|
+
new_pix_value = weighted_values.sum() / weights_array.sum()
|
|
162
|
+
|
|
163
|
+
if (new_pix_value is None) or np.isnan(new_pix_value):
|
|
164
|
+
new_pix_value = 0
|
|
165
|
+
|
|
166
|
+
img_filtered[i, j] = new_pix_value
|
|
167
|
+
|
|
168
|
+
return img_filtered
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
# Copyright 2012 - 2013
|
|
5
|
+
# Matías Herranz <matiasherranz@gmail.com>
|
|
6
|
+
# Joaquín Tita <joaquintita@gmail.com>
|
|
7
|
+
# https://github.com/PyRadar/pyradar
|
|
8
|
+
#
|
|
9
|
+
# 2020: Erdogan Taskesen: <erdogant@gmail.com> Converted to python3.
|
|
10
|
+
#
|
|
11
|
+
# This library is free software; you can redistribute it and/or
|
|
12
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
13
|
+
# License as published by the Free Software Foundation; either
|
|
14
|
+
# version 3 of the License, or (at your option) any later version.
|
|
15
|
+
#
|
|
16
|
+
# This library is distributed in the hope that it will be useful,
|
|
17
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
18
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
19
|
+
# Lesser General Public License for more details.
|
|
20
|
+
#
|
|
21
|
+
# You should have received a copy of the GNU Lesser General Public
|
|
22
|
+
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
import numpy as np
|
|
26
|
+
from scipy.stats import variation
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def weighting(window, cu=0.25):
|
|
30
|
+
"""
|
|
31
|
+
Computes the weighthing function for Kuan filter using cu as the noise
|
|
32
|
+
coefficient.
|
|
33
|
+
"""
|
|
34
|
+
two_cu = cu * cu
|
|
35
|
+
|
|
36
|
+
ci = variation(window, None)
|
|
37
|
+
two_ci = ci * ci
|
|
38
|
+
|
|
39
|
+
if not two_ci: # dirty patch to avoid zero division
|
|
40
|
+
two_ci = 0.01
|
|
41
|
+
|
|
42
|
+
divisor = 1.0 + two_cu
|
|
43
|
+
|
|
44
|
+
if not divisor:
|
|
45
|
+
divisor = 0.0001
|
|
46
|
+
|
|
47
|
+
if cu > ci:
|
|
48
|
+
w_t = 0.0
|
|
49
|
+
else:
|
|
50
|
+
w_t = (1.0 - (two_cu / two_ci)) / divisor
|
|
51
|
+
|
|
52
|
+
return w_t
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def kuan_filter(img, win_size=3, cu=0.25):
|
|
56
|
+
"""Kuan filter.
|
|
57
|
+
|
|
58
|
+
Description
|
|
59
|
+
-----------
|
|
60
|
+
Apply kuan to a numpy matrix containing the image, with a window of win_size x win_size.
|
|
61
|
+
|
|
62
|
+
Parameters
|
|
63
|
+
----------
|
|
64
|
+
img : array-like
|
|
65
|
+
Input image.
|
|
66
|
+
win_size : int, int (default: 3)
|
|
67
|
+
Window size.
|
|
68
|
+
cu : float (default: 0.25)
|
|
69
|
+
cu factor.
|
|
70
|
+
|
|
71
|
+
Returns
|
|
72
|
+
-------
|
|
73
|
+
img_filtered : array-like
|
|
74
|
+
Filtered image.
|
|
75
|
+
|
|
76
|
+
Examples
|
|
77
|
+
--------
|
|
78
|
+
>>> import findpeaks
|
|
79
|
+
>>> import matplotlib.pyplot as plt
|
|
80
|
+
>>> img = findpeaks.import_example('2dpeaks_image')
|
|
81
|
+
>>> # Resize
|
|
82
|
+
>>> img = findpeaks.stats.resize(img, size=(300,300))
|
|
83
|
+
>>> # Make grey image
|
|
84
|
+
>>> img = findpeaks.stats.togray(img)
|
|
85
|
+
>>> # Scale between [0-255]
|
|
86
|
+
>>> img = findpeaks.stats.scale(img)
|
|
87
|
+
>>> # Filter
|
|
88
|
+
>>> img_filtered = findpeaks.stats.kuan_filter(img.copy(), win_size=15, cu=0.25)
|
|
89
|
+
>>>
|
|
90
|
+
>>> plt.figure()
|
|
91
|
+
>>> fig, axs = plt.subplots(1,2)
|
|
92
|
+
>>> axs[0].imshow(img, cmap='gray'); axs[0].set_title('Input')
|
|
93
|
+
>>> axs[1].imshow(img_filtered, cmap='gray'); axs[1].set_title('Kuan filter')
|
|
94
|
+
|
|
95
|
+
"""
|
|
96
|
+
if win_size < 3: raise Exception('[findpeaks] >ERROR: win size must be at least 3')
|
|
97
|
+
if len(img.shape) > 2: raise Exception(
|
|
98
|
+
'[findpeaks] >ERROR: Image should be 2D. Hint: set the parameter: togray=True')
|
|
99
|
+
if ((win_size % 2) == 0): print(
|
|
100
|
+
'[findpeaks] >It is highly recommended to user odd window sizes. You provided %s, an even number.' % (win_size))
|
|
101
|
+
|
|
102
|
+
# we process the entire img as float64 to avoid type overflow error
|
|
103
|
+
img = np.float64(img)
|
|
104
|
+
img_filtered = np.zeros_like(img)
|
|
105
|
+
|
|
106
|
+
N, M = img.shape
|
|
107
|
+
# win_offset = win_size / 2
|
|
108
|
+
win_offset = int(win_size / 2)
|
|
109
|
+
|
|
110
|
+
for i in np.arange(0, N):
|
|
111
|
+
xleft = i - win_offset
|
|
112
|
+
xright = i + win_offset
|
|
113
|
+
|
|
114
|
+
if xleft < 0:
|
|
115
|
+
xleft = 0
|
|
116
|
+
if xright >= N:
|
|
117
|
+
xright = N
|
|
118
|
+
|
|
119
|
+
for j in np.arange(0, M):
|
|
120
|
+
yup = j - win_offset
|
|
121
|
+
ydown = j + win_offset
|
|
122
|
+
|
|
123
|
+
if yup < 0:
|
|
124
|
+
yup = 0
|
|
125
|
+
if ydown >= M:
|
|
126
|
+
ydown = M
|
|
127
|
+
|
|
128
|
+
pix_value = img[i, j]
|
|
129
|
+
window = img[xleft:xright, yup:ydown]
|
|
130
|
+
w_t = weighting(window, cu)
|
|
131
|
+
window_mean = window.mean()
|
|
132
|
+
new_pix_value = (pix_value * w_t) + (window_mean * (1.0 - w_t))
|
|
133
|
+
|
|
134
|
+
if (new_pix_value is None) or np.isnan(new_pix_value):
|
|
135
|
+
new_pix_value = 0
|
|
136
|
+
|
|
137
|
+
img_filtered[i, j] = round(new_pix_value)
|
|
138
|
+
|
|
139
|
+
return img_filtered
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
# Copyright 2012 - 2013
|
|
5
|
+
# Matías Herranz <matiasherranz@gmail.com>
|
|
6
|
+
# Joaquín Tita <joaquintita@gmail.com>
|
|
7
|
+
# https://github.com/PyRadar/pyradar
|
|
8
|
+
#
|
|
9
|
+
# 2020: Erdogan Taskesen: <erdogant@gmail.com> Converted to python3.
|
|
10
|
+
#
|
|
11
|
+
# This library is free software; you can redistribute it and/or
|
|
12
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
13
|
+
# License as published by the Free Software Foundation; either
|
|
14
|
+
# version 3 of the License, or (at your option) any later version.
|
|
15
|
+
#
|
|
16
|
+
# This library is distributed in the hope that it will be useful,
|
|
17
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
18
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
19
|
+
# Lesser General Public License for more details.
|
|
20
|
+
#
|
|
21
|
+
# You should have received a copy of the GNU Lesser General Public
|
|
22
|
+
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
import numpy as np
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _weighting(window, cu=0.25):
|
|
29
|
+
"""
|
|
30
|
+
Computes the weighthing function for Lee filter using cu as the noise
|
|
31
|
+
coefficient.
|
|
32
|
+
"""
|
|
33
|
+
# cu is the noise variation coefficient
|
|
34
|
+
two_cu = cu * cu
|
|
35
|
+
|
|
36
|
+
# ci is the variation coefficient in the window
|
|
37
|
+
window_mean = window.mean()
|
|
38
|
+
window_std = window.std()
|
|
39
|
+
ci = window_std / window_mean
|
|
40
|
+
|
|
41
|
+
two_ci = ci * ci
|
|
42
|
+
|
|
43
|
+
if not two_ci: # dirty patch to avoid zero division
|
|
44
|
+
two_ci = 0.01
|
|
45
|
+
|
|
46
|
+
if cu > ci: # preserve the original value (I guess)
|
|
47
|
+
w_t = 0.0
|
|
48
|
+
else: # use the filter
|
|
49
|
+
w_t = 1.0 - (two_cu / two_ci)
|
|
50
|
+
|
|
51
|
+
return w_t
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def lee_filter(img, win_size=3, cu=0.25):
|
|
55
|
+
"""Lee filter.
|
|
56
|
+
|
|
57
|
+
Description
|
|
58
|
+
-----------
|
|
59
|
+
The Additive Noise Lee Despeckling Filter.
|
|
60
|
+
Apply lee to a numpy matrix containing the image, with a window of win_size x win_size.
|
|
61
|
+
Let's assume that the despeckling noise is additive with a constant mean of zero, a constant variance, and drawn from a Gaussian distribution. Use a window (I x J pixels) to scan the image with a stride of 1 pixels (and I will use reflective boundary conditions). The despeckled value of the pixel in the center of the window located in the ith row and jth column is, zhat_ij = mu_k + W*(z_ij = mu_z), where mu_k is the mean value of all pixels in the window centered on pixel i,j, z_ij is the unfiltered value of the pixel, and W is a weight calculated as, W = var_k / (var_k + var_noise), where var_k is the variance of all pixels in the window and var_noise is the variance of the speckle noise. A possible alternative to using the actual value of the center pixel for z_ij is to use the median pixel value in the window.
|
|
62
|
+
The parameters of the filter are the window/kernel size and the variance of the noise (which is unknown but can perhaps be estimated from the image as the variance over a uniform feature smooth like the surface of still water). Using a larger window size and noise variance will increase radiometric resolution at the expense of spatial resolution.
|
|
63
|
+
For more info on the Lee Filter and other despeckling filters see http://desktop.arcgis.com/en/arcmap/10.3/manage-data/raster-and-images/speckle-function.htm
|
|
64
|
+
Assumes noise mean = 0
|
|
65
|
+
If you don't want the window to be a square of size x size, just replace uniform_filter with something else (convolution with a disk, gaussian filter, etc). Any type of (weighted) averaging filter will do, as long as it is the same for calculating both img_mean and img_square_mean.
|
|
66
|
+
The Lee filter seems rather old-fashioned as a filter. It won't behave well at edges because for any window that has an edge in it, the variance is going to be much higher than the overall image variance, and therefore the weights (of the unfiltered image relative to the filtered image) are going to be close to 1.
|
|
67
|
+
|
|
68
|
+
Parameters
|
|
69
|
+
----------
|
|
70
|
+
img : array-like
|
|
71
|
+
Input image.
|
|
72
|
+
win_size : int, int (default: 3)
|
|
73
|
+
Window size.
|
|
74
|
+
cu : float (default: 0.25)
|
|
75
|
+
cu factor.
|
|
76
|
+
|
|
77
|
+
Returns
|
|
78
|
+
-------
|
|
79
|
+
img_filtered : array-like
|
|
80
|
+
Filtered image.
|
|
81
|
+
|
|
82
|
+
Examples
|
|
83
|
+
--------
|
|
84
|
+
>>> import findpeaks
|
|
85
|
+
>>> import matplotlib.pyplot as plt
|
|
86
|
+
>>> img = findpeaks.import_example('2dpeaks_image')
|
|
87
|
+
>>> # Resize
|
|
88
|
+
>>> img = findpeaks.stats.resize(img, size=(300,300))
|
|
89
|
+
>>> # Make grey image
|
|
90
|
+
>>> img = findpeaks.stats.togray(img)
|
|
91
|
+
>>> # Scale between [0-255]
|
|
92
|
+
>>> img = findpeaks.stats.scale(img)
|
|
93
|
+
>>> # Filter
|
|
94
|
+
>>> img_filtered = findpeaks.stats.lee_filter(img.copy(), win_size=15, cu=0.25)
|
|
95
|
+
>>>
|
|
96
|
+
>>> plt.figure()
|
|
97
|
+
>>> fig, axs = plt.subplots(1,2)
|
|
98
|
+
>>> axs[0].imshow(img, cmap='gray'); axs[0].set_title('Input')
|
|
99
|
+
>>> axs[1].imshow(img_filtered, cmap='gray'); axs[1].set_title('Lee filter')
|
|
100
|
+
|
|
101
|
+
"""
|
|
102
|
+
if win_size < 3: raise Exception('[findpeaks] >ERROR: window size (win_size) must be at least 3')
|
|
103
|
+
if len(img.shape) > 2: raise Exception(
|
|
104
|
+
'[findpeaks] >ERROR: Image should be 2D. Hint: set the parameter: togray=True')
|
|
105
|
+
if ((win_size % 2) == 0): print(
|
|
106
|
+
'[findpeaks] >It is highly recommended to user odd window sizes. You provided %s, an even number.' % (win_size))
|
|
107
|
+
|
|
108
|
+
# we process the entire img as float64 to avoid type overflow error
|
|
109
|
+
img = np.float64(img)
|
|
110
|
+
img_filtered = np.zeros_like(img)
|
|
111
|
+
N, M = img.shape
|
|
112
|
+
win_offset = int(win_size / 2)
|
|
113
|
+
|
|
114
|
+
for i in np.arange(0, N):
|
|
115
|
+
xleft = i - win_offset
|
|
116
|
+
xright = i + win_offset
|
|
117
|
+
|
|
118
|
+
if xleft < 0:
|
|
119
|
+
xleft = 0
|
|
120
|
+
if xright >= N:
|
|
121
|
+
xright = N
|
|
122
|
+
|
|
123
|
+
for j in np.arange(0, M):
|
|
124
|
+
yup = j - win_offset
|
|
125
|
+
ydown = j + win_offset
|
|
126
|
+
|
|
127
|
+
if yup < 0:
|
|
128
|
+
yup = 0
|
|
129
|
+
if ydown >= M:
|
|
130
|
+
ydown = M
|
|
131
|
+
|
|
132
|
+
# assert_indices_in_range(N, M, xleft, xright, yup, ydown)
|
|
133
|
+
|
|
134
|
+
pix_value = img[i, j]
|
|
135
|
+
window = img[xleft:xright, yup:ydown]
|
|
136
|
+
w_t = _weighting(window, cu)
|
|
137
|
+
window_mean = window.mean()
|
|
138
|
+
|
|
139
|
+
new_pix_value = (pix_value * w_t) + (window_mean * (1.0 - w_t))
|
|
140
|
+
|
|
141
|
+
if new_pix_value < 0.0: raise Exception("ERROR: lee_filter(), pixel filtered can't be negative")
|
|
142
|
+
if (new_pix_value is None) or np.isnan(new_pix_value):
|
|
143
|
+
new_pix_value = 0
|
|
144
|
+
|
|
145
|
+
img_filtered[i, j] = round(new_pix_value)
|
|
146
|
+
|
|
147
|
+
return img_filtered
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
# Copyright 2012 - 2013
|
|
5
|
+
# Matías Herranz <matiasherranz@gmail.com>
|
|
6
|
+
# Joaquín Tita <joaquintita@gmail.com>
|
|
7
|
+
# https://github.com/PyRadar/pyradar
|
|
8
|
+
#
|
|
9
|
+
# 2020: Erdogan Taskesen: <erdogant@gmail.com> Converted to python3.
|
|
10
|
+
#
|
|
11
|
+
# This library is free software; you can redistribute it and/or
|
|
12
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
13
|
+
# License as published by the Free Software Foundation; either
|
|
14
|
+
# version 3 of the License, or (at your option) any later version.
|
|
15
|
+
#
|
|
16
|
+
# This library is distributed in the hope that it will be useful,
|
|
17
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
18
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
19
|
+
# Lesser General Public License for more details.
|
|
20
|
+
#
|
|
21
|
+
# You should have received a copy of the GNU Lesser General Public
|
|
22
|
+
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
from math import exp
|
|
26
|
+
|
|
27
|
+
import numpy as np
|
|
28
|
+
|
|
29
|
+
K_DEFAULT = 1.0
|
|
30
|
+
CU_DEFAULT = 0.523
|
|
31
|
+
CMAX_DEFAULT = 1.73
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def weighting(pix_value, window, k=K_DEFAULT, cu=CU_DEFAULT, cmax=CMAX_DEFAULT):
|
|
35
|
+
"""
|
|
36
|
+
Computes the weighthing function for Lee filter using cu as the noise
|
|
37
|
+
coefficient.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
# cu is the noise variation coefficient
|
|
41
|
+
|
|
42
|
+
# ci is the variation coefficient in the window
|
|
43
|
+
window_mean = window.mean()
|
|
44
|
+
window_std = window.std()
|
|
45
|
+
ci = window_std / window_mean
|
|
46
|
+
|
|
47
|
+
if ci <= cu: # use the mean value
|
|
48
|
+
w_t = 1.0
|
|
49
|
+
elif cu < ci < cmax: # use the filter
|
|
50
|
+
w_t = exp((-k * (ci - cu)) / (cmax - ci))
|
|
51
|
+
elif ci >= cmax: # preserve the original value
|
|
52
|
+
w_t = 0.0
|
|
53
|
+
else: # use the mean value
|
|
54
|
+
w_t = 1.0
|
|
55
|
+
|
|
56
|
+
return w_t
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def assert_parameters(win_size, k, cu, cmax):
|
|
60
|
+
"""
|
|
61
|
+
Asserts parameters in range.
|
|
62
|
+
Parameters:
|
|
63
|
+
- k: in [0:10]
|
|
64
|
+
- cu: positive
|
|
65
|
+
- cmax: positive and greater equal than cu
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
if 0 > k > 10: raise Exception("k parameter out of range 0<= k <= 10, submitted %s" % (k))
|
|
69
|
+
if cu < 0: raise Exception("cu can't be negative")
|
|
70
|
+
if cmax < 0 and cmax < cu: raise Exception("cmax must be positive and greater equal to cu: %s" % (cu))
|
|
71
|
+
if win_size < 3: raise Exception('ERROR: win size must be at least 3')
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def lee_enhanced_filter(img, win_size=3, k=K_DEFAULT, cu=CU_DEFAULT, cmax=CMAX_DEFAULT):
|
|
75
|
+
"""Lee enhanced filter.
|
|
76
|
+
|
|
77
|
+
Description
|
|
78
|
+
-----------
|
|
79
|
+
Apply Enhanced Lee filter to a numpy matrix containing the image, with a window of win_size x win_size.
|
|
80
|
+
|
|
81
|
+
Parameters
|
|
82
|
+
----------
|
|
83
|
+
img : array-like
|
|
84
|
+
Input image.
|
|
85
|
+
win_size : int, int (default: 3)
|
|
86
|
+
Window size.
|
|
87
|
+
cu : float (default: 0.25)
|
|
88
|
+
cu factor.
|
|
89
|
+
k : float, (default: 1.0)
|
|
90
|
+
Kvalue.
|
|
91
|
+
cmax : float, (default: 1.73)
|
|
92
|
+
cmax value.
|
|
93
|
+
|
|
94
|
+
Returns
|
|
95
|
+
-------
|
|
96
|
+
img_filtered : array-like
|
|
97
|
+
Filtered image.
|
|
98
|
+
|
|
99
|
+
Examples
|
|
100
|
+
--------
|
|
101
|
+
>>> import findpeaks
|
|
102
|
+
>>> import matplotlib.pyplot as plt
|
|
103
|
+
>>> img = findpeaks.import_example('2dpeaks_image')
|
|
104
|
+
>>> # Resize
|
|
105
|
+
>>> img = findpeaks.stats.resize(img, size=(300,300))
|
|
106
|
+
>>> # Make grey image
|
|
107
|
+
>>> img = findpeaks.stats.togray(img)
|
|
108
|
+
>>> # Scale between [0-255]
|
|
109
|
+
>>> img = findpeaks.stats.scale(img)
|
|
110
|
+
>>> # Filter
|
|
111
|
+
>>> img_filtered = findpeaks.stats.lee_enhanced_filter(img.copy(), win_size=15)
|
|
112
|
+
>>>
|
|
113
|
+
>>> plt.figure()
|
|
114
|
+
>>> fig, axs = plt.subplots(1,2)
|
|
115
|
+
>>> axs[0].imshow(img, cmap='gray'); axs[0].set_title('Input')
|
|
116
|
+
>>> axs[1].imshow(img_filtered, cmap='gray'); axs[1].set_title('Lee enhanced filter')
|
|
117
|
+
|
|
118
|
+
"""
|
|
119
|
+
if win_size < 3: raise Exception('[findpeaks] >ERROR: win size must be at least 3')
|
|
120
|
+
if len(img.shape) > 2: raise Exception(
|
|
121
|
+
'[findpeaks] >ERROR: Image should be 2D. Hint: set the parameter: togray=True')
|
|
122
|
+
if ((win_size % 2) == 0): print(
|
|
123
|
+
'[findpeaks] >It is highly recommended to user odd window sizes. You provided %s, an even number.' % (win_size))
|
|
124
|
+
assert_parameters(win_size, k, cu, cmax)
|
|
125
|
+
|
|
126
|
+
# we process the entire img as float64 to avoid type overflow error
|
|
127
|
+
img = np.float64(img)
|
|
128
|
+
img_filtered = np.zeros_like(img)
|
|
129
|
+
N, M = img.shape
|
|
130
|
+
win_offset = int(win_size / 2)
|
|
131
|
+
|
|
132
|
+
for i in np.arange(0, N):
|
|
133
|
+
xleft = i - win_offset
|
|
134
|
+
xright = i + win_offset
|
|
135
|
+
|
|
136
|
+
if xleft < 0:
|
|
137
|
+
xleft = 0
|
|
138
|
+
if xright >= N:
|
|
139
|
+
xright = N
|
|
140
|
+
|
|
141
|
+
for j in np.arange(0, M):
|
|
142
|
+
yup = j - win_offset
|
|
143
|
+
ydown = j + win_offset
|
|
144
|
+
|
|
145
|
+
if yup < 0:
|
|
146
|
+
yup = 0
|
|
147
|
+
if ydown >= M:
|
|
148
|
+
ydown = M
|
|
149
|
+
|
|
150
|
+
pix_value = img[i, j]
|
|
151
|
+
window = img[xleft:xright, yup:ydown]
|
|
152
|
+
w_t = weighting(pix_value, window, k, cu, cmax)
|
|
153
|
+
window_mean = window.mean()
|
|
154
|
+
|
|
155
|
+
new_pix_value = (window_mean * w_t) + (pix_value * (1.0 - w_t))
|
|
156
|
+
|
|
157
|
+
if new_pix_value < 0.0: raise Exception("ERROR: lee_filter(), pixel filtered can't be negative")
|
|
158
|
+
if (new_pix_value is None) or np.isnan(new_pix_value):
|
|
159
|
+
new_pix_value = 0
|
|
160
|
+
|
|
161
|
+
img_filtered[i, j] = round(new_pix_value)
|
|
162
|
+
|
|
163
|
+
return img_filtered
|