【数字图像处理系列一】opencv-python快速入门篇

【数字图像处理系列一】opencv-python快速入门篇

本系列python版本:python3.5.4
本系列opencv-python版本:opencv-python3.4.2.17
本系列使用的开发环境是jupyter notebook,是一个python的交互式开发环境,测试十分方便,并集成了vim操作,安装教程可参考:windows上jupyter notebook主题背景、字体及扩展插件配置(集成vim环境)


本文我们将一起学习使用opencv-python对数字图像进行简单的处理,快速理解数字图像的原理,主要介绍opencv-python的安装;如何读取、展示和存储图像以及对于数字图像的基本操作和理解

先展示一张程序运行截图:


一、opencv-python简介与安装


opencv 是用于快速处理图像处理、计算机视觉问题的工具,支持多种语言进行开发如c++、python、java等。本教程所有示例基于opencv-python,使用python语言对数字图像进行处理和研究。

首先我们需要安装一下环境
1、 python3
2、 numpy
3、 opencv-python

安装python3: 廖雪峰python教程有详细的说明,网址安装python
安装numpy:pip install numpy
安装opencv-python: pip install opencv-python

安装完opencv-python后命令行打开python交互式环境:import cv2 成功,便说明成功安装了opencv-python


二、opencv-python读取、展示和存储图像


1、imread函数

imread函数读取数字图像,先看一下官网对于该函数的定义

cv2.imread(path_of_image, intflag)

函数参数一: 需要读入图像的完整的路径
函数参数二: 标志以什么形式读入图像,可以选择一下方式:
· cv2.IMREAD_COLOR: 加载彩色图像。任何图像的透明度都将被忽略。它是默认标志
· cv2.IMREAD_GRAYSCALE:以灰度模式加载图像
· cv2.IMREAD_UNCHANGED:保留读取图片原有的颜色通道

· 1 :等同于cv2.IMREAD_COLOR
· 0 :等同于cv2.IMREAD_GRAYSCALE
· -1 :等同于cv2.IMREAD_UNCHANGED

来个示例更清楚:

import numpy as np
import cv2

gray_img = cv2.imread('img/cartoon.jpg', 0)  #加载灰度图像
rgb_img = cv2.imread('img/cartoon.jpg', 1)   #加载RGB彩色图像


2、imshow函数

imshow函数作用是在窗口中显示图像,窗口自动适合于图像大小,我们也可以通过imutils模块调整显示图像的窗口的大小。函数官方定义如下:

cv2.imshow(windows_name, image)

函数参数一: 窗口名称(字符串)
函数参数二: 图像对象,类型是numpy中的ndarray类型,注:这里可以通过imutils模块改变图像显示大小,下面示例展示

上示例:

cv2.imshow('origin image', rgb_img)   #显示原图
cv2.imshow('origin image', imutils.resize(rgb_img, 800))  #利用imutils模块调整显示图像大小
cv2.imshow('gray image', imutils.resize(gray_img, 800))
if cv2.waitKey(0) == 27:
    cv2.destroyAllWindows()


3、imwrite函数

imwrite函数检图像保存到本地,官方定义:

cv2.imwrite(image_filename, image)

函数参数一: 保存的图像名称(字符串)
函数参数二: 图像对象,类型是numpy中的ndarray类型

cv2.imwrite('rgb_img.jpg', rgb_img)   #将图像保存成jpg文件
cv2.imwrite('gray_img.png', gray_img) #将图像保存成png文件


4、窗口销毁函数

当我们使用imshow函数展示图像时,最后需要在程序中对图像展示窗口进行销毁,否则程序将无法正常终止,常用的销毁窗口的函数有下面两个:
(1)、cv2.destroyWindow(windows_name) #销毁单个特定窗口
参数: 将要销毁的窗口的名字

(2)、cv2.destroyAllWindows() #销毁全部窗口,无参数

那我们合适销毁窗口,肯定不能图片窗口一出现我们就将窗口销毁,这样便没法观看窗口,试想有两种方式:
(1) 让窗口停留一段时间然后自动销毁;
(2) 接收指定的命令,如接收指定的键盘敲击然后结束我们想要结束的窗口
以上两种情况都将使用cv2.waitKey函数, 首先产看函数定义:

cv2.waitKey(time_of_milliseconds)

唯一参数 time_of_milliseconds是整数,可正可负也可是零,含义和操作也不同,分别对应上面说的两种情况

(1) time_of_milliseconds > 0 :此时time_of_milliseconds表示时间,单位是毫秒,含义表示等待 time_of_milliseconds毫秒后图像将自动销毁,看以下示例

#表示等待10秒后,将销毁所有图像
if cv2.waitKey(10000):
    cv2.destroyAllWindows()

#表示等待10秒,将销毁窗口名称为'origin image'的图像窗口
if cv2.waitKey(10000):
    cv2.destroyWindow('origin image')


(2) time_of_milliseconds <= 0 : 此时图像窗口将等待一个键盘敲击,接收到指定的键盘敲击便会进行窗口销毁。我们可以自定义等待敲击的键盘,通过下面的例子进行更好的解释

#当指定waitKey(0) == 27时当敲击键盘 Esc 时便销毁所有窗口
if cv2.waitKey(0) == 27:
    cv2.destroyAllWindows()

#当接收到键盘敲击A时,便销毁名称为'origin image'的图像窗口
if cv2.waitKey(-1) == ord('A'):
    cv2.destroyWindow('origin image')


下面给出一个完整读取、展示、保存和图像销毁示例:

import cv2
import imutils
import numpy as np

rgb_img = cv2.imread('E:/peking_rw/ocr_project/base_prehandle/img/cartoon.jpg')
gray_img = cv2.cvtColor(rgb_img, cv2.COLOR_BGR2GRAY)
cv2.imshow('origin image', imutils.resize(rgb_img, 800))
cv2.imshow('gray image', imutils.resize(gray_img, 800))
cv2.imwrite('rgb_img.jpg', rgb_img)
cv2.imwrite('gray_img.png', gray_img)

#等待一定时间自动销毁图像窗口
#if cv2.waitKey(10000):
#    cv2.destroyAllWindows()
#if cv2.waitKey(10000):
#    cv2.destroyWindow('origin image')

#接收特定键盘销毁图像窗口
#if cv2.waitKey(-1) == ord('A'):
#    cv2.destroyWindow('origin image')
if cv2.waitKey(0) == 27:
    cv2.destroyAllWindows()


原图展示在本文开头展示,灰度图像如下所示:


三、图像色彩空间变换函数cv2.cvtColor


本节将图像色彩空间变换函数单独拉出来说,原因:

1、该函数十分常用; 2、应明白为什么需要做图像色彩空间的处理

首先展示一下图像色彩空间变换函数定义:

cv2.cvtColor(input_image, flag)

参数一: input_image表示将要变换色彩的图像ndarray对象
参数二: 表示图像色彩空间变换的类型,以下介绍常用的两种:
· cv2.COLOR_BGR2GRAY: 表示将图像从BGR空间转化成灰度图,最常用
· cv2.COLOR_BGR2HSV: 表示将图像从RGB空间转换到HSV空间

如果想查看参数flag的全部类型,请执行以下程序便可查阅,总共有274种空间转换类型:

import cv2
flags = [i for i in dir(cv2) if i.startswith('COLOR_')]
print(flags)


在之后的图像特征提取和识别学习中,我们经常使用的是将彩色图像转化成灰度图像, 这里解释一下为什么我么总是对灰度图进行处理,增强对以后图像处理操作的理解

图像的颜色主要是由于图像受到外界光照影响随之产生的不同颜色信息,同一个背景物的图像在不同光源照射下产生的不同颜色效果的图像,因此在我们做图像特征提取和识别过程时,我们要的是图像的梯度信息,也就是图像的本质内容,而颜色信息会对我们对梯度信息提取造成一定的干扰,因此我们会在做图像特征提取和识别前将图像转化为灰度图,这样同时也降低了处理的数据量并且增强了处理效果。


四、绘制自定义数字图像


本小节目的主要是跟着大家通过自定义数字图像来理解什么是数字图像? 为什么前面提到的图像对象是numpy中的ndarray对象


1、绘图简单图像

对于一个长宽分别为w、h的RGB彩色图像来说,它的每个像素值是由(B、G、R)的一个tuple组成,opencv-python中每个像素三个值的顺序是B、G、R,而对于灰度图像来说,每个像素对应的便只是一个整数,如果要把像素缩放到0、1,则灰度图像就是二值图像,0便是黑色,1便是白色。我们通过下面的例子来理解一下

import cv2
#这里图像采用的仍旧是上面那个卡通美女啦
rgb_img = cv2.imread('E:/peking_rw/ocr_project/base_prehandle/img/cartoon.jpg')
print(rgb_img.shape)     #(1200, 1600, 3)
print(rgb_img[0, 0])     #[137 124  38]
print(rgb_img[0, 0, 0])  #137

gray_img = cv2.cvtColor(rgb_img, cv2.COLOR_BGR2GRAY)
print(gray_img.shape)    #(1200, 1600)
print(gray_img[0, 0])    #100

从上面我们可以看到彩色图像的高度height = 1200, 宽度w=1600且通道数为3, 像素(0, 0)的值是(137 124 38),即R=137, G=124, B=38, 对于灰度图像来说便只是单通道的了

因此(0, 0, 0)便是代表一个黑色像素,(255, 255, 255)便是代表一个白色像素。这么想,B=0, G=0, R=0相当于关闭了颜色通道也就相当于无光照进入,所以图像整个是黑的,而(255, 255, 255)即B=255, G=255, R=255, 相当于打开了B、G、R所有通道光线全部进入,因此便是白色。


明白了上面的原理我们便可以通过创建numpy的ndarray对象来创建任意的彩色图像和灰度图像了,例如:

import cv2
import numpy as np

white_img = np.ones((512,512,3), np.uint8)
white_img = 255*white_img
cv2.imshow('white_img', white_img)
if cv2.waitKey(0) == 27:
    cv2.destroyAllWindows()

效果图:


接下来我们先来熟悉一下opencv中一些简单几何图像基本绘制函数,然后我们尝试着在上面白色的图像上进行添加新的图像物体,是不是还挺有趣的,我们将介绍直线cv2.line、长方形cv2.rectangle、圆cv2.circle、椭圆cv2.ellipse、多边形cv2.polylines等集合图像绘制函数


先介绍一下它们的公共参数:
· img: 表示需要进行绘制的图像对象ndarray
· color: 表示绘制几何图形的颜色,采用BGR即上述说的(B、G、R)
· thickness: 表示绘制几何图形中线的粗细,默认为1,对于圆、椭圆等封闭图像取-1时是填充图形内部
· lineType : 表示绘制几何图形线的类型,默认8-connected线是光滑的,当取cv2.LINE_AA时线呈现锯齿状


(1) cv2.line函数

直线绘制函数, 函数官方定义为:

cv2.line(image, starting, ending, color, thickness, lineType)

参数image、color、thickness、lineType分别是上述公共定义,参数starting、ending分别表示线的起点像素坐标、终点像素坐标


(2) cv2.rectangle函数

长方形绘制函数,函数官方定义:

cv2.rectangle(image, top-left, bottom-right, color, thickness, lineType)

参数image、color、thickness、lineType分别是上述公共定义,参数top-left、bottom-right分别表示长方形的左上角像素坐标、右下角像素坐标


(3) cv2.circle函数
圆形绘制函数,官方定义函数为:

cv2.circle(image, center, radius, color, thickness, lineType)

参数image、color、thickness、lineType分别是上述公共定义,参数center、radius分别表示圆的圆心像素坐标、圆的半径长度,圆绘制函数中当参数thickness = -1 时绘制的是实心圆,当thickness >= 0 时绘制的是空心圆


(4) cv2.ellipse函数
椭圆绘制函数,官方定义为:

cv2.circle(image, center, (major-axis-length, minor-axis-length), angle, startAngle, endAngle, color, thickness, lineType)

椭圆的参数较多,首先参数image、color、thickness、lineType分别是上述公共定义,椭圆绘制函数中当参数thickness = -1 时绘制的是实心椭圆,当thickness >= 0 时绘制的是空心椭圆,其他参数如下

· center: 表示椭圆中心像素坐标
· major-axis-length: 表示椭圆的长轴长度
· minor-axis-length: 表示椭圆的短轴长度
· angle: 表示椭圆在逆时针方向旋转的角度
· startAngle: 表示椭圆从主轴向顺时针方向测量的椭圆弧的起始角度
· endAngle: 表示椭圆从主轴向顺时针方向测量的椭圆弧的终止时角度


(5) cv2.polylines函数
多边形绘制函数,官方定义函数为:

cv2.polylines(image, [point-set], flag, color, thickness, lineType)

参数image、color、thickness、lineType分别是上述公共定义,其他参数如下:

· [point-set]: 表示多边形点的集合,如果多边形有m个点,则便是一个m*1*2的数组,表示共m个点
· flag: 当flag = True 时,则多边形是封闭的,当flag = False 时,则多边形只是从第一个到最后一个点连线组成的图像,没有封闭


现在我们将上面五种几何图像绘制到开始的白色图像上,观看效果:

import cv2
import numpy as np

img = np.ones((512,512,3), np.uint8)
img = 255*img
img = cv2.line(img, (100,100), (400,400),(255, 0, 0), 5)
img = cv2.rectangle(img,(200, 20),(400,120),(0,255,0),3)
img = cv2.circle(img,(100,400), 50, (0,0,255), 2)
img = cv2.circle(img,(250,400), 50, (0,0,255), 0)
img = cv2.ellipse(img,(256,256),(100,50),0,0,180,(0, 255, 255), -1)
pts = np.array([[10,5],[20,30],[70,20],[50,10]], np.int32)
img = cv2.polylines(img,[pts],True,(0, 0, 0), 2)

cv2.imshow('img', img)
if cv2.waitKey(0) == 27:
    cv2.destroyAllWindows()


自定义图像效果图:


2、对图像的简单像素操作

除了根据数字图像特点绘制特定图像,我们还可以对已有的图像像素进行操作然后得到很多神奇的效果,也就是对图像的像素进行变换

(1) 对图像取反

reverse_img = 255 - gray_img  

图像取反效果图:



(2) 对图像像素线性变换

for i in range(gray_img.shape[0]):
    for j in range(gray_img.shape[1]):
        random_img[i, j] = gray_img[i, j]*1.2

图像像素线性变换效果图:


上述两个图像变换完整示例代码:

import cv2
import imutils
import numpy as np

rgb_img = cv2.imread('E:/peking_rw/ocr_project/base_prehandle/img/cartoon.jpg')
gray_img = cv2.cvtColor(rgb_img, cv2.COLOR_BGR2GRAY)
reverse_img = 255 - gray_img

random_img = np.zeros((gray_img.shape[0], gray_img.shape[1]), dtype=np.uint8)
for i in range(gray_img.shape[0]):
    for j in range(gray_img.shape[1]):
        random_img[i, j] = gray_img[i, j]*1.2
cv2.imshow('reverse_img', imutils.resize(reverse_img, 800))
cv2.imshow('random_img', imutils.resize(random_img, 800))
if cv2.waitKey(0) == 27:
    cv2.destroyAllWindows()


五、结语


相信认真一起看完上述知识点,opencv-python已经对于图像的基本操作可以熟练掌握了,同时对数字图像有了一定的理解,在接下来的教程中我还将陆续和大家一起学习诸如:
· 基本概念:亮度、对比度、分辨率、饱和度、尖锐化等基础概念
· 图像灰度变换:线性、分段线性、对数、反对数、幂律(伽马)变换等
· 图像滤波:线性滤波和非线性滤波、空间滤波和频率域滤波,均值滤波、中值滤波、高斯滤波、逆滤波、维纳滤波等各种图像的基本操作

在上述学习完之后然后我们在和大家一起学习一些高级的图像操作如:
· 文本图像的倾斜矫正方法:霍夫变换、透视变换等
· 图像边缘检测:canny算子、sobel算子、Laplace算子、Scharr滤波器等。。。


更多资源

CSDN博客可访问: feilong_csdn的博客 - 第 1 页 - CSDN博客

机器学习更多资源请关注公众号: 机器学习与TensorFlow实战

如需可扫码关注: thyrsi.com/t6/360/15347

发布于 2018-09-11

文章被以下专栏收录