OpenCV 图像的基本处理 1.1 图片读取和显示 1.2 写入文件(保存) 1.3 像素操作 1.4 图片剪切 1.5 镜像处理: 1.6 图像缩放 1.7 图像位移 1.8 图像旋转 1.9 仿射变换 1.10 图像融合 1.11 灰度处理 1.12 颜色反转 1.13 马赛克 1.14 毛玻璃 1.15 浮雕效果 1.16 图形绘制 1.17 亮度增强 1.18 直方图均衡化 1.19 视频处理 1.20 HSV颜色空间 1.21 阈值处理 1.22 人脸识别 最近因项目需要加上自己的兴趣,需要用一些opencv相关的东西,虽然之前零零碎碎学习过一些,但是很久不用就忘了,打算写篇文章总结一下学习的过程以及一些常用的函数。类似的博文有很多,但还是觉得自己总结一编印象深一些。

1.1 图片读取和显示

读取:cv.imread(“图片路径”, “读取的方式”) 显示:cv.imshow(“窗口名称”, “图片数据”) 读取方式: 分别有如下三种: cv.IMREAD_COLOR : 以彩图的方式加载,会忽略透明度(默认方式) cv.IMREAD_GRAYSCALE: 以灰色图片方式加载 cv.IMREAD_UNCHANGED: 直接加载,透明度会得到保留 例:  
import cv2 as cv

# 读取图片 参数1:图片路径, 参数2:读取的方式 
img = cv.imread("img/lena.png", cv.IMREAD_COLOR)
# 显示窗口 参数1:窗口名称, 参数2:图片数据
cv.imshow("src", img)

# 让程序处于等待推出状态
cv.waitKey(0)
# 当程序推出时,释放所有窗口资源
cv.destroyAllWindows()

1.2 写入文件(保存)

import cv2 as cv
img = cv.imread("img/lena.png", cv.IMREAD_UNCHANGED)

# 将图片写入到磁盘中,参数1: 图片写入路径,参数2: 图片数据
cv.imwrite("img/lena_copy.png", img)

cv.waitKey(0)
cv.destroyAllWindows()

1.3 像素操作

import cv2 as cv
import numpy as np

# 构建一个空白的矩阵
img = np.zeros((30, 40, 3), np.uint8)

# 将第15行所有像素点全都改成红色
for i in range(40):
    # 设置第15行颜色为红色
    img[15, i] = (0, 0, 255)

# 显示图片
cv.imshow("src", img)

cv.waitKey(0)
cv.destroyAllWindows()

1.4 图片剪切

剪切:mat[起始行号:结束行号,开始列号:结束列号]  
import cv2 as cv

# 读取原图
img = cv.imread("img/lena.jpg", cv.IMREAD_COLOR)
cv.imshow("source", img)
# 从图片(230,230) 截取一张 宽度130,高度70的图片
dstimg = img[180:250, 180:310]
# 显示图片
cv.imshow("result", dstimg)

cv.waitKey(0)

1.5 镜像处理:

  获取宽高信息:  
imgInfo = img.shape
imgInfo[0] : 表示高度
imgInfo[1] : 表示宽度
imgInfo[2] : 表示每个像素点由几个颜色值构成
  实现步骤: 创建一个两倍于原图的空白矩阵 将图像的数据按照从前向后,从后向前进行绘制  
import cv2 as cv
import numpy as np

# 创建两倍原图的大小的画布出来
img = cv.imread("../img/lena.jpg")
#  获取图像尺寸
print img.shape
height = img.shape[0]
width = img.shape[1]
print height, width

dst = np.zeros((height * 2, width, 3), np.uint8)

for row in range(height):
    for col in range(width):
        dst[row, col] = img[row, col]

        dst[height*2 - row - 1, col] = img[row, col]

cv.imshow("img", img)
cv.imshow("dst", dst)

cv.waitKey(0)

1.6 图像缩放

关于图片的缩放,常用有两种:
  • 等比例缩放
  • 任意比例缩放
  图片缩放的常见算法:
  • 最近领域插值
  • 双线性插值
  • 像素关系重采样
  • 立方插值
默认使用的是双线性插值法,可以利用opencv提供的 resize 方法来进行图片的缩放  
import cv2 as cv

img = cv.imread("../img/lena.jpg")

cv.imshow("src", img)
height = img.shape[0]
width = img.shape[1]

dst = cv.resize(img, (height*2, width*2))
cv.imshow("dst", dst)

cv.waitKey()

1.7 图像位移

矩阵运算:cv.warpAffine(原始图像,变换矩阵,(高度,宽度))  
import cv2 as cv
import numpy as np

img = cv.imread("../img/lena.jpg")
height, width = img.shape[0:2]
# 图像的位移
matrixShift = np.float32([[1, 0, 50], [0, 1, 100], ])
# 图像矩阵运算
dst = cv.warpAffine(img, matrixShift, (width, height))
cv.imshow("dst", dst)
cv.waitKey()

1.8 图像旋转

旋转变换:cv.getRotationMatrix2D((旋转中心),旋转角度,缩放系数)  
import cv2 as cv

img = cv.imread("../img/lena.jpg")
height, width = img.shape[0:2]
# 1.旋转中心, 2.旋转角度, 3. 缩放系数
M = cv.getRotationMatrix2D((width/2, height/2), 45, 0.5);
# 图像矩阵运算
dst = cv.warpAffine(img, M, (width, height));
cv.imshow("dst", dst)
cv.waitKey()

1.9 仿射变换

import cv2 as cv
import numpy as np

img = cv.imread("../img/itheima.jpg")
height, width = img.shape[0:2]
# 定义变换的参考点: 左上角,左下角,右上角
matrixSrc = np.float32([[0, 0], [0, height-1], [width-1, 0]]);
# 将上述三个点映射到一个新的坐标系中
matrixDst = np.float32([[50, 100], [300, height-200], [width-300,100]]);
# 计算从Src到Dst的变换矩阵
M = cv.getAffineTransform(matrixSrc, matrixDst);
# 仿射变换
dst = cv.warpAffine(img, M, (width, height))
cv.imshow("src", img)
cv.imshow("dst", dst)
cv.waitKey()

1.10 图像融合

import cv2 as cv
import numpy as np

src = cv.imread("../img/itheima.jpg")
tony = cv.imread("../img/tony.jpg")

dst = cv.addWeighted(src, 0.5, tony, 0.5, 100)

cv.imshow("src", src)
cv.imshow("tony", tony)
cv.imshow("dst", dst)

cv.waitKey()

1.11 灰度处理

import cv2 as cv

# 方式一 : 直接以灰度图像的形式读取
img = cv.imread("img/itheima.jpg", cv.IMREAD_GRAYSCALE)
cv.imshow("dstImg", img)
cv.waitKey(0)

# 方式二: 以彩图的方式读取
img = cv.imread("img/itheima.jpg", cv.IMREAD_COLOR)
# 将原图的所有颜色转成灰色
dstImg = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
cv.imshow("dstImg", dstImg)

cv.waitKey(0)
  原理演示  
import cv2 as cv
import numpy as np

src = cv.imread("../img/lena.jpg")
height, width = src.shape[0:2]

# 创建一个画布  0-255 + 0-255
dst = np.zeros((height, width, 1), np.uint8)

for row in range(height):
    for col in range(width):
        b, g, r = src[row, col]
        # gray = (int(b) + int(g) + int(r))/3
        # 0.299∗color.r + 0.587∗color.g + 0.114∗color.b
        gray = int(b) * 0.114 + int(g) * 0.587 + int(r) * 0.299
        # 将计算出来的灰度值填充到画布中
        dst[row, col] = gray

cv.imshow("dst", dst)
cv.waitKey()

1.12 颜色反转

灰图反转
import cv2 as cv
import numpy as np

src = cv.imread("../img/itheima.jpg")
height, width = src.shape[0:2]
grayImg = cv.cvtColor(src, cv.COLOR_BGR2GRAY)

cv.imshow("gray1", grayImg)
# 100 ---> 255 - 100 = 155
for row in range(height):
    for col in range(width):
        value = grayImg[row, col]
        grayImg[row, col] = 255 - value

cv.imshow("gray2", grayImg)
cv.imshow("src", src)
cv.waitKey()
彩图反转
import cv2 as cv
import numpy as np

src = cv.imread("../img/itheima.jpg")
height, width = src.shape[0:2]

# 创建画布
dst = np.zeros_like(src)

for row in range(height):
    for col in range(width):
        b, g, r = src[row, col]

        dst[row, col] = (255-b, 255-g, 255-r)

cv.imshow("src", src)
cv.imshow("dst", dst)
cv.waitKey()

1.13 马赛克

import cv2 as cv
import numpy as np

src = cv.imread('../img/itheima.jpg')
height, width = src.shape[0:2]
# 将图像划分成若干个4*4的小方块,
# 每一个小方块里面的所有像素值修改为和第一个像素块的颜色一样

offset = 10
for row in range(160, 240):
    for col in range(380, 670):
        # 将图像划分成若干个4*4的小方块,
        if row%offset == 0 and col%offset == 0:
            # 获取当前位置的颜色快
            color = src[row, col]
            # 每一个小方块里面的所有像素值修改为和第一个像素块的颜色一样
            for i in range(offset):
                for j in range(offset):
                    src[row+i, col+j] = color

cv.imshow("src", src)
cv.waitKey()

1.14 毛玻璃

import cv2 as cv
import numpy as np
import random

src = cv.imread("../img/itheima.jpg")
height, width = src.shape[0:2]

offset = 10
# 创建一个和原图同样大小的画布
dst = np.zeros_like(src)

# 处理每一个像素
for row in range(height):
    for col in range(width):
        # 计算当前位置,周围的一个随机数
        # index = random.randint(0,offset);
        # 随机的行号
        randomRow = row + random.randint(0, offset)
        # 随机的列号
        randomCol = col + random.randint(0, offset)

        if randomRow > height - 1:
            randomRow = height - 1
        if randomCol > width - 1:
            randomCol = width - 1
        # 获取随机的周围颜色值
        color = src[randomRow, randomCol]
        # 填充到画布中
        dst[row, col] = color

cv.imshow("dst", dst)
cv.imshow("src", src)
cv.waitKey()

1.15 浮雕效果

import cv2 as cv
import numpy as np

src = cv.imread("../img/itheima.jpg")

# 将彩图转成灰度图
grayImg = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
height, width = src.shape[0:2]

# 创建一个空白的矩阵 , 画布
dst = np.zeros_like(grayImg)

for row in range(height):
    for col in range(width - 1):
        # 计算相邻两个像素的差值 , 水平方向
        gray0 = grayImg[row, col]
        gray1 = grayImg[row, col+1]

        # 计算相邻像素的梯度 uint8 0-255
        value = int(gray0) - int(gray1) + 120

        if value < 0:
            value = -value
        # 将计算出来的值填充一个新的画布中
        dst[row, col] = value

cv.imshow("src", src)
cv.imshow("dst", dst)
cv.imshow("gray", grayImg)
cv.waitKey()

1.16 图形绘制

import cv2 as cv
import numpy as np

src = np.zeros((400, 600, 3), np.uint8)

pt1 = (200, 100)
pt2 = (300, 200)
color = (255, 255, 0)

# 绘制线段 参数2:起始点 参数3:结束点 参数4:颜色 参数5:线条宽度
cv.line(src, pt1, pt2, color, 2)  # 图,zuoshang, youxia, yanse, xiankuan

# 绘制一个矩形 参数2:左上角  参数3:右下角 参数4:颜色  参数5:线条宽度,若为负数,则填充整个矩形
cv.rectangle(src, pt1, pt2, color, 1)

# 绘制圆形 参数2:圆心  参数3:半径  参数4:颜色 参数5:线条宽度,若为负数,则填充整个圆形
cv.circle(src, (400, 200), 50, color, -1)

# 绘制文字 参数2:文字内容  参数3:文字起始左下点
cv.putText(src, "hello", (200, 100), cv.FONT_HERSHEY_SIMPLEX, 2, (255, 0, 255), 2)

# 显示图片
cv.imshow("src", src)
cv.waitKey()

1.17 亮度增强

import cv2 as cv
import matplotlib.pyplot as plt

src = cv.imread("../img/itheima.jpg")
height, width = src.shape[0:2]

offset = 90
cv.imshow("src1", src)
for row in range(height):
    for col in range(width):
        b, g, r = src[row, col]

        # 增加亮度
        b = b + offset
        g = g + offset
        r = r + offset

        if b > 255: b = 255
        if g > 255: g = 255
        if r > 255: r = 255

        src[row,col] = (b,g,r)

cv.imshow("src2", src)

# 计算图像直方图
hist = cv.calcHist([src], [0], None, [256], [0, 255])
print hist
plt.plot(hist)
plt.show()
cv.waitKey()

1.18 直方图均衡化

直方图:cv.calcHist(图片,通道,掩膜,数量,值的范围) 直方图均衡化:cv.equalizeHist
import cv2 as cv
import matplotlib.pyplot as plt

src = cv.imread("../img/itheima.jpg")
cv.imshow("src", src)
# 将彩色图像拆成3层灰度图像: B通道 G通道 R通道
channels = cv.split(src)

channel_B = cv.equalizeHist(channels[0])
channel_G = cv.equalizeHist(channels[1])
channel_R = cv.equalizeHist(channels[2])

# 将三个通道的结果合并在一起
dst = cv.merge([channel_B, channel_G, channel_R])
cv.imshow("dst", dst)
cv.waitKey()

1.19 视频处理

视频:cv.VideoCapture(路径)
import cv2 as cv
import matplotlib.pyplot as plt

capture = cv.VideoCapture("../img/vtest.avi")
print capture.isOpened()

# 获取视频的信息
height = capture.get(cv.CAP_PROP_FRAME_HEIGHT)
width = capture.get(cv.CAP_PROP_FRAME_WIDTH)

# 获取视频的帧率: 1s 切换图片的数量
fps = capture.get(cv.CAP_PROP_FPS)
print("height={}, width={}, fps={}".format(height, width, fps))

# 读视频数据
ok, frame = capture.read()
while ok:
    cv.imshow("frame", frame)
    ok, frame = capture.read()

    # 彩色图像直方图均衡化
    channels = cv.split(frame)
    channel_B = cv.equalizeHist(channels[0])
    channel_G = cv.equalizeHist(channels[1])
    channel_R = cv.equalizeHist(channels[2])
    # 将三个通道的结果合并在一起
    dst = cv.merge([channel_B, channel_G, channel_R])
    cv.imshow("dst", dst)

    cv.waitKey(int(1000/fps))

1.20 HSV颜色空间

将RGB图像转成HSV图像
hsv = cv.cvtColor(rgb, cv.COLOR_BGR2HSV)

1.21 阈值处理

所使用的阈值,结果图片 = cv.threshold(img,阈值,最大值,类型)
代码示例:
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np


def onChange(value):
    _, binary = cv.threshold(car, value, 255, cv.THRESH_BINARY_INV)        # 第一个值空,_INV反转颜色
    cv.imshow("binary", binary)


car = cv.imread("../img/car.jpg", cv.IMREAD_GRAYSCALE)

onChange(0)        
# 增加滑动条
cv.createTrackbar("thresh", "binary", 0, 255, onChange)         # 变量名字,窗口名字,min,max,回调函数

cv.imshow("car", car)
cv.waitKey(0)

1.22 人脸识别

核心API:
# 加载已经训练好的特征文件
face_classifier = cv.CascadeClassifier("/haarcascade_frontalface_default.xml")
# 根据特征文件去查找人脸
face_classifier.detectMultiScale(图像, 缩放系数, 至少检验次数)
实现步骤: 加载特征xml文件 加载图片 灰度处理 判决 绘制出检测出来的人脸  
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np

# 第1步:加载xml文件
face_classifier = cv.CascadeClassifier("../img/haarcascade_frontalface_default.xml")
eye_classifier = cv.CascadeClassifier("../img/haarcascade_eye.xml")

# 第2步:加载图片
lena = cv.imread("../img/lena.jpg")

# 第3步:将图片转成灰色图片
lena_gray = cv.cvtColor(lena, cv.COLOR_BGR2GRAY)

# 第4步:使用api进行人脸识别 参数2:缩放系数  参数3:至少要检测几次才算正确
faces = face_classifier.detectMultiScale(lena_gray, 1.3, 3)
print faces        # 返回值:左上点的x,y,宽w,高h

# 第5步:在人脸上绘制矩形
for x, y, w, h in faces:
    # 从灰色图片中找到人脸
    grayFace = lena_gray[y:y+h, x:x+w]
    colorFace = lena[y:y+h, x:x+w]
    # 在当前人脸上找到眼睛的位置
    eyes = eye_classifier.detectMultiScale(grayFace, 1.2, 5)

    # 在找到人脸上画矩形
    cv.rectangle(lena, (x, y), (x+w, y+h), (0, 0, 255), 2)
    # 在眼睛上绘制矩形
    for eye_x, eye_y, eye_w, eye_h in eyes:
        cv.rectangle(colorFace, (eye_x,  eye_y), (eye_x+eye_w, eye_y+eye_h), (0, 255, 255), 2)

cv.imshow("src", lena)
cv.waitKey()
  识别结果如下: