--- tags: OpenCV --- # OpenCV with Python -- 5 [Back to book mode](https://hackmd.io/@Justin123/opencv) ## Introduction We often come across the problem that we only want the robot to see the specific color. In fact, this help robot only to analyze the wanted info. To achieve the result, we will learn how to do the color detection and how to add trackbar to tune the parameter in image windows. ## Color detection In normal event, we will use **HSV** format to do the color detection. Therefore, we have try different value to certain that we can remove unwanted color and leave the target. To achieve the filtering, we will first use **trackbar** to find the values. ### Windows To add the trackbar, we have to create a new window for trackbar. The syntax is as follows: * `cv2.namedWindow(name, flags)` * name: Window's name. * flags: Flags of the window. See the [documentation](https://docs.opencv.org/2.4/modules/highgui/doc/user_interface.html?highlight=namedwindow#namedwindow) for more detail. * `cv2.resizeWindow(name, width, height)` * name: The name of the window to be resized. * width: Width after resize. * height: Height after resize. ```python # Create window and make window resizable. cv2.namedWindow("TrackBars", cv2.WINDOW_NORMAL) # Resize the window cv2.resizeWindow("TrackBars", 1000, 100) ``` ### Trackbars We shoule ensure that we can ==set and get the values==. Therefore, we alway have to implement two function for each trackbars. * `cv2.createTracker(trackbar_name, window_name, min_value, max_value, callback)` * trackbar_name: Name of the new trackbar. * window_name: Window to add the trackbar. * min_value: Minimum value of the trackbar. * max_value: Maximum value of the trackbar. * callback: Function to be called when the value of trackbar has changed. * `cv2.getTrackbarPos(trackbar_name, window_name)` Get the result of the trackbar * trackbar_name: The target trackbar's name. * window_name: Name of the window where the trackbar exists. ```python # Create trackbar cv2.createTrackbar("Hue Min", "TrackBars", 0, 179, empty) # Get the trackbar value h_lower = cv2.getTrackbarPos("Hue Min", "TrackBars") ``` --- ```python= import cv2 import numpy as np # Callback function def empty(x): pass # Create window cv2.namedWindow("TrackBars", cv2.WINDOW_NORMAL) cv2.resizeWindow("TrackBars", 1000, 40) # Create trackbar cv2.createTrackbar("Hue Min", "TrackBars", 0, 179, empty) cv2.createTrackbar("Hue Max", "TrackBars", 179, 179, empty) cv2.createTrackbar("Sat Min", "TrackBars", 0, 255, empty) cv2.createTrackbar("Sat Max", "TrackBars", 255, 255, empty) cv2.createTrackbar("Value Min", "TrackBars", 0, 255, empty) cv2.createTrackbar("Value Max", "TrackBars", 255, 255, empty) cv2.waitKey(0) cv2.destroyAllWindows() cv2.waitKey(1) ``` You will see: </br> ![](https://i.imgur.com/SbPHgvl.png) ### Mask To get the specifi range of hsv value, we can use mask to filter the value. If the value is outside the range, it will be set to 0 and 1 otherwise. To put it simply, mask help us to transform the image to binary format. ```python= import cv2 import numpy as np # Convert image to HSV format img = cv2.imread("resources/car.jpg") img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # Using the mask to filter the color lower = np.array([0, 93, 0]) upper = np.array([10, 255, 255]) mask = cv2.inRange(img_hsv, lower, upper) result = np.hstack([img, cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)]) cv2.imshow("Mask image", result) cv2.waitKey(0) cv2.destroyAllWindows() cv2.waitKey(1) ``` <center><img src=https://i.imgur.com/CkEshMW.jpg width=500/></center> </br> ### Bitwise and We expect to get the image in RGB format. Thus, we can use `cv2.bitwise_and` to get the result. * `cv2.bitwise_and(img1, img2)` Perform bitwise operation between **img1** and **img2**. * img1: First input array. * img2: Second input array. ```python= # Result image import cv2 import numpy as np # Convert image to HSV format img = cv2.imread("resources/car.jpg") img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # Using the mask to filter the color lower = np.array([0, 93, 0]) upper = np.array([10, 255, 255]) mask = cv2.inRange(img_hsv, lower, upper) # Result image ''' Mask should have the same size of img. Then we should cv2.cvtColor() to convert mask to RGB but still remain binary format. ''' img_result = cv2.bitwise_and(img, cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)) result = np.hstack([img, cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR), img_result]) cv2.imshow("Mask image", result) cv2.waitKey(0) cv2.destroyAllWindows() cv2.waitKey(1) ``` ![](https://i.imgur.com/erbAJgX.jpg) --- ### Pack it all together! To filter the right color we want, we just have to use `while` to pack everything together. Hense, we can change the values and observe the results simultaneously. ```python= import cv2 import numpy as np def empty(x): pass # Create window cv2.namedWindow("TrackBars", cv2.WINDOW_NORMAL) cv2.resizeWindow("TrackBars", 1000, 100) # Create trackbar cv2.createTrackbar("Hue Min", "TrackBars", 0, 179, empty) cv2.createTrackbar("Hue Max", "TrackBars", 179, 179, empty) cv2.createTrackbar("Sat Min", "TrackBars", 0, 255, empty) cv2.createTrackbar("Sat Max", "TrackBars", 255, 255, empty) cv2.createTrackbar("Value Min", "TrackBars", 0, 255, empty) cv2.createTrackbar("Value Max", "TrackBars", 255, 255, empty) # Convert image to HSV format img = cv2.imread("resources/car.jpg") img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) while True: # Get the trackbar value h_lower = cv2.getTrackbarPos("Hue Min", "TrackBars") h_upper = cv2.getTrackbarPos("Hue Max", "TrackBars") s_lower = cv2.getTrackbarPos("Sat Min", "TrackBars") s_upper = cv2.getTrackbarPos("Sat Max", "TrackBars") v_lower = cv2.getTrackbarPos("Value Min", "TrackBars") v_upper = cv2.getTrackbarPos("Value Max", "TrackBars") # Using the mask to filter the color lower = np.array([h_lower, s_lower, v_lower]) upper = np.array([h_upper, s_upper, v_upper]) mask = cv2.inRange(img_hsv, lower, upper) # Result image img_result = cv2.bitwise_and(img, img, mask=mask) # Show the image img_stack = stackImages(0.5, [[img, img_hsv], [mask, img_result]]) cv2.imshow("Image", img_stack) if cv2.waitKey(1) & 0xFF == ord('q'): break; # Print out the wanted range print(h_lower, s_lower, v_lower) print(h_upper, s_upper, v_upper) cv2.destroyAllWindows() cv2.waitKey(1) ``` ## Cascade classifier **Cascade classifier** is an object detection technique that used in **OpenCV**. You can learn more about it in this [article](http://www.willberger.org/cascade-haar-explained/) written by **Will Berger**. We're only focus on how to use the **OpenCV** function to get the result on the pretrained model (You can use your model as well!). We're going to download the pretrained model for face recognition. The pretrained model is in [this](https://github.com/opencv/opencv/tree/master/data/haarcascades) github repo. We choose **haarcascade_frontalface_default.xml** to do the demonstation. You should prepare a image with face in it! * `cv2.CascadeClassifier.detectMultiScale(img, scaleFactor, minNeighbors)` [Documentation](https://docs.opencv.org/2.4/modules/objdetect/doc/cascade_classification.html#cascadeclassifier-detectmultiscale) * img: Image to detect. * scaleFactor: Specifying how much the image size is reduced at each image scale. * minNeighbors: Specifying how many neighbors each candidate rectangle should have to retain it. The param `minNeighbor` is implict in the documentation. I stronly recommend to see [this](https://stackoverflow.com/questions/22249579/opencv-detectmultiscale-minneighbors-parameter) explanation from **stack overflow**. The param `scalerFactor` help you to detect different shape of faces. Because the model have fixed size during training, therefore, we should resize the image to match the detection size to. If the value is **1.05**, it will decrease **0.05%** every iteration. ![](https://i.imgur.com/1bFqp8w.jpg) **Demonstration** ```python= import cv2 import numpy as np # Read in the xml file face_cascade = cv2.CascadeClassifier("cascade_files/haarcascade_frontalface_default.xml") # Read in the face image img = cv2.imread("resources/me.jpg") # Convert into gray scale img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Dectect the face faces = face_cascade.detectMultiScale(img_gray, 1.1, 4) # Draw the bounding boxes for (x, y, w, h) in faces: cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2) cv2.imshow("Result", img) cv2.waitKey(0) cv2.destroyAllWindows() cv2.waitKey(1) ``` <center><img src="https://i.imgur.com/9wDsJiX.jpg" width=450/></center> ## Summary We have finished introducting the basic knowledge of image preprocessing and the use of **OpenCV**. From convolution, resizing, color detection and so on. I hope you guys can really learn a lot from the articles and use it in your next project! Thanks for reading and see you in next series! ## Reference 1. [OBJECT DETECTION : FACE DETECTION USING HAAR CASCADE CLASSFIERS](https://www.bogotobogo.com/python/OpenCV_Python/python_opencv3_Image_Object_Detection_Face_Detection_Haar_Cascade_Classifiers.php) 2. [OpenCV detectMultiScale() minNeighbors parameter](https://stackoverflow.com/questions/22249579/opencv-detectmultiscale-minneighbors-parameter)