Opencv

一:图像基本操作

  1. 数据读取-图像
    cv2.IMREAD_COLOR: 彩色图像
    cv2.IMREAD_GRAYSCALE: 灰度图像
    cv2.imread(“image_path”, cv2.IMREAD_COLOR/cv2.IMREAD_GRAYSCALE)
    opencv读取的格式是BGR
img = cv2.imread("car01.jpg", cv2.IMREAD_COLOR)
  1. 图像显示,可以创建多个窗口
    cv2.imshow(“窗口名称”, 数据对象)
cv2.imshow("image", img)
  1. 等待时间,毫秒级,0表示任意键终止
    cv2.waitKey()
    cv.destroyAllWindows()
cv2.waitKey(0)
cv.destroyAllWindows()
  1. 查看结构
    如果是rgb三通道则shape为(h, w, 3),如果是灰度图则shape为(h, w)
img.shape
  1. 图像的保存
    cv2.imwrite(“save_path”, 图片对象)
cv2.imwrite("mycar.png", img)
  1. img属性查看
type(img)  # numpy.ndarray
img.size  # 207000
img.dtype  # dtype("uint8")

二:数据读取-视频

  • cv2.VideoCapture可以捕获摄像头,用数字来控制不同的设备,例如0,1
  • 如果是视频文件,直接指定好路径即可
vc = cv2.VideoCapture("test.mp4")
# 检查是否打开正确
if vc.isOpened():
    open, frame = vc.read()  # open返回的是一个bool值,frame返回的是img对象
else:
    open = False
while open:
    ret, frame = vc.read()  # 每一次循环读取一帧,即一幅图片
    if frame is None:
        break
    if ret == True:
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  # 将每一帧图像转换为灰度图
        cv2.imshow("result", gray)  # 展示结果
        if cv2.waitKey(10) & 0xFF == 27:  # 10表示每一帧之间的等待时间,27表示按esc退出
            break
vc.release()
cv2.destroyAllWindows()

三:图像数据处理

  1. 定义图像读取函数
def cv_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
  1. 截取部分图像数据
img = cv2.imread("car01.jpg", cv2.IMREAD_COLOR)

# 图像截取
car = img[0:50, 0:200]

cv_show("cat", cat)
  1. 颜色通道提取
    r,g,b的数值不同,但结构相同
b, g, r = cv2.split(img)
  1. 通道合并
cv2.merge((b,g,r))
  1. 只显示R通道
img = cv2.imread("car01.jpg", cv2.IMREAD_COLOR)

cur_img = img.copy()
cur_img[:, :, 0] = 0  # 将B通道的数值改为0
cur_img[:, :, 1] = 0  # 将G通道的数值改为0
cv_show("R", cur_img)
  1. 边界填充
    BORDER_REPLICATE:复制法,也就是复制最边缘像素
    BORDER_REFLECT: 反射法,对感兴趣的图像中国的像素在两边进行复制。 fedcba|abcdef|fedcba
    BORDER_PEFLECT_101: 反射法,也就是以最边缘像素为轴,对称, fedcb|abcdef|edcba
    BORDER_WRAP: 外包装法 cde|abcde|abc
    BORDER_CONSTANT: 常量法,常数值填充
top_size, bottom_size, left_size, right_size = (50, 50, 50, 50)
replicate = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_REPLICATE)
...
constant = cv2.copyMakeBorder(img, top_size, bottom, left_size, cv2.BORDER_CONSTANT, value=0)
  1. 数值计算
car01 = cv2.imread("car01.jpg")
car02 = cv2.imread("car02.jpg")

# 对每个像素点进行操作,如果计算后的值大于255,则进行取余操作
# 当两个图片相加时,shape不同无法相加
# car01 = car01 + 10
  1. 图像重构
car01 = cv2.resize(car01, (500, 360))  # 修改图像尺寸
car02 = cv2.resize(car02, (0, 0), fx=3, fy=1)  # 按比例对图像进行缩放
  1. 图像融合
# 融合公式:0.4*car01 + 0.6*car02 + 0
# res = cv2.addWeighted(car01, 0.4, car02, 0.6, 0)
# plt.imshow(res)
# plt.show()
  1. 图像阈值
    ret, dst = cv2.threshold(src, thresh, maxval, type)
  • src:输入图,只能输入单通道图像,通常来说为灰度图
  • dst:输出图
  • thresh:阈值
  • maxval:当像素值超过了阈值(或者小于阈值,根据type来决定)
  • type:二值化操作的类型,包含以下5中类型:
  • cv2.THRESH_BINARY 超过阈值部分取maxval(最大值),否则取0
  • cv2.THRESH_BINARY_INV THRESH_BINARY的反转
  • cv2.THRESH_TRUNC 大于阈值部分设为阈值,否则不变
  • cv2.THRESH_TOZERO 大于阈值的部分不改变,否则设为0
  • cv2.THRESH_TOZERO_INV THRESH_TOZERO的翻转
# 图像阈值
ret, dst = cv2.threshold(car01, 127, 255, cv2.THRESH_TOZERO_INV)
plt.imshow(dst)
plt.show()
  1. 图像平滑
  • 均值滤波
    简单的平均卷积操作
blur = cv2.blur(car02, (3, 3))
  • 方框滤波
    基本和均值一样,可以选择归一化
# -1表示输出图的通道数和输入图的通道数相同,normalize=True表示使用归一化,与均值化滤波效果一样
# 如果normalize=False,则只相加求和不平均,超出255部分都按255算
blur = cv2.boxFilter(car02, -1, (3, 3), normalize=True)
  • 高斯滤波
    服从高斯分布,离均值越近则概率越大
aussioan = cv2.GaussianBlur(car01, (5, 5), 1)
  • 中值滤波
median = cv2.medianBlur(car02, 5)

四:形态学

只能针对二值图像进行操作。

  1. 形态学–腐蚀操作
    以一个卷积核覆盖像素点,如果卷积核内的像素点都为255则不发生变化,如果小于255则将此像素点变为0.
kernel = np.ones((3,3), np.uint8)
erosion = cv2.erode(img, kernel, iterations=1)  # iteration为操作次数
  1. 形态学–膨胀操作
    原理与腐蚀操作相似,只是卷积核内的像素点只要有255,则都为255
kernel = np.ones((3, 3), np.uint8)
dige_dilate = cv2.dilate(img, kernel, iteration=1)

一般情况下在使用腐蚀操作在消除噪声时会使原本的像素丢失,这时可用膨胀操作进行恢复。

  1. 开运算与闭运算
    开:先腐蚀,再膨胀
kernel = np.ones((5,5), np.uint8)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)

闭:先膨胀,再腐蚀

kernel = np.ones((5, 5), np.uint8)
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
  1. 梯度运算
    梯度 = 膨胀后图像 - 腐蚀后图像,得到一个边界图像
kernel = np.ones((7,7), np.uint8)
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
  1. 礼帽和黑帽
    礼帽:原始输入 - 开运算结果(剩余的为噪声像素)
kernel = np.ones((7,7), np.uint8)
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)

黑帽:闭运算 - 原始输入(剩余的为原图像的一个轮廓)

kernel = np.ones((7,7), np.uint8)
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)

五:图像梯度–Sobel算子

dst = cv2.Sobel(src, ddepth, dx, dy, ksize)

  • ddepth:图像的深度
  • dx和dy分别表示水平和竖直方向
  • ksize是Sobel算子的大小

假设使用3*3的卷积核,像素点p5为计算一个黑底白圆图片的像素点,求梯度时,则将卷积核分为x和yx两个方阵,即x和y方向,如下图所示:

OpenCV 发布 opencv官方教程_OpenCV 发布

离p5像素点越近的像素点赋予越高的权重,运算规则为右边减左边,下边减上边。白到黑是正数,黑到白是负数,所有的负数会被截断为0,最终结果是半个白色轮廓,所以要取绝对值才能得到完整的圆的轮廓。

# cv2.CV_64F表示可以用负数表示
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)  # x方向梯度运算
sobelx = cv2.converScaleAbs(sobelx)  # 取绝对值

sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)
sobely = cv2.convertScaleAbs(sobely)

分别计算x和y,再求和

# x和y的权重各为0.5, 0为偏置项
sobelxy = cv2.addWeight(sobelx, 0.5, sobely, 0.5, 0)

不建议直接计算,效果不如分开计算x,y的好。

六:图像梯度–Scharr算子

Scharr算子的计算方式与sobel相同,不同的地方就在于卷积核的各个权重数值都有了一定的增加。

scharrx = cv2.Scharr(img, cv2.CV_64F, 1, 0, ksize=3)  # x方向梯度运算
scharrx = cv2.converScaleAbs(scharrx)  # 取绝对值

scharry = cv2.Scharr(img, cv2.CV_64F, 0, 1, ksize=3)
scharry = cv2.convertScaleAbs(scharry)

scharrxy = cv2.addWeighted(scharrx, 0.5, scharry, 0.5, 0)

七:图像梯度–laplacian算子

OpenCV 发布 opencv官方教程_卷积_02

laplacian算子的思想是比较中心像素点和它周围新像素点的一个差距。

laplacian = cv2.Laplacian(img, cv2_CV_64F)
laplacian = cv2.converScaleAbs(laplacian)

总结:scharry相较于sobel更敏感一些,更能细致的描述原始图片的轮廓,而laplacian则预测效果较差,常与其它方法结合使用。