---
# System prepended metadata

title: OpenCV with Python -- 5
tags: [OpenCV]

---

---
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)
