This is a mask detector, an algorithm based on deep neural networks that detects people through your
36 | camera and write a bounding box around faces,
37 | looking if they were masks or not. This is not for security purpose.
38 |
If you are interested in more details, check this post I wrote!
39 |
40 |
41 |
Who I am
42 |
43 |
44 |
I'm Galileo Parise, data scientist and matematician, and I've developed what you see during Italy's
45 | second lockdown in November, in which I had lots of free time. If you are interested in this and ohter
46 | stories,
47 | you can follow me on Linkedin and on Medium.
48 | Hoping to get soon over this situation,
49 | I hope you all good health:
This is a mask detector, an algorithm based on deep neural networks that detects people in images and
56 | write a bounding box around faces, looking if they were masks or not. This is not for security
57 | purpose.
58 |
If you are interested in more details, check this post I wrote!
59 |
60 |
61 |
Who I am
62 |
63 |
64 |
I'm Galileo Parise, data scientist and matematician, and I've developed what you see during Italy's
65 | second lockdown in November, in which I had lots of free time. If you are interested in this and ohter
66 | stories,
67 | you can follow me on Linkedin and on Medium.
68 | Hoping to get soon over this situation,
69 | I hope you all good health:
Please do! Contributions, updates, and pull requests are welcome. This project is community-built and welcomes collaboration. Contributors are expected to adhere to the GOSSC Code of Conduct.
157 |
158 |
159 | Jump into our Discord! Our projects are community-built and welcome collaboration. 👍Be sure to see the Face-X Community Welcome Guide for a tour of resources available to you.
160 |
161 |
162 | Not sure where to start? Grab an open issue with the help-wanted label
163 |
164 |
165 | **Open Source First**
166 |
167 | best practices for managing all aspects of distributed services. Our shared commitment to the open-source spirit push the Face-X community and its projects forward.
168 |
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonification/cartoonify_without_GUI.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | import argparse
3 |
4 | video_capture = cv2.VideoCapture(0)
5 | fourcc = cv2.VideoWriter_fourcc(*'XVID')
6 | out = cv2.VideoWriter('cartoonised.avi', fourcc, 20.0, (1200, 600))
7 |
8 | while (video_capture.isOpened()):
9 | ret, frame = video_capture.read()
10 |
11 | if ret == True:
12 |
13 | gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
14 | resized_image= cv2.resize(gray, (1200, 600))
15 | blurred = cv2.medianBlur(resized_image, 9)
16 |
17 | thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_MEAN_C,
18 | cv2.THRESH_MASK, 11,11)
19 |
20 |
21 | original_image = cv2.bilateralFilter(frame,9, 300, 300)
22 |
23 | cartoon = cv2.bitwise_and(original_image, original_image, mask= thresh)
24 |
25 | out.write(cartoon)
26 |
27 |
28 |
29 | cv2.imshow('Cartoon_image', cartoon)
30 | cv2.imshow('Original Image', frame)
31 |
32 | if cv2.waitKey(1) & 0xFF ==27:
33 | break
34 |
35 | else:
36 | print("Camera not available, Please upload a photo")
37 |
38 |
39 | if(video_capture.isOpened() == False):
40 | arg_parse = argparse.ArgumentParser()
41 | arg_parse.add_argument("-i", "--image", required=True, help= "Image Path")
42 |
43 | args= vars(arg_parse.parse_args())
44 | image = cv2.imread(args['image'])
45 | filename = 'Cartoonified_image.jpg'
46 | resized_image = cv2.resize(image, (600, 450))
47 | gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
48 |
49 | blurred = cv2.medianBlur(gray_image, 9)
50 | thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11,11)
51 |
52 | original_image = cv2.bilateralFilter(image, 9, 300, 300)
53 |
54 | cartoon = cv2.bitwise_and(original_image, original_image, mask=thresh)
55 | cartoon_resize= cv2.resize(cartoon, (600,450))
56 |
57 | cv2.imshow("Cartoonified", cartoon_resize)
58 | cv2.imwrite(filename, cartoon)
59 | cv2.imshow("Main Image", resized_image)
60 |
61 | cv2.waitKey(0)
62 |
63 | out.release()
64 | video_capture.release()
65 | cv2.destroyAllWindows()
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonify using KMeans/README.md:
--------------------------------------------------------------------------------
1 | [](https://www.python.org/)
2 |
3 | [](https://www.python.org/downloads/release/python-360/)
4 | # Cartoonify_reality
5 |
6 | Even the basics of image processing if done properly can be handy which otherwise would require a machine learning model.This project is one of such inspiration which **cartoonizes** images and videos using only core **opencv filters** and functions.It also uses K-means clustering algorithm to compress the image. This clustering gives it the basic cartoonish tinge it requires.
7 |
8 | **Algorithm**- K_Means Clustering
9 |
10 | **Filters**-Bialateral Filter, Contours, erode, Canny(edge detection)
11 |
12 |
13 | ### Prerequisites
14 |
15 | What things you need to install the software and how to install them
16 |
17 | ```
18 | scipy
19 | numpy
20 | cv2
21 | ```
22 |
23 | ## Getting Started
24 | Download a python interpeter preferable a version beyond 3.0. Install the prerequisute libraries given above. Run vid.py file to cartonify your webcamp feed. Uncomment the last 2 lines of cartoonize.py and run to cartoonify an image.
25 |
26 | ```
27 | $vid.py
28 |
29 | $cartoonize.py
30 | ```
31 | ## Original Image
32 | 
33 |
34 |
35 | ## Cartoon Output
36 | 
37 |
38 | ## Built With
39 | * [python](https://www.python.org/) - The software used
40 |
41 | ## Documentation
42 | The entire documentation and explanation of code as well as concepts can be found in this article: https://iot4beginners.com/cartoonize-reality-with-opencv-and-raspberry-pi/
43 |
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonify using KMeans/Resources/cartoon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Cartoonify using KMeans/Resources/cartoon.jpg
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonify using KMeans/Resources/original2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Cartoonify using KMeans/Resources/original2.jpg
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonify using KMeans/Script/cartoonize.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | import scipy
3 | from scipy import stats
4 | import numpy as np
5 | from collections import defaultdict
6 |
7 |
8 | def update_c(C,hist):
9 | while True:
10 | groups=defaultdict(list)
11 |
12 | for i in range(len(hist)):
13 | if(hist[i] == 0):
14 | continue
15 | d=np.abs(C-i)
16 | index=np.argmin(d)
17 | groups[index].append(i)
18 |
19 | new_C=np.array(C)
20 | for i,indice in groups.items():
21 | if(np.sum(hist[indice])==0):
22 | continue
23 | new_C[i]=int(np.sum(indice*hist[indice])/np.sum(hist[indice]))
24 |
25 | if(np.sum(new_C-C)==0):
26 | break
27 | C=new_C
28 |
29 | return C,groups
30 |
31 | # Calculates K Means clustering
32 | def K_histogram(hist):
33 |
34 | alpha=0.001
35 | N=80
36 | C=np.array([128])
37 |
38 | while True:
39 | C,groups=update_c(C,hist)
40 |
41 | new_C=set()
42 | for i,indice in groups.items():
43 | if(len(indice)=3):
53 | c1=(C[i]+left)/2
54 | c2=(C[i]+right)/2
55 | new_C.add(c1)
56 | new_C.add(c2)
57 | else:
58 | new_C.add(C[i])
59 | else:
60 | new_C.add(C[i])
61 | if(len(new_C)==len(C)):
62 | break
63 | else:
64 | C=np.array(sorted(new_C))
65 | return C
66 |
67 | # The main controlling function
68 | def caart(img):
69 |
70 | kernel=np.ones((2,2), np.uint8)
71 | output=np.array(img)
72 | x,y,c=output.shape
73 | for i in range(c):
74 | output[:,:,i]=cv2.bilateralFilter(output[:,:,i],5,150,150)
75 |
76 | edge=cv2.Canny(output, 100, 200)
77 | output=cv2.cvtColor(output,cv2.COLOR_RGB2HSV)
78 |
79 | hists = []
80 |
81 | hist,_=np.histogram(output[:,:,0],bins =np.arange(180+1))
82 | hists.append(hist)
83 | hist,_=np.histogram(output[:,:,1],bins =np.arange(256+1))
84 | hists.append(hist)
85 | hist,_=np.histogram(output[:,:,2],bins =np.arange(256+1))
86 | hists.append(hist)
87 |
88 |
89 | C=[]
90 | for h in hists:
91 | C.append(K_histogram(h))
92 | #print("centroids: {0}".format(C))
93 |
94 | output=output.reshape((-1,c))
95 | for i in range(c):
96 | channel=output[:,i]
97 | index=np.argmin(np.abs(channel[:, np.newaxis] - C[i]), axis=1)
98 | output[:,i]=C[i][index]
99 | output=output.reshape((x,y,c))
100 | output=cv2.cvtColor(output, cv2.COLOR_HSV2RGB)
101 |
102 | contours,_=cv2.findContours(edge,cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
103 | cv2.drawContours(output,contours,-1,0,thickness=1)
104 | #cartoon = cv2.bitwise_and(output, output, mask=contours)
105 | for i in range(3):
106 | output[:,:,i]=cv2.erode(output[:,:,i], kernel, iterations=1)
107 | #Laplacian = cv2.Laplacian(output,cv2.CV_8U, ksize=11)
108 | #output=output-Laplacian
109 | return output
110 |
111 | #output=caart(cv2.imread("original.jpg"))
112 | #cv2.imwrite("cartoon.jpg", output)
113 |
114 |
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonify using KMeans/Script/vid.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import cv2
3 | from caartoonize import caart
4 |
5 |
6 |
7 | videoCaptureObject = cv2.VideoCapture(0)
8 |
9 | out = cv2.VideoWriter('out.mp4', cv2.VideoWriter_fourcc(*'MP4V'), 24, (720, 1280))
10 | result = True
11 | while(result):
12 | ret,img = videoCaptureObject.read()
13 | img=caart(img)
14 | cv2.imshow("original",np.array(img))
15 | out.write(img)
16 | if(cv2.waitKey(1) & 0xFF==ord('q')):
17 | break
18 | videoCaptureObject.release()
19 | cv2.destroyAllWindows()
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonify using KMeans/images/readme.md:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonify-GUI/GUI.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Cartoonify-GUI/GUI.png
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonify-GUI/Readme.md:
--------------------------------------------------------------------------------
1 | ## Cartoonify Image and save it
2 | ### This is a very baisc GUI for cartoonifying iage and save it
3 | ## How to start
4 |
5 |
6 | - Fork the repository
7 |
8 | - Git clone your forked repository
9 | - Create virtual environment-
10 | ```
11 | - python -m venv env
12 | - source env/bin/activate (Linux)
13 | - env\Scripts\activate (Windows)
14 | ```
15 | - Install dependencies
16 | - Go to project directory
17 | ```
18 | - cd Cartoonify Image
19 | ```
20 | - install these requirements
21 |
22 | ```
23 | - pip install opencv-python
24 | - pip install tkinter
25 | - pip install easygui
26 | - pip install pillow
27 | ```
28 | - Open Terminal
29 | ```
30 | python cartoonify_GUI.py
31 | ```
32 |
33 | ### Video recording of the process
34 |
35 | [](https://youtu.be/VDqEv6_FDt4 "Cartoonify GUI")
36 |
37 |
38 | ### Screenshots:
39 |
40 |
41 | ### GUI Interface
42 |
43 |
44 | ### Cartoonified Image
45 |
46 |
47 | ### Original Image
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonify-GUI/Updated GUI.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Cartoonify-GUI/Updated GUI.png
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonify-GUI/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Cartoonify-GUI/background.png
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonify-GUI/cartoonified.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Cartoonify-GUI/cartoonified.jpg
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonify-GUI/cartoonify-gui.py:
--------------------------------------------------------------------------------
1 | #Importing the necessary libraries
2 | import tkinter as tk
3 | import numpy as np
4 | from tkinter import *
5 | from tkinter import messagebox
6 | from PIL import Image,ImageTk
7 | import cv2
8 | import easygui
9 | import sys
10 | import os
11 |
12 | #Function Defined for Uploading function:
13 | def upload():
14 | imagepath = easygui.fileopenbox()
15 | cartoon(imagepath)
16 |
17 | #Function to convert image to cartoon
18 | def cartoon(imagepath):
19 | #Image variable takes image using imagepath
20 | image = cv2.imread(imagepath)
21 |
22 | if image is None:
23 | print('Choose another file')
24 | sys.exit()
25 | height, width, channels = image.shape
26 | print(width, height, channels)
27 |
28 | #Image_resize
29 | if height >=900 and width >=1200:
30 | resized_image = cv2.resize(image, (800, int(700*0.8)))
31 | else:
32 | resized_image = cv2.resize(image, (width, int(width*0.8)))
33 | #sharpen image
34 |
35 | #Putting a filter using numpy array
36 | filter = np.array([[-1, -1, -1], [-1, 9, -1], [-1, -1, -1]])
37 | #Sharpening Image using Open CV filter2D function
38 | sharpen_image = cv2.filter2D(resized_image, -1, filter)
39 | #Converting to Fray Image Scale
40 | gray_image = cv2.cvtColor(sharpen_image, cv2.COLOR_BGR2GRAY)
41 | #Blurring the Image
42 | blurred = cv2.medianBlur(gray_image, 9)
43 | # For every pixel, the same threshold value is applied. If the pixel value is smaller than the threshold, it is set to 0, otherwise it is set to a maximum value
44 | thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 11)
45 | #Original Image
46 | original_image = cv2.bilateralFilter(resized_image, 13, 150, 150)
47 |
48 | cartoon = cv2.bitwise_and(original_image, original_image, mask=thresh)
49 | if cartoon.shape[0] >=900 and cartoon.shape[1] >=1200:
50 | cartoon_resize = cv2.resize(cartoon, (800, int(700*0.8)))
51 | else:
52 | cartoon_resize = cv2.resize(cartoon, (cartoon.shape[1], int(cartoon.shape[0]*0.8)))
53 | #cartoon_resize = cv2.resize(cartoon, (width, int(width*0.8)))
54 |
55 | #Displaying the Main,Cartoonified and Sharpened Image
56 | cv2.imshow("Cartoonified", cartoon_resize)
57 | cv2.imshow("Main Image", image)
58 | cv2.imshow("Sharped Image", sharpen_image)
59 | save1 = Button(GUI, text="Save cartoon image", command=lambda: save_image(cartoon_resize, imagepath ), padx=30, pady=5)
60 | save1.configure(background='black', foreground='white', font=('calibri', 12, 'bold'))
61 | save1.pack(side=TOP, pady=50)
62 |
63 | #Saving Image
64 | def save_image(cartoon_resize, imagepath):
65 | name= "CartooniFied"
66 | file = os.path.dirname(os.path.realpath(imagepath))
67 | last_name = os.path.splitext(imagepath)[1]
68 | path = os.path.join(file, name + last_name )
69 | cv2.imwrite(path, cartoon_resize)
70 | full_name = "Image " + name + "saved at" + path
71 |
72 | tk.messagebox.showinfo(message=full_name)
73 |
74 |
75 | #create GUI Interface:
76 |
77 | #Defining the basic structure of the application
78 | GUI = tk.Tk()
79 | GUI.geometry('650x500')
80 | GUI.title("Cartoonify Image")
81 | GUI.configure(background='skyblue')
82 | #Loading the Background Image for the Application
83 | load=Image.open("D:\\GitRepo\\Face-X\\Cartoonify Image\\Cartoonify-GUI\\background.png")
84 | render=ImageTk.PhotoImage(load)
85 | img=Label(GUI,image=render)
86 | img.place(x=0,y=0)
87 |
88 | #Defining Buttons
89 | label=Label(GUI, background='black', font=('calibri',20,'bold'))
90 | upload=Button(GUI, text="Cartoonify Image",command=upload, padx=30,pady=5)
91 | upload.configure(background='black', foreground='white',font=('calibri',12,'bold'))
92 | upload.pack(side=TOP,pady=50)
93 |
94 | GUI.mainloop()
95 |
96 |
97 |
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonify-GUI/dicaprio.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Cartoonify-GUI/dicaprio.jpg
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonify-GUI/mq2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Cartoonify-GUI/mq2.jpg
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonify-GUI/wp2030093.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Cartoonify-GUI/wp2030093.jpg
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonify_face_image/Cartoonify-face_image.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | frame_cap = cv2.VideoCapture(0) #Capturing each Frames from the Camera
3 | while(True):
4 | ret, frame = frame_cap.read() #Reading the Captured Frames
5 | gray_img = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) #Applying gray filter
6 | blur_img = cv2.medianBlur(gray_img, 5) #Applying Median Blur
7 | edges = cv2.adaptiveThreshold(blur_img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 9)
8 | color = cv2.bilateralFilter(frame, 9, 250, 250) #Applying Bilateral Filter
9 | cartoon_img = cv2.bitwise_and(color, color, mask=edges) # Bit wise And operation on color and edges images
10 | cv2.imshow("Cartoon Image", cartoon_img) #Displaying the cartoonified Image
11 | if cv2.waitKey(1) & 0xFF == ord(' '): #Press space bar to exit
12 | break
13 | frame_cap.release()
14 | cv2.destroyAllWindows()
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonify_face_image/Images/after_face.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Cartoonify_face_image/Images/after_face.png
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonify_face_image/Images/face.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Cartoonify_face_image/Images/face.jpg
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonify_face_image/Images/readme.md:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonify_face_image/Images/recof.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Cartoonify_face_image/Images/recof.gif
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonify_face_image/readme.md:
--------------------------------------------------------------------------------
1 | # Cartoonifying a face image.
2 |
3 | - To Cartoonify the image we have used Computer vision, Where we apply various filters to the input image to produce a Cartoonified image. To accomplish this we have used Python programming language and opencv a Computer Vision library.
4 |
5 | ## Dependencies:
6 | The Dependencies used are:
7 | - Opencv :It provides the tool for applying computer vison techniques on the image.
8 | - Numpy :Images are stored and processed as numbers, These are taken as arrays.
9 |
10 | ## How to Run:
11 | - Download the directory.
12 | - You can use any Editor, Notebook Or IDE's to open the Cartoonify-face_image.py file.
13 | - Run Cartoonify-face_image.py file.
14 | - Press Space bar to exit.
15 |
16 | ## Steps of its working:
17 |
18 | - We have imported the cv2 and numpy library.
19 | - We are capturing the image frames using cv2.VideoCapture().
20 | - We are reading the image frames by using frame_cap.read().
21 | - We are applying Gray scale filter to the image frames using cv2.cvtcolor() and the by passing second parameter as cv2.COLOR_BGR2GRAY.
22 | - We are using MedianBlur on the gray scale image obtained above by setting the kernal size as 5 to blur the image using cv2.medianBlur().
23 | - We are using adaptive threshold on the image obtained after applying Medianblur, we are using a threshold value of 255 to filter out the pixel and we are using the adaptive method cv2.ADAPTIVE_THRESH_MEAN_C with a threshold type as cv2.THRESH_BINARY and block size 9.
24 | - We are applying a Bilateral filter on the original image frames using cv2.bilateralFilter() with kernal size 9 and the threshold as 250 to remove the Noise in the image.
25 | - We are then applying Bitwise and operation on the Bilateral image and the image obtained after using Adaptive threshold which gives the resulting cartoonified image.
26 |
27 | ## Result:
28 | ### Input Video
29 | 
30 |
31 | ### Output Video
32 | 
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonifying using OpenCV/Cartoonify.py:
--------------------------------------------------------------------------------
1 | #step 1
2 | #Use bilateral filter for edge-aware smoothing.
3 | import cv2
4 |
5 | num_down = 2 # number of downsampling steps
6 | num_bilateral = 7 # number of bilateral filtering steps
7 |
8 | img_rgb = cv2.imread("myCat.jpg")
9 |
10 | # downsample image using Gaussian pyramid
11 | img_color = img_rgb
12 | for _ in range(num_down):
13 | img_color = cv2.pyrDown(img_color)
14 |
15 | # repeatedly apply small bilateral filter instead of
16 | # applying one large filter
17 | for _ in range(num_bilateral):
18 | img_color = cv2.bilateralFilter(img_color, d=9, sigmaColor=9, sigmaSpace=7)
19 |
20 | # upsample image to original size
21 | for _ in range(num_down):
22 | img_color = cv2.pyrUp(img_color)
23 |
24 | #STEP 2 & 3
25 | #Use median filter to reduce noise
26 | # convert to grayscale and apply median blur
27 | img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2GRAY)
28 | img_blur = cv2.medianBlur(img_gray, 7)
29 |
30 | #STEP 4
31 | #Use adaptive thresholding to create an edge mask
32 | # detect and enhance edges
33 | img_edge = cv2.adaptiveThreshold(img_blur, 255,
34 | cv2.ADAPTIVE_THRESH_MEAN_C,
35 | cv2.THRESH_BINARY,
36 | blockSize=9,
37 | C=2)
38 |
39 | # Step 5
40 | # Combine color image with edge mask & display picture
41 | # convert back to color, bit-AND with color image
42 | img_edge = cv2.cvtColor(img_edge, cv2.COLOR_GRAY2RGB)
43 | img_cartoon = cv2.bitwise_and(img_color, img_edge)
44 |
45 | # display
46 | cv2.imshow("myCat_cartoon", img_cartoon)
47 |
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonifying using OpenCV/Readme.md:
--------------------------------------------------------------------------------
1 | Currently there are lots of professional cartoonizer applications available in the market but most of the them are not freeware. In order to get the basic cartoon effect, we just need the bilateral filter and some edge dectection mechanism. The bilateral filter will reduce the color palette, which is essential for the cartoon look and edge detection is to produce bold silhouettes.
2 |
3 | We are going to use openCV python library to convert an RGB color image to a cartoon image.
4 |
5 | Steps to develop Image Cartoonifier
6 | Download Image Cartoonifies Code
7 | Please download source code of Image Cartoonfier Project: Cartoonify an Image in Python
8 |
9 | Step 1: Importing the required modules
10 | We will import the following modules:
11 |
12 | CV2: Imported to use OpenCV for image processing
13 | easygui: Imported to open a file box. It allows us to select any file from our system.
14 | Numpy: Images are stored and processed as numbers. These are taken as arrays. We use NumPy to deal with arrays.
15 | Imageio: Used to read the file which is chosen by file box using a path.
16 | Matplotlib: This library is used for visualization and plotting. Thus, it is imported to form the plot of images.
17 | OS: For OS interaction. Here, to read the path and save images to that path.
18 |
19 | Step 2: Building a File Box to choose a particular file
20 | In this step, we will build the main window of our application, where the buttons, labels, and images will reside. We also give it a title by title() function.
21 |
22 |
23 | Code:
24 |
25 | """ fileopenbox opens the box to choose file
26 | and help us store file path as string """
27 | def upload():
28 | ImagePath=easygui.fileopenbox()
29 | cartoonify(ImagePath)
30 |
31 |
32 | Explanation:
33 | The above code opens the file box, i.e the pop-up box to choose the file from the device, which opens every time you run the code. fileopenbox() is the method in easyGUI module which returns the path of the chosen file as a string.
34 |
35 | Step 3: How is an image stored?
36 | Now, just think, how will a program read an image? For a computer, everything is just numbers. Thus, in the below code, we will convert our image into a numpy array.
37 |
38 | Beginning with image transformations:
39 |
40 | To convert an image to a cartoon, multiple transformations are done. Firstly, an image is converted to a Grayscale image. Yes, similar to the old day’s pictures.! Then, the Grayscale image is smoothened, and we try to extract the edges in the image. Finally, we form a color image and mask it with edges. This creates a beautiful cartoon image with edges and lightened color of the original image.
41 |
42 | Let’s start with these transformations to convert an image to its cartoon image.
43 |
44 | Step 4: Transforming an image to grayscale
45 | Code:
46 |
47 | #converting an image to grayscale
48 | grayScaleImage = cv2.cvtColor(originalmage, cv2.COLOR_BGR2GRAY)
49 | ReSized2 = cv2.resize(grayScaleImage, (960, 540))
50 | #plt.imshow(ReSized2, cmap='gray')
51 | Explanation:
52 |
53 | cvtColor(image, flag) is a method in cv2 which is used to transform an image into the colour-space mentioned as ‘flag’. Here, our first step is to convert the image into grayscale. Thus, we use the BGR2GRAY flag. This returns the image in grayscale. A grayscale image is stored as grayScaleImage.
54 |
55 | After each transformation, we resize the resultant image using the resize() method in cv2 and display it using imshow() method. This is done to get more clear insights into every single transformation step.
56 |
57 | The above code will generate the following output:
58 |
59 |
60 |
61 |
62 |
63 |
64 | Step 5: Smoothening a grayscale image
65 | Code:
66 |
67 | #applying median blur to smoothen an image
68 | smoothGrayScale = cv2.medianBlur(grayScaleImage, 5)
69 | ReSized3 = cv2.resize(smoothGrayScale, (960, 540))
70 | #plt.imshow(ReSized3, cmap='gray')
71 | Explanation:
72 |
73 |
74 | To smoothen an image, we simply apply a blur effect. This is done using medianBlur() function. Here, the center pixel is assigned a mean value of all the pixels which fall under the kernel. In turn, creating a blur effect.
75 |
76 | The above code generates the following output:
77 |
78 |
79 |
80 |
81 | Step 6: Retrieving the edges of an image
82 | Code:
83 |
84 | #retrieving the edges for cartoon effect
85 | #by using thresholding technique
86 | getEdge = cv2.adaptiveThreshold(smoothGrayScale, 255,
87 | cv2.ADAPTIVE_THRESH_MEAN_C,
88 | cv2.THRESH_BINARY, 9, 9)
89 | ReSized4 = cv2.resize(getEdge, (960, 540))
90 | #plt.imshow(ReSized4, cmap='gray')
91 | Explanation:
92 |
93 | Cartoon effect has two specialties:
94 |
95 | Highlighted Edges
96 | Smooth colors
97 | In this step, we will work on the first specialty. Here, we will try to retrieve the edges and highlight them. This is attained by the adaptive thresholding technique. The threshold value is the mean of the neighborhood pixel values area minus the constant C. C is a constant that is subtracted from the mean or weighted sum of the neighborhood pixels. Thresh_binary is the type of threshold applied, and the remaining parameters determine the block size.
98 |
99 | The above code will generate output like below:
100 |
101 |
102 |
103 |
104 |
105 |
106 | Step 7: Preparing a Mask Image
107 | Code:
108 |
109 | #applying bilateral filter to remove noise
110 | #and keep edge sharp as required
111 | colorImage = cv2.bilateralFilter(originalmage, 9, 300, 300)
112 | ReSized5 = cv2.resize(colorImage, (960, 540))
113 | #plt.imshow(ReSized5, cmap='gray')
114 | Explanation:
115 |
116 | In the above code, we finally work on the second specialty. We prepare a lightened color image that we mask with edges at the end to produce a cartoon image. We use bilateralFilter which removes the noise. It can be taken as smoothening of an image to an extent.
117 |
118 | The third parameter is the diameter of the pixel neighborhood, i.e, the number of pixels around a certain pixel which will determine its value. The fourth and Fifth parameter defines signmaColor and sigmaSpace. These parameters are used to give a sigma effect, i.e make an image look vicious and like water paint, removing the roughness in colors.
119 |
120 | Yes, it’s similar to BEAUTIFY or AI effect in cameras of modern mobile phones.
121 |
122 | The above code generates the following output:
123 |
124 |
125 |
126 |
127 |
128 |
129 | Step 8: Giving a Cartoon Effect
130 | Code:
131 |
132 |
133 | #masking edged image with our "BEAUTIFY" image
134 | cartoonImage = cv2.bitwise_and(colorImage, colorImage, mask=getEdge)
135 | ReSized6 = cv2.resize(cartoonImage, (960, 540))
136 | #plt.imshow(ReSized6, cmap='gray')
137 | Explanation:
138 |
139 | So, let’s combine the two specialties. This will be done using MASKING. We perform bitwise and on two images to mask them. Remember, images are just numbers?
140 |
141 | Yes, so that’s how we mask edged image on our “BEAUTIFY” image.
142 |
143 | This finally CARTOONIFY our image!
144 |
145 | The above code will generate output like below:
146 |
147 |
148 |
149 |
150 |
151 |
152 | Step 9: Plotting all the transitions together
153 | Code:
154 |
155 | # Plotting the whole transition
156 | images=[ReSized1, ReSized2, ReSized3, ReSized4, ReSized5, ReSized6]
157 | fig, axes = plt.subplots(3,2, figsize=(8,8), subplot_kw={'xticks':[], 'yticks':[]}, gridspec_kw=dict(hspace=0.1, wspace=0.1))
158 | for i, ax in enumerate(axes.flat):
159 | ax.imshow(images[i], cmap='gray')
160 | //save button code
161 | plt.show()
162 | Explanation:
163 |
164 | To plot all the images, we first make a list of all the images. The list here is named “images” and contains all the resized images. Now, we create axes like subl=plots in a plot and display one-one images in each block on the axis using imshow() method.
165 |
166 | plt.show() plots the whole plot at once after we plot on each subplot.
167 |
168 | The above code will generate output like below:
169 |
170 |
171 |
172 |
173 |
174 |
175 | Step 10: Functionally of save button
176 | def save(ReSized6, ImagePath):
177 | #saving an image using imwrite()
178 | newName="cartoonified_Image"
179 | path1 = os.path.dirname(ImagePath)
180 | extension=os.path.splitext(ImagePath)[1]
181 | path = os.path.join(path1, newName+extension)
182 | cv2.imwrite(path, cv2.cvtColor(ReSized6, cv2.COLOR_RGB2BGR))
183 | I = "Image saved by name " + newName +" at "+ path
184 | tk.messagebox.showinfo(title=None, message=I)
185 | Explanation:
186 |
187 | Here, the idea is to save the resultant image. For this, we take the old path, and just change the tail (name of the old file) to a new name and store the cartoonified image with a new name in the same folder by appending the new name to the head part of the file.
188 |
189 |
190 | For this, we extract the head part of the file path by os.path.dirname() method. Similarly, os.path.splitext(ImagePath)[1] is used to extract the extension of the file from the path.
191 |
192 | Here, newName stores “Cartoonified_Image” as the name of a new file. os.path.join(path1, newName + extension) joins the head of path to the newname and extension. This forms the complete path for the new file.
193 |
194 | imwrite() method of cv2 is used to save the file at the path mentioned. cv2.cvtColor(ReSized6, cv2.COLOR_RGB2BGR) is used to assure that no color get extracted or highlighted while we save our image. Thus, at last, the user is given confirmation that the image is saved with the name and path of the file.
195 |
196 |
197 | Step 11: Making the main window
198 | top=tk.Tk()
199 | top.geometry('400x400')
200 | top.title('Cartoonify Your Image !')
201 | top.configure(background='white')
202 | label=Label(top,background='#CDCDCD', font=('calibri',20,'bold'))
203 | Step 12: Making the Cartoonify button in the main window
204 | upload=Button(top,text="Cartoonify an Image",command=upload,padx=10,pady=5)
205 | upload.configure(background='#364156', foreground='white',font=('calibri',10,'bold'))
206 | upload.pack(side=TOP,pady=50)
207 | box
208 |
209 | Step 13: Making a Save button in the main window
210 | save1=Button(top,text="Save cartoon image",command=lambda: save(ImagePath, ReSized6),padx=30,pady=5)
211 | save1.configure(background='#364156', foreground='white',font=('calibri',10,'bold'))
212 | save1.pack(side=TOP,pady=50)
213 | The above code makes a button as soon as the image transformation is done. It gives an option to the user to save cartoonified image.
214 |
215 | save
216 |
217 | Step 14: Main function to build the tkinter window
218 | top.mainloop()
219 | The Final Result:
220 |
221 |
222 |
223 |
224 |
225 | Summary
226 | Yes, now you have a reason to tease your sibling by saying “You look like a cartoon”. Just cartoonify his/ her image, and show it!
227 |
228 | We have successfully developed Image Cartoonifier with OpenCV in Python. This is the magic of openCV which let us do miracles. We suggest you make a photo editor of your own and try different effects.
229 |
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonized-Image/images/cry_baby.jfif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Cartoonized-Image/images/cry_baby.jfif
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonized-Image/images/smile.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Cartoonized-Image/images/smile.jpg
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonized-Image/images/virat.jfif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Cartoonized-Image/images/virat.jfif
--------------------------------------------------------------------------------
/Cartoonify-Image/Cartoonized-Image/readme.md:
--------------------------------------------------------------------------------
1 | This application uses openCV to create cartoonish filter for any image with the help of Gaussian Filter
2 |
3 | Gaussian Filter- Uses a blurring function, adaptive thresholding and dilation to expose the main features of an image.
--------------------------------------------------------------------------------
/Cartoonify-Image/Differentiate between Human and Cartoon Faces/Assets/cartoon.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Differentiate between Human and Cartoon Faces/Assets/cartoon.jpeg
--------------------------------------------------------------------------------
/Cartoonify-Image/Differentiate between Human and Cartoon Faces/Assets/image.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Differentiate between Human and Cartoon Faces/Assets/image.webp
--------------------------------------------------------------------------------
/Cartoonify-Image/Differentiate between Human and Cartoon Faces/Media/blurred_hsv.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Differentiate between Human and Cartoon Faces/Media/blurred_hsv.jpeg
--------------------------------------------------------------------------------
/Cartoonify-Image/Differentiate between Human and Cartoon Faces/Media/image.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Differentiate between Human and Cartoon Faces/Media/image.webp
--------------------------------------------------------------------------------
/Cartoonify-Image/Differentiate between Human and Cartoon Faces/Media/img_hsv.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Differentiate between Human and Cartoon Faces/Media/img_hsv.jpeg
--------------------------------------------------------------------------------
/Cartoonify-Image/Differentiate between Human and Cartoon Faces/Media/new.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Differentiate between Human and Cartoon Faces/Media/new.jpeg
--------------------------------------------------------------------------------
/Cartoonify-Image/Differentiate between Human and Cartoon Faces/README.md:
--------------------------------------------------------------------------------
1 | # Differentiate between Cartoon and Human Faces
2 |
3 | One way to discriminate between cartoon and natural scene images is to compare a given image to its "smoothed" self. The motivation behind this is that a "smoothed" cartoon image statistically will not change much, where as a natural scene image will. In other words, take an image, cartoonify (i.e. smooth) it and subtract the result from the original.
4 |
5 | This difference (i.e. taking its mean value) will give the level of change caused by the smoothing. The index should be high for non-smooth original (natural scene) images and low for smooth original (cartoony) images.
6 |
7 | Smoothing/Cartoonifying is done with bilateral filtering.
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | As for subtracting the cartoonyfied image from the original, it is done with the Hue channel of the HSV images. This means, first the images are converted from BGR to HSV and then subtracted.
16 |
17 |
18 |
19 |
20 |
21 |
22 | ## Dependencies
23 |
24 | - OpenCV - This is used to perform different operations like blurring on the given image.
25 | - Numpy - This is used for calculating the mean of subtraction.
26 |
27 | ## Setup
28 |
29 | - Fork the repository - Creates a copy of this project in your github.
30 |
31 | - Clone the repository to your local machine using
32 | ```
33 | git clone https://github.com/akshitagupta15june/Face-X.git
34 | ```
35 | - Use a virtual environment to keep the all dependencies in a separate enviroment for example - conda, virtualenv, pipenv, etc.
36 |
37 | - Navigate to the Differentiate between Human and Cartoon Faces inside Cartoonify Image Folder using
38 | ```
39 | cd Cartoonify-Image/Differentiate\ between\ Human\ and\ Cartoon\ Faces
40 | ```
41 |
42 | - Install the dependencies either by using the below pip commands or by using the requirements.txt file given.
43 |
44 | - By using pip commands
45 | ```
46 | pip install numpy
47 | ```
48 | ```
49 | pip install opencv-python
50 | ```
51 |
52 | - By using requirements.txt
53 | ```
54 | pip install -r requirements.txt
55 | ```
56 |
57 | - Run the cartoon.py script using
58 | ```
59 | python3 cartoon.py
60 | ```
61 |
62 | ## Want to Contribute?
63 |
64 | - Follow the steps for Setup
65 |
66 | - Make a new branch
67 | ```
68 | git branch < YOUR_USERNAME >
69 | ```
70 |
71 | - Switch to Development Branch
72 | ```
73 | git checkout < YOURUSERNAME >
74 | ```
75 |
76 | - Make a folder and add your code file and a readme file with screenshots.
77 |
78 | - Add your files or changes to staging area
79 | ```
80 | git add.
81 | ```
82 |
83 | - Commit Message
84 | ```
85 | git commit -m "Enter message"
86 | ```
87 |
88 | - Push your code
89 | ```
90 | git push
91 | ```
92 |
93 | - Make Pull request with the Master branch of akshitagupta15june/Face-X repo.
94 |
95 | - Wait for reviewers to review your PR
96 |
--------------------------------------------------------------------------------
/Cartoonify-Image/Differentiate between Human and Cartoon Faces/cartoon.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | import numpy as np
3 |
4 |
5 | def check(image_path):
6 | # Reading the image
7 | img = cv2.imread(image_path)
8 |
9 | # Parameters for Bilateral Filter
10 |
11 | # Diameter of the pixel neighborhood — the larger this diameter is,
12 | # the more pixels will be included in the blurring computation.
13 | diameter = 11
14 |
15 | # SigmaColor is the number of colors in the neighborhood
16 | # that will be considered when computing the blur.
17 | sigmaColor = 61
18 |
19 | # The value of SigmaSpace indicates pixels farther out
20 | # from the central pixel diameter will influence the blurring calculation.
21 | sigmaSpace = 39
22 |
23 | # Applying Bilateral Filter
24 | blurred = cv2.bilateralFilter(img, diameter, sigmaColor, sigmaSpace)
25 |
26 | # Converting original image to HSV
27 | img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
28 |
29 | # Converting blurred image to hsv
30 | blurred_hsv = cv2.cvtColor(blurred, cv2.COLOR_BGR2HSV)
31 |
32 | # Subtracting blurred from original and storing value
33 | isNotACartoonIndex = np.mean( img_hsv - blurred_hsv )
34 |
35 | if isNotACartoonIndex >= 55:
36 | print("Human Face")
37 | else:
38 | print("Cartoon Face")
39 |
40 |
41 | check("/Assets/cartoon.jpeg")
42 | check("/Assets/image.webp")
--------------------------------------------------------------------------------
/Cartoonify-Image/Differentiate between Human and Cartoon Faces/requirements.txt:
--------------------------------------------------------------------------------
1 | numpy==1.21.0
2 | opencv-python==4.5.5.62
--------------------------------------------------------------------------------
/Cartoonify-Image/Glitter Cartoon Filter/Glitter Cartoon Filter.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import cv2
3 | import os.path
4 |
5 |
6 | img_path = input("Enter the path here:") #example -> C:\Users\xyz\OneDrive\Desktop\project\image.jpg
7 |
8 | img = cv2.imread(img_path)
9 |
10 | from matplotlib import pyplot as plt
11 | #plt.imshow(img)
12 | #plt.show()
13 |
14 | image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
15 |
16 | plt.figure(figsize= (10,10))
17 | #plt.imshow(image)
18 | #plt.show()
19 |
20 | img_small = cv2.pyrDown(image)
21 | num_iter = 5
22 | for _ in range(num_iter):
23 | img_small= cv2.bilateralFilter(img_small, d=9, sigmaColor=9, sigmaSpace=7)
24 |
25 | img_rgb = cv2.pyrUp(img_small)
26 |
27 | #plt.imshow(img_rgb)
28 | #plt.show()
29 |
30 | img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2GRAY)
31 | img_blur = cv2.medianBlur(img_gray, 7)
32 | img_edge = cv2.adaptiveThreshold(img_blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 7, 2)
33 |
34 | #plt.imshow(img_edge)
35 | #plt.show()
36 |
37 | img_edge = cv2.cvtColor(img_edge, cv2.COLOR_GRAY2RGB)
38 | #plt.imshow(img_edge)
39 | #plt.show()
40 |
41 |
42 |
43 | array = cv2.bitwise_or(image, img_rgb)
44 | final_img = cv2.bitwise_and(array, img_edge)
45 |
46 |
47 | # set up side-by-side image display
48 | fig = plt.figure()
49 | fig.set_figheight(15)
50 | fig.set_figwidth(15)
51 |
52 | # display the real image
53 | fig.add_subplot(1,2,1)
54 | plt.imshow(image, cmap='gray')
55 | plt.title("Original Image")
56 |
57 | # display the new image
58 | fig.add_subplot(1,2,2)
59 | plt.imshow(final_img, cmap='gray')
60 | plt.title("Glitter Cartoon Filtered Image")
61 |
62 |
63 | plt.show()
64 |
--------------------------------------------------------------------------------
/Cartoonify-Image/Glitter Cartoon Filter/Images/Final_Output.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Glitter Cartoon Filter/Images/Final_Output.jpg
--------------------------------------------------------------------------------
/Cartoonify-Image/Glitter Cartoon Filter/Images/Original_image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/Glitter Cartoon Filter/Images/Original_image.jpg
--------------------------------------------------------------------------------
/Cartoonify-Image/Glitter Cartoon Filter/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Applying "Glitter Cartoon Filter" on an image.
3 |
4 | Converting an image into a glitter cartoon filtered image using OpenCv, Os, Matplotlib and Numpy.
5 |
6 | ## Steps:
7 | * Firstly imported the required libraries which are Numpy, Os, Matplotlib and Cv2.
8 | * Taking path of the image/Real image as input using os and finally reading it using cv2
9 |
10 | ## Methods Used
11 | * Used Bilateral Filter
12 | * Followed by Median Blur
13 | * Followed by Adaptive Threshold
14 | * Followed by Bitwise "or" between original image and image_rgb
15 | * And at last used Bitwise "and" between image_edge and output of the above "bitwise or image"
16 | * Finally converted the image into "Glitter Cartoon Filtered" image
17 |
18 |
19 |
20 |
21 | ## Comparision between the "Original" and "Glitter Cartoon Filtered" Image
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Cartoonify-Image/Images/readme.md:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Cartoonify-Image/facex.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/facex.jpeg
--------------------------------------------------------------------------------
/Cartoonify-Image/logo/Face-X.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/logo/Face-X.png
--------------------------------------------------------------------------------
/Cartoonify-Image/logo/FaceX.svg:
--------------------------------------------------------------------------------
1 |
106 |
--------------------------------------------------------------------------------
/Cartoonify-Image/logo/cartoonified.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/logo/cartoonified.png
--------------------------------------------------------------------------------
/Cartoonify-Image/logo/original.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Cartoonify-Image/logo/original.jpeg
--------------------------------------------------------------------------------
/Cartoonify-Image/readme.md:
--------------------------------------------------------------------------------
1 | # Cartoonify Image
2 | Currently many of us wants to have our photo to be cartoonify, and we try to use the professional cartoonizer application available in market and most of them are not freeware. In order to have basic cartoonifying effects, we just need the bilateral filter, some edge detection mechanism and some filters.
3 |
4 | The bilateral filter is use to reduce the color palettle, which is the most important task for cartoonifying the image and have a look like cartoon.And then comes the edge detection to produce the bold silhouettes.
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Dependencies:
12 |
13 | The Dependencies used are:
14 |
15 | - Opencv :It provides the tool for applying computer vison techniques on the image.
16 | - Numpy :Images are stored and processed as numbers, These are taken as arrays.
17 |
18 | ## How to create a Cortoonify Image?
19 | - Cartoonify Images can be created using the opencv library.
20 | - OpenCV (Open Source Computer Vision Library) is an open source computer vision and machine learning software library. It is mainly aimed at real-time computer vision and image processing. It is used to perform different operations on images which transform them using different techniques. Majorly supports all lannguages like Python, C++,Android, Java, etc.
21 | - In Opencv there are various functions like bilateral filters, median blur, adaptive thresholding which help in cartoonify the image.
22 |
23 | ## Algorithm
24 | - Firstly importing the cv2 and numpy library.
25 | - Now applying the bilateral filter to reduce the color palette of the image.
26 | - Covert the actual image to grayscale.
27 | - Apply the median blur to reduce the image noise in the grayscale image.
28 | - reate an edge mask from the grayscale image using adaptive thresholding.
29 | - Finally combine the color image produced from step 1 with edge mask produced from step 4.
30 |
31 |
32 | ## Want to contribute in Cartoonify Images?
33 | You can refer to CONTRIBUTING.md (`https://github.com/akshitagupta15june/Face-X/blob/master/CONTRIBUTING.md`)
34 | #### Or follow the below steps -
35 | - Fork this repository `https://github.com/akshitagupta15june/Face-X`.
36 | - Clone the forked repository
37 | ```
38 | git clone https://github.com//
39 | ```
40 | - Create a Virtual Environment(that can fulfill the required dependencies)
41 | ```
42 | - python -m venv env
43 | - source env/bin/activate (Linux)
44 | - env\Scripts\activate (Windows)
45 | ```
46 | - Install dependencies
47 | - Go to project directory
48 | ```
49 | cd Cartoonify Image
50 | ```
51 | - Make a new branch
52 | ```
53 | git branch < YOUR_USERNAME >
54 | ```
55 | - Switch to Development Branch
56 | ```
57 | git checkout < YOURUSERNAME >
58 | ```
59 | - Make a folder and add your code file and a readme file with screenshots.
60 | - Add your files or changes to staging area
61 | ```
62 | git add .
63 | ```
64 | - Commit message
65 | ```
66 | git commit -m "Enter message"
67 | ```
68 | - Push your code
69 | ```
70 | git push
71 | ```
72 | - Make Pull request with the Master branch of `akshitagupta15june/Face-X` repo.
73 | - Wait for reviewers to review your PR
--------------------------------------------------------------------------------
/Chronic-Kidney-Disease-main.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Chronic-Kidney-Disease-main.zip
--------------------------------------------------------------------------------
/Color-Detection-Project:
--------------------------------------------------------------------------------
1 | import cv2
2 | import numpy as np
3 | import pandas as pd
4 | import argparse
5 |
6 | #Creating argument parser to take image path from command line
7 | ap = argparse.ArgumentParser()
8 | ap.add_argument('-i', '--image', required=True, help="Image Path")
9 | args = vars(ap.parse_args())
10 | img_path = args['image']
11 |
12 | #Reading the image with opencv
13 | img = cv2.imread(img_path)
14 |
15 | #declaring global variables (are used later on)
16 | clicked = False
17 | r = g = b = xpos = ypos = 0
18 |
19 | #Reading csv file with pandas and giving names to each column
20 | index=["color","color_name","hex","R","G","B"]
21 | csv = pd.read_csv('colors.csv', names=index, header=None)
22 |
23 | #function to calculate minimum distance from all colors and get the most matching color
24 | def getColorName(R,G,B):
25 | minimum = 10000
26 | for i in range(len(csv)):
27 | d = abs(R- int(csv.loc[i,"R"])) + abs(G- int(csv.loc[i,"G"]))+ abs(B- int(csv.loc[i,"B"]))
28 | if(d<=minimum):
29 | minimum = d
30 | cname = csv.loc[i,"color_name"]
31 | return cname
32 |
33 | #function to get x,y coordinates of mouse double click
34 | def draw_function(event, x,y,flags,param):
35 | if event == cv2.EVENT_LBUTTONDBLCLK:
36 | global b,g,r,xpos,ypos, clicked
37 | clicked = True
38 | xpos = x
39 | ypos = y
40 | b,g,r = img[y,x]
41 | b = int(b)
42 | g = int(g)
43 | r = int(r)
44 |
45 | cv2.namedWindow('image')
46 | cv2.setMouseCallback('image',draw_function)
47 |
48 | while(1):
49 |
50 | cv2.imshow("image",img)
51 | if (clicked):
52 |
53 | #cv2.rectangle(image, startpoint, endpoint, color, thickness)-1 fills entire rectangle
54 | cv2.rectangle(img,(20,20), (750,60), (b,g,r), -1)
55 |
56 | #Creating text string to display( Color name and RGB values )
57 | text = getColorName(r,g,b) + ' R='+ str(r) + ' G='+ str(g) + ' B='+ str(b)
58 |
59 | #cv2.putText(img,text,start,font(0-7),fontScale,color,thickness,lineType )
60 | cv2.putText(img, text,(50,50),2,0.8,(255,255,255),2,cv2.LINE_AA)
61 |
62 | #For very light colours we will display text in black colour
63 | if(r+g+b>=600):
64 | cv2.putText(img, text,(50,50),2,0.8,(0,0,0),2,cv2.LINE_AA)
65 |
66 | clicked=False
67 |
68 | #Break the loop when user hits 'esc' key
69 | if cv2.waitKey(20) & 0xFF ==27:
70 | break
71 |
72 | cv2.destroyAllWindows()
73 |
--------------------------------------------------------------------------------
/Covid:
--------------------------------------------------------------------------------
1 | /*
2 | Covid 19 Data Exploration
3 | */
4 |
5 | Select *
6 | From PortfolioProject..CovidDeaths
7 | Where continent is not null
8 | order by 3,4
9 |
10 |
11 | -- Select Data that we are going to be starting with
12 |
13 | Select Location, date, total_cases, new_cases, total_deaths, population
14 | From PortfolioProject..CovidDeaths
15 | Where continent is not null
16 | order by 1,2
17 |
18 |
19 | -- Total Cases vs Total Deaths
20 | -- Shows likelihood of dying if you contract covid in your country
21 |
22 | Select Location, date, total_cases,total_deaths, (total_deaths/total_cases)*100 as DeathPercentage
23 | From PortfolioProject..CovidDeaths
24 | Where location like '%states%'
25 | and continent is not null
26 | order by 1,2
27 |
28 |
29 | -- Total Cases vs Population
30 | -- Shows what percentage of population infected with Covid
31 |
32 | Select Location, date, Population, total_cases, (total_cases/population)*100 as PercentPopulationInfected
33 | From PortfolioProject..CovidDeaths
34 | --Where location like '%states%'
35 | order by 1,2
36 |
37 |
38 | -- Countries with Highest Infection Rate compared to Population
39 |
40 | Select Location, Population, MAX(total_cases) as HighestInfectionCount, Max((total_cases/population))*100 as PercentPopulationInfected
41 | From PortfolioProject..CovidDeaths
42 | --Where location like '%states%'
43 | Group by Location, Population
44 | order by PercentPopulationInfected desc
45 |
46 |
47 | -- Countries with Highest Death Count per Population
48 |
49 | Select Location, MAX(cast(Total_deaths as int)) as TotalDeathCount
50 | From PortfolioProject..CovidDeaths
51 | --Where location like '%states%'
52 | Where continent is not null
53 | Group by Location
54 | order by TotalDeathCount desc
55 |
56 |
57 |
58 | -- BREAKING THINGS DOWN BY CONTINENT
59 |
60 | -- Showing contintents with the highest death count per population
61 |
62 | Select continent, MAX(cast(Total_deaths as int)) as TotalDeathCount
63 | From PortfolioProject..CovidDeaths
64 | --Where location like '%states%'
65 | Where continent is not null
66 | Group by continent
67 | order by TotalDeathCount desc
68 |
69 |
70 |
71 | -- GLOBAL NUMBERS
72 |
73 | Select SUM(new_cases) as total_cases, SUM(cast(new_deaths as int)) as total_deaths, SUM(cast(new_deaths as int))/SUM(New_Cases)*100 as DeathPercentage
74 | From PortfolioProject..CovidDeaths
75 | --Where location like '%states%'
76 | where continent is not null
77 | --Group By date
78 | order by 1,2
79 |
80 |
81 |
82 | -- Total Population vs Vaccinations
83 | -- Shows Percentage of Population that has recieved at least one Covid Vaccine
84 |
85 | Select dea.continent, dea.location, dea.date, dea.population, vac.new_vaccinations
86 | , SUM(CONVERT(int,vac.new_vaccinations)) OVER (Partition by dea.Location Order by dea.location, dea.Date) as RollingPeopleVaccinated
87 | --, (RollingPeopleVaccinated/population)*100
88 | From PortfolioProject..CovidDeaths dea
89 | Join PortfolioProject..CovidVaccinations vac
90 | On dea.location = vac.location
91 | and dea.date = vac.date
92 | where dea.continent is not null
93 | order by 2,3
94 |
95 |
96 | -- Using CTE to perform Calculation on Partition By in previous query
97 |
98 | With PopvsVac (Continent, Location, Date, Population, New_Vaccinations, RollingPeopleVaccinated)
99 | as
100 | (
101 | Select dea.continent, dea.location, dea.date, dea.population, vac.new_vaccinations
102 | , SUM(CONVERT(int,vac.new_vaccinations)) OVER (Partition by dea.Location Order by dea.location, dea.Date) as RollingPeopleVaccinated
103 | --, (RollingPeopleVaccinated/population)*100
104 | From PortfolioProject..CovidDeaths dea
105 | Join PortfolioProject..CovidVaccinations vac
106 | On dea.location = vac.location
107 | and dea.date = vac.date
108 | where dea.continent is not null
109 | --order by 2,3
110 | )
111 | Select *, (RollingPeopleVaccinated/Population)*100
112 | From PopvsVac
113 |
114 |
115 |
116 | -- Using Temp Table to perform Calculation on Partition By in previous query
117 |
118 | DROP Table if exists #PercentPopulationVaccinated
119 | Create Table #PercentPopulationVaccinated
120 | (
121 | Continent nvarchar(255),
122 | Location nvarchar(255),
123 | Date datetime,
124 | Population numeric,
125 | New_vaccinations numeric,
126 | RollingPeopleVaccinated numeric
127 | )
128 |
129 | Insert into #PercentPopulationVaccinated
130 | Select dea.continent, dea.location, dea.date, dea.population, vac.new_vaccinations
131 | , SUM(CONVERT(int,vac.new_vaccinations)) OVER (Partition by dea.Location Order by dea.location, dea.Date) as RollingPeopleVaccinated
132 | --, (RollingPeopleVaccinated/population)*100
133 | From PortfolioProject..CovidDeaths dea
134 | Join PortfolioProject..CovidVaccinations vac
135 | On dea.location = vac.location
136 | and dea.date = vac.date
137 | --where dea.continent is not null
138 | --order by 2,3
139 |
140 | Select *, (RollingPeopleVaccinated/Population)*100
141 | From #PercentPopulationVaccinated
142 |
143 |
144 |
145 |
146 | -- Creating View to store data for later visualizations
147 |
148 | Create View PercentPopulationVaccinated as
149 | Select dea.continent, dea.location, dea.date, dea.population, vac.new_vaccinations
150 | , SUM(CONVERT(int,vac.new_vaccinations)) OVER (Partition by dea.Location Order by dea.location, dea.Date) as RollingPeopleVaccinated
151 | --, (RollingPeopleVaccinated/population)*100
152 | From PortfolioProject..CovidDeaths dea
153 | Join PortfolioProject..CovidVaccinations vac
154 | On dea.location = vac.location
155 | and dea.date = vac.date
156 | where dea.continent is not null
157 |
158 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Data-Science-Projects
2 | Add your data analysis/Artifical Intelligence/Machine Learning projects in this repo for the welfare of data science community
3 |
4 |
5 | 
6 |
7 | ## Rules to contribute to this Repo
8 |
9 | - Use any programming language
10 | - Use any data science tools and techniques and create data projects.
11 | - Projects should be different from the uploaded ones or it should be optimized version of existing ones
12 |
13 |
14 | ## Steps for Contributing
15 |
16 | ## Getting started
17 |
18 | - Fork this repository (Click the Fork button in the top right of this page, click your Profile Image)
19 | - Clone your fork down to your local machine
20 |
21 | ```markdown
22 | git clone https://github.com/SARTHAK2511/Data-Analysis-Projects-for-Hacktoberfest.git
23 | ```
24 |
25 | - Create a branch
26 |
27 | ```markdown
28 | git checkout -b branch-name
29 | ```
30 |
31 | - Make your changes (choose from any task below)
32 | - Commit and push
33 |
34 | ```markdown
35 | git add .
36 | git commit -m 'Commit message'
37 | git push origin branch-name
38 | ```
39 |
40 | - Create a new pull request from your forked repository (Click the `New Pull Request` button located at the top of your repo)
41 | - Wait for your PR review and merge approval!
42 | - **Star this repository** if you had fun!
43 |
--------------------------------------------------------------------------------
/Sentiment Analysis/SenAnal.py:
--------------------------------------------------------------------------------
1 | from init import *
2 | import streamlit as st
3 |
4 | def SentimentAnalysis(sq):
5 | tweets = tp.Cursor(api.search_tweets,
6 | q = sq+'-filter:retweets',
7 | lang = "en",
8 | tweet_mode = "extended").items(500)
9 | data = []
10 | for tweet in tweets:
11 | try:
12 | content = tweet.full_text
13 | sentiment = sentiment_analysis(content)
14 | data.append([content, sentiment[0]['label']])
15 | except:
16 | pass
17 | columns = ['Tweet', 'Sentiment']
18 | df = pd.DataFrame(data, columns=columns)
19 | f = df.to_csv().encode('utf-8')
20 | return f
--------------------------------------------------------------------------------
/Sentiment Analysis/app.py:
--------------------------------------------------------------------------------
1 | import SenAnal
2 | import streamlit as st
3 |
4 | st.image('twitter.png', width=80)
5 | st.title("Twitter Sentiment Analysis")
6 | search_query = st.text_input('Twitter Keywords')
7 | if len(search_query) != 0:
8 | st.download_button(label='Download', data=SenAnal.SentimentAnalysis(search_query), file_name='data.csv')
--------------------------------------------------------------------------------
/Sentiment Analysis/init - Copy.py:
--------------------------------------------------------------------------------
1 | import os
2 | from transformers import pipeline
3 | import tweepy as tp
4 | import configparser as cp
5 | import numpy as np
6 | import csv
7 | import pandas as pd
8 | import streamlit as st
9 |
10 | config = cp.ConfigParser()
11 | config.read('config.ini')
12 |
13 | api_key = ""
14 | api_secret = ""
15 |
16 | access_token = ""
17 | access_token_secret = ""
18 |
19 | auth = tp.OAuthHandler(api_key, api_secret)
20 | auth.set_access_token(access_token, access_token_secret)
21 |
22 | api = tp.API(auth)
23 |
24 | sentiment_analysis = pipeline(model="finiteautomata/bertweet-base-sentiment-analysis")
--------------------------------------------------------------------------------
/Streamlit-Stock-Prediction-main.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/Streamlit-Stock-Prediction-main.zip
--------------------------------------------------------------------------------
/bark-texture-classification-with-resnet50.ipynb:
--------------------------------------------------------------------------------
1 | {"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Changes\n### Most changes between versions are small. All experiments should have only one small change each, so it would be easy to understand how changes affect the result. \n\n**v1**: Made a functional CNN with 94% accuracy.\n\n**v2**: Resizing to 256 px before cropping. This way we can retain more of the image after the crop, and this helps us too as most of the images are actually focused and centered on the trees. Accuracy boosted to 96%.\n\n**v3**: 30 epochs has been overfitting the model over the validation data. Reduced to 15 epochs. Retains the original 96-97% accuracy as compared to 30 epochs\n\n**v4**: Added L2 regularization while training and used updated model weights for ResNet50 using new API\n\n**v5**: Increased number of epochs to 45 due to new lr decay\n\n**v6**: Moved from ResNet50 to ResNet34, with 1% performance change in testing, but considerable reduction in model execution (training, testing) time. \n\n**v7**: Added AutoAugment and moved back to Resnet50. Creates marginal performance improvement.\n\n**Accuracies**:\n\n - *ResNet50* - 97%\n\n - *ResNet34* - 96%\n \n We can choose ResNet50 for accuracy ResNet34 for speed","metadata":{}},{"cell_type":"markdown","source":"### Transfer Learning\n\nHere I decided to use a transfer learning model, as using a base model did not quite meet my personal expectations on the accuracy of the model.\n\nTransfer Learning allows us to apply features already learned from other datasets to our dataset, leading to lower training times and higher accuracies. Here we use models trained on the IMAGENET dataset, which work very well for most CNN image classification tasks.","metadata":{}},{"cell_type":"code","source":"import numpy as np\nfrom glob import glob\nimport os\nimport torch\nimport torchvision.models as models\nimport torchvision.transforms as transforms\nfrom torchvision import datasets\nfrom PIL import ImageFile\nfrom torch.utils.data.sampler import SubsetRandomSampler\nimport matplotlib.pyplot as plt\nimport torch.optim as optim\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Creating our transforms**:\n- Cropping to 224 x 224 px for transfer learning model input param. This reduction of the size of the images also helps decrease processing time\n- We augumented the dataset to add more training variations by horizontal flipping and slight rotation. \n- **v2**: Resizing to 256 px before cropping. This way we can retain more of the image after the crop, and this helps us too as most of the images are actually focused and centered on the trees. Accuracy boosted to 96%.\n- **v7**: Added AutoAugment, a data augmentation strategy based on the paper [AutoAugment: Learning Augmentation Strategies from Data](https://arxiv.org/pdf/1805.09501.pdf)","metadata":{}},{"cell_type":"code","source":"import torchvision.transforms as transforms\n\n# Declare the transforms for train, valid and test sets.\n# Convert to Tensor\n# Normalize images because the values of images should be loaded between [0 - 1]\ntransforms = {\n \n # RandomHorizontalFlip() & RandomRotation() to augement data in train transformation\n 'train' : transforms.Compose([transforms.Resize(256),\n transforms.AutoAugment(transforms.AutoAugmentPolicy.IMAGENET),\n transforms.RandomHorizontalFlip(),\n transforms.RandomRotation(30),\n transforms.CenterCrop(224),\n transforms.ToTensor(),\n transforms.Normalize(mean=[0.485, 0.456, 0.406],\n std=[0.229, 0.224, 0.225])]),\n \n 'valid' : transforms.Compose([transforms.Resize(256),\n transforms.CenterCrop(224),\n transforms.ToTensor(),\n transforms.Normalize(mean=[0.485, 0.456, 0.406],\n std=[0.229, 0.224, 0.225])]),\n \n 'test' : transforms.Compose([transforms.Resize(256),\n transforms.CenterCrop(224),\n transforms.ToTensor(),\n transforms.Normalize(mean=[0.485, 0.456, 0.406],\n std=[0.229, 0.224, 0.225])])\n}\n\n# number of subprocesses to use for data loading\nnum_workers = 2\n# how many samples per batch to load\nbatch_size = 20\n# where our data is stored\ndata_dir = \"./BarkVN-50_mendeley\"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Data Exploration\n\nWe plot our data distribution and observe that our data has 50 classes/directories with roughly 100 images in each directory.","metadata":{}},{"cell_type":"code","source":"x_plt = []\ny_plt = []\nfor directory in os.listdir(data_dir):\n x_plt.append(directory)\n y_plt.append(len(os.listdir(os.path.join(data_dir, directory))))\n\n# creating the bar plot\nfig, ax = plt.subplots(figsize =(16, 16))\nplt.barh(x_plt, y_plt, color ='maroon')\n# Remove x, y Ticks\nax.xaxis.set_ticks_position('none')\nax.yaxis.set_ticks_position('none')\n \n# Add padding between axes and labels\nax.xaxis.set_tick_params(pad = 5)\nax.yaxis.set_tick_params(pad = 10)\n \n# Show top values\nax.invert_yaxis()\n\n\nplt.ylabel(\"Bark Type\")\nplt.xlabel(\"No. of images\")\nplt.title(\"Bark Texture Dataset\")\nplt.show()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Based on this, we allocated 10% testing, 9% to validation and 81% to training.\n\nWe need to be careful of overfitting since this is a small dataset and hence during training, we will save the model only when the validation accuracy goes down. ","metadata":{}},{"cell_type":"code","source":"# how much % we want to allocate for testing\ntest_size=0.1\n# how much % of the remaining train data we want to allocate for validation\nvalid_size=0.1\n\n# load the dataset\ntrain_dataset = datasets.ImageFolder(\n root=data_dir, transform=transforms[\"train\"],\n)\n\nvalid_dataset = datasets.ImageFolder(\n root=data_dir, transform=transforms[\"valid\"],\n)\n\ntest_dataset = datasets.ImageFolder(\n root=data_dir, transform=transforms[\"test\"],\n)\n\nnum_train = len(train_dataset)\nindices = list(range(num_train))\n\n# Splitting test into test and train\nsplit = int(np.floor(test_size * num_train))\n\nnp.random.shuffle(indices)\n\ntrain_idx, test_idx = indices[split:], indices[:split]\ntrain_sampler = SubsetRandomSampler(train_idx)\ntest_sampler = SubsetRandomSampler(test_idx)\n\n# Splitting remaining test into test and validation\nsplit = int(np.floor(valid_size * num_train))\n\nnp.random.shuffle(indices)\n\ntrain_idx, valid_idx = indices[split:], indices[:split]\ntrain_sampler = SubsetRandomSampler(train_idx)\nvalid_sampler = SubsetRandomSampler(valid_idx)\n\n# Creating dataloaders\ntrain_loader = torch.utils.data.DataLoader(\n train_dataset, batch_size=batch_size, sampler=train_sampler,num_workers=num_workers\n)\nvalid_loader = torch.utils.data.DataLoader(\n valid_dataset, batch_size=batch_size, sampler=valid_sampler, num_workers=num_workers\n)\ntest_loader = torch.utils.data.DataLoader(\n test_dataset, batch_size=batch_size, sampler=test_sampler, num_workers=num_workers\n)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Here we can group the dataloaders into a single object to pass it into our train/test functions as a single object","metadata":{}},{"cell_type":"code","source":"dataloaders = {\n \"train\": train_loader,\n \"valid\": valid_loader,\n \"test\": test_loader\n}","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Get the all labels\nclass_names = train_dataset.classes\nprint(class_names)\nlen(class_names)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Testing to see if the dataloaders work correctly","metadata":{}},{"cell_type":"code","source":"from torchvision import utils\n\ndef visualize_sample_images(inp):\n inp = inp.numpy().transpose((1, 2, 0))\n inp = inp * np.array((0.229, 0.224, 0.225)) + np.array((0.485, 0.456, 0.406))\n inp = np.clip(inp, 0, 1)\n \n fig = plt.figure(figsize=(60, 25))\n plt.axis('off')\n plt.imshow(inp)\n plt.pause(0.001)\n \n# Get a batch of training data. \ninputs, classes = next(iter(train_loader))\n\n# Convert the batch to a grid.\ngrid = utils.make_grid(inputs, nrow=5)\n\n# Display!\nvisualize_sample_images(grid)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Model Architecture\n\nThe ResNet model had been chosen as in all first tests, resnet performed better compared to candidates like efficientnet, alexnet and a custom neural network\n\nSmaller datasets tend to do well with less complex networks and it shows here. Resnet50 works better than ResNet101 or ResNet152\n\n**v4**: Used updated model weights for ResNet50 using new API\n\n**v6**: Moved from ResNet50 to ResNet34, with 1% performance change in testing, but considerable reduction in model execution (training, testing) time. ","metadata":{}},{"cell_type":"code","source":"import torchvision.models as models\nfrom torchvision.models import resnet34, ResNet34_Weights\nfrom torchvision.models import resnet50, ResNet50_Weights\nimport torch.nn as nn\n\n## TODO: Specify model architecture \n#model_transfer = models.resnet34(weights=ResNet34_Weights.DEFAULT)\nmodel_transfer = models.resnet50(weights=ResNet50_Weights.DEFAULT)\n\n# Freeze parameters so we don't backprop through them\nfor param in model_transfer.parameters():\n param.requires_grad = False\n\n# Replace the last fully connected layer with a Linnear layer with 50 out features\nmodel_transfer.fc = nn.Linear(2048, len(class_names)) # Resnet 50+\n#model_transfer.fc = nn.Linear(512, len(class_names)) # Resnet18,34\n\nuse_cuda = torch.cuda.is_available()\n\nif use_cuda:\n model_transfer = model_transfer.cuda()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Model Training Optimization Algorithms\n\nThe optimizers are responsible for the feedforwand and backpropagation mechanisms. In more appropriate words, they will hold the current state and will update the parameters based on the computed gradients.\n\n**v4**: Added L2 regularization while training.\n\nThe Adam optimizer in pytorch does not implement true weight decay but rather uses L2 Regularization. It is mysteriously added in the Optimization functions because loss functions are used during Optimization. More has been discussed in this paper: [Fixing Weight Decay Regularization in Adam](https://openreview.net/pdf?id=rk6qdGgCZ)","metadata":{}},{"cell_type":"code","source":"criterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model_transfer.fc.parameters(), lr=0.001, weight_decay=5e-5)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Training our model\n\nAfter obtaining the data, creating the model architecture, definiting optimization algorithm we can finally begin our training. Here we only save the model every time the validation loss goes down in order to make sure we don't have an overfitted model. If the validation loss stops decreasing for a few epochs, we can know that we have started overfitting and can accordingly lower the training epochs. Conversely, if it keeps decreasing, we can increase the training epochs. \n\nAn important thing to keep in mind is to make sure during training, our model is in training mode by using `model.train()` and during evaluation, it is in evaluation mode by using `model.eval()`. This ensures that during a feedforward operation, the gradients/weights are not updated, if we are currently just evaluating the model on our validation data. And conversely, the gradients/weights *are* updated if we wish to train our parameters.\n\nHere I perform the training on my RTX 2060 Mobile GPU.\n\n**v3**: 30 epochs has been overfitting the model over the validation data. Reduced to 15 epochs. Retains the original 96-97% accuracy as compared to 30 epochs\n\n**v5**: Increased number of epochs to 45 due to new lr decay (L2 regularization)","metadata":{}},{"cell_type":"code","source":"def train(n_epochs, loaders, model, optimizer, criterion, use_cuda, save_path):\n \"\"\"returns trained model\"\"\"\n # initialize tracker for minimum validation loss\n valid_loss_min = np.Inf \n \n for epoch in range(1, n_epochs+1):\n # initialize variables to monitor training and validation loss\n train_loss = 0.0\n valid_loss = 0.0\n \n ###################\n # train the model #\n ###################\n model.train()\n for batch_idx, (data, target) in enumerate(loaders['train']):\n # move to GPU\n if use_cuda:\n data, target = data.cuda(), target.cuda()\n ## find the loss and update the model parameters accordingly\n ## record the average training loss, using something like\n ## train_loss = train_loss + ((1 / (batch_idx + 1)) * (loss.data - train_loss))\n \n # clear the gradients of all optimized variables, initialize weights to zero\n optimizer.zero_grad()\n # forward pass\n output = model(data)\n # calculate batch loss\n loss = criterion(output, target)\n # backward pass\n loss.backward()\n # parameter update\n optimizer.step()\n # update training loss\n train_loss += loss.item() * data.size(0)\n \n ###################### \n # validate the model #\n ######################\n model.eval()\n for batch_idx, (data, target) in enumerate(loaders['valid']):\n # move to GPU\n if use_cuda:\n data, target = data.cuda(), target.cuda()\n ## update the average validation loss\n # forward pass\n output = model(data)\n # batch loss\n loss = criterion(output, target)\n # update validation loss\n valid_loss += loss.item() * data.size(0)\n \n # calculate average losses\n train_loss = train_loss/len(loaders['train'].dataset)\n valid_loss = valid_loss/len(loaders['valid'].dataset)\n \n # print training/validation statistics \n print('Epoch: {} \\tTraining Loss: {:.6f} \\tValidation Loss: {:.6f}'.format(\n epoch, \n train_loss,\n valid_loss\n ))\n \n ## TODO: save the model if validation loss has decreased\n if valid_loss <= valid_loss_min:\n print('Validation loss decreased ({:.6f} --> {:.6f}). Saving model...'.\n format(valid_loss_min, valid_loss))\n torch.save(model.state_dict(), save_path)\n valid_loss_min = valid_loss\n \n # return trained model\n return model\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# train the model\nmodel_transfer = train(45, dataloaders, model_transfer, optimizer, criterion, use_cuda, 'model_transfer.pt')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Testing the model\n\nOnce we finish training, we can finally test our model to see how well it will perform with data it hasn't seen before. It is a fairly simple process, and we get a final accuracy of 97%","metadata":{}},{"cell_type":"code","source":"def test(loaders, model, criterion, use_cuda):\n\n # monitor test loss and accuracy\n test_loss = 0.\n correct = 0.\n total = 0.\n\n model.eval()\n for batch_idx, (data, target) in enumerate(loaders['test']):\n # move to GPU\n if use_cuda:\n data, target = data.cuda(), target.cuda()\n # forward pass: compute predicted outputs by passing inputs to the model\n output = model(data)\n # calculate the loss\n loss = criterion(output, target)\n # update average test loss \n test_loss = test_loss + ((1 / (batch_idx + 1)) * (loss.data - test_loss))\n # convert output probabilities to predicted class\n pred = output.data.max(1, keepdim=True)[1]\n # compare predictions to true label\n correct += np.sum(np.squeeze(pred.eq(target.data.view_as(pred))).cpu().numpy())\n total += data.size(0)\n \n print('Test Loss: {:.6f}\\n'.format(test_loss))\n\n print('\\nTest Accuracy: %2d%% (%2d/%2d)' % (\n 100. * correct / total, correct, total))\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test(dataloaders, model_transfer, criterion, use_cuda)","metadata":{},"execution_count":null,"outputs":[]}]}
--------------------------------------------------------------------------------
/brain-tumor-detection-v1-0-cnn-vgg-16.ipynb:
--------------------------------------------------------------------------------
1 | {"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"**
Brain Tumor Detection with VGG-16 Model
**\n***\n**author**: Ruslan Klymentiev\n\n**date**: 10th June, 2019\n\n**Table of Contents**\n- 1. Project Overview and Objectives \n - 1.1. Data Set Description\n - 1.2. What is Brain Tumor?\n- 2. Setting up the Environment\n- 3. Data Import and Preprocessing\n- 4. CNN Model\n - 4.1. Data Augmentation\n - 4.1.1. Demo\n - 4.1.2. Apply\n - 4.2. Model Building\n - 4.3. Model Performance\n- 5. Conclusions","metadata":{}},{"cell_type":"markdown","source":"# 1. Project Overview and Objectives\n\nThe main purpose of this project was to build a CNN model that would classify if subject has a tumor or not base on MRI scan. I used the [VGG-16](https://www.kaggle.com/navoneel/brain-mri-images-for-brain-tumor-detection) model architecture and weights to train the model for this binary problem. I used `accuracy` as a metric to justify the model performance which can be defined as:\n\n$\\textrm{Accuracy} = \\frac{\\textrm{Number of correclty predicted images}}{\\textrm{Total number of tested images}} \\times 100\\%$\n\nFinal results look as follows:\n\n| Set | Accuracy |\n|:-:|:-:|\n| Validation Set* | ~88% |\n| Test Set* | ~80% |\n \n\\* *Note: there might be some misunderstanding in terms of set names so I want to describe what do I mean by `test` and `validation` set:*\n* *`validation set` - is the set used during the model training to adjust the hyperparameters. *\n* *`test set` - is the small set that I don't touch for the whole training process at all. It's been used for final model performance evaluation.*\n\n## 1.1. Data Set Description\n\nThe image data that was used for this problem is [Brain MRI Images for Brain Tumor Detection](https://www.kaggle.com/navoneel/brain-mri-images-for-brain-tumor-detection). It conists of MRI scans of two classes:\n\n* `NO` - no tumor, encoded as `0`\n* `YES` - tumor, encoded as `1`\n\nUnfortunately, the data set description doesn't hold any information where this MRI scans come from and so on.\n\n## 1.2. What is Brain Tumor?\n\n> A brain tumor occurs when abnormal cells form within the brain. There are two main types of tumors: cancerous (malignant) tumors and benign tumors. Cancerous tumors can be divided into primary tumors, which start within the brain, and secondary tumors, which have spread from elsewhere, known as brain metastasis tumors. All types of brain tumors may produce symptoms that vary depending on the part of the brain involved. These symptoms may include headaches, seizures, problems with vision, vomiting and mental changes. The headache is classically worse in the morning and goes away with vomiting. Other symptoms may include difficulty walking, speaking or with sensations. As the disease progresses, unconsciousness may occur.\n>\n> \n>\n> *Brain metastasis in the right cerebral hemisphere from lung cancer, shown on magnetic resonance imaging.*\n\nSource: [Wikipedia](https://en.wikipedia.org/wiki/Brain_tumor)","metadata":{}},{"cell_type":"markdown","source":"# 2. Setting up the Environment","metadata":{}},{"cell_type":"code","source":"from IPython.display import clear_output\n!pip install imutils\nclear_output()","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np \nfrom tqdm import tqdm\nimport cv2\nimport os\nimport shutil\nimport itertools\nimport imutils\nimport matplotlib.pyplot as plt\nfrom sklearn.preprocessing import LabelBinarizer\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import accuracy_score, confusion_matrix\n\nimport plotly.graph_objs as go\nfrom plotly.offline import init_notebook_mode, iplot\nfrom plotly import tools\n\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.applications.vgg16 import VGG16, preprocess_input\nfrom keras import layers\nfrom keras.models import Model, Sequential\nfrom keras.optimizers import Adam, RMSprop\nfrom keras.callbacks import EarlyStopping\n\ninit_notebook_mode(connected=True)\nRANDOM_SEED = 123","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Right now all images are in one folder with `yes` and `no` subfolders. I will split the data into `train`, `val` and `test` folders which makes its easier to work for me. The new folder heirarchy will look as follows:","metadata":{}},{"cell_type":"code","source":"!apt-get install tree\nclear_output()\n# create new folders\n!mkdir TRAIN TEST VAL TRAIN/YES TRAIN/NO TEST/YES TEST/NO VAL/YES VAL/NO\n!tree -d","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"IMG_PATH = '../input/brain-mri-images-for-brain-tumor-detection/brain_tumor_dataset/'\n# split the data by train/val/test\nfor CLASS in os.listdir(IMG_PATH):\n if not CLASS.startswith('.'):\n IMG_NUM = len(os.listdir(IMG_PATH + CLASS))\n for (n, FILE_NAME) in enumerate(os.listdir(IMG_PATH + CLASS)):\n img = IMG_PATH + CLASS + '/' + FILE_NAME\n if n < 5:\n shutil.copy(img, 'TEST/' + CLASS.upper() + '/' + FILE_NAME)\n elif n < 0.8*IMG_NUM:\n shutil.copy(img, 'TRAIN/'+ CLASS.upper() + '/' + FILE_NAME)\n else:\n shutil.copy(img, 'VAL/'+ CLASS.upper() + '/' + FILE_NAME)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 3. Data Import and Preprocessing","metadata":{}},{"cell_type":"code","source":"def load_data(dir_path, img_size=(100,100)):\n \"\"\"\n Load resized images as np.arrays to workspace\n \"\"\"\n X = []\n y = []\n i = 0\n labels = dict()\n for path in tqdm(sorted(os.listdir(dir_path))):\n if not path.startswith('.'):\n labels[i] = path\n for file in os.listdir(dir_path + path):\n if not file.startswith('.'):\n img = cv2.imread(dir_path + path + '/' + file)\n X.append(img)\n y.append(i)\n i += 1\n X = np.array(X)\n y = np.array(y)\n print(f'{len(X)} images loaded from {dir_path} directory.')\n return X, y, labels\n\n\n\ndef plot_confusion_matrix(cm, classes,\n normalize=False,\n title='Confusion matrix',\n cmap=plt.cm.Blues):\n \"\"\"\n This function prints and plots the confusion matrix.\n Normalization can be applied by setting `normalize=True`.\n \"\"\"\n plt.figure(figsize = (6,6))\n plt.imshow(cm, interpolation='nearest', cmap=cmap)\n plt.title(title)\n plt.colorbar()\n tick_marks = np.arange(len(classes))\n plt.xticks(tick_marks, classes, rotation=90)\n plt.yticks(tick_marks, classes)\n if normalize:\n cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]\n\n thresh = cm.max() / 2.\n cm = np.round(cm,2)\n for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):\n plt.text(j, i, cm[i, j],\n horizontalalignment=\"center\",\n color=\"white\" if cm[i, j] > thresh else \"black\")\n plt.tight_layout()\n plt.ylabel('True label')\n plt.xlabel('Predicted label')\n plt.show()","metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TRAIN_DIR = 'TRAIN/'\nTEST_DIR = 'TEST/'\nVAL_DIR = 'VAL/'\nIMG_SIZE = (224,224)\n\n# use predefined function to load the image data into workspace\nX_train, y_train, labels = load_data(TRAIN_DIR, IMG_SIZE)\nX_test, y_test, _ = load_data(TEST_DIR, IMG_SIZE)\nX_val, y_val, _ = load_data(VAL_DIR, IMG_SIZE)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Let's take a look at the distribution of classes among sets:","metadata":{}},{"cell_type":"code","source":"y = dict()\ny[0] = []\ny[1] = []\nfor set_name in (y_train, y_val, y_test):\n y[0].append(np.sum(set_name == 0))\n y[1].append(np.sum(set_name == 1))\n\ntrace0 = go.Bar(\n x=['Train Set', 'Validation Set', 'Test Set'],\n y=y[0],\n name='No',\n marker=dict(color='#33cc33'),\n opacity=0.7\n)\ntrace1 = go.Bar(\n x=['Train Set', 'Validation Set', 'Test Set'],\n y=y[1],\n name='Yes',\n marker=dict(color='#ff3300'),\n opacity=0.7\n)\ndata = [trace0, trace1]\nlayout = go.Layout(\n title='Count of classes in each set',\n xaxis={'title': 'Set'},\n yaxis={'title': 'Count'}\n)\nfig = go.Figure(data, layout)\niplot(fig)","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_samples(X, y, labels_dict, n=50):\n \"\"\"\n Creates a gridplot for desired number of images (n) from the specified set\n \"\"\"\n for index in range(len(labels_dict)):\n imgs = X[np.argwhere(y == index)][:n]\n j = 10\n i = int(n/j)\n\n plt.figure(figsize=(15,6))\n c = 1\n for img in imgs:\n plt.subplot(i,j,c)\n plt.imshow(img[0])\n\n plt.xticks([])\n plt.yticks([])\n c += 1\n plt.suptitle('Tumor: {}'.format(labels_dict[index]))\n plt.show()","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_samples(X_train, y_train, labels, 30)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"As you can see, images have different `width` and `height` and diffent size of \"black corners\". Since the image size for VGG-16 imput layer is `(224,224)` some wide images may look weird after resizing. Histogram of ratio distributions (`ratio = width/height`):","metadata":{}},{"cell_type":"code","source":"RATIO_LIST = []\nfor set in (X_train, X_test, X_val):\n for img in set:\n RATIO_LIST.append(img.shape[1]/img.shape[0])\n \nplt.hist(RATIO_LIST)\nplt.title('Distribution of Image Ratios')\nplt.xlabel('Ratio Value')\nplt.ylabel('Count')\nplt.show()","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The first step of \"normalization\" would be to crop the brain out of the images. I used technique which was perfectly described in [pyimagesearch](https://www.pyimagesearch.com/2016/04/11/finding-extreme-points-in-contours-with-opencv/) blog and I highly suggest to looks deeper into it.","metadata":{}},{"cell_type":"code","source":"def crop_imgs(set_name, add_pixels_value=0):\n \"\"\"\n Finds the extreme points on the image and crops the rectangular out of them\n \"\"\"\n set_new = []\n for img in set_name:\n gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)\n gray = cv2.GaussianBlur(gray, (5, 5), 0)\n\n # threshold the image, then perform a series of erosions +\n # dilations to remove any small regions of noise\n thresh = cv2.threshold(gray, 45, 255, cv2.THRESH_BINARY)[1]\n thresh = cv2.erode(thresh, None, iterations=2)\n thresh = cv2.dilate(thresh, None, iterations=2)\n\n # find contours in thresholded image, then grab the largest one\n cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n cnts = imutils.grab_contours(cnts)\n c = max(cnts, key=cv2.contourArea)\n\n # find the extreme points\n extLeft = tuple(c[c[:, :, 0].argmin()][0])\n extRight = tuple(c[c[:, :, 0].argmax()][0])\n extTop = tuple(c[c[:, :, 1].argmin()][0])\n extBot = tuple(c[c[:, :, 1].argmax()][0])\n\n ADD_PIXELS = add_pixels_value\n new_img = img[extTop[1]-ADD_PIXELS:extBot[1]+ADD_PIXELS, extLeft[0]-ADD_PIXELS:extRight[0]+ADD_PIXELS].copy()\n set_new.append(new_img)\n\n return np.array(set_new)","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Let's look at example what this function will do with MRI scans:","metadata":{}},{"cell_type":"code","source":"img = cv2.imread('../input/brain-mri-images-for-brain-tumor-detection/brain_tumor_dataset/yes/Y108.jpg')\nimg = cv2.resize(\n img,\n dsize=IMG_SIZE,\n interpolation=cv2.INTER_CUBIC\n )\ngray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)\ngray = cv2.GaussianBlur(gray, (5, 5), 0)\n\n# threshold the image, then perform a series of erosions +\n# dilations to remove any small regions of noise\nthresh = cv2.threshold(gray, 45, 255, cv2.THRESH_BINARY)[1]\nthresh = cv2.erode(thresh, None, iterations=2)\nthresh = cv2.dilate(thresh, None, iterations=2)\n\n# find contours in thresholded image, then grab the largest one\ncnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\ncnts = imutils.grab_contours(cnts)\nc = max(cnts, key=cv2.contourArea)\n\n# find the extreme points\nextLeft = tuple(c[c[:, :, 0].argmin()][0])\nextRight = tuple(c[c[:, :, 0].argmax()][0])\nextTop = tuple(c[c[:, :, 1].argmin()][0])\nextBot = tuple(c[c[:, :, 1].argmax()][0])\n\n# add contour on the image\nimg_cnt = cv2.drawContours(img.copy(), [c], -1, (0, 255, 255), 4)\n\n# add extreme points\nimg_pnt = cv2.circle(img_cnt.copy(), extLeft, 8, (0, 0, 255), -1)\nimg_pnt = cv2.circle(img_pnt, extRight, 8, (0, 255, 0), -1)\nimg_pnt = cv2.circle(img_pnt, extTop, 8, (255, 0, 0), -1)\nimg_pnt = cv2.circle(img_pnt, extBot, 8, (255, 255, 0), -1)\n\n# crop\nADD_PIXELS = 0\nnew_img = img[extTop[1]-ADD_PIXELS:extBot[1]+ADD_PIXELS, extLeft[0]-ADD_PIXELS:extRight[0]+ADD_PIXELS].copy()","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(15,6))\nplt.subplot(141)\nplt.imshow(img)\nplt.xticks([])\nplt.yticks([])\nplt.title('Step 1. Get the original image')\nplt.subplot(142)\nplt.imshow(img_cnt)\nplt.xticks([])\nplt.yticks([])\nplt.title('Step 2. Find the biggest contour')\nplt.subplot(143)\nplt.imshow(img_pnt)\nplt.xticks([])\nplt.yticks([])\nplt.title('Step 3. Find the extreme points')\nplt.subplot(144)\nplt.imshow(new_img)\nplt.xticks([])\nplt.yticks([])\nplt.title('Step 4. Crop the image')\nplt.show()","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# apply this for each set\nX_train_crop = crop_imgs(set_name=X_train)\nX_val_crop = crop_imgs(set_name=X_val)\nX_test_crop = crop_imgs(set_name=X_test)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_samples(X_train_crop, y_train, labels, 30)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def save_new_images(x_set, y_set, folder_name):\n i = 0\n for (img, imclass) in zip(x_set, y_set):\n if imclass == 0:\n cv2.imwrite(folder_name+'NO/'+str(i)+'.jpg', img)\n else:\n cv2.imwrite(folder_name+'YES/'+str(i)+'.jpg', img)\n i += 1","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# saving new images to the folder\n!mkdir TRAIN_CROP TEST_CROP VAL_CROP TRAIN_CROP/YES TRAIN_CROP/NO TEST_CROP/YES TEST_CROP/NO VAL_CROP/YES VAL_CROP/NO\n\nsave_new_images(X_train_crop, y_train, folder_name='TRAIN_CROP/')\nsave_new_images(X_val_crop, y_val, folder_name='VAL_CROP/')\nsave_new_images(X_test_crop, y_test, folder_name='TEST_CROP/')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The next step would be resizing images to `(224,224)` and applying preprocessing needed for VGG-16 model input.","metadata":{}},{"cell_type":"code","source":"def preprocess_imgs(set_name, img_size):\n \"\"\"\n Resize and apply VGG-15 preprocessing\n \"\"\"\n set_new = []\n for img in set_name:\n img = cv2.resize(\n img,\n dsize=img_size,\n interpolation=cv2.INTER_CUBIC\n )\n set_new.append(preprocess_input(img))\n return np.array(set_new)","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train_prep = preprocess_imgs(set_name=X_train_crop, img_size=IMG_SIZE)\nX_test_prep = preprocess_imgs(set_name=X_test_crop, img_size=IMG_SIZE)\nX_val_prep = preprocess_imgs(set_name=X_val_crop, img_size=IMG_SIZE)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# plot_samples(X_train_prep, y_train, labels, 30)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 4. CNN Model\n\nI was using [Transfer Learning](https://towardsdatascience.com/keras-transfer-learning-for-beginners-6c9b8b7143e) with VGG-16 architecture and weights as a base model.\n\n## 4.1. Data Augmentation\n\nSince I had small data set I used the technique called [Data Augmentation](https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html) which helps to \"increase\" the size of training set.\n\n### 4.1.1. Demo\n\nThat's the example from one image how does augmentation look like.","metadata":{}},{"cell_type":"code","source":"# set the paramters we want to change randomly\ndemo_datagen = ImageDataGenerator(\n rotation_range=15,\n width_shift_range=0.05,\n height_shift_range=0.05,\n rescale=1./255,\n shear_range=0.05,\n brightness_range=[0.1, 1.5],\n horizontal_flip=True,\n vertical_flip=True\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.mkdir('preview')\nx = X_train_crop[0] \nx = x.reshape((1,) + x.shape) \n\ni = 0\nfor batch in demo_datagen.flow(x, batch_size=1, save_to_dir='preview', save_prefix='aug_img', save_format='jpg'):\n i += 1\n if i > 20:\n break ","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(X_train_crop[0])\nplt.xticks([])\nplt.yticks([])\nplt.title('Original Image')\nplt.show()\n\nplt.figure(figsize=(15,6))\ni = 1\nfor img in os.listdir('preview/'):\n img = cv2.cv2.imread('preview/' + img)\n img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n plt.subplot(3,7,i)\n plt.imshow(img)\n plt.xticks([])\n plt.yticks([])\n i += 1\n if i > 3*7:\n break\nplt.suptitle('Augemented Images')\nplt.show()","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!rm -rf preview/","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 4.1.2. Apply","metadata":{}},{"cell_type":"code","source":"TRAIN_DIR = 'TRAIN_CROP/'\nVAL_DIR = 'VAL_CROP/'\n\ntrain_datagen = ImageDataGenerator(\n rotation_range=15,\n width_shift_range=0.1,\n height_shift_range=0.1,\n shear_range=0.1,\n brightness_range=[0.5, 1.5],\n horizontal_flip=True,\n vertical_flip=True,\n preprocessing_function=preprocess_input\n)\n\ntest_datagen = ImageDataGenerator(\n preprocessing_function=preprocess_input\n)\n\n\ntrain_generator = train_datagen.flow_from_directory(\n TRAIN_DIR,\n color_mode='rgb',\n target_size=IMG_SIZE,\n batch_size=32,\n class_mode='binary',\n seed=RANDOM_SEED\n)\n\n\nvalidation_generator = test_datagen.flow_from_directory(\n VAL_DIR,\n color_mode='rgb',\n target_size=IMG_SIZE,\n batch_size=16,\n class_mode='binary',\n seed=RANDOM_SEED\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 4.2. Model Building","metadata":{}},{"cell_type":"code","source":"# load base model\nvgg16_weight_path = '../input/keras-pretrained-models/vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5'\nbase_model = VGG16(\n weights=vgg16_weight_path,\n include_top=False, \n input_shape=IMG_SIZE + (3,)\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"NUM_CLASSES = 1\n\nmodel = Sequential()\nmodel.add(base_model)\nmodel.add(layers.Flatten())\nmodel.add(layers.Dropout(0.5))\nmodel.add(layers.Dense(NUM_CLASSES, activation='sigmoid'))\n\nmodel.layers[0].trainable = False\n\nmodel.compile(\n loss='binary_crossentropy',\n optimizer=RMSprop(lr=1e-4),\n metrics=['accuracy']\n)\n\nmodel.summary()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"EPOCHS = 30\nes = EarlyStopping(\n monitor='val_acc', \n mode='max',\n patience=6\n)\n\nhistory = model.fit_generator(\n train_generator,\n steps_per_epoch=50,\n epochs=EPOCHS,\n validation_data=validation_generator,\n validation_steps=25,\n callbacks=[es]\n)","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 4.3. Model Performance","metadata":{}},{"cell_type":"code","source":"# plot model performance\nacc = history.history['acc']\nval_acc = history.history['val_acc']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\nepochs_range = range(1, len(history.epoch) + 1)\n\nplt.figure(figsize=(15,5))\n\nplt.subplot(1, 2, 1)\nplt.plot(epochs_range, acc, label='Train Set')\nplt.plot(epochs_range, val_acc, label='Val Set')\nplt.legend(loc=\"best\")\nplt.xlabel('Epochs')\nplt.ylabel('Accuracy')\nplt.title('Model Accuracy')\n\nplt.subplot(1, 2, 2)\nplt.plot(epochs_range, loss, label='Train Set')\nplt.plot(epochs_range, val_loss, label='Val Set')\nplt.legend(loc=\"best\")\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.title('Model Loss')\n\nplt.tight_layout()\nplt.show()","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# validate on val set\npredictions = model.predict(X_val_prep)\npredictions = [1 if x>0.5 else 0 for x in predictions]\n\naccuracy = accuracy_score(y_val, predictions)\nprint('Val Accuracy = %.2f' % accuracy)\n\nconfusion_mtx = confusion_matrix(y_val, predictions) \ncm = plot_confusion_matrix(confusion_mtx, classes = list(labels.items()), normalize=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# validate on test set\npredictions = model.predict(X_test_prep)\npredictions = [1 if x>0.5 else 0 for x in predictions]\n\naccuracy = accuracy_score(y_test, predictions)\nprint('Test Accuracy = %.2f' % accuracy)\n\nconfusion_mtx = confusion_matrix(y_test, predictions) \ncm = plot_confusion_matrix(confusion_mtx, classes = list(labels.items()), normalize=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now let's take a look at the images from the `test set` that were misclassified:","metadata":{}},{"cell_type":"code","source":"ind_list = np.argwhere((y_test == predictions) == False)[:, -1]\nif ind_list.size == 0:\n print('There are no missclassified images.')\nelse:\n for i in ind_list:\n plt.figure()\n plt.imshow(X_test_crop[i])\n plt.xticks([])\n plt.yticks([])\n plt.title(f'Actual class: {y_val[i]}\\nPredicted class: {predictions[i]}')\n plt.show()","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"First scan looks a bit misleading - what is that light spot in the middle? 🤔 I can clearly see why model classified it as `Tumor`.","metadata":{}},{"cell_type":"markdown","source":"# 5. Conclusions\n\nThis project was a combination of CNN model classification problem (to predict wheter the subject has brain tumor or not) & Computer Vision problem (to automate the process of brain cropping from MRI scans). The final accuracy is much higher than 50% baseline (random guess). However, it could be increased by larger number of train images or through model hyperparameters tuning.","metadata":{}},{"cell_type":"code","source":"# clean up the space\n!rm -rf TRAIN TEST VAL TRAIN_CROP TEST_CROP VAL_CROP\n# save the model\nmodel.save('2019-06-07_VGG_model.h5')","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]}]}
--------------------------------------------------------------------------------
/tensorflow-pneumonia-classification-on-x-rays.ipynb:
--------------------------------------------------------------------------------
1 | {"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 1. Introduction + Set-up\n\nMachine learning has a phenomenal range of applications, including in health and diagnostics. This tutorial will explain the complete pipeline from loading data to predicting results, and it will explain how to build an X-ray image classification model from scratch to predict whether an X-ray scan shows presence of pneumonia. This is especially useful during these current times as COVID-19 is known to cause pneumonia.\n\nThis tutorial will explain how to utilize TPUs efficiently, load in image data, build and train a convolution neural network, finetune and regularize the model, and predict results. Data augmentation is not included in the model because X-ray scans are only taken in a specific orientation, and variations such as flips and rotations will not exist in real X-ray images. For a tutorial on image data augmentation, check out this [tutorial](https://www.kaggle.com/amyjang/tensorflow-data-augmentation-efficientnet).\n\nRun the following cell to load the necessary packages. Make sure to change the Accelerator on the right to `TPU`.","metadata":{}},{"cell_type":"code","source":"import re\nimport os\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\nfrom kaggle_datasets import KaggleDatasets\nimport matplotlib.pyplot as plt\nfrom sklearn.model_selection import train_test_split\n\ntry:\n tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n print('Device:', tpu.master())\n tf.config.experimental_connect_to_cluster(tpu)\n tf.tpu.experimental.initialize_tpu_system(tpu)\n strategy = tf.distribute.experimental.TPUStrategy(tpu)\nexcept:\n strategy = tf.distribute.get_strategy()\nprint('Number of replicas:', strategy.num_replicas_in_sync)\n \nprint(tf.__version__)\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We need a Google Cloud link to our data to load the data using a TPU. While we're at it, we instantiate constant variables. It is generally better practice to use constant variables instead of hard-coding numbers.","metadata":{}},{"cell_type":"code","source":"AUTOTUNE = tf.data.experimental.AUTOTUNE\nGCS_PATH = KaggleDatasets().get_gcs_path()\nBATCH_SIZE = 16 * strategy.num_replicas_in_sync\nIMAGE_SIZE = [180, 180]\nEPOCHS = 25","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 2. Load the data\n\nThe Chest X-ray data we are using from [*Cell*](https://www.kaggle.com/paultimothymooney/chest-xray-pneumonia) divides the data into train, val, and test files. There are only 16 files in the validation folder, and we would prefer to have a less extreme division between the training and the validation set. We will append the validation files and create a new split that resembes the standard 80:20 division instead.","metadata":{}},{"cell_type":"code","source":"filenames = tf.io.gfile.glob(str(GCS_PATH + '/chest_xray/train/*/*'))\nfilenames.extend(tf.io.gfile.glob(str(GCS_PATH + '/chest_xray/val/*/*')))\n\ntrain_filenames, val_filenames = train_test_split(filenames, test_size=0.2)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Run the following cell to see how many healthy/normal chest X-rays we have and how many pneumonia chest X-rays we have.","metadata":{}},{"cell_type":"code","source":"COUNT_NORMAL = len([filename for filename in train_filenames if \"NORMAL\" in filename])\nprint(\"Normal images count in training set: \" + str(COUNT_NORMAL))\n\nCOUNT_PNEUMONIA = len([filename for filename in train_filenames if \"PNEUMONIA\" in filename])\nprint(\"Pneumonia images count in training set: \" + str(COUNT_PNEUMONIA))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Notice that the there are way more images that are classified as pneumonia than normal. This shows that we have a imbalance in our data. We will correct for this imbalance later on in our notebook.","metadata":{}},{"cell_type":"code","source":"train_list_ds = tf.data.Dataset.from_tensor_slices(train_filenames)\nval_list_ds = tf.data.Dataset.from_tensor_slices(val_filenames)\n\nfor f in train_list_ds.take(5):\n print(f.numpy())","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Run the following cell to see how many images we have in our training dataset and how many images we have in our validation set. Verify that the ratio of images is 80:20.","metadata":{}},{"cell_type":"code","source":"TRAIN_IMG_COUNT = tf.data.experimental.cardinality(train_list_ds).numpy()\nprint(\"Training images count: \" + str(TRAIN_IMG_COUNT))\n\nVAL_IMG_COUNT = tf.data.experimental.cardinality(val_list_ds).numpy()\nprint(\"Validating images count: \" + str(VAL_IMG_COUNT))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"As expected, we have two labels for our images.","metadata":{}},{"cell_type":"code","source":"CLASS_NAMES = np.array([str(tf.strings.split(item, os.path.sep)[-1].numpy())[2:-1]\n for item in tf.io.gfile.glob(str(GCS_PATH + \"/chest_xray/train/*\"))])\nCLASS_NAMES","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Currently our dataset is just a list of filenames. We want to map each filename to the corresponding (image, label) pair. The following methods will help us do that.\n\nAs we only have two labels, we will rewrite the label so that `1` or `True` indicates pneumonia and `0` or `False` indicates normal.","metadata":{}},{"cell_type":"code","source":"def get_label(file_path):\n # convert the path to a list of path components\n parts = tf.strings.split(file_path, os.path.sep)\n # The second to last is the class-directory\n return parts[-2] == \"PNEUMONIA\"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The images originally have values that range from [0, 255]. CNNs work better with smaller numbers so we will scale this down.","metadata":{}},{"cell_type":"code","source":"def decode_img(img):\n # convert the compressed string to a 3D uint8 tensor\n img = tf.image.decode_jpeg(img, channels=3)\n # Use `convert_image_dtype` to convert to floats in the [0,1] range.\n img = tf.image.convert_image_dtype(img, tf.float32)\n # resize the image to the desired size.\n return tf.image.resize(img, IMAGE_SIZE)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def process_path(file_path):\n label = get_label(file_path)\n # load the raw data from the file as a string\n img = tf.io.read_file(file_path)\n img = decode_img(img)\n return img, label","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_ds = train_list_ds.map(process_path, num_parallel_calls=AUTOTUNE)\n\nval_ds = val_list_ds.map(process_path, num_parallel_calls=AUTOTUNE)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Let's visualize the shape of an (image, label) pair.","metadata":{}},{"cell_type":"code","source":"for image, label in train_ds.take(1):\n print(\"Image shape: \", image.numpy().shape)\n print(\"Label: \", label.numpy())","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Load and format the test data as well.","metadata":{}},{"cell_type":"code","source":"test_list_ds = tf.data.Dataset.list_files(str(GCS_PATH + '/chest_xray/test/*/*'))\nTEST_IMAGE_COUNT = tf.data.experimental.cardinality(test_list_ds).numpy()\ntest_ds = test_list_ds.map(process_path, num_parallel_calls=AUTOTUNE)\ntest_ds = test_ds.batch(BATCH_SIZE)\n\nTEST_IMAGE_COUNT","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 3. Visualize the dataset\n\nFirst, let's use buffered prefetching so we can yield data from disk without having I/O become blocking.","metadata":{}},{"cell_type":"code","source":"def prepare_for_training(ds, cache=True, shuffle_buffer_size=1000):\n # This is a small dataset, only load it once, and keep it in memory.\n # use `.cache(filename)` to cache preprocessing work for datasets that don't\n # fit in memory.\n if cache:\n if isinstance(cache, str):\n ds = ds.cache(cache)\n else:\n ds = ds.cache()\n\n ds = ds.shuffle(buffer_size=shuffle_buffer_size)\n\n # Repeat forever\n ds = ds.repeat()\n\n ds = ds.batch(BATCH_SIZE)\n\n # `prefetch` lets the dataset fetch batches in the background while the model\n # is training.\n ds = ds.prefetch(buffer_size=AUTOTUNE)\n\n return ds","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Call the next batch iteration of the training data.","metadata":{}},{"cell_type":"code","source":"train_ds = prepare_for_training(train_ds)\nval_ds = prepare_for_training(val_ds)\n\nimage_batch, label_batch = next(iter(train_ds))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Define the method to show the images in the batch.","metadata":{}},{"cell_type":"code","source":"def show_batch(image_batch, label_batch):\n plt.figure(figsize=(10,10))\n for n in range(25):\n ax = plt.subplot(5,5,n+1)\n plt.imshow(image_batch[n])\n if label_batch[n]:\n plt.title(\"PNEUMONIA\")\n else:\n plt.title(\"NORMAL\")\n plt.axis(\"off\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"As the method takes in numpy arrays as its parameters, call the numpy function on the batches to return the tensor in numpy array form.","metadata":{}},{"cell_type":"code","source":"show_batch(image_batch.numpy(), label_batch.numpy())","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 4. Build the CNN\n\nTo make our model more modular and easier to understand, let's define some blocks. As we're building a convolution neural network, we'll create a convolution block and a dense layer block.\n\nThe architecture for this CNN has been inspired by this [article](https://towardsdatascience.com/deep-learning-for-detecting-pneumonia-from-x-ray-images-fc9a3d9fdba8).","metadata":{}},{"cell_type":"code","source":"def conv_block(filters):\n block = tf.keras.Sequential([\n tf.keras.layers.SeparableConv2D(filters, 3, activation='relu', padding='same'),\n tf.keras.layers.SeparableConv2D(filters, 3, activation='relu', padding='same'),\n tf.keras.layers.BatchNormalization(),\n tf.keras.layers.MaxPool2D()\n ]\n )\n \n return block","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def dense_block(units, dropout_rate):\n block = tf.keras.Sequential([\n tf.keras.layers.Dense(units, activation='relu'),\n tf.keras.layers.BatchNormalization(),\n tf.keras.layers.Dropout(dropout_rate)\n ])\n \n return block","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The following method will define the function to build our model for us. The Dropout layers are important as they \"drop out,\" hence the name, certain nodes to reduce the likelikhood of the model overfitting. We want to end the model with a Dense layer of one node, as this will be the output that determines if an X-ray shows an image of pneumonia.","metadata":{}},{"cell_type":"code","source":"def build_model():\n model = tf.keras.Sequential([\n tf.keras.Input(shape=(IMAGE_SIZE[0], IMAGE_SIZE[1], 3)),\n \n tf.keras.layers.Conv2D(16, 3, activation='relu', padding='same'),\n tf.keras.layers.Conv2D(16, 3, activation='relu', padding='same'),\n tf.keras.layers.MaxPool2D(),\n \n conv_block(32),\n conv_block(64),\n \n conv_block(128),\n tf.keras.layers.Dropout(0.2),\n \n conv_block(256),\n tf.keras.layers.Dropout(0.2),\n \n tf.keras.layers.Flatten(),\n dense_block(512, 0.7),\n dense_block(128, 0.5),\n dense_block(64, 0.3),\n \n tf.keras.layers.Dense(1, activation='sigmoid')\n ])\n \n return model","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 5. Correct for data imbalance\n\nWe saw earlier in this notebook that the data was imbalanced, with more images classified as pneumonia than normal. We will correct for that in this following section.","metadata":{}},{"cell_type":"code","source":"initial_bias = np.log([COUNT_PNEUMONIA/COUNT_NORMAL])\ninitial_bias","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"weight_for_0 = (1 / COUNT_NORMAL)*(TRAIN_IMG_COUNT)/2.0 \nweight_for_1 = (1 / COUNT_PNEUMONIA)*(TRAIN_IMG_COUNT)/2.0\n\nclass_weight = {0: weight_for_0, 1: weight_for_1}\n\nprint('Weight for class 0: {:.2f}'.format(weight_for_0))\nprint('Weight for class 1: {:.2f}'.format(weight_for_1))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The weight for class `0` (Normal) is a lot higher than the weight for class `1` (Pneumonia). Because there are less normal images, each normal image will be weighted more to balance the data as the CNN works best when the training data is balanced.","metadata":{}},{"cell_type":"markdown","source":"# 6. Train the model\n\nSince there are only two possible labels for the image, we will be using the `binary_crossentropy` loss. When we fit the model, identify the class weights. Because we are using a TPU, training will be relatively quick.\n\nFor our metrics, we want to include precision and recall as they will provide use with a more informed picture of how good our model is. Accuracy tells us what fractions are the labels are correct. Since our data is not balanced, accuracy might give a skewed sense of a good model (i.e. a model that always predicts PNEUMONIA will be 74% accurate but is not a good model).\n\nPrecision is the number of true positives (TP) over the sum of TP and false positives (FP). It shows what fraction of labeled positives are actually correct.\n\nRecall is the number of TP over the sum of TP and false negatves (FN). It shows what fraction of actual positives are correct.","metadata":{}},{"cell_type":"code","source":"with strategy.scope():\n model = build_model()\n\n METRICS = [\n 'accuracy',\n tf.keras.metrics.Precision(name='precision'),\n tf.keras.metrics.Recall(name='recall')\n ]\n \n model.compile(\n optimizer='adam',\n loss='binary_crossentropy',\n metrics=METRICS\n )","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"From exploring the data and the model, I noticed that the training for the model has a slow start. However, after 25 epochs, the model slowly starts to converge.","metadata":{}},{"cell_type":"code","source":"history = model.fit(\n train_ds,\n steps_per_epoch=TRAIN_IMG_COUNT // BATCH_SIZE,\n epochs=EPOCHS,\n validation_data=val_ds,\n validation_steps=VAL_IMG_COUNT // BATCH_SIZE,\n class_weight=class_weight,\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 7. Finetune the model\n\nFinetuning is an art when it comes to Machine Learning, and there are many ways to adjust the model in efforts to improve it. Finetuning is beyond the scope of this notebook, but check out this [article](https://www.pyimagesearch.com/2019/06/03/fine-tuning-with-keras-and-deep-learning/) for more information.\n\nFor our purposes, we'll use Keras callbacks to further finetune our model. The checkpoint callback saves the best weights of the model, so next time we want to use the model, we do not have to spend time training it. The early stopping callback stops the training process when the model starts becoming stagnant, or even worse, when the model starts overfitting. Since we set `restore_best_weights` to `True`, the returned model at the end of the training process will be the model with the best weights (i.e. low loss and high accuracy).","metadata":{}},{"cell_type":"code","source":"checkpoint_cb = tf.keras.callbacks.ModelCheckpoint(\"xray_model.h5\",\n save_best_only=True)\n\nearly_stopping_cb = tf.keras.callbacks.EarlyStopping(patience=10,\n restore_best_weights=True)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We also want to finetune our learning rate. Too high of a learning rate will cause the model to diverge. Too small of a learning rate will cause the model to be too slow. We implement the exponential learning rate scheduling method below.","metadata":{}},{"cell_type":"code","source":"def exponential_decay(lr0, s):\n def exponential_decay_fn(epoch):\n return lr0 * 0.1 **(epoch / s)\n return exponential_decay_fn\n\nexponential_decay_fn = exponential_decay(0.01, 20)\n\nlr_scheduler = tf.keras.callbacks.LearningRateScheduler(exponential_decay_fn)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(\n train_ds,\n steps_per_epoch=TRAIN_IMG_COUNT // BATCH_SIZE,\n epochs=100,\n validation_data=val_ds,\n validation_steps=VAL_IMG_COUNT // BATCH_SIZE,\n class_weight=class_weight,\n callbacks=[checkpoint_cb, early_stopping_cb, lr_scheduler]\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 8. Visualizing model performance\n\nLet's plot the model accuracy and loss for the training and the validating set. These plots show the accuracy and loss values for the second round of training. Since we initially trained the model with 30 epochs, these would be epochs 31-45. Note that no random seed is specified for this notebook. For your notebook, there might be slight variance.","metadata":{}},{"cell_type":"code","source":"fig, ax = plt.subplots(1, 4, figsize=(20, 3))\nax = ax.ravel()\n\nfor i, met in enumerate(['precision', 'recall', 'accuracy', 'loss']):\n ax[i].plot(history.history[met])\n ax[i].plot(history.history['val_' + met])\n ax[i].set_title('Model {}'.format(met))\n ax[i].set_xlabel('epochs')\n ax[i].set_ylabel(met)\n ax[i].legend(['train', 'val'])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We see that the accuracy for our model is around 98%. Finetune the model further to see if we can achieve a higher accuracy.","metadata":{}},{"cell_type":"markdown","source":"# 9. Predict and evaluate results\n\nLet's evaluate the model on our test data!","metadata":{}},{"cell_type":"code","source":"loss, acc, prec, rec = model.evaluate(test_ds)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We see that our accuracy on our test data is 83%, which is lower than the accuracy for our validating set. This may indicate overfitting. Try finetuning the model further to decrease overfitting to the training and validation sets.\n\nOur recall is greater than our precision, indicating that almost all pneumonia images are correctly identified but some normal images are falsely identified. We should aim to increase our precision.","metadata":{}},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}
--------------------------------------------------------------------------------
/wcwp-climate-master.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SARTHAK2511/Data-Science-Projects/4f5e6a5ec6ab14d699ba5f4f4564420387de7abe/wcwp-climate-master.zip
--------------------------------------------------------------------------------