---
# System prepended metadata

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

---

---
tags: OpenCV
---

# OpenCV with Python -- 3

[Back to book mode](https://hackmd.io/@Justin123/opencv)

## Introduction
In today's tutorial, we're going to talk about how to crop the image. Also, add additional infomation on the images such as lines, retangle and text. Furthermore, we 'are going to know how to change the perspective of the image.

## Resize and crop
We have already mentioned how to resize the image. However, in some special event, we want to random crop our image or crop the image at the center to get the specific information. 

For example, when we train the classification model and want to improve the performance, we may try to do the random crop to get different kinds of images. (In fact, most of the deep learning library have built-in function to finish the job.)

Essentially put, image is a matrix will value in it. Therefore, if we want to crop the image, we can just focus on one part of the matrix and only get those values. The only thing should be noticed is the matrix was start from top-left corner.


<center><img src=https://i.imgur.com/hYdL50V.jpg width=450/></center>

* **Function in OpenCV**
```python=
import cv2

img = cv2.imread("resources/food.jpg")

'''
# Crop the image
target region: (height, width)
height pixel: 500~900
width pixel: 300~1000
'''
img_cropped = img[500:900, 300:1000]

# Show the image
cv2.imshow("Image", img)
cv2.imshow("Cropped image", img_cropped)

cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.waitKey(1)
```
<center><img src=https://i.imgur.com/7nJCIm4.jpg width=450/></center>
<center><b>Origin image</b></center></br>

<center><img src=https://i.imgur.com/4XChJqz.jpg width=250/></center>
<center><b>Cropped image</b></center>

## Draw on the image
We're going to demonstrate how to use the function.

* **Circle**
    * `cv2.circle(img, origin, radius, color, thickness)`
    
        * img: Image to draw
        * origin: Pixel to be the origin.
        * radius: Radius of the circle.
        * color: Color of the circle. ==(RGB)==
        * thickness: Thickness of the circle. To fill the circle put `cv2.FILLED`.
    </br>
    ```python
    # Example
    cv2.circle(img_cir, (250, 250), 100, (255, 0, 255), 3)
    cv2.circle(img_cir, (250, 250), 100, (255, 0, 255), cv2.FILLED)
    ```
* **Rectangle**
    * `cv2.rectangle(img, upper_left, lower_right, color, thickness)`
    
        * img: Image to add rectangle.
        * upper_left: Top-left corner of the rectangle. ==(Place of the matrix)==
        * lower_right: Down-right corner of the rectangle. ==(Place of the matrix)==
        * color: Color of rectangle.
        * thickness: Thickness of rectangle. To fill the circle put `cv2.FILLED`.
    </br>
    ```python
    # Example
    cv2.rectangle(img_rec, (0, 0), (250, 350), (0, 0, 255), 3)
    cv2.rectangle(img_rec, (250, 350), (250, 350), (255, 0, 0), cv2.FILLED)
    ```
    
* **Line**
    * `cv2.line(img, start_point, end_point, color, thickness)`

        * img: Image to add line.
        * start_point: Position to start line. ==(Place of the matrix)==
        * end_point: Position to end line. ==(Place of the matrix)==
        * color: Color of line.
        * thickness: Thickness of line.
    </br>
    ```python
    cv2.line(img_line, (0, 0), (img.shape[1], img.shape[0]), (0, 255, 0), 3)
    ```
    
* **Text**
    * `cv2.putText(img, text, start_place, font type, scale, color, thickness)`
    
        * text: Text to be put on.
        * start_point: buttom-left corner of the text. ==(Place of the matrix)==
        * font type: The type of the text.
        * scale: Scale of the text.
        </br>
    ```python
    cv2.putText(img_text, "OpenCV", (300, 100), 
                cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 255), 3)
    ```
   
**Demostration**

```python=
import cv2
import numpy as np

'''
# Create a black image
0: black
255: white
'''
img_black = np.zeros((512, 512), np.uint8)

# Create color image, need 3 channels
img_blue = np.zeros((512, 512, 3), np.uint8)
img_blue[:] = [255, 0, 0]

'''
Try out
img_blue[200:300, 300, 400] = [255, 0, 0]
'''

# Add green line
img_line = np.zeros((512, 512, 3), np.uint8)
cv2.line(img_line, (0, 0), (img.shape[1], img.shape[0]), (0, 255, 0), 3)

## Add rectangle
img_rec = np.zeros((512, 512, 3), np.uint8)
cv2.rectangle(img_rec, (0, 0), (250, 350), (0, 0, 255), 3)
cv2.rectangle(img_rec, (250, 350), (img.shape[1], img.shape[0]), (255, 0, 0), cv2.FILLED)

## Add Circle
img_cir = np.zeros((512, 512, 3), np.uint8)
cv2.circle(img_cir, (250, 250), 100, (255, 0, 255), cv2.FILLED)

## Add Text
img_text = np.zeros((512, 512, 3), np.uint8)
cv2.putText(img_text, "OpenCV", (300, 100), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 255), 3)

# Show the result
cv2.imshow("Black image", img_black)
cv2.imshow("Blue image", img_blue)
cv2.imshow("Line", img_line)
cv2.imshow("Rectangle", img_rec)
cv2.imshow("Circle", img_cir)
cv2.imshow("Text", img_text)


cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.waitKey(1)
```

## Perspective

To get the specific part of the image, we have to change the perspective of the image. For example, we have lots of pockers.

<center><img src=https://i.imgur.com/KShrc4c.jpg width=300/></center>
</br>

We only want to get the **Ace** in the image.

<center><img src=https://i.imgur.com/nH4WtdI.jpg width=200/></center>
</br>

Let's see how we achieve the result. In order to change the perspective, we should first know all four vertexs of the target. After that, we have to determine the new size of the image. Then we can do the transform.
![](https://i.imgur.com/68aExgZ.jpg)

You can use different application such as Photoshop or just the image viewer in your computer to find out the vertex. The order of `pst1`(in below code session) doesn't matter. However, you should be aware the order of `pst2` should have the right transformation w.r.t. `pst1`.

```python=
import cv2
import numpy as np

img = cv2.imread("resources/pocker.jpg")

cv2.imshow("Image", img)

# New size of the output
width, height = 250, 350

'''
pst1: old position
pst2: new position 
transform pst1 -> pst2
'''
pts1 = np.float32([[239, 103], [356, 146], [179, 277], [296, 320]])
pts2 = np.float32([[0, 0], [width, 0], [0, height], [width, height]])

# Transformation matrix
matrix = cv2.getPerspectiveTransform(pts1, pts2)

# Get the new image
img_output = cv2.warpPerspective(img, matrix, (width, height))

cv2.imshow("New image", img_output)

cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.waitKey(1)
```

Try to break the correct transformation or change the order to see the result by yourself! </br>
For instance:
```python
# Break the correct transformation
pts1 = np.float32([[356, 146], [239, 103], [179, 277], [296, 320]])
pts2 = np.float32([[0, 0], [width, 0], [0, height], [width, height]])

#-------------------#

# Change the order but still with right transformation
pts1 = np.float32([[356, 146], [239, 103], [179, 277], [296, 320]])
pts2 = np.float32([[width, 0], [0, 0], [0, height], [width, height]])
```

## Join the image

To show different kinds of images in one result or feel tedious to type `cv2.imshow(...)` we can stack the images together.

* `np.hstack()`

    We use numpy function to stack the image. You can make a list of images to be the input. </br></br>
    ```python=
    import cv2
    import numpy as np

    img = cv2.imread("resources/food.jpg")

    # horizotal stack
    img_hor = np.hstack((img, img))

    # Show the result
    cv2.imshow("Horizontal image", img_hor)

    cv2.waitKey(0)
    cv2.destroyAllWindows()
    cv2.waitKey(1)
    ```
    <center><img src=https://i.imgur.com/Kw85NL3.jpg width=500/></center>
    
* `np.vstack()`
    
    Same as `np.hstack()`, but with the vertical result.
    ```python=
    import cv2
    import numpy as np

    img = cv2.imread("resources/food.jpg")

    # Vertival stack
    img_ver = np.vstack((img, img))

    # Show the result
    cv2.imshow("Vertical image", img_ver)

    cv2.waitKey(0)
    cv2.destroyAllWindows()
    cv2.waitKey(1)
    ```
    <center><img src=https://i.imgur.com/294x66t.jpg height=450/></center>

* **Self-define function**
    
    To first scale the image and stack the images with multilayers, we can write our own function. ==The code below is came from [MURTAZA'S WORKSHOP](https://www.murtazahassan.com/learn-opencv-in-3-hours-chapter-6/).==
    ```python=
    '''
    The code below came from MURTAZA'S WORKSHOP
    '''
    
    def stackImages(scale, imgArray):
    '''
    scale: New scale of the image
    imgArray: Images to stack.
    '''
    
    rows = len(imgArray)
    cols = len(imgArray[0])
    
    # Check whether we have multilayers
    rowsAvailable = isinstance(imgArray[0], list)
    
    width = imgArray[0][0].shape[1]
    height = imgArray[0][0].shape[0]
    
    if rowsAvailable:
        for x in range (0, rows):
            for y in range(0, cols):
                if imgArray[x][y].shape[:2] == imgArray[0][0].shape[:2]:
                    imgArray[x][y] = cv2.resize(imgArray[x][y], (0, 0), None, scale, scale)
                else:
                    imgArray[x][y] = cv2.resize(imgArray[x][y], (imgArray[0][0].shape[1], imgArray[0][0].shape[0]), None, scale, scale)
                    
                if len(imgArray[x][y].shape) == 2: 
                    imgArray[x][y]= cv2.cvtColor(imgArray[x][y], cv2.COLOR_GRAY2BGR)
                    
        imageBlank = np.zeros((height, width, 3), np.uint8)
        
        hor = [imageBlank] * rows
        
        # First put each horizontal image to its horizontal place
        for x in range(0, rows):
            hor[x] = np.hstack(imgArray[x])
        
        # Stack each array to the vertical format
        ver = np.vstack(hor)
    else:
        for x in range(0, rows):
            if imgArray[x].shape[:2] == imgArray[0].shape[:2]:
                imgArray[x] = cv2.resize(imgArray[x], (0, 0), None, scale, scale)
            else:
                imgArray[x] = cv2.resize(imgArray[x], (imgArray[0].shape[1], imgArray[0].shape[0]), None,scale, scale)
                
            if len(imgArray[x].shape) == 2: 
                imgArray[x] = cv2.cvtColor(imgArray[x], cv2.COLOR_GRAY2BGR)
                
        hor = np.hstack(imgArray)
        ver = hor
        
    return ver
    ```
    ```python=
    import cv2
    import numpy as np

    img = cv2.imread('resources/beauty.jpg')
    img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

    # Stack image
    img_stack = stackImages(0.5, [[img, img_gray, img],[img, img, img]])

    # Show the image
    cv2.imshow("ImageStack",img_stack)

    cv2.waitKey(0)
    cv2.destroyAllWindows()
    cv2.waitKey(1)
    ```
    <center><img src=https://i.imgur.com/OG3q7DP.jpg width=500/></center>

## Reference
1. [MURTAZA'S WORKSHOP](https://www.murtazahassan.com/learn-opencv-in-3-hours-chapter-6/)
2. [LEARN OPENCV in 3 HOURS with Python (2020)](https://youtu.be/WQeoO7MI0Bs)