@@ -17,15 +17,17 @@ Image processing. Getting data from images in form of matrix with numbers, slici
1717
1818## Content
1919Codes (it'll send you to appropriate file):
20- * [ Opening_png_jpg] ( https://github.com/sichkar-valentyn/Image_processing_in_Python/tree/master/Codes/Opening_png_jpg.py )
21- * [ Converting_RGB_to_GreyScale] ( https://github.com/sichkar-valentyn/Image_processing_in_Python/tree/master/Codes/Converting_RGB_to_GreyScale.py )
22- * [ Simple_Filtering] ( https://github.com/sichkar-valentyn/Image_processing_in_Python/tree/master/Codes/Simple_Filtering.py )
20+ * [ Opening_png_jpg.py] ( https://github.com/sichkar-valentyn/Image_processing_in_Python/tree/master/Codes/Opening_png_jpg.py )
21+ * [ Converting_RGB_to_GreyScale.py] ( https://github.com/sichkar-valentyn/Image_processing_in_Python/tree/master/Codes/Converting_RGB_to_GreyScale.py )
22+ * [ Simple_Filtering.py] ( https://github.com/sichkar-valentyn/Image_processing_in_Python/tree/master/Codes/Simple_Filtering.py )
23+ * [ Convolution_of_Images.py] ( https://github.com/sichkar-valentyn/Image_processing_in_Python/tree/master/Codes/Convolution_of_Images.py )
2324
2425<br />
2526Experimental results (figures and tables on this page):
2627
2728* <a href =" #RGB channels of the image separately " >RGB channels of the image separately</a >
2829* <a href =" #Examples of Simple Filtering for Edge Detection " >Examples of Simple Filtering for Edge Detection</a >
30+ * <a href =" #Convolution of Images " >Convolution of Images</a >
2931
3032<br />
3133
@@ -142,6 +144,225 @@ Full code is available here: [Simple_Filtering.py](https://github.com/sichkar-va
142144
143145<br />
144146
147+ ### <a name =" Convolution of Images " >Convolution of Images</a >
148+ Implementing image processing via convolution operation.
149+ <br />Creating dunction for convolution, defining filters and showing resulted images.
150+
151+ Reading images, cropping and resizing them.
152+ <br />Consider following part of the code:
153+
154+ ``` py
155+ # Importing needed libraries
156+ import numpy as np
157+ import matplotlib.pyplot as plt
158+ from scipy.misc import imread, imresize
159+
160+ # Reading images
161+ cat, dog = imread(' images/cat.jpg' ), imread(' images/dog.jpg' )
162+
163+ # Defining difference between width and height
164+ print (cat.shape) # (1080, 1920, 3)
165+ print (dog.shape) # (1050, 1680, 3)
166+ difference_cat = cat.shape[1 ] - cat.shape[0 ]
167+ difference_dog = dog.shape[1 ] - dog.shape[0 ]
168+ # Cropping images to make it square size
169+ # Cropping by width and taking middle part
170+ cat_cropped = cat[:, int (difference_cat / 2 ):int (- difference_cat / 2 ), :]
171+ dog_cropped = dog[:, int (difference_dog / 2 ):int (- difference_dog / 2 ), :]
172+ print (cat_cropped.shape) # (1080, 1080, 3)
173+ print (dog_cropped.shape) # (1050, 1050, 3)
174+
175+ # Defining needed image size for resizing
176+ image_size = 200
177+ # Defining output array for new images
178+ # For 2 images with height = width = image_size and 3 channels
179+ # (channels come at the end in order to show resized image)
180+ image_resized = np.zeros((2 , image_size, image_size, 3 ))
181+ print (image_resized.shape) # (2, 200, 200, 3)
182+ # Resizing two images
183+ image_resized[0 , :, :, :] = imresize(cat_cropped, (image_size, image_size)) # (200, 200, 3)
184+ image_resized[1 , :, :, :] = imresize(dog_cropped, (image_size, image_size)) # (200, 200, 3)
185+ ```
186+
187+ Preparing data for convolution operation.
188+ <br />Consider following part of the code:
189+
190+ ``` py
191+ # Defining output array for new image
192+ # For 2 images with 3 channels and height = width = image_size
193+ x = np.zeros((2 , 3 , image_size, image_size))
194+ # Resizing two images
195+ # And transposing in order to put channels first
196+ x[0 , :, :, :] = imresize(cat_cropped, (image_size, image_size)).transpose((2 , 0 , 1 ))
197+ x[1 , :, :, :] = imresize(dog_cropped, (image_size, image_size)).transpose((2 , 0 , 1 ))
198+ print (x[0 ].shape) # (3, 200, 200)
199+ print (x[1 ].shape) # (3, 200, 200)
200+ ```
201+
202+ Preparing weights for convolution for 2 filters with 3 channels and size 3x3.
203+ <br />Consider following part of the code:
204+
205+ ``` py
206+ # Defining array for weights
207+ w = np.zeros((2 , 3 , 3 , 3 ))
208+
209+ # First filter converts images into grayscale
210+ # Defining three channels for this filter - red, green and blue
211+ w[0 , 0 , :, :] = [[0 , 0 , 0 ], [0 , 0.3 , 0 ], [0 , 0 , 0 ]]
212+ w[0 , 1 , :, :] = [[0 , 0 , 0 ], [0 , 0.6 , 0 ], [0 , 0 , 0 ]]
213+ w[0 , 2 , :, :] = [[0 , 0 , 0 ], [0 , 0.1 , 0 ], [0 , 0 , 0 ]]
214+
215+ # Second filter will detect horizontal edges in the blue channel
216+ w[1 , 2 , :, :] = [[1 , 2 , 1 ], [0 , 0 , 0 ], [- 1 , - 2 , - 1 ]]
217+
218+ # Defining 128 biases for the edge detection filter
219+ # in order to make output non-negative
220+ b = np.array([0 , 128 ])
221+ ```
222+
223+ Defining function for naive forward pass with convolution.
224+ <br />Consider following part of the code:
225+
226+ ``` py
227+ """
228+ Input consists of following:
229+ x of shape (N, C, H, W) - N data, each with C channels, height H and width W.
230+ w of shape (F, C, HH, WW) - We convolve each input with F different filters,
231+ where each filter spans all C channels; each filter has height HH and width WW.
232+
233+ 'cnn_params' is a dictionary with following keys:
234+ 'stride' - step for sliding
235+ 'pad' - zero-pad frame around input
236+
237+ Function returns volume of feature maps of shape (N, F, H', W') where:
238+ H' = 1 + (H + 2 * pad - HH) / stride
239+ W' = 1 + (W + 2 * pad - WW) / stride
240+
241+ N here is the same as we have it as number of input images.
242+ F here is as number of channels of each N (that are now as feature maps)
243+
244+ """
245+
246+
247+ def cnn_forward_naive (x , w , b , cnn_params ):
248+ # Preparing parameters for convolution operation
249+ stride = cnn_params[' stride' ]
250+ pad = cnn_params[' pad' ]
251+ N, C, H, W = x.shape
252+ F, _, HH , WW = w.shape
253+
254+ # Applying to the input image volume Pad frame with zero values for all channels
255+ # As we have in input x N as number of inputs, C as number of channels,
256+ # then we don't have to pad them
257+ # That's why we leave first two tuples with 0 - (0, 0), (0, 0)
258+ # And two last tuples with pad parameter - (pad, pad), (pad, pad)
259+ # In this way we pad only H and W of N inputs with C channels
260+ x_padded = np.pad(x, ((0 , 0 ), (0 , 0 ), (pad, pad), (pad, pad)), mode = ' constant' , constant_values = 0 )
261+
262+ # Defining spatial size of output image volume (feature maps) by following formulas:
263+ height_out = int (1 + (H + 2 * pad - HH ) / stride)
264+ width_out = int (1 + (W + 2 * pad - WW ) / stride)
265+ # Depth of output volume is number of filters which is F
266+ # And number of input images N remains the same - it is number of output image volumes now
267+
268+ # Creating zero valued volume for output feature maps
269+ feature_maps = np.zeros((N, F, height_out, width_out))
270+
271+ # Implementing convolution through N input images, each with F filters
272+ # Also, with respect to C channels
273+ # For every image
274+ for n in range (N):
275+ # For every filter
276+ for f in range (F):
277+ # Defining variable for indexing height in output feature map
278+ # (because our step might not be equal to 1)
279+ height_index = 0
280+ # Convolving every channel of the image with every channel of the current filter
281+ # Result is summed up
282+ # Going through all input image (2D convolution) through all channels
283+ for i in range (0 , H, stride):
284+ # Defining variable for indexing width in output feature map
285+ # (because our step might not be equal to 1)
286+ width_index = 0
287+ for j in range (0 , W, stride):
288+ feature_maps[n, f, height_index, width_index] = \
289+ np.sum(x_padded[n, :, i:i+ HH , j:j+ WW ] * w[f, :, :, :]) + b[f]
290+ # Increasing index for width
291+ width_index += 1
292+ # Increasing index for height
293+ height_index += 1
294+
295+ # Returning resulted volumes of feature maps and cash
296+ return feature_maps
297+ ```
298+
299+ Implementing convolution of each image with each filter and offsetting by bias.
300+ <br />Consider following part of the code:
301+
302+ ``` py
303+ results = cnn_forward_naive(x, w, b, {' stride' : 1 , ' pad' : 1 })
304+ print (results.shape) # (2, 2, 200, 200) - two images with two channels
305+ ```
306+
307+ Creating function for normalizing resulted images.
308+ <br />Consider following part of the code:
309+
310+ ``` py
311+ def normalize_image (img ):
312+ image_max, image_min = np.max(img), np.min(img)
313+ return 255 * (img - image_min) / (image_max - image_min)
314+ ```
315+
316+ Preparing figures for plotting.
317+ <br />Consider following part of the code:
318+
319+ ``` py
320+ figure_1, ax = plt.subplots(nrows = 2 , ncols = 5 )
321+ # 'ax 'is as (2, 5) np array and we can call each time ax[0, 0]
322+
323+ # Plotting original, cropped and resized images
324+ # By adding 'astype' we convert float numbers to integer
325+ ax[0 , 0 ].imshow(cat)
326+ ax[0 , 0 ].set_title(' Original (900, 1600, 3))' )
327+ ax[0 , 1 ].imshow(cat_cropped)
328+ ax[0 , 1 ].set_title(' Cropped (900, 900, 3)' )
329+ ax[0 , 2 ].imshow(image_resized[0 , :, :, :].astype(' int' ))
330+ ax[0 , 2 ].set_title(' Resized (200, 200, 3)' )
331+ ax[0 , 3 ].imshow(normalize_image(results[0 , 0 ]), cmap = plt.get_cmap(' gray' ))
332+ ax[0 , 3 ].set_title(' Grayscale' )
333+ ax[0 , 4 ].imshow(normalize_image(results[0 , 1 ]), cmap = plt.get_cmap(' gray' ))
334+ ax[0 , 4 ].set_title(' Edges' )
335+
336+ ax[1 , 0 ].imshow(dog)
337+ ax[1 , 0 ].set_title(' Original (1050, 1680, 3)' )
338+ ax[1 , 1 ].imshow(dog_cropped)
339+ ax[1 , 1 ].set_title(' Cropped (1050, 1050, 3)' )
340+ ax[1 , 2 ].imshow(image_resized[1 , :, :, :].astype(' int' ))
341+ ax[1 , 2 ].set_title(' Resized (200, 200, 3)' )
342+ ax[1 , 3 ].imshow(normalize_image(results[1 , 0 ]), cmap = plt.get_cmap(' gray' ))
343+ ax[1 , 3 ].set_title(' Grayscale' )
344+ ax[1 , 4 ].imshow(normalize_image(results[1 , 1 ]), cmap = plt.get_cmap(' gray' ))
345+ ax[1 , 4 ].set_title(' Edges' )
346+
347+ # Setting axes 'off'
348+ for i in range (2 ):
349+ for j in range (5 ):
350+ ax[i, j].set_axis_off()
351+
352+ # Giving the name to the window with figure
353+ figure_1.canvas.set_window_title(' Image convolution' )
354+ # Showing the plots
355+ plt.show()
356+ ```
357+
358+ Showing resulted images on the figure.
359+
360+ ![ Convolution_of_Images] ( images/Image_convolution.png )
361+
362+ Full code is available here: [ Convolution_of_Images.py] ( https://github.com/sichkar-valentyn/Image_processing_in_Python/tree/master/Codes/Convolution_of_Images.py )
363+
364+ <br />
365+
145366### MIT License
146367### Copyright (c) 2018 Valentyn N Sichkar
147368### github.com/sichkar-valentyn
0 commit comments