├── .gitattributes ├── .gitignore ├── Autoencoder Image Compression ├── README.md └── Stack autoen compress.py ├── Basic Intensity Transformation ├── Gamma Correction.py ├── Log Transform.py ├── Negative Image.py └── README.md ├── CITATION.cff ├── Convolution ├── Edge_kernel.py ├── Gaussain_kernel.py ├── Image_convolution.py ├── Image_gradient_using_sobel_operator.py ├── Median_filtering_gradient_finding_operations_combined.py ├── README.md └── Sharpen_edge_KernelCombined.py ├── Images ├── dec_to_bin.png ├── demo_1.jpg ├── demo_2.jpg ├── rgb_explain.png └── satimg.jpg ├── LICENSE ├── README.md ├── Scripts ├── Greyscale_Image.py ├── Masking_Imaging.py ├── Splitting Layers.py ├── logical_operator_image_processing.py ├── observe_image_properties.py └── satellite_img_processing.py ├── Segmentation ├── Object Detection │ ├── Canny Edge Detector │ │ ├── CannyEdge │ │ │ ├── core.py │ │ │ └── utils.py │ │ ├── README.md │ │ ├── detector.py │ │ └── r.jpg │ ├── Hough Transform │ │ ├── README.md │ │ └── hough_transform.py │ └── README.md ├── README.md └── Threshold │ ├── KMeans Clustering │ └── KMeans_Clustering.py │ └── Ostu-s Method │ └── Ostu's Method.py ├── Vectorization ├── Contour_tracking.py └── README.md └── _config.yml /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /Autoencoder Image Compression/README.md: -------------------------------------------------------------------------------- 1 | 2 | ![autoen](https://user-images.githubusercontent.com/17668390/44370229-191ede00-a4fb-11e8-8b7c-ba2ff6fcfcce.png) 3 | 4 | [Read](https://iphton.github.io/iphton.github.io/Image-Processing-in-Python-Part-2/#10-bullet) on blog in more details. 5 | 6 | An **autoencoder** is the combination of an **encoder** function that converts the input data into a different representation and a **decoder** function that converts the new representation back into the original format. It's a data compression algorithm where the compression and decompression functions are 7 | 8 | - Data-specific, 9 | - Lossy, and 10 | - Learned automatically from **examples** rather than engineered by a human. 11 | 12 | As it's data specific and lossy, it's not good for image compression in general. The fact that autoencoders are data-specific which makes them generally impractical for real-world data compression problems. But there's a hope, future advances might change this. I find it interesting, though it's not good enoguh and also very poor performance compared to othr compression algorithm like **JPEG**, **MPEG** etc. [Check out](https://blog.keras.io/building-autoencoders-in-keras.html) this **keras** blog post regarding on this issue. 13 | 14 | And also fllowing, in case of you're interested too. 15 | 16 | - [1](https://arxiv.org/abs/1802.09371) 17 | - [2](https://arxiv.org/abs/1703.00395) 18 | - [1](https://www.irisa.fr/temics/demos/visualization_ae/visualizationAE.htm) 19 | 20 | **output:** 21 | 22 | ![out_auto](https://user-images.githubusercontent.com/17668390/44370248-3653ac80-a4fb-11e8-8174-f9e9a7e453b1.JPG) 23 | -------------------------------------------------------------------------------- /Autoencoder Image Compression/Stack autoen compress.py: -------------------------------------------------------------------------------- 1 | """ 2 | Image Data Analysis Using Numpy & OpenCV 3 | author: Mohammed Innat 4 | email: innat1994@gmail.com 5 | website: https://iphton.github.io/iphton.github.io/ 6 | Please feel free to use and modify this, but keep the above information. Thanks! 7 | """ 8 | 9 | 10 | import numpy as np 11 | import matplotlib.pyplot as plt 12 | import tensorflow as tf 13 | 14 | from tensorflow.examples.tutorials.mnist import input_data 15 | mnist = input_data.read_data_sets("MNIST_data",one_hot=True) 16 | 17 | # Parameter 18 | num_inputs = 784 # 28*28 19 | neurons_hid1 = 392 20 | neurons_hid2 = 196 21 | neurons_hid3 = neurons_hid1 # Decoder Begins 22 | num_outputs = num_inputs 23 | 24 | learning_rate = 0.01 25 | 26 | # activation function 27 | actf = tf.nn.relu 28 | 29 | # place holder 30 | X = tf.placeholder(tf.float32, shape=[None, num_inputs]) 31 | 32 | # Weights 33 | initializer = tf.variance_scaling_initializer() 34 | 35 | w1 = tf.Variable(initializer([num_inputs, neurons_hid1]), dtype=tf.float32) 36 | w2 = tf.Variable(initializer([neurons_hid1, neurons_hid2]), dtype=tf.float32) 37 | w3 = tf.Variable(initializer([neurons_hid2, neurons_hid3]), dtype=tf.float32) 38 | w4 = tf.Variable(initializer([neurons_hid3, num_outputs]), dtype=tf.float32) 39 | 40 | 41 | # Biases 42 | b1 = tf.Variable(tf.zeros(neurons_hid1)) 43 | b2 = tf.Variable(tf.zeros(neurons_hid2)) 44 | b3 = tf.Variable(tf.zeros(neurons_hid3)) 45 | b4 = tf.Variable(tf.zeros(num_outputs)) 46 | 47 | # Activation Function and Layers 48 | act_func = tf.nn.relu 49 | 50 | hid_layer1 = act_func(tf.matmul(X, w1) + b1) 51 | hid_layer2 = act_func(tf.matmul(hid_layer1, w2) + b2) 52 | hid_layer3 = act_func(tf.matmul(hid_layer2, w3) + b3) 53 | output_layer = tf.matmul(hid_layer3, w4) + b4 54 | 55 | # Loss Function 56 | loss = tf.reduce_mean(tf.square(output_layer - X)) 57 | 58 | # Optimizer 59 | optimizer = tf.train.AdamOptimizer(learning_rate) 60 | train = optimizer.minimize(loss) 61 | 62 | # Intialize Variables 63 | init = tf.global_variables_initializer() 64 | saver = tf.train.Saver() 65 | 66 | num_epochs = 5 67 | batch_size = 150 68 | 69 | with tf.Session() as sess: 70 | sess.run(init) 71 | 72 | # Epoch == Entire Training Set 73 | for epoch in range(num_epochs): 74 | 75 | num_batches = mnist.train.num_examples // batch_size 76 | 77 | # 150 batch size 78 | for iteration in range(num_batches): 79 | 80 | X_batch, y_batch = mnist.train.next_batch(batch_size) 81 | sess.run(train, feed_dict={X: X_batch}) 82 | 83 | training_loss = loss.eval(feed_dict={X: X_batch}) 84 | 85 | print("Epoch {} Complete. Training Loss: {}".format(epoch,training_loss)) 86 | 87 | saver.save(sess, "./stacked_autoencoder.ckpt") 88 | 89 | # Test Autoencoder output on Test Data 90 | num_test_images = 10 91 | 92 | with tf.Session() as sess: 93 | saver.restore(sess,"./stacked_autoencoder.ckpt") 94 | results = output_layer.eval(feed_dict={X:mnist.test.images[:num_test_images]}) 95 | 96 | 97 | # Compare original images with their reconstructions 98 | f, a = plt.subplots(2, 10, figsize=(20, 4)) 99 | for i in range(num_test_images): 100 | a[0][i].imshow(np.reshape(mnist.test.images[i], (28, 28))) 101 | a[1][i].imshow(np.reshape(results[i], (28, 28))) 102 | -------------------------------------------------------------------------------- /Basic Intensity Transformation/Gamma Correction.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Image Data Analysis Using Numpy & OpenCV 4 | author: Mohammed Innat 5 | email: innat1994@gmail.com 6 | website: https://iphton.github.io/iphton.github.io/ 7 | Please feel free to use and modify this, but keep the above information. Thanks! 8 | """ 9 | 10 | 11 | # read details on blog post 12 | 13 | import imageio 14 | import numpy as np 15 | import matplotlib.pyplot as plt 16 | 17 | pic = imageio.imread('') 18 | gamma = 2.2 19 | original = ((pic/255) ** (1/gamma)) 20 | 21 | plt.imshow(original) 22 | -------------------------------------------------------------------------------- /Basic Intensity Transformation/Log Transform.py: -------------------------------------------------------------------------------- 1 | """ 2 | Image Data Analysis Using Numpy & OpenCV 3 | author: Mohammed Innat 4 | email: innat1994@gmail.com 5 | website: https://iphton.github.io/iphton.github.io/ 6 | Please feel free to use and modify this, but keep the above information. Thanks! 7 | """ 8 | 9 | # read details on blog post 10 | 11 | import imageio 12 | import numpy as np 13 | import matplotlib.pyplot as plt 14 | 15 | pic = imageio.imread('') 16 | gray = lambda rgb : np.dot(rgb[... , :3] , [0.299 , 0.587, 0.114]) 17 | gray = gray(pic) 18 | 19 | max_ = np.max(gray) 20 | 21 | ''' 22 | log transform 23 | # s = c*log(1+r) 24 | # r = np.log(1+gray) 25 | # c = (L-1)/log(1+|I_max|) 26 | 27 | ''' 28 | def log_transform(): 29 | return 255/np.log(1+max_) * np.log(1+gray) 30 | 31 | plt.figure(figsize = (5,5)) 32 | plt.imshow(log_transform()[:,300:1500], cmap = plt.get_cmap(name = 'gray')) 33 | -------------------------------------------------------------------------------- /Basic Intensity Transformation/Negative Image.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Image Data Analysis Using Numpy & OpenCV 4 | author: Mohammed Innat 5 | email: innat1994@gmail.com 6 | website: https://iphton.github.io/iphton.github.io/ 7 | Please feel free to use and modify this, but keep the above information. Thanks! 8 | """ 9 | 10 | # read details on blog post 11 | 12 | import imageio 13 | import matplotlib.pyplot as plt 14 | 15 | pic = imageio.imread('') 16 | plt.figure(figsize = (6,6)) 17 | plt.imshow(255 - pic); 18 | -------------------------------------------------------------------------------- /Basic Intensity Transformation/README.md: -------------------------------------------------------------------------------- 1 | 2 | [Read](https://iphton.github.io/iphton.github.io/Image-Processing-in-Python-Part-2/#A-bullet) on blog in more details. 3 | 4 | ## Intensity Transformation 5 | 6 | #### Image Negative 7 | 8 | The transformation function has been given below 9 | 10 | `s = T ( r )` 11 | 12 | where r is the pixels of the input image and s is the pixels of the output image. T is a transformation function that maps each value of r to each value of s. 13 | 14 | negative transformation, which is invert of identity transformation. In negative transformation, each value of the input image is subtracted from the `L-1` and mapped onto the output image. 15 | 16 | In this case the following transition has been done. 17 | 18 | `s = (L – 1) – r` 19 | 20 | So each value is subtracted by 255 and the result image has been shown below. So what happens is that, the lighter pixels become dark and the darker picture becomes light. And it results in image negative. 21 | 22 | 23 | 24 | # Log transformation 25 | 26 | The log transformations can be defined by this formula 27 | 28 | `s = c log(r + 1)`. 29 | 30 | Where s and r are the pixel values of the output and the input image and c is a constant. The value 1 is added to each of the pixel value of the input image because if there is a pixel intensity of 0 in the image, then log (0) is equal to infinity. So 1 is added, to make the minimum value at least 1. 31 | 32 | During log transformation, the dark pixels in an image are expanded as compare to the higher pixel values. The higher pixel values are kind of compressed in log transformation. This result in following image enhancement. 33 | 34 | The value of c in the log transform adjust the kind of enhancement you are looking for. 35 | 36 | 37 | 38 | # Gamma Correction 39 | 40 | Gamma correction, or often simply gamma, is a nonlinear operation used to encode and decode luminance or tristimulus values in video or still image systems. Gamma correction is also known as the Power Law Transform. First, our image pixel intensities must be scaled from the range [0, 255] to [0, 1.0]. From there, we obtain our output gamma corrected image by applying the following equation: 41 | 42 | `V_out = V_in ^ (1 / G)` 43 | 44 | Where V_in is our input image and G is our gamma value. The output image O is then scaled back to the range [0, 255]. 45 | 46 | A gamma value, G < 1 is sometimes called an `encoding gamma`, and the process of encoding with this compressive power-law nonlinearity is called `gamma compression`; Gamma values < 1 will shift the image towards the darker end of the spectrum. 47 | 48 | Conversely a gamma value G > 1 is called a `decoding gamma` and the application of the expansive power-law nonlinearity is called `gamma expansion.` Gamma values > 1 will make the image appear lighter. A gamma value of G=1 will have no affect on the input image. 49 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Convolution/Edge_kernel.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Image Data Analysis Using Numpy & OpenCV 4 | author: Mohammed Innat 5 | email: innat1994@gmail.com 6 | website: https://iphton.github.io/iphton.github.io/ 7 | Please feel free to use and modify this, but keep the above information. Thanks! 8 | """ 9 | 10 | # importing necessary packages 11 | from skimage import color 12 | from skimage import exposure 13 | import numpy as np 14 | import imageio 15 | import matplotlib.pyplot as plt 16 | from scipy.signal import convolve2d 17 | 18 | # load the image 19 | pic = imageio.imread('') 20 | plt.figure(figsize = (6,6)) 21 | plt.imshow(pic); 22 | 23 | # Convert the image to grayscale 24 | img = color.rgb2gray(pic) 25 | 26 | # outline kernel - used for edge detection 27 | kernel = np.array([[-1,-1,-1], 28 | [-1,8,-1], 29 | [-1,-1,-1]]) 30 | 31 | # we use 'valid' which means we do not add zero padding to our image 32 | edges = convolve2d(img, kernel, mode = 'valid') 33 | 34 | 35 | # Adjust the contrast of the filtered image by applying Histogram Equalization 36 | edges_equalized = exposure.equalize_adapthist(edges/np.max(np.abs(edges)), 37 | clip_limit = 0.03) 38 | 39 | # plot the edges_clipped 40 | plt.imshow(edges_equalized, cmap='gray') 41 | plt.axis('off') 42 | plt.show() 43 | -------------------------------------------------------------------------------- /Convolution/Gaussain_kernel.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Image Data Analysis Using Numpy & OpenCV 4 | author: Mohammed Innat 5 | email: innat1994@gmail.com 6 | website: https://iphton.github.io/iphton.github.io/ 7 | Please feel free to use and modify this, but keep the above information. Thanks! 8 | """ 9 | 10 | 11 | # importing necessary packages 12 | from skimage import color 13 | from skimage import exposure 14 | import numpy as np 15 | import imageio 16 | import matplotlib.pyplot as plt 17 | from scipy.signal import convolve2d 18 | 19 | # Convert the image to grayscale 20 | pic = imageio.imread('') 21 | img = color.rgb2gray(pic) 22 | 23 | # gaussian kernel - used for blurring 24 | kernel = np.array([[1,2,1], 25 | [2,4,2], 26 | [1,2,1]]) 27 | kernel = kernel / np.sum(kernel) 28 | 29 | # we use 'valid' which means we do not add zero padding to our image 30 | edges = convolve2d(img, kernel, mode = 'valid') 31 | 32 | 33 | # Adjust the contrast of the filtered image by applying Histogram Equalization 34 | edges_equalized = exposure.equalize_adapthist(edges/np.max(np.abs(edges)), 35 | clip_limit = 0.03) 36 | 37 | # plot the edges_clipped 38 | plt.imshow(edges_equalized, cmap='gray') 39 | plt.axis('off') 40 | plt.show() 41 | -------------------------------------------------------------------------------- /Convolution/Image_convolution.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Image Data Analysis Using Numpy & OpenCV 4 | author: Mohammed Innat 5 | email: innat1994@gmail.com 6 | website: https://iphton.github.io/iphton.github.io/ 7 | Please feel free to use and modify this, but keep the above information. Thanks! 8 | """ 9 | 10 | # importing necessary packages 11 | import numpy as np 12 | import imageio 13 | import matplotlib.pyplot as plt 14 | from scipy.signal import convolve2d 15 | 16 | # load the image 17 | pic = imageio.imread('') 18 | plt.figure(figsize = (6,6)) 19 | plt.imshow(pic); 20 | 21 | # convolution function 22 | def Convolution(image, kernel): 23 | conv_bucket = [] 24 | for d in range(image.ndim): 25 | conv_channel = convolve2d(image[:,:,d], kernel, 26 | mode="same", boundary="symm") 27 | conv_bucket.append(conv_channel) 28 | return np.stack(conv_bucket, axis=2).astype("uint8") 29 | 30 | # different size of kernel 31 | kernel_sizes = [9,15,30,60] 32 | fig, axs = plt.subplots(nrows = 1, ncols = len(kernel_sizes), figsize=(15,15)); 33 | 34 | # iterate through all the kernel and convoluted image 35 | for k, ax in zip(kernel_sizes, axs): 36 | kernel = np.ones((k,k)) 37 | kernel /= np.sum(kernel) 38 | ax.imshow(Convolution(pic, kernel)); 39 | ax.set_title("Convolved By Kernel: {}".format(k)); 40 | ax.set_axis_off(); 41 | -------------------------------------------------------------------------------- /Convolution/Image_gradient_using_sobel_operator.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Image Data Analysis Using Numpy & OpenCV 4 | author: Mohammed Innat 5 | email: innat1994@gmail.com 6 | website: https://iphton.github.io/iphton.github.io/ 7 | Please feel free to use and modify this, but keep the above information. Thanks! 8 | """ 9 | 10 | 11 | # importing necessary packages 12 | from skimage import color 13 | from skimage import exposure 14 | import numpy as np 15 | import imageio 16 | import matplotlib.pyplot as plt 17 | from scipy.signal import convolve2d 18 | 19 | # right sobel 20 | sobel_x = np.c_[ 21 | [-1,0,1], 22 | [-2,0,2], 23 | [-1,0,1] 24 | ] 25 | 26 | # top sobel 27 | sobel_y = np.c_[ 28 | [1,2,1], 29 | [0,0,0], 30 | [-1,-2,-1] 31 | ] 32 | 33 | ims = [] 34 | for i in range(3): 35 | sx = convolve2d(pic[:,:,i], sobel_x, mode="same", boundary="symm") 36 | sy = convolve2d(pic[:,:,i], sobel_y, mode="same", boundary="symm") 37 | ims.append(np.sqrt(sx*sx + sy*sy)) 38 | 39 | img_conv = np.stack(ims, axis=2).astype("uint8") 40 | 41 | plt.figure(figsize = (6,5)) 42 | plt.axis('off') 43 | plt.imshow(img_conv); 44 | -------------------------------------------------------------------------------- /Convolution/Median_filtering_gradient_finding_operations_combined.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Image Data Analysis Using Numpy & OpenCV 4 | author: Mohammed Innat 5 | email: innat1994@gmail.com 6 | website: https://iphton.github.io/iphton.github.io/ 7 | Please feel free to use and modify this, but keep the above information. Thanks! 8 | """ 9 | 10 | # importing necessary packages 11 | from skimage import color 12 | from skimage import exposure 13 | import numpy as np 14 | import imageio 15 | import matplotlib.pyplot as plt 16 | from scipy.signal import convolve2d 17 | from scipy.ndimage import median_filter 18 | 19 | def median_filter_(img, mask): 20 | """ 21 | Applies a median filer to all channels 22 | """ 23 | ims = [] 24 | for d in range(3): 25 | img_conv_d = median_filter(img[:,:,d], size=(mask,mask)) 26 | ims.append(img_conv_d) 27 | 28 | return np.stack(ims, axis=2).astype("uint8") 29 | 30 | pic = imageio.imread('') 31 | filtered_img = median_filter_(pic, 80) 32 | 33 | # right sobel 34 | sobel_x = np.c_[ 35 | [-1,0,1], 36 | [-2,0,2], 37 | [-1,0,1] 38 | ] 39 | 40 | # top sobel 41 | sobel_y = np.c_[ 42 | [1,2,1], 43 | [0,0,0], 44 | [-1,-2,-1] 45 | ] 46 | 47 | ims = [] 48 | for d in range(3): 49 | sx = convolve2d(filtered_img[:,:,d], sobel_x, mode="same", boundary="symm") 50 | sy = convolve2d(filtered_img[:,:,d], sobel_y, mode="same", boundary="symm") 51 | ims.append(np.sqrt(sx*sx + sy*sy)) 52 | 53 | img_conv = np.stack(ims, axis=2).astype("uint8") 54 | 55 | plt.figure(figsize=(7,7)) 56 | plt.axis('off') 57 | plt.imshow(img_conv); 58 | -------------------------------------------------------------------------------- /Convolution/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Read](https://iphton.github.io/iphton.github.io/Image-Processing-in-Python-Part-2/#4-bullet) on blog in more details. 4 | 5 | # Convolution 6 | 7 | We've discussed briefly in previous [article](https://iphton.github.io/iphton.github.io/Up-&-Running-of-Image-Data-Analysis-Using-Numpy-&-OpenCV-Part-1/) that, when a computer sees an image, it sees an array of pixel values. Now, Depending on the resolution and size of the image, it will see a 32 x 32 x 3 array of numbers where the 3 refers to RGB values or channels. Just to drive home the point, let's say we have a color image in PNG form and its size is 480 x 480. The representative array will be 480 x 480 x 3. Each of these numbers is given a value from 0 to 255 which describes the pixel intensity at that point. 8 | 9 | Like we mentioned before, the input is a 32 x 32 x 3 array of pixel values. Now, the best way to explain a convolution is to imagine a flashlight that is shining over the top left of the image. Let’s say that the flashlight shines covers a 3 x 3 area. And now, let’s imagine this flashlight sliding across all the areas of the input image. In machine learning terms, this flashlight is called a **filter** or **kernel** or sometimes refer to as **weights** or **mux** and the region that it is shining over is called the **receptive field**. 10 | 11 | Now this filter is also an array of numbers where the numbers are called weights or parameters. A very important note is that the depth of this filter has to be the same as the depth of the input, so the dimensions of this filter is 3 x 3 x 3. 12 | 13 | An image **kernel** or **filter** is a small matrix used to apply effects like the ones we might find in Photoshop or Gimp, such as blurring, sharpening, outlining or embossing. They're also used in machine learning for `feature extraction`, a technique for determining the most important portions of an image. For more, have a look at Gimp's excellent documentation on using [Image kernel's](https://docs.gimp.org/en/plug-in-convmatrix.html). We can find a list of most common kernels [here](https://en.wikipedia.org/wiki/Kernel_(image_processing)) 14 | 15 | Now, let’s take the filter to the top left corner. As the filter is sliding, or **convolving**, around the input image, it is multiplying the values in the filter with the original pixel values of the image (aka computing element wise multiplications). These multiplications are all summed up. So now we have a single number. Remember, this number is just representative of when the filter is at the top left of the image. Now, we repeat this process for every location on the input volume. Next step would be moving the filter to the right by **stride** or **step** 1 unit, then right again by **stride** 1, and so on. Every unique location on the input volume produces a number. We can also choose stride or the step size 2 or more, but we have to carefull wheter it will fit or not on the input image. 16 | 17 | ![convoving](https://user-images.githubusercontent.com/17668390/44360200-f4673e00-a4db-11e8-9422-f39e0693ba05.gif) 18 | 19 | After sliding the filter over all the locations, we will find out that, what we’re left with is a 30 x 30 x 1 array of numbers, which we call an **activation map** or **feature map**. The reason we get a 30 x 30 array is that there are 900 different locations that a 3 x 3 filter can fit on a 32 x 32 input image. These 900 numbers are mapped to a 30 x 30 array. 20 | 21 | Let's say we've a following $3x3$ filter, convolving on a $5x5$ matri and according to the equation we should get a $3x3$ matrix, technically called **activation map** or **feature map**. 22 | 23 | ![conv_gif](https://user-images.githubusercontent.com/17668390/44360222-05b04a80-a4dc-11e8-8c57-48b7d2c96fd2.gif) 24 | 25 | Moreover, we practically use more filters instead of one. Then our output volume would be `28 x 28 x n` (where n is the number of **activation map**). By using more filters, we are able to preserve the spatial dimensions better. 26 | 27 | However, For the pixels on the border of image matrix, some elements of the kernel might stands out of the image matrix and therefore does not have any corresponding element from the image matrix. In this case, we can eliminate the convolution operation for these position which end up an output matrix smaller than the input or we can apply **padding** to the input matrix 28 | -------------------------------------------------------------------------------- /Convolution/Sharpen_edge_KernelCombined.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Image Data Analysis Using Numpy & OpenCV 4 | author: Mohammed Innat 5 | email: innat1994@gmail.com 6 | website: https://iphton.github.io/iphton.github.io/ 7 | Please feel free to use and modify this, but keep the above information. Thanks! 8 | """ 9 | 10 | #importing necessary packages 11 | from skimage import color 12 | from skimage import exposure 13 | import numpy as np 14 | import imageio 15 | import matplotlib.pyplot as plt 16 | from scipy.signal import convolve2d 17 | 18 | pic = imageio.imread('') 19 | # Convert the image to grayscale 20 | img = color.rgb2gray(img) 21 | 22 | # apply sharpen filter to the original image 23 | sharpen_kernel = np.array([[0,-1,0], 24 | [-1,5,-1], 25 | [0,-1,0]]) 26 | image_sharpen = convolve2d(img, sharpen_kernel, mode = 'valid') 27 | 28 | # apply edge kernel to the output of the sharpen kernel 29 | edge_kernel = np.array([[-1,-1,-1], 30 | [-1,8,-1], 31 | [-1,-1,-1]]) 32 | edges = convolve2d(image_sharpen, edge_kernel, mode = 'valid') 33 | 34 | # apply normalize box blur filter to the edge detection filtered image 35 | blur_kernel = np.array([[1,1,1], 36 | [1,1,1], 37 | [1,1,1]])/9.0; 38 | denoised = convolve2d(edges, blur_kernel, mode = 'valid') 39 | 40 | # Adjust the contrast of the filtered image by applying Histogram Equalization 41 | denoised_equalized = exposure.equalize_adapthist(denoised/np.max(np.abs(denoised)), 42 | clip_limit=0.03) 43 | plt.imshow(denoised_equalized, cmap='gray') # plot the denoised_clipped 44 | plt.axis('off') 45 | plt.show() 46 | -------------------------------------------------------------------------------- /Images/dec_to_bin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innat/DIP-In-Python/cdf52c893242cd10c9d401af8ba5d31ef41b588a/Images/dec_to_bin.png -------------------------------------------------------------------------------- /Images/demo_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innat/DIP-In-Python/cdf52c893242cd10c9d401af8ba5d31ef41b588a/Images/demo_1.jpg -------------------------------------------------------------------------------- /Images/demo_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innat/DIP-In-Python/cdf52c893242cd10c9d401af8ba5d31ef41b588a/Images/demo_2.jpg -------------------------------------------------------------------------------- /Images/rgb_explain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innat/DIP-In-Python/cdf52c893242cd10c9d401af8ba5d31ef41b588a/Images/rgb_explain.png -------------------------------------------------------------------------------- /Images/satimg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innat/DIP-In-Python/cdf52c893242cd10c9d401af8ba5d31ef41b588a/Images/satimg.jpg -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | ### [Image Data Analysis Using Python - Part 1](https://innat.github.io/innat.github.io/Image-Processing-in-Python-Part-1/) 9 | 10 | 11 | **Table of Contents : Part 1** 12 | 13 | - [Importing images and observe it’s properties](https://github.com/iphton/Image-Data-Analysis-Using-Pythons/tree/gh-pages/Scripts) 14 | - [Splitting the layers](https://github.com/iphton/Image-Data-Analysis-Using-Pythons/blob/gh-pages/Scripts/Splitting%20Layers.py) 15 | - [Greyscale](https://github.com/iphton/Image-Data-Analysis-Using-Pythons/blob/gh-pages/Scripts/Greyscale_Image.py) 16 | - [Using Logical Operator on pixel values](https://github.com/iphton/Image-Data-Analysis-Using-Pythons/blob/gh-pages/Scripts/logical_operator_image_processing.py) 17 | - [Masking using Logical Operator](https://github.com/iphton/Image-Data-Analysis-Using-Pythons/blob/gh-pages/Scripts/Masking_Imaging.py) 18 | - [Satellite Image Data Analysis](https://github.com/iphton/Image-Data-Analysis-Using-Pythons/blob/gh-pages/Scripts/satellite_img_processing.py) 19 | 20 | --- 21 | 22 | ### [Image Data Analysis Using Python - Part 2](https://innat.github.io/innat.github.io/Image-Processing-in-Python-Part-2/) 23 | 24 | **Table of Contents : Part 2** 25 | 26 | - [Intensity Transformation](https://github.com/iphton/Image-Data-Analysis-Using-Pythons/tree/gh-pages/Basic%20Intensity%20Transformation) 27 | - [Convolution](https://github.com/iphton/Image-Data-Analysis-Using-Pythons/tree/gh-pages/Convolution) 28 | - [Segmentation](https://github.com/iphton/Image-Data-Analysis-Using-Pythons/tree/gh-pages/Segmentation) 29 | - [Vectorization](https://github.com/iphton/Image-Data-Analysis-Using-Pythons/tree/gh-pages/Vectorization) 30 | - [Image Compression](https://github.com/iphton/Image-Data-Analysis-Using-Pythons/tree/gh-pages/Autoencoder%20Image%20Compression) 31 | 32 | 33 | 34 | 35 | 37 | -------------------------------------------------------------------------------- /Scripts/Greyscale_Image.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Image Data Analysis Using Numpy & OpenCV 4 | 5 | author: Mohammed Innat 6 | email: innat1994@gmail.com 7 | website: https://iphton.github.io/iphton.github.io/ 8 | Please feel free to use and modify this, but keep the above information. Thanks! 9 | """ 10 | 11 | import imageio 12 | import numpy as np 13 | import matplotlib.pyplot as plt 14 | 15 | pic = imageio.imread('F:/demo_2.jpg') 16 | 17 | gray = lambda rgb : np.dot(rgb[... , :3] , [0.299 , 0.587, 0.114]) 18 | gray = gray(pic) 19 | 20 | plt.figure( figsize = (10,10)) 21 | plt.imshow(gray, cmap = plt.get_cmap(name = 'gray')) 22 | plt.show() 23 | 24 | ''' 25 | However, the GIMP converting color to grayscale image software 26 | has three algorithms to do the task. 27 | 28 | Lightness The graylevel will be calculated as 29 | 30 | Lightness = ½ × (max(R,G,B) + min(R,G,B)) 31 | 32 | Luminosity The graylevel will be calculated as 33 | 34 | Luminosity = 0.21 × R + 0.72 × G + 0.07 × B 35 | 36 | Average The graylevel will be calculated as 37 | 38 | Average Brightness = (R + G + B) ÷ 3 39 | 40 | ''' 41 | 42 | pic = imageio.imread('F:/demo_2.jpg') 43 | 44 | gray = lambda rgb : np.dot(rgb[... , :3] , [0.21 , 0.72, 0.07]) 45 | gray = gray(pic) 46 | 47 | plt.figure( figsize = (10,10)) 48 | plt.imshow(gray, cmap = plt.get_cmap(name = 'gray')) 49 | plt.show() 50 | 51 | ''' 52 | Let's take a quick overview some the changed properties now the color image. 53 | Like we observe some properties of color image, same statements are applying 54 | now for gray scaled image. 55 | ''' 56 | 57 | print('Type of the image : ' , type(gray)) 58 | print() 59 | print('Shape of the image : {}'.format(gray.shape)) 60 | print('Image Hight {}'.format(gray.shape[0])) 61 | print('Image Width {}'.format(gray.shape[1])) 62 | print('Dimension of Image {}'.format(gray.ndim)) 63 | print() 64 | print('Image size {}'.format(gray.size)) 65 | print('Maximum RGB value in this image {}'.format(gray.max())) 66 | print('Minimum RGB value in this image {}'.format(gray.min())) 67 | print('Random indexes [X,Y] : {}'.format(gray[100, 50])) 68 | -------------------------------------------------------------------------------- /Scripts/Masking_Imaging.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Image Data Analysis Using Numpy & OpenCV 4 | 5 | author: Mohammed Innat 6 | email: innat1994@gmail.com 7 | website: https://iphton.github.io/iphton.github.io/ 8 | Please feel free to use and modify this, but keep the above information. Thanks! 9 | """ 10 | 11 | import imageio 12 | import numpy as np 13 | import matplotlib.pyplot as plt 14 | 15 | if __name__ == '__main__': 16 | 17 | # load the image 18 | pic = imageio.imread('F:/demo_1.jpg') 19 | 20 | # seperate the row and column values 21 | total_row , total_col , layers = pic.shape 22 | 23 | ''' 24 | Create vector. 25 | 26 | Ogrid is a compact method of creating a multidimensional- 27 | ndarray operations in single lines. 28 | for ex: 29 | 30 | >>> ogrid[0:5,0:5] 31 | output: [array([[0], 32 | [1], 33 | [2], 34 | [3], 35 | [4]]), 36 | array([[0, 1, 2, 3, 4]])] 37 | 38 | ''' 39 | x , y = np.ogrid[:total_row , :total_col] 40 | 41 | # get the center values of the image 42 | cen_x , cen_y = total_row/2 , total_col/2 43 | 44 | 45 | ''' 46 | Measure distance value from center to each border pixel. 47 | To make it easy, we can think it's like, we draw a line from center- 48 | to each edge pixel value --> s**2 = (Y-y)**2 + (X-x)**2 49 | ''' 50 | distance_from_the_center = np.sqrt((x-cen_x)**2 + (y-cen_y)**2) 51 | 52 | # Select convenient radius value 53 | radius = (total_row/2) 54 | 55 | # Using logical operator '>' 56 | ''' 57 | logical operator to do this task which will return as a value 58 | of True for all the index according to the given condition 59 | ''' 60 | circular_pic = distance_from_the_center > radius 61 | 62 | ''' 63 | let assign value zero for all pixel value that outside the cirular disc. 64 | All the pixel value outside the circular disc, will be black now. 65 | ''' 66 | pic[circular_pic] = 0 67 | plt.figure(figsize = (10,10)) 68 | plt.imshow(pic) 69 | plt.show() -------------------------------------------------------------------------------- /Scripts/Splitting Layers.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Image Data Analysis Using Numpy & OpenCV 4 | 5 | author: Mohammed Innat 6 | email: innat1994@gmail.com 7 | website: https://iphton.github.io/iphton.github.io/ 8 | Please feel free to use and modify this, but keep the above information. Thanks! 9 | """ 10 | 11 | import numpy as np 12 | import matplotlib.pyplot as plt 13 | 14 | pic = imageio.imread('F:/demo_2.jpg') 15 | 16 | fig, ax = plt.subplots(nrows = 1, ncols=3, figsize=(15,5)) 17 | 18 | for c, ax in zip(range(3), ax): 19 | 20 | # create zero matrix 21 | split_img = np.zeros(pic.shape, dtype="uint8") # 'dtype' by default: 'numpy.float64' 22 | 23 | # assing each channel 24 | split_img[ :, :, c] = pic[ :, :, c] 25 | 26 | # display each channel 27 | ax.imshow(split_img) -------------------------------------------------------------------------------- /Scripts/logical_operator_image_processing.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Image Data Analysis Using Numpy & OpenCV 4 | 5 | author: Mohammed Innat 6 | email: innat1994@gmail.com 7 | website: https://iphton.github.io/iphton.github.io/ 8 | Please feel free to use and modify this, but keep the above information. Thanks! 9 | """ 10 | 11 | import imageio 12 | import numpy as np 13 | import matplotlib.pyplot as plt 14 | 15 | pic = imageio.imread('F:/demo_1.jpg') 16 | plt.figure(figsize = (10,10)) 17 | plt.imshow(pic) 18 | plt.show() 19 | 20 | 21 | low_pixel = pic < 20 22 | 23 | # to ensure of it let's check if all values in low_pixel are True or not 24 | if low_pixel.any() == True: 25 | print(low_pixel.shape) 26 | 27 | 28 | print(pic.shape) 29 | print(low_pixel.shape) 30 | 31 | ''' 32 | We generated that low value filter using a global comparison operator for 33 | all the values less than 200. However, we can use this low_pixel array as an index 34 | to set those low values to some specific values which may be higher than or lower 35 | than the previous pixel value. 36 | ''' 37 | 38 | # randomly choose a value 39 | import random 40 | 41 | # load the orginal image 42 | pic = imageio.imread('F:/demo_1.jpg') 43 | 44 | # set value randomly range from 25 to 225 - these value also randomly choosen 45 | pic[low_pixel] = random.randint(25,225) 46 | 47 | # display the image 48 | plt.figure( figsize = (10,10)) 49 | plt.imshow(pic) 50 | plt.show() -------------------------------------------------------------------------------- /Scripts/observe_image_properties.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Image Data Analysis Using Numpy & OpenCV 4 | 5 | author: Mohammed Innat 6 | email: innat1994@gmail.com 7 | website: https://iphton.github.io/iphton.github.io/ 8 | Please feel free to use and modify this, but keep the above information. Thanks! 9 | """ 10 | 11 | 12 | 13 | # Importing Image 14 | if __name__ == '__main__': 15 | import imageio 16 | import matplotlib.pyplot as plt 17 | %matplotlib inline 18 | 19 | pic = imageio.imread('F:/demo_2.jpg') 20 | plt.figure(figsize = (15,15)) 21 | 22 | plt.imshow(pic) 23 | 24 | print('Type of the image : ' , type(pic)) 25 | print() 26 | print('Shape of the image : {}'.format(pic.shape)) 27 | print('Image Hight {}'.format(pic.shape[0])) 28 | print('Image Width {}'.format(pic.shape[1])) 29 | print('Dimension of Image {}'.format(pic.ndim)) 30 | 31 | print('Image size {}'.format(pic.size)) 32 | 33 | print('Maximum RGB value in this image {}'.format(pic.max())) 34 | print('Minimum RGB value in this image {}'.format(pic.min())) 35 | 36 | ''' 37 | Let's pick a specific pixel located at 100 th Rows and 50 th Column. 38 | And view the RGB value gradually. 39 | ''' 40 | pic[ 100, 50 ] 41 | 42 | # A specific pixel located at Row : 100 ; Column : 50 43 | # Each channel's value of it, gradually R , G , B 44 | print('Value of only R channel {}'.format(pic[ 100, 50, 0])) 45 | print('Value of only G channel {}'.format(pic[ 100, 50, 1])) 46 | print('Value of only B channel {}'.format(pic[ 100, 50, 2])) 47 | 48 | # let's take a quick view of each channels in the whole image. 49 | 50 | plt.title('R channel') 51 | plt.ylabel('Height {}'.format(pic.shape[0])) 52 | plt.xlabel('Width {}'.format(pic.shape[1])) 53 | 54 | plt.imshow(pic[ : , : , 0]) 55 | plt.show() 56 | 57 | plt.title('G channel') 58 | plt.ylabel('Height {}'.format(pic.shape[0])) 59 | plt.xlabel('Width {}'.format(pic.shape[1])) 60 | 61 | plt.imshow(pic[ : , : , 1]) 62 | plt.show() 63 | 64 | plt.title('B channel') 65 | plt.ylabel('Height {}'.format(pic.shape[0])) 66 | plt.xlabel('Width {}'.format(pic.shape[1])) 67 | 68 | plt.imshow(pic[ : , : , 2]) 69 | plt.show() 70 | 71 | 72 | 73 | # ------------------------------------------------------ 74 | 75 | ''' 76 | 77 | Now, here we can also able to change the number of RGB values. As an example, let's set the Red, Green, Blue layer for following Rows values to full intensity. 78 | 79 | R channel: Row- 50 to 150 80 | G channel: Row- 200 to 300 81 | B channel: Row- 350 to 450 82 | We'll load the image once, so that we can visualize each change simultaneously. 83 | 84 | ''' 85 | 86 | pic = imageio.imread('F:/demo_2.jpg') 87 | 88 | pic[50:150 , : , 0] = 255 # full intensity to those pixel's R channel 89 | plt.figure( figsize = (10,10)) 90 | plt.imshow(pic) 91 | plt.show() 92 | 93 | 94 | pic[200:300 , : , 1] = 255 # full intensity to those pixel's G channel 95 | plt.figure( figsize = (10,10)) 96 | plt.imshow(pic) 97 | plt.show() 98 | 99 | pic[350:450 , : , 2] = 255 # full intensity to those pixel's B channel 100 | plt.figure( figsize = (10,10)) 101 | plt.imshow(pic) 102 | plt.show() 103 | 104 | # To make it more clear let's change the column section and this time 105 | # we'll change the RGB channel simultaneously 106 | 107 | # set value 200 of all channels to those pixels which turns them to white 108 | pic[ 50:450 , 400:600 , [0,1,2] ] = 200 109 | plt.figure( figsize = (10,10)) 110 | plt.imshow(pic) 111 | plt.show() 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /Scripts/satellite_img_processing.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Image Data Analysis Using Numpy & OpenCV 4 | 5 | author: Mohammed Innat 6 | email: innat1994@gmail.com 7 | website: https://iphton.github.io/iphton.github.io/ 8 | Please feel free to use and modify this, but keep the above information. Thanks! 9 | """ 10 | 11 | import imageio 12 | import numpy as np 13 | import matplotlib.pyplot as plt 14 | 15 | pic = imageio.imread('F:\satimg.jpg') 16 | plt.figure(figsize = (10,10)) 17 | plt.imshow(pic) 18 | plt.show() 19 | 20 | print(f'Shape of the image {pic.shape}') 21 | print(f'hieght {pic.shape[0]} pixels') 22 | print(f'width {pic.shape[1]} pixels') 23 | 24 | # Detecting High Pixel of Each Channel 25 | 26 | # Only Red Pixel value , higher than 180 27 | pic = imageio.imread('F:\satimg.jpg') 28 | red_mask = pic[:, :, 0] < 180 29 | 30 | pic[red_mask] = 0 31 | plt.figure(figsize=(15,15)) 32 | plt.imshow(pic) 33 | 34 | 35 | # Only Green Pixel value , higher than 180 36 | pic = imageio.imread('F:\satimg.jpg') 37 | green_mask = pic[:, :, 1] < 180 38 | 39 | pic[green_mask] = 0 40 | plt.figure(figsize=(15,15)) 41 | plt.imshow(pic) 42 | 43 | 44 | # Only Blue Pixel value , higher than 180 45 | pic = imageio.imread('F:\satimg.jpg') 46 | blue_mask = pic[:, :, 2] < 180 47 | 48 | pic[blue_mask] = 0 49 | plt.figure(figsize=(15,15)) 50 | plt.imshow(pic) 51 | 52 | # Composite mask using logical_and 53 | pic = imageio.imread('F:\satimg.jpg') 54 | final_mask = np.logical_and(red_mask, green_mask, blue_mask) 55 | pic[final_mask] = 40 56 | plt.figure(figsize=(15,15)) 57 | plt.imshow(pic) -------------------------------------------------------------------------------- /Segmentation/Object Detection/Canny Edge Detector/CannyEdge/core.py: -------------------------------------------------------------------------------- 1 | """ Canny Edge Detection is based on the following five steps: 2 | 3 | 1. Gaussian filter 4 | 2. Gradient Intensity 5 | 3. Non-maximum suppression 6 | 4. Double threshold 7 | 5. Edge tracking 8 | 9 | This module contains these five steps as five separate Python functions. 10 | """ 11 | 12 | # Third party imports 13 | from scipy.ndimage.filters import gaussian_filter 14 | from scipy.ndimage import (sobel, generic_gradient_magnitude, generic_filter) 15 | from scipy import ndimage 16 | import numpy as np 17 | 18 | # Module imports 19 | from CannyEdge.utils import round_angle 20 | 21 | 22 | def gs_filter(img, sigma): 23 | """ Step 1: Gaussian filter 24 | 25 | Args: 26 | img: Numpy ndarray of image 27 | sigma: Smoothing parameter 28 | 29 | Returns: 30 | Numpy ndarray of smoothed image 31 | """ 32 | if type(img) != np.ndarray: 33 | raise TypeError('input image must be of type ndarray') 34 | else: 35 | return gaussian_filter(img, sigma) 36 | 37 | 38 | def gradient_intensity(img): 39 | """ Step 2: Find gradients 40 | 41 | Args: 42 | img: Numpy ndarray of image to be processed (denoised image) 43 | 44 | Returns: 45 | grad: gradient-intensed image 46 | thetas: gradient directions 47 | """ 48 | 49 | # Kernel for Gradient in x-direction 50 | sobel_x = np.array( 51 | [[-1, 0, 1], 52 | [-2, 0, 2], 53 | [-1, 0, 1]], np.int32 54 | ) 55 | # Kernel for Gradient in y-direction 56 | sobel_y = np.array( 57 | [[1, 2, 1], 58 | [0, 0, 0], 59 | [-1, -2, -1]], np.int32 60 | ) 61 | # Apply kernels to the image 62 | sx = ndimage.filters.convolve(img, sobel_x) 63 | sy = ndimage.filters.convolve(img, sobel_y) 64 | 65 | # return the hypothenuse of (Ix, Iy) 66 | grad = np.hypot(sx, sy) # Equivalent to sqrt(x1**2 + x2**2) 67 | thetas = np.arctan2(sy, sy) # Equivalent to tan inverse sy / sx 68 | 69 | return (grad, thetas) 70 | 71 | 72 | def suppression(img, thetas): 73 | """ Step 3: Non-maximum suppression 74 | 75 | Args: 76 | img: Numpy ndarray of image to be processed (gradient-intensed image) 77 | D: Numpy ndarray of gradient directions for each pixel in img 78 | 79 | Returns: 80 | ... 81 | """ 82 | # gray image shape 83 | h, w = img.shape 84 | z = np.zeros((h,w), dtype=np.int32) 85 | 86 | for i in range(h): 87 | for j in range(w): 88 | # find neighbour pixels to visit from the gradient directions 89 | loc = round_angle(thetas[i, j]) 90 | try: 91 | if loc == 0: 92 | if (img[i, j] >= img[i, j - 1]) and (img[i, j] >= img[i, j + 1]): 93 | z[i,j] = img[i,j] 94 | elif loc == 90: 95 | if (img[i, j] >= img[i - 1, j]) and (img[i, j] >= img[i + 1, j]): 96 | z[i,j] = img[i,j] 97 | elif loc == 135: 98 | if (img[i, j] >= img[i - 1, j - 1]) and (img[i, j] >= img[i + 1, j + 1]): 99 | z[i,j] = img[i,j] 100 | elif loc == 45: 101 | if (img[i, j] >= img[i - 1, j + 1]) and (img[i, j] >= img[i + 1, j - 1]): 102 | z[i,j] = img[i,j] 103 | except IndexError as e: 104 | pass 105 | return z 106 | 107 | 108 | def threshold(img, t, T): 109 | """ Step 4: Thresholding 110 | Iterates through image pixels and marks them as WEAK and STRONG edge 111 | pixels based on the threshold values. 112 | 113 | Args: 114 | img: Numpy ndarray of image to be processed (suppressed image) 115 | t: lower threshold 116 | T: upper threshold 117 | 118 | Return: 119 | img: Thresholdes image 120 | 121 | """ 122 | # define gray value of a WEAK and a STRONG pixel 123 | cf = { 124 | 'WEAK': np.int32(70), 125 | 'STRONG': np.int32(255), 126 | } 127 | 128 | # get strong pixel indices 129 | strong_i, strong_j = np.where(img > T) 130 | 131 | # get weak pixel indices 132 | weak_i, weak_j = np.where((img >= t) & (img <= T)) 133 | 134 | # get pixel indices set to be zero 135 | zero_i, zero_j = np.where(img < t) 136 | 137 | # set values 138 | img[strong_i, strong_j] = cf.get('STRONG') 139 | img[weak_i, weak_j] = cf.get('WEAK') 140 | img[zero_i, zero_j] = np.int32(0) 141 | 142 | return (img, cf.get('WEAK')) 143 | 144 | def tracking(img, weak, strong=255): 145 | """ Step 5: 146 | Checks if edges marked as weak are connected to strong edges. 147 | 148 | Note that there are better methods (blob analysis) to do this, 149 | but they are more difficult to understand. This just checks neighbour 150 | edges. 151 | 152 | Also note that for perfomance reasons you wouldn't do this kind of tracking 153 | in a seperate loop, you would do it in the loop of the tresholding process. 154 | Since this is an **educational** implementation ment to generate plots 155 | to help people understand the major steps of the Canny Edge algorithm, 156 | we exceptionally don't care about perfomance here. 157 | 158 | Args: 159 | img: Numpy ndarray of image to be processed (thresholded image) 160 | weak: Value that was used to mark a weak edge in Step 4 161 | 162 | Returns: 163 | final Canny Edge image. 164 | """ 165 | 166 | h, w = img.shape 167 | for i in range(h): 168 | for j in range(w): 169 | if img[i, j] == weak: 170 | # check if one of the neighbours is strong (=255 by default) 171 | try: 172 | if ((img[i + 1, j] == strong) or (img[i - 1, j] == strong) 173 | or (img[i, j + 1] == strong) or (img[i, j - 1] == strong) 174 | or (img[i+1, j + 1] == strong) or (img[i-1, j - 1] == strong)): 175 | img[i, j] = strong 176 | else: 177 | img[i, j] = 0 178 | except IndexError as e: 179 | pass 180 | return img 181 | -------------------------------------------------------------------------------- /Segmentation/Object Detection/Canny Edge Detector/CannyEdge/utils.py: -------------------------------------------------------------------------------- 1 | """ Canny Edge Detection is based on the following five steps: 2 | 3 | 1. Gaussian filter 4 | 2. Gradient Intensity 5 | 3. Non-maximum suppression 6 | 4. Double threshold 7 | 5. Edge tracking 8 | 9 | This module contains these five steps as five separate Python functions. 10 | """ 11 | 12 | from scipy import misc 13 | import numpy as np 14 | 15 | def to_ndarray(img): 16 | im = misc.imread(img, flatten=True) 17 | im = im.astype('int32') 18 | return im 19 | 20 | def round_angle(angle): 21 | """ Input angle must be in [0,180) """ 22 | angle = np.rad2deg(angle) % 180 23 | if (0 <= angle < 22.5) or (157.5 <= angle < 180): 24 | angle = 0 25 | elif (22.5 <= angle < 67.5): 26 | angle = 45 27 | elif (67.5 <= angle < 112.5): 28 | angle = 90 29 | elif (112.5 <= angle < 157.5): 30 | angle = 135 31 | return angle 32 | -------------------------------------------------------------------------------- /Segmentation/Object Detection/Canny Edge Detector/README.md: -------------------------------------------------------------------------------- 1 | Canny Edge Detectoin 2 | ---------------------- 3 | 4 | This repository contains an **educational** implementation of the Canny Edge Detector in Python 3x. 5 | 6 | A multi-stage edge detection operation capable of detecting wide range of edges in images. Now, the Process of Canny edge detection algorithm can be broken down to 5 different steps: 7 | 8 | 1. Apply Gaussian Filter 9 | 2. Find the intensity gradients 10 | 3. Apply non-maximum suppression 11 | 4. Apply double threshold 12 | 5. Track edge by hysteresis. 13 | 14 | 15 | **Usage** 16 | ----- 17 | A demo pic is provided, namely `r.jpg`. Download this repo. Operate CMD on that directory and run following command. 18 | 19 | `python detector.py r.jpg 1.4 20 40` 20 | 21 | **Expected Output:** 22 | 23 | ![canny](https://user-images.githubusercontent.com/17668390/44365545-fb964800-a4eb-11e8-8e23-81f49ef517fe.png) 24 | -------------------------------------------------------------------------------- /Segmentation/Object Detection/Canny Edge Detector/detector.py: -------------------------------------------------------------------------------- 1 | 2 | """ Canny Edge Detection is based on the following five steps: 3 | 4 | 1. Gaussian filter 5 | 2. Gradient Intensity 6 | 3. Non-maximum suppression 7 | 4. Double threshold 8 | 5. Edge tracking 9 | 10 | This module contains these five steps as five separate Python functions. 11 | """ 12 | 13 | from CannyEdge.utils import to_ndarray 14 | from CannyEdge.core import (gs_filter, gradient_intensity, suppression, 15 | threshold, tracking) 16 | import numpy as np 17 | from copy import copy 18 | import argparse 19 | from scipy import misc 20 | import matplotlib.pyplot as plt 21 | 22 | # Argparse 23 | parser = argparse.ArgumentParser(description='Educational Edge Detector') 24 | parser.add_argument('source', metavar='src', help='image source (jpg, png)') 25 | parser.add_argument('sigma', type=float, metavar='sigma', help='Gaussian smoothing parameter') 26 | parser.add_argument('t', type=int, metavar='t', help='lower threshold') 27 | parser.add_argument('T', type=int, metavar='T', help='upper threshold') 28 | parser.add_argument("--all", help="Plot all in-between steps") 29 | args = parser.parse_args() 30 | 31 | def ced(img_file, sigma, t, T, all=False): 32 | img = to_ndarray(img_file) 33 | if not all: 34 | # avoid copies, just do all steps: 35 | img = gs_filter(img, sigma) 36 | img, D = gradient_intensity(img) 37 | img = suppression(img, D) 38 | img, weak = threshold(img, t, T) 39 | img = tracking(img, weak) 40 | return [img] 41 | else: 42 | # make copies, step by step 43 | img1 = gs_ilter(img, sigma) 44 | img2, D = gradient_intensity(img1) 45 | img3 = suppression(copy(img2), D) 46 | img4, weak = threshold(copy(img3), t, T) 47 | img5 = tracking(copy(img4), weak) 48 | return [to_ndarray(img_file), img1, img2, img3, img4, img5] 49 | 50 | def plot(img_list, safe=False): 51 | for d, img in enumerate(img_list): 52 | plt.subplot(1, len(img_list), d+1), plt.imshow(img, cmap='gray'), 53 | plt.xticks([]), plt.yticks([]) 54 | plt.show() 55 | 56 | img_list = ced(args.source, args.sigma, args.t, args.T, all=args.all) 57 | plot(img_list) 58 | -------------------------------------------------------------------------------- /Segmentation/Object Detection/Canny Edge Detector/r.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innat/DIP-In-Python/cdf52c893242cd10c9d401af8ba5d31ef41b588a/Segmentation/Object Detection/Canny Edge Detector/r.jpg -------------------------------------------------------------------------------- /Segmentation/Object Detection/Hough Transform/README.md: -------------------------------------------------------------------------------- 1 | 2 | ![houh](https://user-images.githubusercontent.com/17668390/44597685-52549800-a7f2-11e8-9cf1-d197fb126dfd.JPG) 3 | 4 | -------------------------------------------------------------------------------- /Segmentation/Object Detection/Hough Transform/hough_transform.py: -------------------------------------------------------------------------------- 1 | """ 2 | Image Data Analysis Using Numpy & OpenCV 3 | author: Mohammed Innat 4 | email: innat1994@gmail.com 5 | website: https://iphton.github.io/iphton.github.io/ 6 | Please feel free to use and modify this, but keep the above information. Thanks! 7 | """ 8 | 9 | import imageio 10 | import numpy as np 11 | import matplotlib.pyplot as plt 12 | from skimage.color import rgb2gray 13 | 14 | 15 | def hough_line(img, angle_step = 1, white_lines = True, threshold = 5): 16 | 17 | """ 18 | param:: img - 2D binary image 19 | param:: angle_step - Spacing between angles to use every n-th angle, Default step is 1. 20 | param:: lines_are_white - boolean indicator 21 | param:: value_threshold - Pixel values above or below the threshold are edges 22 | 23 | Returns: 24 | param:: accumulator - 2D array of the hough transform accumulator 25 | param:: theta - array of angles used in computation, in radians. 26 | param:: rhos - array of rho values. 27 | """ 28 | # Rho and Theta ranges 29 | thetas = np.deg2rad(np.arange(-90.0, 90.0, angle_step)) 30 | width, height = img.shape 31 | diag_len = int(np.ceil(np.sqrt(width * width + height * height))) 32 | rhos = np.linspace(-diag_len, diag_len, diag_len * 2) 33 | 34 | # Cache some resuable values 35 | cos_t = np.cos(thetas) 36 | sin_t = np.sin(thetas) 37 | num_thetas = len(thetas) 38 | 39 | # Hough accumulator array of theta vs rho 40 | accumulator = np.zeros((2 * diag_len, num_thetas), dtype=np.uint8) 41 | # (row, col) indexes to edges 42 | are_edges = img > threshold if white_lines else img < threshold 43 | y_idxs, x_idxs = np.nonzero(are_edges) 44 | 45 | # Vote in the hough accumulator 46 | for i in range(len(x_idxs)): 47 | x = x_idxs[i] 48 | y = y_idxs[i] 49 | 50 | for t_idx in range(num_thetas): 51 | # Calculate rho. diag_len is added for a positive index 52 | rho = diag_len + int(round(x * cos_t[t_idx] + y * sin_t[t_idx])) 53 | accumulator[rho, t_idx] += 1 54 | 55 | return accumulator, thetas, rhos 56 | 57 | 58 | def viz_hough_line(img, accumulator, thetas, rhos, save_path=None): 59 | 60 | # plot 61 | fig, ax = plt.subplots(1, 2, figsize=(10, 10)) 62 | 63 | ax[0].imshow(img, cmap=plt.cm.gray) 64 | ax[0].set_title('Input Image') 65 | ax[0].axis('image') 66 | 67 | ax[1].imshow( accumulator, cmap='jet', extent=[np.rad2deg(thetas[-1]), 68 | np.rad2deg(thetas[0]), rhos[-1], rhos[0]]) 69 | ax[1].set_aspect('equal', adjustable='box') 70 | ax[1].set_title('Hough Transform') 71 | ax[1].set_xlabel('Angles (deg)') 72 | ax[1].set_ylabel('Distance (px)') 73 | ax[1].axis('image') 74 | 75 | plt.axis('off') 76 | plt.show() 77 | 78 | 79 | gray = lambda rgb : np.dot(rgb[... , :3] , [0.299 , 0.587, 0.114]) 80 | 81 | if __name__ == '__main__': 82 | # import and function calling 83 | pic = imageio.imread('') 84 | gray = gray(pic) 85 | 86 | accumulator, thetas, rhos = hough_line(gray) # get the parameter 87 | viz_hough_line(gray, accumulator, thetas, rhos) # visualization 88 | -------------------------------------------------------------------------------- /Segmentation/Object Detection/README.md: -------------------------------------------------------------------------------- 1 | [Read](https://iphton.github.io/iphton.github.io/Image-Processing-in-Python-Part-2/#7-bullet) on blog for more detials explanations. 2 | -------------------------------------------------------------------------------- /Segmentation/README.md: -------------------------------------------------------------------------------- 1 | 2 | [Read](https://innat.github.io/innat.github.io/Image-Processing-in-Python-Part-2/#5-bullet) on blog in more details. 3 | 4 | **Ostu's Method** 5 | 6 | Thresholding is a very basic operation in image processing. Converting a greyscale image to monochrome is a common image processing task. And, a good algorithm always begins with a good basis! 7 | 8 | Otsu thresholding is a simple yet effective global automatic thresholding method for binarizing grayscale images such as foregrounds and backgrounds. In image processing, Otsu’s thresholding method (1979) is used for automatic **binarization** level decision, based on the shape of the **histogram**. It is based entirely on computation peformed on the histogram of an image. 9 | 10 | The algorithm assumes that the image is composed of two basic classes: **Foreground** and **Background**. It then computes an optimal threshold value that minimizes the weighted within class variances of these two classes. 11 | 12 | Otsu threshold is used in many applications from medical imaging to low level computer vision. It's many advantages and assumptions. 13 | 14 | Otsu shows that minimizing the **intra-class variance** is the same as **maximizing inter-class variance**. Inter calss variance is mathematically defined as: 15 | 16 | 17 | **Algorithm** 18 | 19 | If we incorporate a little math into that simple step-wise algorithm, such an explanation evolves: 20 | 21 | - Compute histogram and probabilities of each intensity level. 22 | - Set up initial w_i and mu_i. 23 | - Step through from threshold `t = 0` to `t = L-1`: 24 | - update: w_i and mu_i 25 | - compute: sigma_b^2(t) 26 | - Desired threshold corresponds to the maximum value of sigma_b^2(t). 27 | 28 | 29 | --- 30 | 31 | 32 | ## KMeans Clustering 33 | 34 | k-means clustering is a method of [vector quantization](https://en.wikipedia.org/wiki/Vector_quantization), originally from signal processing, that is popular for [cluster analysis](https://en.wikipedia.org/wiki/Cluster_analysis) in [data mining](https://en.wikipedia.org/wiki/Data_mining). 35 | 36 | In Otsu thresholding, we found the threshold which minimised the intra-segment pixel variance. So, rather then looking for a threshold from an gray level image, we can look for clusters in colour space, and by doing so we end up with the K-means clustering technique. 37 | -------------------------------------------------------------------------------- /Segmentation/Threshold/KMeans Clustering/KMeans_Clustering.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Image Data Analysis Using Numpy & OpenCV 4 | author: Mohammed Innat 5 | email: innat1994@gmail.com 6 | website: https://iphton.github.io/iphton.github.io/ 7 | Please feel free to use and modify this, but keep the above information. Thanks! 8 | """ 9 | from sklearn import cluster 10 | pic = imageio.imread('') 11 | plt.imshow(pic) 12 | 13 | x, y, z = pic.shape 14 | pic_2d = pic.reshape(x*y, z) 15 | 16 | kmeans_cluster = cluster.KMeans(n_clusters=5) 17 | kmeans_cluster.fit(pic_2d) 18 | cluster_centers = kmeans_cluster.cluster_centers_ 19 | cluster_labels = kmeans_cluster.labels_ 20 | 21 | plt.figure(figsize = (15,8)) 22 | plt.imshow(cluster_centers[cluster_labels].reshape(x, y, z)) 23 | -------------------------------------------------------------------------------- /Segmentation/Threshold/Ostu-s Method/Ostu's Method.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Image Data Analysis Using Numpy & OpenCV 4 | author: Mohammed Innat 5 | email: innat1994@gmail.com 6 | website: https://iphton.github.io/iphton.github.io/ 7 | Please feel free to use and modify this, but keep the above information. Thanks! 8 | """ 9 | 10 | import numpy as np 11 | import imageio 12 | import matplotlib.pyplot as plt 13 | 14 | pic = imageio.imread('') 15 | plt.imshow(pic); 16 | 17 | def otsu_threshold(im): 18 | 19 | # Compute histogram and probabilities of each intensity level 20 | pixel_counts = [np.sum(im == i) for i in range(256)] 21 | 22 | # Initialization 23 | s_max = (0,0) 24 | 25 | for threshold in range(256): 26 | 27 | # update 28 | w_0 = sum(pixel_counts[:threshold]) 29 | w_1 = sum(pixel_counts[threshold:]) 30 | 31 | mu_0 = sum([i * pixel_counts[i] for i in range(0,threshold)]) / w_0 if w_0 > 0 else 0 32 | mu_1 = sum([i * pixel_counts[i] for i in range(threshold, 256)]) / w_1 if w_1 > 0 else 0 33 | 34 | # calculate - inter class variance 35 | s = w_0 * w_1 * (mu_0 - mu_1) ** 2 36 | 37 | if s > s_max[1]: 38 | s_max = (threshold, s) 39 | 40 | 41 | return s_max[0] 42 | 43 | 44 | def threshold(pic, threshold): 45 | return ((pic > threshold) * 255).astype('uint8') 46 | 47 | gray = lambda rgb : np.dot(rgb[... , :3] , [0.21 , 0.72, 0.07]) 48 | plt.imshow(threshold(gray(pic), otsu_threshold(pic)), cmap='Greys') 49 | plt.axis('off') 50 | -------------------------------------------------------------------------------- /Vectorization/Contour_tracking.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Image Data Analysis Using Numpy & OpenCV 4 | author: Mohammed Innat 5 | email: innat1994@gmail.com 6 | website: https://iphton.github.io/iphton.github.io/ 7 | Please feel free to use and modify this, but keep the above information. Thanks! 8 | """ 9 | 10 | 11 | ''' 12 | We can use a contour tracing algorithm from Scikit-Image to extract the 13 | paths around the object. This controls how accurately the path follows the 14 | original bitmap shape. 15 | ''' 16 | 17 | from sklearn.cluster import KMeans 18 | import matplotlib.pyplot as plt 19 | from skimage import measure 20 | import numpy as np 21 | import imageio 22 | import warnings 23 | import matplotlib.cbook 24 | warnings.filterwarnings("ignore",category=matplotlib.cbook.mplDeprecation) 25 | 26 | pic = imageio.imread('') 27 | 28 | h,w = pic.shape[:2] 29 | 30 | im_small_long = pic.reshape((h * w, 3)) 31 | im_small_wide = im_small_long.reshape((h,w,3)) 32 | 33 | km = KMeans(n_clusters=2) 34 | km.fit(im_small_long) 35 | 36 | seg = np.asarray([(1 if i == 1 else 0) 37 | for i in km.labels_]).reshape((h,w)) 38 | 39 | contours = measure.find_contours(seg, 0.5, fully_connected="high") 40 | simplified_contours = [measure.approximate_polygon(c, tolerance=5) 41 | for c in contours] 42 | 43 | plt.figure(figsize=(5,10)) 44 | for n, contour in enumerate(simplified_contours): 45 | plt.plot(contour[:, 1], contour[:, 0], linewidth=2) 46 | 47 | 48 | plt.ylim(h,0) 49 | plt.axes().set_aspect('equal') 50 | -------------------------------------------------------------------------------- /Vectorization/README.md: -------------------------------------------------------------------------------- 1 | 2 | [Read](https://iphton.github.io/iphton.github.io/Image-Processing-in-Python-Part-2/#9-bullet) on blog. 3 | 4 | We use a contour tracing algorithm from `Scikit-Image` to extract the paths around the object. This controls how accurately the path follows the original bitmap shape. 5 | 6 | ![vec](https://user-images.githubusercontent.com/17668390/44360498-d6e6a400-a4dc-11e8-8983-da7970aea27d.JPG) 7 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate --------------------------------------------------------------------------------