# 四、圖像預處理
> 作者:[Chris Albon](https://chrisalbon.com/)
>
> 譯者:[飛龍](https://github.com/wizardforcel)
>
> 協議:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
## 圖像二值化
```py
# 加載庫
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 將圖像加載為灰度
image_grey = cv2.imread('img/plane_256x256.jpg', cv2.IMREAD_GRAYSCALE)
# 應用自適應閾值
max_output_value = 255
neighorhood_size = 99
subtract_from_mean = 10
image_binarized = cv2.adaptiveThreshold(image_grey,
max_output_value,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY,
neighorhood_size,
subtract_from_mean)
# 展示圖像
plt.imshow(image_binarized, cmap='gray'), plt.axis("off")
plt.show()
```

## 圖像模糊
```py
# 加載庫
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 將圖像加載為灰度
image = cv2.imread('img/plane_256x256.jpg', cv2.IMREAD_GRAYSCALE)
# 使圖像模糊
image_blurry = cv2.blur(image, (5,5))
# 展示圖像
plt.imshow(image_blurry, cmap='gray'), plt.xticks([]), plt.yticks([])
plt.show()
```

## 圖像剪裁
```py
# 加載庫
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 將圖像加載為灰度
image = cv2.imread('img/plane_256x256.jpg', cv2.IMREAD_GRAYSCALE)
# 選擇所有行,和前一半的列
image_cropped = image[:,:126]
# 查看圖像
plt.imshow(image_cropped, cmap='gray'), plt.axis("off")
plt.show()
```

## 邊緣檢測
```py
# 加載庫
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 將圖像加載為灰度
image_gray = cv2.imread('img/plane_256x256.jpg', cv2.IMREAD_GRAYSCALE)
# 計算強度中值
median_intensity = np.median(image_gray)
# 將閾值設為強度中值上下一個標準差
lower_threshold = int(max(0, (1.0 - 0.33) * median_intensity))
upper_threshold = int(min(255, (1.0 + 0.33) * median_intensity))
# 應用 canny 邊緣檢測
image_canny = cv2.Canny(image_gray, lower_threshold, upper_threshold)
# 展示圖像
plt.imshow(image_canny, cmap='gray'), plt.axis("off")
plt.show()
```

## 增強彩色圖像的對比度
```py
# 加載庫
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 加載圖像
image_bgr = cv2.imread('img/plane.jpg')
# 轉換為 YUV
image_yuv = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2YUV)
# 應用直方圖均衡
image_yuv[:, :, 0] = cv2.equalizeHist(image_yuv[:, :, 0])
# 轉換為 RGB
image_rgb = cv2.cvtColor(image_yuv, cv2.COLOR_YUV2RGB)
# 展示圖像
plt.imshow(image_rgb), plt.axis("off")
plt.show()
```

## 增強灰度圖像的對比度
```py
# 加載庫
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 將圖像加載為灰度
image = cv2.imread('img/plane_256x256.jpg', cv2.IMREAD_GRAYSCALE)
# 增強圖像
image_enhanced = cv2.equalizeHist(image)
# 展示圖像
plt.imshow(image_enhanced, cmap='gray'), plt.axis("off")
plt.show()
```

# Harris 角點檢測
Harris 角點檢測器是檢測兩個邊緣角點的常用方法。 它尋找窗口(也稱為鄰域或補丁),其中窗口的小移動(想象搖動窗口)使窗口內的像素內容產生大的變化。
```py
# 加載庫
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 將圖像加載為灰度
image_bgr = cv2.imread('img/plane_256x256.jpg')
image_gray = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2GRAY)
image_gray = np.float32(image_gray)
# 設置角點檢測器的參數
block_size = 2
aperture = 29
free_parameter = 0.04
# 檢測角點
detector_responses = cv2.cornerHarris(image_gray, block_size, aperture, free_parameter)
# 大型角點標記器
detector_responses = cv2.dilate(detector_responses, None)
# 只保留大于閾值的檢測器結果,標記為白色
threshold = 0.02
image_bgr[detector_responses > threshold * detector_responses.max()] = [255,255,255]
# 轉換為灰度
image_gray = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2GRAY)
# 展示圖像
plt.imshow(image_gray, cmap='gray'), plt.axis("off")
plt.show()
```

# 安裝 OpenCV
雖然有許多好的庫,OpenCV 是最受歡迎和文檔最全的圖像處理庫。 使用 OpenCV 的最大障礙之一就是安裝它。 但是,幸運的是,我們可以使用 Anaconda 的軟件包管理器工具 conda,在我們的終端中用一行代碼安裝 OpenCV:
```
conda install --channel https://conda.anaconda.org/menpo opencv3
```
之后,我們可以通過打開筆記本,導入 OpenCV 并檢查版本號(3.1.0)來檢查安裝:
```py
# 加載庫
import cv2
# 查看版本號
cv2.__version__
# '3.2.0'
```
## 顏色隔離
```py
# 加載庫
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 加載圖像
image_bgr = cv2.imread('img/plane_256x256.jpg')
# 將 BGR 轉換為 HSV
image_hsv = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2HSV)
# 定義 HSV 中藍色值的范圍
lower_blue = np.array([50,100,50])
upper_blue = np.array([130,255,255])
# 創建遮罩
mask = cv2.inRange(image_hsv, lower_blue, upper_blue)
# 屏蔽圖像
image_bgr_masked = cv2.bitwise_and(image_bgr, image_bgr, mask=mask)
# 將 BGR 轉換為 RGB
image_rgb = cv2.cvtColor(image_bgr_masked, cv2.COLOR_BGR2RGB)
# 展示圖像
plt.imshow(image_rgb), plt.axis("off")
plt.show()
```

## 加載圖像
```py
# 加載庫
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 將圖像加載為灰度
image = cv2.imread('img/plane.jpg', cv2.IMREAD_GRAYSCALE)
# 展示圖像
plt.imshow(image, cmap='gray'), plt.axis("off")
plt.show()
```

```py
# 加載彩色圖像
image_bgr = cv2.imread('img/plane.jpg', cv2.IMREAD_COLOR)
# 轉換為 RGB
image_rgb = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB)
# 展示圖像
plt.imshow(image_rgb), plt.axis("off")
plt.show()
```

```py
# 展示圖像數據
image
'''
array([[140, 136, 146, ..., 132, 139, 134],
[144, 136, 149, ..., 142, 124, 126],
[152, 139, 144, ..., 121, 127, 134],
...,
[156, 146, 144, ..., 157, 154, 151],
[146, 150, 147, ..., 156, 158, 157],
[143, 138, 147, ..., 156, 157, 157]], dtype=uint8)
'''
# 展示維度
image.shape
# (2270, 3600)
```
# 背景移除
[](https://machinelearningflashcards.com)
```py
# 加載庫
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 加載圖像
image_bgr = cv2.imread('img/plane_256x256.jpg')
# 轉換為 RGB
image_rgb = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB)
# 矩形值:起點 x,起點 y,寬度,高度
rectangle = (0, 56, 256, 150)
# 創建初始遮罩
mask = np.zeros(image_rgb.shape[:2], np.uint8)
# 創建用于 grabCut 的臨時數組
bgdModel = np.zeros((1, 65), np.float64)
fgdModel = np.zeros((1, 65), np.float64)
# 執行 grabCut
cv2.grabCut(image_rgb, # 我們的圖像
mask, # 遮罩
rectangle, # 我們的矩形
bgdModel, # 用于背景的臨時數組
fgdModel, # 用于前景的臨時數組
5, # 迭代數量
cv2.GC_INIT_WITH_RECT) # 使用我們的矩形來初始化
# 創建遮罩,其中背景設置為 0,否則為 1
mask_2 = np.where((mask==2) | (mask==0), 0, 1).astype('uint8')
# 使用新的遮罩移除多個圖像的背景
image_rgb_nobg = image_rgb * mask_2[:, :, np.newaxis]
# 展示圖像
plt.imshow(image_rgb_nobg), plt.axis("off")
plt.show()
```

## 保存圖像
```py
# 加載庫
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 將圖像加載為灰度
image = cv2.imread('img/plane.jpg', cv2.IMREAD_GRAYSCALE)
# 展示圖像
plt.imshow(image, cmap='gray'), plt.axis("off")
plt.show()
```

```py
# 保存圖像
cv2.imwrite('img/plane_new.jpg', image)
# True
```
## 圖像銳化
```py
# 加載庫
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 將圖像加載為灰度
image = cv2.imread('img/plane_256x256.jpg', cv2.IMREAD_GRAYSCALE)
# 創建核
kernel = np.array([[0, -1, 0],
[-1, 5,-1],
[0, -1, 0]])
# 銳化圖像
image_sharp = cv2.filter2D(image, -1, kernel)
# 展示圖像
plt.imshow(image_sharp, cmap='gray'), plt.axis("off")
plt.show()
```

## Shi-Tomasi 角點檢測
```py
# 加載庫
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 加載圖像
image_bgr = cv2.imread('img/plane_256x256.jpg')
image_gray = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2GRAY)
# 要檢測的角點數量
corners_to_detect = 10
minimum_quality_score = 0.05
minimum_distance = 25
# 檢測角點
corners = cv2.goodFeaturesToTrack(image_gray,
corners_to_detect,
minimum_quality_score,
minimum_distance)
corners = np.float32(corners)
# 在每個角點上繪制白色圓圈
for corner in corners:
x, y = corner[0]
cv2.circle(image_bgr, (x,y), 10, (255,255,255), -1)
# 轉換為灰度
image_gray = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2GRAY)
# 展示圖像
plt.imshow(image_gray, cmap='gray'), plt.axis("off")
plt.show()
```

## 使用顏色均值作為特征
```py
# 加載庫
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 將圖像加載為 BGR
image_bgr = cv2.imread('img/plane_256x256.jpg', cv2.IMREAD_COLOR)
# 計算每個通道的均值
channels = cv2.mean(image_bgr)
# 交換藍色和紅色值(使其變成 RGB 而不是 BGR)
observation = np.array([(channels[2], channels[1], channels[0])])
# 展示通道的均值
observation
# array([[ 90.53204346, 133.11735535, 169.03074646]])
# 展示圖像
plt.imshow(observation), plt.axis("off")
plt.show()
```
