/
filter.py
324 lines (280 loc) · 10.3 KB
/
filter.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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
import numpy as np
import cv2
from scipy.interpolate import UnivariateSpline
def nothing(x):
pass
cv2.namedWindow('Tint')
# create trackbars for color change
cv2.createTrackbar('R','Tint',0,255,nothing)
cv2.createTrackbar('G','Tint',0,255,nothing)
cv2.createTrackbar('B','Tint',0,255,nothing)
# create switch for ON/OFF functionality
switch = '0 : OFF \n1 : ON'
cv2.createTrackbar(switch, 'Tint',0,1,nothing)
#Set up a video capture instnance
cap=cv2.VideoCapture(0)
#capture the shape of image to generate filters of same size
l,b,n=cap.read()[1].shape
temp3=np.zeros((l,b,n),dtype=np.int)
temp3[:,:,0]=200
temp3[:,:,1]=128
for i in range(b):
temp3[:,i,2]= i%640
#temp3[:,i,1]= 255/(i%256 +1)
class Hotshot:
"""
HotShot
We are simply subtracting the frame from a scalar value of 150. This would cause all the RGB values
to be subtracted by 150 with a wrap around. This creates a hot texture in the image.
"""
def __init__(self):
pass
def render(self,frame):
return 150-frame
class Negative:
"""
Negative
We are subtracting the RGB values from a scalar value of 255. This would render a negative strip
kind of an effect on the image
"""
def __init__(self):
pass
def render(self,frame):
return 255-frame
class WaterColor:
"""
Water Color
We follow a simple methodology to implement this. We downsample the image, apply iterative bilateral
filtering to it to make the colors uniform and then upsample it back to the original resolution.
We then need to perform median blurring and adaptive thresholding to the obtained image to obtain the
edges.
These operatios are performed in grayscale and then converted back to RGB.
Eventually we add the blurred image and obtained edges by means of bitwise and and return a median blurred
image from that.
"""
def __init__(self):
pass
def render(self,frame):
numDownSamples = 2
img_rgb = frame
# number of downscaling steps
numBilateralFilters = 7
# number of bilateral filtering steps
# -- STEP 1 --
# downsample image using Gaussian pyramid
img_color = img_rgb
for _ in xrange(numDownSamples):
img_color = cv2.pyrDown(img_color)
# repeatedly apply small bilateral filter instead of applying
# one large filter
for _ in xrange(numBilateralFilters):
img_color = cv2.bilateralFilter(img_color, 9, 9, 7)
# upsample image to original size
for _ in xrange(numDownSamples):
img_color = cv2.pyrUp(img_color)
# convert to grayscale and apply median blur
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2GRAY)
img_blur = cv2.medianBlur(img_gray, 7)
# detect and enhance edges
img_edge = cv2.adaptiveThreshold(img_blur, 255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY, 9, 2)
# -- STEP 5 --
# convert back to color so that it can be bit-ANDed with color image
img_edge = cv2.cvtColor(img_edge, cv2.COLOR_GRAY2RGB)
final = cv2.bitwise_and(img_color, img_edge)
return cv2.medianBlur(final,7)
class ComicSketch:
'''
ComicSketch
We followed a similar approach to what we followed in the Water Color filter.
But this time around after obtaining the major edges of the image, we
multiplied it with a pre built canvas sheet to give a Comic like image.
'''
def __init__(self):
pass
def render(self,frame):
canvas = cv2.imread("pen.jpg", cv2.CV_8UC1)
numDownSamples = 2
img_rgb = frame
# number of downscaling steps
numBilateralFilters = 3
# number of bilateral filtering steps
# -- STEP 1 --
# downsample image using Gaussian pyramid
img_color = img_rgb
for _ in xrange(numDownSamples):
img_color = cv2.pyrDown(img_color)
# repeatedly apply small bilateral filter instead of applying
# one large filter
for _ in xrange(numBilateralFilters):
img_color = cv2.bilateralFilter(img_color, 9, 9, 3)
# upsample image to original size
for _ in xrange(numDownSamples):
img_color = cv2.pyrUp(img_color)
# convert to grayscale and apply median blur
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2GRAY)
img_blur = cv2.medianBlur(img_gray, 3)
# detect and enhance edges
img_edge = cv2.adaptiveThreshold(img_blur, 255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY, 9, 2)
return cv2.multiply(cv2.medianBlur(img_edge,7), canvas, scale=1./256)
class Mozaic:
'''
Mozaic
We convert the frame to a grayscale and apply a binarisation thresholding operation.
Gaussian blur operation is performd to smoothen out the image. We have an option to
invert the image at this point of time and reapply the gaussian filtering operation
to hava a varied texture. We eventually divide the inverted thresholded and blurred
image to obtain the mozaic effect. We cam impose it to a canvas so as to obtain the
sketched mozaic.
'''
def __init__(self):
pass
def render(self,frame):
canvas = cv2.imread("pen.jpg", cv2.CV_8UC1)
#convert frame to gray scale.
img_gray=cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#perform binary threshold. With different values of threshold, we get different mozaic patterns
ret,img_thr=cv2.threshold(img_gray,70,255,cv2.THRESH_BINARY)
#apply gaussian blur
img_blur = cv2.GaussianBlur(img_thr, (3, 3), 0)
#invert image
img_invert= 255-img_blur
img_blur=cv2.GaussianBlur(img_invert, ksize=(15, 15),sigmaX=0, sigmaY=0)
#generate final mozaic effect
final =255-cv2.divide(255-img_thr, 255-img_blur, scale=256)
#render image over a canvas
return cv2.multiply(final, canvas, scale=1./256)
class Marker:
'''
Marker
We applied marker effect by means of first converting the frame to a gray scale. The we apply
Gaussian adative threshold operation over the image to locally binarize it. Then we simply
smooth out the image by means of median blur operation.
'''
def __init__(self):
pass
def render(self,frame):
return cv2.medianBlur(cv2.adaptiveThreshold(cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY),255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY,27,3),5)
class Sketch:
'''
A very simple tactic. Run a canny edge detection algorithm and invert the image.
'''
def __init__(self):
pass
def render(self,frame):
return 255-cv2.Canny((cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)),50,65)
class Tint:
'''
Tint
Select the rgb value of a color tone and multiply it with he frame to create
a tinted effect into your image.
'''
def __init__(self):
pass
#create mask and render frame
def render(self,frame,r,g,bl,s):
if s == 0:
temp=np.full((l,b,n),[255,255,255],dtype=np.int)
else:
temp=np.full((l,b,n),[bl,g,r],dtype=np.int)
return np.multiply(frame,temp)
class Gradient:
'''
Tint
Select the rgb value of a color tone and multiply it with he frame to create
a tinted effect into your image.
'''
def __init__(self):
pass
#create mask and render frame
def render(self,frame):
return np.multiply(frame,temp3)
class WarmingFilter:
"""
Warming filter
A class that applies a warming filter to an image.
The class uses curve filters to manipulate the perceived color
temparature of an image. The warming filter will shift the image's
color spectrum towards red, away from blue.
"""
def __init__(self):
# create look-up tables for increasing and decreasing a channel
self.incr_ch_lut = self._create_LUT_8UC1([0, 64, 128, 192, 256],
[0, 70, 140, 210, 256])
self.decr_ch_lut = self._create_LUT_8UC1([0, 64, 128, 192, 256],
[0, 30, 80, 120, 192])
def render(self, img_rgb):
# warming filter: increase red, decrease blue
c_r, c_g, c_b = cv2.split(img_rgb)
c_r = cv2.LUT(c_r, self.incr_ch_lut).astype(np.uint8)
c_b = cv2.LUT(c_b, self.decr_ch_lut).astype(np.uint8)
img_rgb = cv2.merge((c_r, c_g, c_b))
# increase color saturation
c_h, c_s, c_v = cv2.split(cv2.cvtColor(img_rgb, cv2.COLOR_RGB2HSV))
c_s = cv2.LUT(c_s, self.incr_ch_lut).astype(np.uint8)
return cv2.cvtColor(cv2.merge((c_h, c_s, c_v)), cv2.COLOR_HSV2RGB)
def _create_LUT_8UC1(self, x, y):
spl = UnivariateSpline(x, y)
return spl(xrange(256))
class CoolingFilter:
"""
Cooling filter
A class that applies a cooling filter to an image.
The class uses curve filters to manipulate the perceived color
temparature of an image. The warming filter will shift the image's
color spectrum towards blue, away from red.
"""
def __init__(self):
# create look-up tables for increasing and decreasing a channel
self.incr_ch_lut = self._create_LUT_8UC1([0, 64, 128, 192, 256],
[0, 70, 140, 210, 256])
self.decr_ch_lut = self._create_LUT_8UC1([0, 64, 128, 192, 256],
[0, 30, 80, 120, 192])
def render(self, img_rgb):
# cooling filter: increase blue, decrease red
c_r, c_g, c_b = cv2.split(img_rgb)
c_r = cv2.LUT(c_r, self.decr_ch_lut).astype(np.uint8)
c_b = cv2.LUT(c_b, self.incr_ch_lut).astype(np.uint8)
img_rgb = cv2.merge((c_r, c_g, c_b))
# decrease color saturation
c_h, c_s, c_v = cv2.split(cv2.cvtColor(img_rgb, cv2.COLOR_RGB2HSV))
c_s = cv2.LUT(c_s, self.decr_ch_lut).astype(np.uint8)
return cv2.cvtColor(cv2.merge((c_h, c_s, c_v)), cv2.COLOR_HSV2RGB)
def _create_LUT_8UC1(self, x, y):
spl = UnivariateSpline(x, y)
return spl(xrange(256))
if __name__=="__main__":
h1=Marker()
h2=Mozaic()
h3=WaterColor()
h4=WarmingFilter()
h5=CoolingFilter()
h6=Tint()
h7=Sketch()
h8=Negative()
h9=Hotshot()
h10=ComicSketch()
h11=Gradient()
while(True):
ret,frame=cap.read()
r = cv2.getTrackbarPos('R','Tint')
g = cv2.getTrackbarPos('G','Tint')
bl = cv2.getTrackbarPos('B','Tint')
s = cv2.getTrackbarPos(switch,'Tint')
cv2.imshow("Marker",h1.render(frame))
cv2.imshow("Mozaic",h2.render(frame))
cv2.imshow("WaterColor",h3.render(frame))
cv2.imshow('Warm',h4.render(frame))
cv2.imshow('Cool',h5.render(frame))
cv2.imshow("Tint",h6.render(frame,r,g,bl,s))
cv2.imshow("Skecth",h7.render(frame))
cv2.imshow("Negative",h8.render(frame))
cv2.imshow("Hotshot",h9.render(frame))
cv2.imshow("ComicSketch",h10.render(frame))
cv2.imshow("Gradient",h11.render(frame))
if (cv2.waitKey(1) & 0xFF) == 27:
break
# When everything done, release the capture
cv2.imwrite("Mozaic.jpg",h2.render(frame))
cv2.imwrite("WaterColor.jpg",h3.render(frame))
cap.release()
cv2.destroyAllWindows()