图片处理

图片的预处理在机器学习中是一个重要且有效的步骤,可以使图片转换成适应模型的格式,也可进行数据增强和数据归一化等。
本文将对常用的图片处理方法进行归纳。

OpenCV-Python方法

教程:https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_tutorials.html

opencv以BGR模式加载图片。

使用需 import cv2

读写展示图片

读本地图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cv2.imread(filepath,flags)

#参数一:工作路径or完整路径 参数二:读取这幅图片方式,可省略
#参数二:
#cv2.IMREAD_COLOR:默认参数,读入一副彩色图片,忽略alpha通道,实际取值为1
#cv2.IMREAD_GRAYSCALE:读入灰度图片,实际取值为0
#cv2.IMREAD_UNCHANGED:顾名思义,读入完整图片,包括alpha通道

exp:
#读取工作路径下彩色图片
cv2.imread("1.jpg")

#读取完整路径下灰度图片
cv2.imread("/Users/mabelguo/1.jpg",0)

写图片到本地

1
2
3
4
5
6
7
8
9
cv2.imwrite(filepath,img)

#若保存为png,则保留alpha通道;保存为jpg,丢失alpha通道

exp:
cv2.imwrite("1.png",img)
````
### 窗体展示图片

#展示窗体,窗口自适应图片的大小
cv2.imshow(windowName,img)
#参数一:窗体标题 参数二:图像


#等待键盘输入,否则窗体一闪而过
cv2.waitKey(0)
#销毁所有窗口
cv2.destroyAllWindows()

#可调整大小窗口
cv2.namedWindow(windowName,flag)
#如果我们想放大缩小窗口,必须单独用cv2.namedWindow(),并通过flag参数指定窗口模式为cv2.WINDOW_NORMAL,默认为cv2.WINDOW_AUTOSIZE.

flag:
窗口大小可以改变: cv2.WINDOW_NORMAL , cv2.WINDOW_GUI_NORMAL
窗口大小不可以改变: cv2.WINDOW_AUTOSIZE
窗口大小自适应比例: cv2.WINDOW_FREERATIO
窗口大小保持比例: cv2.WINDOW_KEEPRATIO
显示色彩变成暗色: cv2.WINDOW_GUI_EXPANDED

exp:
cv2.namedWindow(“lena”,0)
cv2.imshow(“lena”,img)
cv2.waitKey(0)
cv2.destroyAllWindows()

1
2
3

## 图像标注

#画直线
cv2.line()
cv2.line(img, pt1, pt2, color[, thickness[, lineType[, shift]]])

img,背景图
pt1,直线起点坐标
pt2,直线终点坐标
color,当前绘画的颜色。如在BGR模式下,传递(255,0,0)表示蓝色画笔。灰度图下,只需要传递亮度值即可。
thickness,画笔的粗细,线宽。若是-1表示画封闭图像,如填充的圆。默认值是1.


#画圈
cv2.circle()
cv2.circle(img, center, radius, color[, thickness[, lineType[, shift]]])

img,背景图
center,圆心
radius,半径
color,颜色
thickness,线粗细

#画矩形
cv2.rectangle()
cv2.rectangle(img, pt1, pt2, color[, thickness[, lineType[, shift]]])

1
2
3
4
5

## 图片常见预处理
### 利用numpy创建一张新的图片
OpenCV的基础数据类型为numpy.ndarray,numpy.ndarray中的每个元素的dtype应该为numpy.uint8。

import cv2
import numpy as np

#创建三通道黑色图片
img = np.zeros([w, h, 3], np.uint8)

#创建三通道白色图片
img = np.zeros([w, h, 3], np.uint8) + 255

#创建四通道黑色透明图片(需保存为png才能看到透明度)
img = np.zeros([w, h, 4], np.uint8)

#由于opencv 颜色通道顺序为BGR
蓝色通道为:img[:, :, 0]
绿色通道为:img[:, :, 1]
红色通道为:img[:, :, 2]
透明度通道为:img[:, :, 3]

1
### 颜色空间转换

image = cv2.imread(“1.png”)

#从BGR转到HSV颜色空间
image_hsv = cv2.cvtColor(image,cv2.COLOR_BGR2HSV)

#从彩色图转灰度图
image_ = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)

#从BGR转到RGB颜色空间
image_hsv = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)

1
### 图像去噪

#高斯滤波
cv2.GaussianBlur()

cv2.GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]])
@param: src: nparray
input image.
@param: ksize: (int,int)
Gaussian kernel size. ksize.width and ksize.height can differ
but they both must be positive and odd.
Or, they can be zero’s and then they are computed from sigma* .
@param: sigmaX: float
Gaussian kernel standard deviation in X direction.
@param: sigmaY: float
Gaussian kernel standard deviation in Y direction;
if sigmaY is zero, it is set to be equal to sigmaX,
if both sigmas are zeros, they are computed from ksize.width and ksize.height.
To fully control the result,
it is recommended to specify all of ksize, sigmaX, and sigmaY.

#exp
#可以自己构建高斯核
cv2.getGaussianKernel()
#也可以直接做模糊
blur = cv2.GaussianBlur(img, (6, 6), 1, 0)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
### 二值化
cv2.threshold()

函数原型:

cv2.threshold (src, thresh, maxval, type)

src:源图片,必须是单通道

thresh:阈值,取值范围0~255

maxval:填充色,取值范围0~255

type:阈值类型,见下表

| 阈值 | 小于阈值的像素点| 大于阈值的像素点|
| :--------: | :----- | :---- |
| 0| 置0| 置填充色|
| 1| 置填充色| 置0|
| 2| 保持原色| 置灰色|
| 3| 置0| 保持原色|
| 4| 保持原色| 置0|

ret, binary = cv2.threshold(gray, 80, 255, cv2.THRESH_BINARY_INV)

1
2
3
## 形态学处理
### 腐蚀

import cv2
import numpy as np

img = cv2.imread(‘j.png’,0)
kernel = np.ones((5,5), np.uint8)
erosion = cv2.erode(img,kernel,iterations=1)

1
2
3
4
5

### 膨胀

把分隔对象连起来很有用

dilation = cv2.dilate(img,kernel,iterations=1)

1
2
3
4
### 开运算:先腐蚀后膨胀

cv2.morphologyEx()

opening = cv2.morphologyEx(img,cv2.MORPH_OPEN,kernel)

1
2
3
4
### 闭运算:先膨胀后腐蚀

用来关闭前景对象里的小洞或小黑点很有用

closing = cv2.morphologyEx(img,cv2.MORPH_CLOSE,kernel)

1
2
### 形态梯度:物体的轮廓

gradient = cv2.morphologyEx(img,cv2.MORPH_GRADIENT,kernel)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

## 进阶方法
### 查找、绘制轮廓函数
cv2.findContours()

函数原型:

cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]])

| image| 源图像,一个8位单通道图像|
|------------- | -------------|
| contours| 检测到的轮廓|
| hierarchy| 轮廓级别信息。Hierarchy为可选输出变量|
| mode| 轮廓检索模式|
| method| 轮廓近似法|
| offset| 每个轮廓点移动的偏移量,可选参数,cv::Point()类型|

binary, contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
cv2.drawContours()

函数原型:

image = cv.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]])

函数参数:

|image|输入:源图像。单通道或3通道图像。|
|------------- | -------------|
|contours|输入:待绘制的轮廓|
|contourIdx|输入:待绘制的轮廓序号,-1为绘制所有轮廓。|
|color|输入:轮廓颜色|
|thickness|输入:轮廓粗细。int型变量,默认为1,值越大越粗|
|lineType|输入:绘制轮廓的线型。|
|hierarchy|输入:待绘制的轮廓级别。|
|maxLevel|输入:待绘制的轮廓最大级别。|
|method|输入:轮廓近似法|
|offset|输入:每个轮廓点移动的偏移量,可选参数。|

### 模板检测
cv2.matchTemplate()

函数原型:

cv2.matchTemplate(image, templ, method, result=None, mask=None)

image:待搜索图像

templ:模板图像

result:匹配结果

method:计算匹配程度的方法

关于匹配方法,使用不同的方法产生的结果的意义可能不太一样,有些返回的值越大表示匹配程度越好,而有些方法返回的值越小表示匹配程度越好。

关于参数 method:

CV_TM_SQDIFF 平方差匹配法:该方法采用平方差来进行匹配;最好的匹配值为0;匹配越差,匹配值越大。

CV_TM_CCORR 相关匹配法:该方法采用乘法操作;数值越大表明匹配程度越好。

CV_TM_CCOEFF 相关系数匹配法:1表示完美的匹配;-1表示最差的匹配。

CV_TM_SQDIFF_NORMED 归一化平方差匹配法

CV_TM_CCORR_NORMED 归一化相关匹配法

CV_TM_CCOEFF_NORMED 归一化相关系数匹配法

例子:

#导入所需库文件
import cv2
import numpy as np

#加载原始RGB图像
img_rgb = cv2.imread(“photo.jpg”) #创建一个原始图像的灰度版本,所有操作在灰度版本中处理,然后在RGB图像中使用相同坐标还原
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
#加载将要搜索的图像模板
template = cv2.imread(‘face.jpg’,0)
#记录图像模板的尺寸
w, h = template.shape[::-1]

#使用matchTemplate对原始灰度图像和图像模板进行匹配
res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
#设定阈值 threshold = 0.7
#res大于70%
loc = np.where( res >= threshold)

#使用灰度图像中的坐标对原始RGB图像进行标记
for pt in zip(*loc[::-1]):
cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (7,249,151), 2)

#显示图像
cv2.imshow(‘Detected’,img_rgb)
cv2.waitKey(0)
cv2.destroyAllWindows()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

## 图片常见统计学处理
### 直方图计算
cv.calcHist()函数

cv.calcHist(images,channels,mask,histSize,ranges )

images:uint8或float32类型的源图像,以方括号传入,如:[img]。

channels:计算直方图的通道的索引,也以方括号给出。灰度图像,值为[0]。彩色图B/G/R分别传入[0]/[1]/[2]。

mask:图像掩码。计算整幅图写None。若要查找图像特定区域的直方图,则必须为此创建一个掩码图像并将其作为掩码。

histSize:也叫bins,子区段数目,如果我们统计0-255每个像素值,bins=256;如果划分区间,比如0-15, 16-31…240-255这样16个区间,bins=16。

ranges:要计算的像素值范围,一般为[0,256)

如:hist = cv2.calcHist([img], [0], None, [256], [0, 256])

# Matplotlib方法
## 绘制直方图
Matplotlib.pyplot.hist()

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread(‘home.jpg’,0)
plt.hist(img.ravel(),256,[0,256])
plt.show()
```