Python Lib OpenCV

[TOC]

OpenCV -API (python)

APi Tutorials

imgproc 模块. 图像处理 OpenCV 2.3.2 documentation

  • 图像平滑(模糊)处理 blur /GaussianBlur / MedianBlur / BilaterFilter

  • 腐蚀-膨胀

  • 形态变换

一、Image I/O

imread

imsave

imshow()

resize

cv2.resize的第二个参数dim是(W, H)

1
cv2.resize(array, (W, H))

copyMakeBorder

cv2.copyMakeBorder的第二个到第五个参数是top, bottom, left, right,是先H后W

opencv中以左上角为原点,W方向为x,H方向为y

1
def copyMakeBorder(src, top, bottom, left, right, borderType, dst=None, value=None): # real signature unknown; restored from __doc__

扩充src的边缘,将图像变大,然后以各种外插方式自动填充图像边界,这个函数实际上调用了函数cv::borderInterpolate,这个函数最重要的功能就是为了处理边界,比如均值滤波或者中值滤波中,使用copyMakeBorder将原图稍微放大,然后我们就可以处理边界的情况了

CV demo {实现crop,pad)

使用opencv-python 对图像进行resize和填充
在图像输入神经网络之前,需要进行一定的处理,假设神经网络的图像输入是256 256然后进行了224 224的random crop。

我们需要进行如下处理:

读入原始图像

1
image = cv2.imread("img.jpg")

截取图像中有价值的部分

1
region = image[y1:y2, x1:x2]

确定图片的长边和短边,然后把长边resize到224,保持纵横比的情况下resize短边

1
2
3
4
5
6
w, h = x2 - x1, y2 - y1 # h, w = image.shape
m = max(w, h)
ratio = 224.0 / m
new_w, new_h = int(ratio * w), int(ratio *h)
assert new_w > 0 and new_h > 0
resized = cv2.resize(region, (new_w, new_h))

把图片进行填充,填充到256 256

1
2
3
4
5
6
7
8
9
10
11
12
W, H = 256, 256
top = (H - new_h) // 2
bottom = (H - new_h) // 2
if top + bottom + h < H:
bottom += 1

left = (W - new_w) // 2
right = (W - new_w) // 2
if left + right + w < W:
right += 1

pad_image = cv2.copyMakeBorder(resized, top, bottom, left, right, cv2.BORDER_CONSTANT, value = self.white)

图片在输入网络之后,训练的时候进行random crop,就会发生有一部分被截取掉的情况,而这正是我们想要的图像增强
在test阶段,是进行centre crop,而正好把整个图像都截取出来,而这正是我们想要的
值得注意的是,image.shape,cv2.resize和cv2.copyMakeBorder几个函数

image.shape的输出是(H, W, C)

三、形态变化

  • 形态变化是基于图像中物体的形态进行一些简单变换,通常在二值化的图像上进行,

1.侵蚀

侵蚀的基本思想就像土壤侵蚀一样,侵蚀着物体前景色(白色)的边界。形态学处理内核在图像窗口中滑动,只有当内核下的所有像素都为1时,原始图像中的像素(1或0)才会被视为1,否则它将被侵蚀(变为零)。*我要说话***

因此最终的表现就是,所有靠近前景色边界的像素都将而被丢弃,内核尺寸越大丢的越多,即白色的区域会减小。这种操作对于消除小的白色噪声(如我们在色彩空间一章中所看到的)、分离两个连接的对象等非常有用。

1
2
3
4
5
6
7
8
9
10
11
def pltShow(img):
dst = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(dst)

def testErosion():
img = cv2.imread('test.png', 0)
kernel = np.ones((5, 5), np.uint8)
erosion = cv2.erode(img, kernel, iterations=1)
plt.subplot(121),pltShow(img),plt.title("Origin")
plt.subplot(122),pltShow(erosion),plt.title("Erosion")
plt.show()

2.膨胀

膨胀的效果正好与侵蚀相反,如果内核下至少有一个像素为“1”,则像素元素为“1”。因此,它增加了图像中的白色区域(前景对象)的大小。*我要说话***

在去除噪音的时候,一般采用的操作是侵蚀之后再膨胀。侵蚀消除了白色的噪音,但它也缩小了物体,所以需要通过膨胀来还原。而噪音已经在侵蚀的过程中消失,膨胀的时候也不会再出现。例子:

1
2
img_3 = cv2.imread(img_path, mode)
erosion = cv2.dilate(img_3, kernel, iterations=1)

3 开运算

开运算就是2节中讲到的先侵蚀再膨胀的操作,可以认为是个语法糖吧。(外部杂点去除)

1
2
3
4
5
6
7
8
9
10
def testOpen():
img = cv2.imread("test2.png", 0)
kernel = np.ones((5,5), np.uint8)
erosion = cv2.erode(img, kernel, iterations=1)
dilateAfterErosion = cv2.dilate(erosion, kernel, iterations=1)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
plt.subplot(131), pltShow(img), plt.title("Origin")
plt.subplot(132), pltShow(dilateAfterErosion), plt.title("DilateAfterErosion")
plt.subplot(133), pltShow(opening), plt.title("Opening")
plt.show()

4 闭运算

顾名思义,开运算与闭运算是相反的语法糖——先膨胀再侵蚀,其作用也可以想象到了,可以填充上物体内部的杂点。

1
2
3
4
5
6
7
8
9
10
def testClose():
img = cv2.imread("test3.png", 0)
kernel = np.ones((5,5), np.uint8)
dilate = cv2.dilate(img, kernel, iterations=1)
erosionAfterDilate = cv2.erode(dilate, kernel, iterations=1)
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
plt.subplot(131), pltShow(img), plt.title("Origin")
plt.subplot(132), pltShow(erosionAfterDilate), plt.title("ErosionAfterDilate")
plt.subplot(133), pltShow(closing), plt.title("Closing")
plt.show()

5.形态梯度

出现梯度变化的地方前景色保留,其它的去掉,用于检测边缘

1
2
3
4
5
6
7
def testGradient():
img = cv2.imread('test.png', 0)
kernel = np.ones((2, 2), np.uint8)
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
plt.subplot(121), pltShow(img), plt.title("Origin")
plt.subplot(122), pltShow(gradient), plt.title("Gradient")
plt.show()

6.tophat

顶帽 = 原图 - 开运算

开运算的效果是去除图像外的噪点,因此原图 - 开运算就得到了去掉的噪点

通过API — morphologyEx(img, MORPH_TOPHAT, kernel)

1
2
3
4
5
6
7
8
9
10
import cv2
import numpy as np
cv2.namedWindow("img", cv2.WINDOW_NORMAL)
cv2.resizeWindow("img", 640, 480)
img = cv2.imread("i.png")
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
new_img = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel, iterations=1)
cv2.imshow("img", np.hstack((img, new_img)))
cv2.waitKey(0)
cv2.destroyAllWindows()

7. blackhat

黑帽 = 原图 - 闭运算

闭运算可以将图形内部的噪声点去掉,那么原图 - 闭运算的结果就是图形内部的噪声点

通过API — morphologyEx(img, MORPH_BLACKHAT, kernel)

1
2
3
4
5
6
7
8
9
10
11
import cv2
import numpy as np
cv2.namedWindow("img", cv2.WINDOW_NORMAL)
cv2.resizeWindow("img", 640, 480)
img = cv2.imread("is.png")
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
# 黑帽操作
new_img = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel, iterations=1)
cv2.imshow("img", np.hstack((img, new_img)))
cv2.waitKey(0)
cv2.destroyAllWindows()

8. 自定义内核

四、图像处理

图像金字塔

图像阈值操作

五、仿射变换

  • 旋转(线性)

  • 平移(向量加)

  • 缩放(线性变换)

getAffineTransform

1
2
warp_mat = getAffineTransform( srcTri, dstTri );
warpAffine( src, warp_dst, warp_mat, warp_dst.size() );

rotation

1
2
rot_mat = getRotationMatrix2D( center, angle, scale );
warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() );

轮廓

rectangle & boundingRect

Bounding Rectangle

然后利用cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)画出矩行

1
2
3
4
5
6
参数解释
第一个参数:img是原图
第二个参数:(x,y)是矩阵的左上点坐标
第三个参数:(x+w,y+h)是矩阵的右下点坐标
第四个参数:(0,255,0)是画线对应的rgb颜色
第五个参数:2是所画的线的宽度
1
2
3
4
5
6
7
8
9
10
# 用绿色(0, 255, 0)来画出最小的矩形框架
x, y, w, h = cv2.boundingRect(cnt)
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)

# 用红色表示有旋转角度的矩形框架
rect = cv2.minAreaRect(cnt)
box = cv2.cv.BoxPoints(rect)
box = np.int0(box)
cv2.drawContours(img, [box], 0, (0, 0, 255), 2)
cv2.imwrite('contours.png', img)

七、Video api

1
2
3
4
5
6
7
8
9
10
11
12
# 1、表示打开笔记本的内置摄像头,
cap = cv2.VideoCapture(0)

# 2 视频文件路径
cap = cv2.VideoCapture(“../test.avi”)


# 3
ret,frame = cap.read()

# 4
cap.release()

八、应用

Sobel导数

如何计算梯度,以及如何使用梯度来检测边缘。

Laplace算子

边缘检测算法。

Canny边缘检测

这儿是一个更高级的边缘检测算法。

霍夫线变换

霍夫变换来检测直线。

霍夫圆变换

霍夫变换来检测圆。

Remapping重映射

两副图像之间建立坐标位置的映射。

九、CV Face

CascadeClassifier

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
haarcascade_eye.xml
haarcascade_eye_tree_eyeglasses.xml
haarcascade_frontalcatface.xml
haarcascade_frontalcatface_extended.xml
haarcascade_frontalface_alt.xml
haarcascade_frontalface_alt2.xml
haarcascade_frontalface_alt_tree.xml
haarcascade_frontalface_default.xml
haarcascade_fullbody.xml
haarcascade_lefteye_2splits.xml
haarcascade_licence_plate_rus_16stages.xml
haarcascade_lowerbody.xml
haarcascade_profileface.xml
haarcascade_righteye_2splits.xml
haarcascade_russian_plate_number.xml
haarcascade_smile.xml
haarcascade_upperbody.xml

1、人脸检测

cv.CascadeClassifier

1
2
# 人脸检测haarcascade_frontalface_default
faceCascade = cv2.CascadeClassifier("XML/haarcascade_frontalface_default.xml")

Dlib

人脸提取+关键点检测

CNN人脸检测模型名称: mmod_human_face_detector.dat.bz2

68维人脸检测模型名称: shape_predictor_68_face_landmarks.dat.bz2

5维人脸检测模型名称 shape_predictor_5_face_landmarks.dat.bz2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
detector = dlib.cnn_face_detection_model_v1(face_detector_model_path)  # dlib.cnn_face_detection_model_v1
# detector = dlib.get_frontal_face_detector()

predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')


detections = detector(img, 1)

# step 3. get shape of one face for example
detection = detections[0] # dlib.mmod_rectangle
# the mmod_rectangle contains two parts : confidence and rect

shape = predictor(img, detection.rect) # dlib.full_object_detection

# step 4. get all the face landmark points
landmark_points = shape.parts() # dlib.points