├── .gitattributes ├── README.md ├── installation_scripts ├── linux_install.sh ├── linux_requirements.txt ├── mac_install.sh ├── mac_requirements.txt ├── windows_install.bat └── windows_requirements.txt ├── la_croix_model ├── keras_model.h5 └── labels.txt ├── tm_obj_det.py └── yolo_obj_det.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Teachable Machine Object Detection 2 | This project uses a machine learning model that I created in Teachable Machine to help classify images from a webcam in real-time. The program is written in Python and uses OpenCV and TensorFlow. For more information about how I created the project and to learn how to create an object detection project yourself, you can view a demo video and read my Instructable detailing the project at the links below: 3 | 4 | Video demo: https://youtu.be/ECFZkKfeL2A 5 | Instructables: https://www.instructables.com/id/Easy-Machine-Learning-Object-Detection-With-Teacha 6 | Hackster: https://www.hackster.io/mjdargen/easy-object-detection-with-teachable-machine-python-d4063b 7 | 8 | Buy Me A Coffee 9 | -------------------------------------------------------------------------------- /installation_scripts/linux_install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Install script for OpenCV & TensorFlow for Linux 3 | # Author: Michael D'Argenio 4 | # mjdargen@gmail.com 5 | 6 | echo "This script will update your packages, and install new packages to run OpenCV and TensorFlow." 7 | echo "It can take up to an hour to run depending upon your system." 8 | echo "Upon completion, you may need to reboot your machine before running." 9 | echo "Python 3 should be installed before running script." 10 | sleep 5s 11 | 12 | # update packages and remove any unnecessary packages 13 | sudo apt-get --assume-yes update 14 | sudo apt-get --assume-yes upgrade 15 | sudo apt-get --assume-yes autoremove 16 | sudo apt-get --assume-yes clean 17 | 18 | # install dependency packages 19 | sudo apt-get --assume-yes install python3-pip 20 | sudo apt-get --assume-yes install build-essential cmake pkg-config 21 | sudo apt-get --assume-yes install libjpeg-dev libtiff5-dev libjasper-dev libpng-dev 22 | sudo apt-get --assume-yes install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev 23 | sudo apt-get --assume-yes install libxvidcore-dev libx264-dev 24 | sudo apt-get --assume-yes install libfontconfig1-dev libcairo2-dev 25 | sudo apt-get --assume-yes install libgdk-pixbuf2.0-dev libpango1.0-dev 26 | sudo apt-get --assume-yes install libgtk2.0-dev libgtk-3-dev 27 | sudo apt-get --assume-yes install libatlas-base-dev gfortran 28 | sudo apt-get --assume-yes install libhdf5-dev libhdf5-serial-dev libhdf5-103 29 | sudo apt-get --assume-yes install libqtgui4 libqtwebkit4 libqt4-test python3-pyqt5 30 | sudo apt-get --assume-yes install libespeak-dev 31 | sudo apt-get --assume-yes install python3-dev 32 | sudo apt-get --assume-yes install curl wget 33 | 34 | # install PIP 35 | curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py 36 | sudo python3 get-pip.py 37 | sudo rm get-pip.py 38 | sudo rm -rf ~/.cache/pip 39 | 40 | # install pip packages 41 | sudo pip3 install setuptools virtualenv virtualenvwrapper 42 | 43 | # setup virtual environment 44 | virtualenv TMenv 45 | source TMenv/bin/activate 46 | 47 | # install PIP packages in virtual environment 48 | pip3 install -r ./installation_scripts/linux_requirements.txt 49 | deactivate 50 | 51 | # update packages and remove any unnecessary packages 52 | sudo apt-get --assume-yes update 53 | sudo apt-get --assume-yes upgrade 54 | sudo apt-get --assume-yes autoremove 55 | sudo apt-get --assume-yes clean 56 | 57 | # for linux install 58 | # if you get an error that states something similar to the following: 59 | # X Error: BadDrawable (invalid Pixmap or Window parameter) 9 60 | # you will need to run the following command 61 | sudo sh -c 'echo "QT_X11_NO_MITSHM=1" >> /etc/environment' 62 | 63 | echo "Done!" 64 | echo "To activate your virtual environment, use command 'source TMenv/bin/activate'." 65 | echo "To exit your virtual enviroment, use command 'deactivate'." 66 | -------------------------------------------------------------------------------- /installation_scripts/linux_requirements.txt: -------------------------------------------------------------------------------- 1 | cvlib==0.2.6 2 | opencv-contrib-python==4.5.3.56 3 | tensorflow>=2.4.3 4 | pyttsx3==2.71 5 | matplotlib 6 | -------------------------------------------------------------------------------- /installation_scripts/mac_install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Install script for OpenCV & TensorFlow for Mac 3 | # Author: Michael D'Argenio 4 | # mjdargen@gmail.com 5 | 6 | echo "This script will update your packages, and install new packages to run OpenCV and TensorFlow." 7 | echo "It can take up to an hour to run depending upon your system." 8 | echo "Upon completion, you may need to reboot your machine before running." 9 | echo "Python 3 should be installed before running script." 10 | sleep 5s 11 | 12 | # install homebrew package manager 13 | /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 14 | 15 | # update packages and remove any unnecessary packages 16 | brew update 17 | brew upgrade 18 | brew cleanup 19 | 20 | # install dependency packages 21 | brew install cmake pkg-config curl wget 22 | brew install jpeg libpng libtiff openexr 23 | brew install eigen tbb hdf5 pyqt qt 24 | brew install opencv --with-contrib 25 | brew install espeak 26 | 27 | # PIP Python Package installations 28 | curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py 29 | sudo python3 get-pip.py 30 | sudo rm get-pip.py 31 | sudo rm -rf ~/.cache/pip 32 | 33 | # install pip packages 34 | sudo pip3 install setuptools virtualenv virtualenvwrapper 35 | 36 | # setup virtual environment 37 | virtualenv TMenv 38 | source TMenv/bin/activate 39 | 40 | # install PIP packages in virtual environment 41 | pip3 install -r ./installation_scripts/mac_requirements.txt 42 | deactivate 43 | 44 | # update packages and remove any unnecessary packages 45 | brew update 46 | brew upgrade 47 | brew cleanup 48 | 49 | echo "Done!" 50 | echo "To activate your virtual environment, use command 'source TMenv/bin/activate'." 51 | echo "To exit your virtual enviroment, use command 'deactivate'." 52 | -------------------------------------------------------------------------------- /installation_scripts/mac_requirements.txt: -------------------------------------------------------------------------------- 1 | cvlib==0.2.6 2 | opencv-contrib-python==4.5.3.56 3 | tensorflow>=2.4.0 4 | pyttsx3==2.71 5 | matplotlib 6 | -------------------------------------------------------------------------------- /installation_scripts/windows_install.bat: -------------------------------------------------------------------------------- 1 | :: Install script for OpenCV & TensorFlow for Windows 2 | :: Author: Michael D'Argenio 3 | :: mjdargen@gmail.com 4 | 5 | :: windows 6 | ECHO This script will update your packages, and install new packages to run OpenCV and TensorFlow. 7 | ECHO It can take up to 30 minutes to run depending upon your system. 8 | ECHO Upon completion, you may need to reboot your machine before running. 9 | ECHO Python 3 should be installed before running script. 10 | timeout /t 10 11 | 12 | :: install PIP 13 | curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py 14 | python get-pip.py 15 | del get-pip.py 16 | 17 | :: install PIP packages 18 | pip install setuptools virtualenv virtualenvwrapper-win 19 | 20 | :: setup virtual environment 21 | virtualenv ./TMenv 22 | call .\TMenv\Scripts\activate 23 | 24 | :: install PIP packages in virtual environment 25 | .\TMenv\Scripts\pip install -r ./installation_scripts/windows_requirements.txt 26 | deactivate 27 | 28 | ECHO Done! 29 | echo To activate your virtual environment, use command './TMenv/Scripts/activate'. 30 | echo To exit your virtual environment, use command 'deactivate'. 31 | -------------------------------------------------------------------------------- /installation_scripts/windows_requirements.txt: -------------------------------------------------------------------------------- 1 | pypiwin32 2 | cvlib==0.2.6 3 | opencv-contrib-python==4.5.3.56 4 | tensorflow==2.6.4 5 | pyttsx3==2.71 6 | matplotlib 7 | -------------------------------------------------------------------------------- /la_croix_model/keras_model.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjdargen/Teachable-Machine-Object-Detection/6424ca4377d23f10107683fc0a1ee9f88a2f257d/la_croix_model/keras_model.h5 -------------------------------------------------------------------------------- /la_croix_model/labels.txt: -------------------------------------------------------------------------------- 1 | 0 Mango 2 | 1 Key Lime 3 | 2 Pamplemousse 4 | 3 Tangerine 5 | 4 Pasteque 6 | 5 Coconut 7 | 6 Background 8 | -------------------------------------------------------------------------------- /tm_obj_det.py: -------------------------------------------------------------------------------- 1 | # Easy Machine Learning & Object Detection with Teachable Machine 2 | # 3 | # Michael D'Argenio 4 | # mjdargen@gmail.com 5 | # https://dargen.io 6 | # https://github.com/mjdargen 7 | # Created: February 6, 2020 8 | # Last Modified: February 13, 2021 9 | # 10 | # This program uses Tensorflow and OpenCV to detect objects in the video 11 | # captured from your webcam. This program is meant to be used with machine 12 | # learning models generated with Teachable Machine. 13 | # 14 | # Teachable Machine is a great machine learning model trainer and generator 15 | # created by Google. You can use Teachable Machine to create models to detect 16 | # objects in images, sounds in audio, or poses in images. For more info, go to: 17 | # https://teachablemachine.withgoogle.com/ 18 | # 19 | # For this project, you will be generating a image object detection model. Go 20 | # to the website, click "Get Started" then go to "Image Project". Follow the 21 | # steps to create a model. Export the model as a "Tensorflow->Keras" model. 22 | # 23 | # To run this code in your environment, you will need to: 24 | # * Install Python 3 & library dependencies 25 | # * Follow instructions for your setup 26 | # * Export your teachable machine tensorflow keras model and unzip it. 27 | # * You need both the .h5 file and labels.txt 28 | # * Update model_path to point to location of your keras model 29 | # * Update labels_path to point to location of your labels.txt 30 | # * Adjust width and height of your webcam for your system 31 | # * Adjust frameWidth with your video feed width in pixels 32 | # * Adjust frameHeight with your video feed height in pixels 33 | # * Set your confidence threshold 34 | # * conf_threshold by default is 90 35 | # * If video does not show up properly, use the matplotlib implementation 36 | # * Uncomment "import matplotlib...." 37 | # * Comment out "cv2.imshow" and "cv2.waitKey" lines 38 | # * Uncomment plt lines of code below 39 | # * Run "python3 tm_obj_det.py" 40 | 41 | import multiprocessing 42 | import numpy as np 43 | import cv2 44 | import tensorflow.keras as tf 45 | import pyttsx3 46 | import math 47 | import os 48 | # use matplotlib if cv2.imshow() doesn't work 49 | # import matplotlib.pyplot as plt 50 | 51 | DIR_PATH = os.path.dirname(os.path.realpath(__file__)) 52 | 53 | 54 | # this process is purely for text-to-speech so it doesn't hang processor 55 | def speak(speakQ, ): 56 | # initialize text-to-speech object 57 | engine = pyttsx3.init() 58 | # can adjust volume if you'd like 59 | volume = engine.getProperty('volume') 60 | engine.setProperty('volume', volume) # add number here 61 | # initialize last_msg to be empty 62 | last_msg = "" 63 | # keeps program running forever until ctrl+c or window is closed 64 | while True: 65 | msg = speakQ.get() 66 | # clear out msg queue to get most recent msg 67 | while not speakQ.empty(): 68 | msg = speakQ.get() 69 | # if most recent msg is different from previous msg 70 | # and if it's not "Background" 71 | if msg != last_msg and msg != "Background": 72 | last_msg = msg 73 | # text-to-speech say class name from labels.txt 74 | engine.say(msg) 75 | engine.runAndWait() 76 | if msg == "Background": 77 | last_msg = "" 78 | 79 | 80 | def main(): 81 | 82 | # read .txt file to get labels 83 | labels_path = f"{DIR_PATH}/la_croix_model/labels.txt" 84 | # open input file label.txt 85 | labelsfile = open(labels_path, 'r') 86 | 87 | # initialize classes and read in lines until there are no more 88 | classes = [] 89 | line = labelsfile.readline() 90 | while line: 91 | # retrieve just class name and append to classes 92 | classes.append(line.split(' ', 1)[1].rstrip()) 93 | line = labelsfile.readline() 94 | # close label file 95 | labelsfile.close() 96 | 97 | # load the teachable machine model 98 | model_path = f"{DIR_PATH}/la_croix_model/keras_model.h5" 99 | model = tf.models.load_model(model_path, compile=False) 100 | 101 | # initialize webcam video object 102 | cap = cv2.VideoCapture(0) 103 | 104 | # width & height of webcam video in pixels -> adjust to your size 105 | # adjust values if you see black bars on the sides of capture window 106 | frameWidth = 1280 107 | frameHeight = 720 108 | 109 | # set width and height in pixels 110 | cap.set(cv2.CAP_PROP_FRAME_WIDTH, frameWidth) 111 | cap.set(cv2.CAP_PROP_FRAME_HEIGHT, frameHeight) 112 | # enable auto gain 113 | cap.set(cv2.CAP_PROP_GAIN, 0) 114 | 115 | # creating a queue to share data to speech process 116 | speakQ = multiprocessing.Queue() 117 | 118 | # creating speech process to not hang processor 119 | p1 = multiprocessing.Process(target=speak, args=(speakQ, ), daemon="True") 120 | 121 | # starting process 1 - speech 122 | p1.start() 123 | 124 | # keeps program running forever until ctrl+c or window is closed 125 | while True: 126 | 127 | # disable scientific notation for clarity 128 | np.set_printoptions(suppress=True) 129 | 130 | # Create the array of the right shape to feed into the keras model. 131 | # We are inputting 1x 224x224 pixel RGB image. 132 | data = np.ndarray(shape=(1, 224, 224, 3), dtype=np.float32) 133 | 134 | # capture image 135 | check, frame = cap.read() 136 | # mirror image - mirrored by default in Teachable Machine 137 | # depending upon your computer/webcam, you may have to flip the video 138 | # frame = cv2.flip(frame, 1) 139 | 140 | # crop to square for use with TM model 141 | margin = int(((frameWidth-frameHeight)/2)) 142 | square_frame = frame[0:frameHeight, margin:margin + frameHeight] 143 | # resize to 224x224 for use with TM model 144 | resized_img = cv2.resize(square_frame, (224, 224)) 145 | # convert image color to go to model 146 | model_img = cv2.cvtColor(resized_img, cv2.COLOR_BGR2RGB) 147 | 148 | # turn the image into a numpy array 149 | image_array = np.asarray(model_img) 150 | # normalize the image 151 | normalized_image_array = (image_array.astype(np.float32) / 127.0) - 1 152 | # load the image into the array 153 | data[0] = normalized_image_array 154 | 155 | # run the prediction 156 | predictions = model.predict(data) 157 | 158 | # confidence threshold is 90%. 159 | conf_threshold = 90 160 | confidence = [] 161 | conf_label = "" 162 | threshold_class = "" 163 | # create blach border at bottom for labels 164 | per_line = 2 # number of classes per line of text 165 | bordered_frame = cv2.copyMakeBorder( 166 | square_frame, 167 | top=0, 168 | bottom=30 + 15*math.ceil(len(classes)/per_line), 169 | left=0, 170 | right=0, 171 | borderType=cv2.BORDER_CONSTANT, 172 | value=[0, 0, 0] 173 | ) 174 | # for each one of the classes 175 | for i in range(0, len(classes)): 176 | # scale prediction confidence to % and apppend to 1-D list 177 | confidence.append(int(predictions[0][i]*100)) 178 | # put text per line based on number of classes per line 179 | if (i != 0 and not i % per_line): 180 | cv2.putText( 181 | img=bordered_frame, 182 | text=conf_label, 183 | org=(int(0), int(frameHeight+25+15*math.ceil(i/per_line))), 184 | fontFace=cv2.FONT_HERSHEY_SIMPLEX, 185 | fontScale=0.5, 186 | color=(255, 255, 255) 187 | ) 188 | conf_label = "" 189 | # append classes and confidences to text for label 190 | conf_label += classes[i] + ": " + str(confidence[i]) + "%; " 191 | # prints last line 192 | if (i == (len(classes)-1)): 193 | cv2.putText( 194 | img=bordered_frame, 195 | text=conf_label, 196 | org=(int(0), int(frameHeight+25+15*math.ceil((i+1)/per_line))), 197 | fontFace=cv2.FONT_HERSHEY_SIMPLEX, 198 | fontScale=0.5, 199 | color=(255, 255, 255) 200 | ) 201 | conf_label = "" 202 | # if above confidence threshold, send to queue 203 | if confidence[i] > conf_threshold: 204 | speakQ.put(classes[i]) 205 | threshold_class = classes[i] 206 | # add label class above confidence threshold 207 | cv2.putText( 208 | img=bordered_frame, 209 | text=threshold_class, 210 | org=(int(0), int(frameHeight+20)), 211 | fontFace=cv2.FONT_HERSHEY_SIMPLEX, 212 | fontScale=0.75, 213 | color=(255, 255, 255) 214 | ) 215 | 216 | # original video feed implementation 217 | cv2.imshow("Capturing", bordered_frame) 218 | cv2.waitKey(10) 219 | 220 | # # if the above implementation doesn't work properly 221 | # # comment out two lines above and use the lines below 222 | # # will also need to import matplotlib at the top 223 | # plt_frame = cv2.cvtColor(bordered_frame, cv2.COLOR_BGR2RGB) 224 | # plt.imshow(plt_frame) 225 | # plt.draw() 226 | # plt.pause(.001) 227 | 228 | # terminate process 1 229 | p1.terminate() 230 | 231 | 232 | if __name__ == '__main__': 233 | main() 234 | -------------------------------------------------------------------------------- /yolo_obj_det.py: -------------------------------------------------------------------------------- 1 | # OpenCV Common Object Detection 2 | # 3 | # Michael D'Argenio 4 | # mjdargen@gmail.com 5 | # https://dargen.io 6 | # https://github.com/mjdargen 7 | # Created: February 6, 2020 8 | # Last Modified: February 13, 2021 9 | # 10 | # My program to execute Arun Ponnusamy's OpenCV wrapper for 11 | # a YOLO common object detection model. More info below: 12 | # https://www.arunponnusamy.com/yolo-object-detection-opencv-python.html 13 | # https://github.com/arunponnusamy/object-detection-opencv/ 14 | 15 | import multiprocessing 16 | import cv2 17 | import cvlib as cv 18 | from cvlib.object_detection import draw_bbox 19 | import pyttsx3 20 | 21 | 22 | # this process is purely for text-to-speech so it doesn't hang processor 23 | def speak(speakQ, ): 24 | # initialize text-to-speech object 25 | engine = pyttsx3.init() 26 | # can adjust volume if you'd like 27 | volume = engine.getProperty('volume') 28 | engine.setProperty('volume', volume+0.25) 29 | 30 | # keeps program running forever until ctrl+c or window is closed 31 | while True: 32 | # clear out message and reinit skip 33 | msg = "" 34 | skip = 0 35 | # retrieve all messages 36 | while not speakQ.empty(): 37 | temp = speakQ.get() 38 | # if new, break loop and reset because not newest labels 39 | if '#new#' in temp: 40 | skip = 1 41 | break 42 | # concatenate labels for speech 43 | msg = msg + ', ' + temp 44 | # if we aren't skipping, say the labels 45 | if not skip: 46 | engine.say(msg) 47 | engine.runAndWait() 48 | 49 | 50 | def main(): 51 | 52 | # instantiate video capture object 53 | cap = cv2.VideoCapture(0) 54 | # creating a queue to share data to speech process 55 | speakQ = multiprocessing.Queue() 56 | # creating speech process to not hang processor 57 | p1 = multiprocessing.Process(target=speak, args=(speakQ, )) 58 | # starting process 1 - speech 59 | p1.start() 60 | 61 | # keeps program running forever until ctrl+c or window is closed 62 | while True: 63 | # capture image 64 | _, img = cap.read() 65 | # use detect common objects model to label objects 66 | bbox, labels, conf = cv.detect_common_objects(img) 67 | # draw labels 68 | img = draw_bbox(img, bbox, labels, conf) 69 | # send unique string denoting new labels being sent to speech 70 | speakQ.put('#new#') 71 | # send each label to text to speech process 72 | for label in labels: 73 | speakQ.put(label.lower()) 74 | # display and wait 10ms 75 | cv2.imshow('my webcam', img) 76 | cv2.waitKey(10) 77 | 78 | # clean up if you want to remove while loop 79 | cap.release() 80 | p1.terminate() 81 | cv2.destroyAllWindows() 82 | 83 | 84 | if __name__ == '__main__': 85 | main() 86 | --------------------------------------------------------------------------------