计算机视觉是人工智能最热门的应用领域之一。人工智能技术推动了汽车自动驾驶、机器人以及各种照片处理类软件的巨大发展。目标检测技术也在稳步推进。生成对抗网络(GANs)同样也是人们最近比较关注的一个问题。这些都在向我们展示未来计算机视觉领域的发展前景是多么的不可限量。
让我们一起登上人工智能发展的高速列车。从本文开始我们将有一系列关于图像处理和目标检测基础知识的教程。本篇是OpenCV入门教程第一部分完整的系列教程如下
1. 理解颜色模型与在图像上绘制图形(图像处理基本操作)。
2. 基本的图像处理与过滤。
3. 从特征检测到人脸检测(TBU)
本系列的第一部分将从Opencv的安装结合代码实战讲解颜色模型与图形绘制讲起。本教程的完整代码已经放在Github上方便大家使用。
一、OpenCV简介
图像处理是指对图像执行一些操作以达到预期效果的过程。可以类比数据分析工作在数据分析时我们需要做一些数据预处和特征工程。图像处理也是一样的。我们通过图像处理来处理图片从而可以从中提取处一些更加有用的特征。我们可以通过图像处理减少图像噪声调整图像亮度、颜色或者对比度等等。想要进一步系统了解图像处理基础知识参看
pip install opencv-python3.4.2
pip install opencv-contrib-python3.3.1
安装完成后可以通过下方两条命令测试其是否正常工作。如果没有任何报错那么就可以开始使用了
import cv2
cv2.__version__
我们使用用OpenCV做的第一步就是导入一个图像如下方所示。
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
# Import the image
img cv2.imread(burano.jpg)
plt.imshow(img)
上图是在意大利最美丽的岛屿之一布拉诺所拍摄的。如果你去过这个地方你可能会注意到这幅图里有些不同。这确实和我们通常看到的布拉诺的照片有点不同。这是因为OpenCV中颜色模式的默认设置顺序是BGR不同与Matplotlib。因此要在RGB模式下查看图像我们需要将它从BGR转换为RGB如下所示。
# Convert the image into RGB
img_rgb cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img_rgb)
这张图就是真正的布拉诺了多么美丽
二、不只是RGB
我们再来谈谈颜色模型。颜色模型是一个使用原色构建全系列颜色的系统。这里先介绍这两种不同的颜色模型“加色模型”和”减色模型”。加色模型使用光代表计算机屏幕上的颜色而减色模型使用墨水在纸上打印这些数字图像。前者的原色由红色、绿色和蓝色(RGB)组成后者有蓝色、品红、黄色和黑色(CMYK)四种原色组成。我们在图像上看到的所有其他颜色都是由这些原色组合或混合而成的。所以当分别用RGB、CMYK表示一张图像时图像可以有着略微不同地表达。如下图所示。
日常生活中见到最多的就是这两种颜色模型。然而在彩色模型的世界里不仅仅只有这两种颜色模型。众多的颜色模型中灰度(grayscale)、HSV和HLS也是你会在计算机视觉任务中经常看到的。
灰度(grayscale)很简单。它通过黑白的强度来表示图像和形态这也意味着它只有一个通道。要查看灰度图像我们需要将颜色模型转换为灰色就像前面对BGR图像所做的操作那样。
# Convert the image into gray scale
img_gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
plt.imshow(img_gray, cmap gray)
实际上RGB图像是由三个通道叠加而成的R, G, b。所以如果我们把每个通道一个一个的描绘出来我们就可以理解颜色通道是如何构成的了
# Plot the three channels of the image
fig, axs plt.subplots(nrows 1, ncols 3,figsize (20, 20))
for i in range(0, 3):
ax axs[i]
ax.imshow(img_rgb[:, :, i], cmap gray)
plt.show()
观察上面的图片。这三幅图像展示了每个通道是如何组成的。在R通道图中红色饱和度高的部分看起来是白色的。这是由于红色部分中的值接近255。在灰度模式下值越高颜色就越白。你还可以使用G或B通道来检查这一点并比较某些部分之间的差异。
HSV和HLS有一些不同。正如在上图看到的那样他们有一个三维的表达更类似于人类的感知方式。HSV代表色调、饱和度和色值。HSL代表色调、饱和度和亮度。HSV的中轴是色值HSL的中轴是光量。沿着中心轴的角度有色调和实际的颜色。与中心轴的距离属于饱和度。转换颜色模型的方法如下。
# Transform the image into HSV and HLS models
img_hsv cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
img_hls cv2.cvtColor(img, cv2.COLOR_BGR2HLS)
# Plot the converted images
fig, (ax1, ax2) plt.subplots(nrows 1, ncols 2, figsize (20, 20))
ax1.imshow(img_hsv)
ax2.imshow(img_hls)
plt.show()
但是为什么要变换颜色这些有什么用处一个很典型的例子—车道检测。观察下图不同颜色模式下的车道线。在计算机视觉任务中我们利用掩膜(masking)进行多色模式转换。如果你想了解更多关于图像处理在车道检测任务中的应用可参看这篇文章。
图像处理是就是对图像数据进行预处理。它可以减少噪音提取有用的颜色模型从而简化分类和检测任务。因此所有上述技术包括我们稍后将讨论的技术都是为了帮助模型更容易地实现检测。
三、在图像上绘制图形
让我们在图像上添加一些图形。咱们这次代码示例中使用的图片来自巴黎“爱的墙”。上面用各种国际语言写满了“我爱你”。我们要做的是找到语言中的单词并用矩形标记它们。假如我们要定位韩语版本“我爱你”。首先复制原始图像并用cv2.rectangle()函数绘制一个矩形同时给出左上角和右下角的坐标值。如下
# Copy the image
img_copy img.copy()
# Draw a rectangle
cv2.rectangle(img_copy, pt1 (800, 470), pt2 (980, 530),
color (255, 0, 0), thickness 5)
plt.imshow(img_copy)
使用cv2.circle()函数画一个圆圈出更多的韩语单词。我们需要指定它的圆心的点和半径的长度。
# Draw a circle
cv2.circle(img_copy, center (950, 50), radius 50,
color (0, 0, 255), thickness 5)
plt.imshow(img_copy)
我们还可以将文本数据放在图像上。使用cv2.putText()函数我们可以指定文本的位置、字体样式和大小。
# Add text
cv2.putText(img_copy, text "the Wall ofLove",
org (250, 250),
fontFace cv2.FONT_HERSHEY_DUPLEX,
fontScale 2,
color (0, 255, 0),
thickness 2,
lineType cv2.LINE_AA)
plt.imshow(img_copy)
四、不止是图像
在上边的介绍中我们选取意大利和法国的两张风景图作为示例。假如我们想要画张地图把这些地方标出来。那么首先我们要创建一个窗口并绘制图形。不一样的是这里不是通过指定点绘制图形而是通过点击响应。先试试绘制圆圈。首先创建一个函数它将用位置和鼠标点击的数据绘制一个圆圈。
# Step 1. Define callback function
def draw_circle(event, x, y, flags, param):
ifevent cv2.EVENT_LBUTTONDOWN:
cv2.circle(img, center (x, y), radius 5,
color (87, 184, 237), thickness -1)
elifevent cv2.EVENT_RBUTTONDOWN:
cv2.circle(img, center (x, y), radius 10,
color (87, 184, 237),thickness 1)
当按下鼠标点击按钮时使用cv2.EVENT_LBUTTONDOWN或
cv2.EVENT_RBUTTONDOWN记录位置数据。把鼠标的位置设置为圆心(x, y)并绘制圆圈。
# Step 2. Call the window
img cv2.imread(map.png)
cv2.namedWindow(winname my_drawing)
cv2.setMouseCallback(my_drawing, draw_circle)
设置一个地图作为窗口的背景并将窗口命名为my_drawing。使用cv2.setMouseCallback()函数在窗口和我们在步骤1中创建的函数draw_circle之间建立了一个连接。
# Step 3. Execution
while True:
cv2.imshow(my_drawing,img)
ifcv2.waitKey(10) 27:
break
cv2.destroyAllWindows()
现在我们使用while循环执行窗口。if子句的执行条件是当我们按下键盘上的ESC时将窗口设置为关闭。
接下来尝试绘制一个矩形。由于在cv2.rectangle()函数中矩形需要两个点来表示pt1和pt2所以我们需要一个额外的步骤来设置第一个点击点为pt1最后一个点击点为pt2。我们要用cv2.EVENT_MOUSEMOVE和cv2.EVENT_LBUTTONUP来检测鼠标的移动。
我们首先将drawing False定义为默认值。当按下左键时绘图变为true我们将第一个位置设为pt1。如果正在绘图它将以当前点为pt2并在移动鼠标时继续绘制矩形。就像数字重叠一样。当左键打开时绘图变为false它将鼠标的最后一个位置作为pt2的最后一个点。
# Initialization
drawing False
ix -1
iy -1
# create a drawing function
def draw_rectangle(event, x, y, flags, params):
globalix, iy, drawing
ifevent cv2.EVENT_LBUTTONDOWN:
drawing True
ix,iy x, y
elifevent cv2.EVENT_MOUSEMOVE:
ifdrawing True:
cv2.rectangle(img, pt1(ix, iy), pt2(x, y),
color (87, 184,237), thickness -1)
elifevent cv2.EVENT_LBUTTONUP:
drawing False
cv2.rectangle(img, pt1(ix, iy), pt2(x, y),
color (87, 184, 237),thickness -1)
在步骤1中将draw_circle函数替换为draw_rectangle。请不要忘记在回调函数cv2.setMouseCallback()中进行更改。因此整个代码脚本将如下所示。
import cv2
import numpy as np
# Step 1. Define callback function
drawing False
ix -1
iy -1
def draw_rectangle(event, x, y, flags, params):
globalix, iy, drawing
ifevent cv2.EVENT_LBUTTONDOWN:
drawing True
ix,iy x, y
elifevent cv2.EVENT_MOUSEMOVE:
ifdrawing True:
cv2.rectangle(img, pt1 (ix, iy), pt2 (x, y),
color (87, 184,237), thickness -1)
elifevent cv2.EVENT_LBUTTONUP:
drawing False
cv2.rectangle(img, pt1 (ix, iy), pt2 (x, y),
color (87, 184, 237),thickness -1)
# Step 2. Call the window
img cv2.imread(map.png)
cv2.namedWindow(winname my_drawing)
cv2.setMouseCallback(my_drawing,draw_rectangle)
# Step 3. Execution
while True:
cv2.imshow(my_drawing, img)
ifcv2.waitKey(10) 27:
break
cv2.destroyAllWindows()
五、总结与展望
本篇文章介绍了Opencv的安装、图像颜色模型的转换与图形绘制。下次将介绍图像轮廓提出与目标检测等技术。敬请期待