Opencv Python图像处理笔记二:图像变换、卷积、形态学变换

文章目录

  • 前言
  • 一、几何变换
    • 1.1 缩放
    • 1.2 平移
    • 1.3 旋转
    • 1.4 翻转
    • 1.5 仿射
    • 1.6 透视
  • 二、低通滤波
    • 2.1 均值滤波
    • 2.2 高斯滤波
    • 2.3 中值滤波
    • 2.4 双边滤波
    • 2.5 自定义滤波
  • 三、高通滤波
    • 3.1 Sobel
    • 3.2 Scharr
    • 3.3 Laplacian
    • 3.4 Canny
  • 四、图像金字塔
    • 4.1 高斯金字塔
    • 4.2 拉普拉斯金字塔
  • 五、形态学
    • 5.1 腐蚀
    • 5.2 膨胀
    • 5.3 运算
  • 六、直方图
    • 6.1 计算
    • 6.2 均衡
    • 6.3 反向投影
  • 七、轮廓
    • 7.1 查找显示
    • 7.2 常用特征
  • 参考

前言

图像处理是计算机视觉领域中的核心技术之一,它涉及到对图像进行各种变换、滤波、金字塔构建、形态学操作等一系列处理。在本篇博文中,我们将深入探讨使用OpenCV和Python进行图像处理的各种技术和方法。从几何变换到滤波、金字塔构建再到形态学操作,我们将逐步介绍并实践这些重要的图像处理技术,帮助读者更好地理解和应用于实际项目中。

一、几何变换

1.1 缩放

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


def generateCanvas(img, img2):
    canvas = np.zeros((max(img.shape[0], img2.shape[0]),
                       img.shape[1] + img2.shape[1], 3), dtype=np.uint8)

    # 将图像1和图像2放置在画布上
    canvas[:img.shape[0], :img.shape[1]] = img
    canvas[:img2.shape[0],
           img.shape[1]:] = img2
    return canvas


def main():

    img = cv.imread('sudoku.png')
    assert img is not None, "file could not be read, check with os.path.exists()"

    # dsize:输出图像的大小。如果这个参数不为None,那么就代表将原图像缩放到这个Size(width,height)指定的大小;
    #        如果这个参数为0,那么原图像缩放之后的大小就要通过下面的公式来计算:
    #               dsize = Size(round(fx*src.cols), round(fy*src.rows))
    #       其中,fx和fy就是下面要说的两个参数,是图像width方向和height方向的缩放比例。
    #  fx:width方向的缩放比例,如果它是0,那么它就会按照(double)dsize.width/src.cols来计算;
    #  fy:height方向的缩放比例,如果它是0,那么它就会按照(double)dsize.height/src.rows来计算;
    # interpolation:这个是指定插值的方式,图像缩放之后,肯定像素要进行重新计算的,就靠这个参数来指定重新计算像素的方式,有以下几种:
    #     INTER_NEAREST              - 最近邻插值
    #     INTER_LINEAR               - 双线性插值,如果最后一个参数你不指定,默认使用这种方法
    #     INTER_AREA                 - 使用像素区域关系进行重采样
    #     INTER_CUBIC                - 4x4像素邻域内 的双立方插值
    #     INTER_LANCZOS4             - 8x8像素邻域内的Lanczos插值

    fx = 0.6
    fy = 0.6
    
    img_half_nearest = cv.resize(
        img, dsize=None, fx=fx, fy=fy, interpolation=cv.INTER_NEAREST)
    
    img_half_linear = cv.resize(
        img, dsize=None, fx=fx, fy=fy, interpolation=cv.INTER_LINEAR)
    
    img_half_area = cv.resize(img, dsize=None, fx=fx,
                              fy=fy, interpolation=cv.INTER_AREA)
    
    img_half_cubic = cv.resize(
        img, dsize=None, fx=fx, fy=fy, interpolation=cv.INTER_CUBIC)
    
    img_half_lanczos4 = cv.resize(
        img, dsize=None, fx=fx, fy=fy, interpolation=cv.INTER_LANCZOS4)

    titles = ['nearest', 'linear', 'area', 'cubic', 'Lanczos']
    images = [img_half_nearest, img_half_linear,
              img_half_area, img_half_cubic, img_half_lanczos4]

    # canvas = generateCanvas(img, img_half_linear)

    # cv.imshow('test', canvas)

    for i in range(len(images)):
        show = cv.cvtColor(generateCanvas(img, images[i]), cv.COLOR_BGR2RGB)
        plt.subplot(
            2, 3, i+1), plt.imshow(show)
        plt.title(titles[i])
        plt.xticks([]), plt.yticks([])
    plt.show()

    cv.waitKey(0)

    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

resize

1.2 平移

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


def main():

    img = cv.imread('lena.png')
    assert img is not None, "file could not be read, check with os.path.exists()"

    rows, cols, _ = img.shape
    M = np.float32([[1, 0, 100], [0, 1, 50]])

    # M: 2 * 3 矩阵
    # 根据下面的公式,想实现平移,可以通过构造M=[[1, 0, x], [0, 1, y]],实现向右平移x,向下平移y
    # dst(x, y) = (M[0,0] * x  + M[0, 1] * y + M[0, 2], M[1, 0] * x + M[1, 1] * y + M[1, 2])

    img_right_down = cv.warpAffine(img, M, (cols, rows))
    M = np.float32([[1, 0, -100], [0, 1, -50]])
    img_left_up = cv.warpAffine(img, M, (cols, rows))

    titles = ['origin', 'right down', 'left up']
    images = [img, img_right_down, img_left_up]

    for i in range(len(images)):
        show = cv.cvtColor(images[i], cv.COLOR_BGR2RGB)
        plt.subplot(
            1, 3, i+1), plt.imshow(show)
        plt.title(titles[i])
        plt.xticks([]), plt.yticks([])
    plt.show()
    cv.waitKey(0)
    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_16_img_translate.png

1.3 旋转

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


def main():

    img = cv.imread('lena.png')
    assert img is not None, "file could not be read, check with os.path.exists()"

    rows, cols, _ = img.shape

    M = cv.getRotationMatrix2D(center=(rows / 2, cols / 2), angle=-30, scale=1)
    img_rotete_minus_30 = cv.warpAffine(img, M, (cols, rows))

    M = cv.getRotationMatrix2D(center=(rows / 2, cols / 2), angle=30, scale=1)
    img_rotete_30 = cv.warpAffine(img, M, (cols, rows))

    titles = ['origin', 'rotate -30 degree', 'rotate 30 degree']
    images = [img, img_rotete_minus_30, img_rotete_30]

    for i in range(len(images)):
        show = cv.cvtColor(images[i], cv.COLOR_BGR2RGB)
        plt.subplot(
            1, 3, i+1), plt.imshow(show)
        plt.title(titles[i])
        plt.xticks([]), plt.yticks([])
    plt.show()
    cv.waitKey(0)
    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_17_img_rotate

1.4 翻转

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


def main():

    img = cv.imread('lena.png')
    assert img is not None, "file could not be read, check with os.path.exists()"

    # 竖直翻转
    img_vertical = cv.flip(img, flipCode=1)
    # 水平翻转
    img_horizontal = cv.flip(img, flipCode=0)
    # 两者
    img_both = cv.flip(img, flipCode=-1)

    title = ['Origin', 'flipCode=1,Vertical',
             'flipCode=0,Horizontal', 'flipCode=-1,Both']
    # 对应的图像
    imgs = [img, img_vertical, img_horizontal, img_both]

    for i in range(len(imgs)):
        plt.subplot(2, 2, i + 1)
        plt.imshow(cv.cvtColor(imgs[i], cv.COLOR_BGR2RGB))
        plt.title(title[i])
        plt.axis('off')
    plt.show()
    cv.waitKey(0)

    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_18_img_flip

1.5 仿射

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


def main():

    img = cv.imread('lena.png')
    assert img is not None, "file could not be read, check with os.path.exists()"

    rows, cols, _ = img.shape

    # pts1 表示变换前三个点位置
    # pts2 表示变换后三个点位置
    pts1 = np.float32([[270, 270], [330, 270], [310, 320]])
    pts2 = np.float32([[100, 100], [150, 50], [150, 100]])

    M = cv.getAffineTransform(pts1, pts2)

    img_result = cv.warpAffine(img, M, (cols, rows))

    for p in pts1:
        cv.circle(img, center=(int(p[0]), int(p[1])), radius=3,
                  color=(0, 0, 255), thickness=cv.FILLED)

    for p in pts2:
        cv.circle(img_result, center=(int(p[0]), int(p[1])), radius=3,
                  color=(0, 255, 0), thickness=cv.FILLED)

    title = ['Origin', 'Affine']
    # 对应的图像
    imgs = [img, img_result]

    for i in range(len(imgs)):
        plt.subplot(1, len(imgs), i + 1)
        plt.imshow(cv.cvtColor(imgs[i], cv.COLOR_BGR2RGB))
        plt.title(title[i])
        plt.axis('off')
    plt.show()
    cv.waitKey(0)

    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_19_img_affine

1.6 透视

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


def main():

    img = cv.imread('lena.png')
    assert img is not None, "file could not be read, check with os.path.exists()"

    rows, cols, _ = img.shape

    # 将图像投影到一个新的视平面,需要四个点, 在这4个点中,有3个点不应共线
    # 平面的4个点顺序为 左上 右上 左下 右下
    pts1 = np.float32([[270, 270], [330, 270], [270, 350], [320, 350]])
    pts2 = np.float32([[0, 0], [512, 0], [0, 512], [512, 512]])
    M = cv.getPerspectiveTransform(pts1, pts2)

    img_result = cv.warpPerspective(img, M, (cols, rows))

    for p in pts1:
        cv.circle(img, center=(int(p[0]), int(p[1])), radius=3,
                  color=(0, 0, 255), thickness=cv.FILLED)

    for p in pts2:
        cv.circle(img_result, center=(int(p[0]), int(p[1])), radius=3,
                  color=(0, 255, 0), thickness=cv.FILLED)

    title = ['Origin', 'Perspective',]
    # 对应的图像
    imgs = [img, img_result]

    for i in range(len(imgs)):
        plt.subplot(1, len(imgs), i + 1)
        plt.imshow(cv.cvtColor(imgs[i], cv.COLOR_BGR2RGB))
        plt.title(title[i])
        plt.axis('off')
    plt.show()
    cv.waitKey(0)

    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_20_img_perspective

二、低通滤波

与一维信号一样,图像也可以用各种低通滤波器(low-pass filters,LPF)、高通滤波器(high-pass filters,HPF)等进行过滤

  • LPF 用于降低某些像素强度,可以用于平滑图像,保留图像中的低频成分,过滤高频成分,帮助去除噪点,模糊图像等
  • HPF 用于增强某些像素强度,可以用于帮助寻找图像中的边缘

2.1 均值滤波

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


def main():

    img = cv.imread('lenaNoise.png')
    assert img is not None, "file could not be read, check with os.path.exists()"

    # 均值滤波: 简单的平均卷积操作
    result = cv.blur(img, ksize=(5, 5))

    # 显示图像
    titles = ['origin image', 'blur image']
    images = [img, result]
    for i in range(2):
        plt.subplot(
            1, 2, i+1), plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
        plt.title(titles[i])
        plt.axis('off')
    plt.tight_layout()
    plt.show()
    cv.waitKey(0)

    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_21_blur

2.2 高斯滤波

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


def main():

    img = cv.imread('lenaNoise.png')
    assert img is not None, "file could not be read, check with os.path.exists()"

    # 高斯滤波:
    # ksize: 高斯核大小,可以是0或正奇数,当为0从sigma计算
    result_0 = cv.GaussianBlur(img, ksize=(5, 5), sigmaX=0)

    # 显示图像
    titles = ['origin image', 'gaussian blur']
    images = [img, result_0]
    for i in range(len(images)):
        plt.subplot(
            1, len(images), i+1), plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
        plt.title(titles[i])
        plt.axis('off')
    plt.tight_layout()
    plt.show()
    cv.waitKey(0)

    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_21_gaussian_blur

2.3 中值滤波

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


def main():

    img = cv.imread('lenaNoise.png')
    assert img is not None, "file could not be read, check with os.path.exists()"

    # 中值滤波:
    result_0 = cv.medianBlur(img, ksize=3)
    result_1 = cv.medianBlur(img, ksize=5)
    result_2 = cv.medianBlur(img, ksize=7)

    # 显示图像
    titles = ['origin image', 'ksize=3', 'ksize=5', 'ksize=7']
    images = [img, result_0, result_1, result_2]
    for i in range(len(images)):
        plt.subplot(
            2, 2, i+1), plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
        plt.title(titles[i])
        plt.axis('off')
    plt.show()
    cv.waitKey(0)

    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_21_median_filter

2.4 双边滤波

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


def main():

    img = cv.imread('lenaNoise.png')
    assert img is not None, "file could not be read, check with os.path.exists()"

    # 双边滤波: 在计算像素值的同时会考虑距离和色差信息,从而可在消除噪声得同时保护边缘信息,可用于美颜
    # d 每个像素邻域的直径,当<=0时,从sigmaSpace计算     注意:当 d > 5 非常慢,所以建议使用=5作为实时应用,或者使用=9作为需要重噪声过滤的离线应用
    # sigmaColor 颜色标准方差,一般尽可能大,较大的值表示在颜色相近的区域内像素将会被更多地保留
    # sigmaSpace 坐标空间标准方差(像素单位),一般尽可能小,较小的值表示在距离中心像素较远的像素的权重较小
    result_0 = cv.bilateralFilter(img, d=0, sigmaColor=100, sigmaSpace=15)
    result_1 = cv.bilateralFilter(img, d=0, sigmaColor=50, sigmaSpace=15)

    # 显示图像
    titles = ['origin image', 'color=100 space=5', 'color=50 space=5']
    images = [img, result_0, result_1]
    for i in range(len(images)):
        plt.subplot(
            1, len(images), i+1), plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
        plt.title(titles[i])
        plt.axis('off')
    plt.show()
    cv.waitKey(0)

    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_22_bilateral_filter

2.5 自定义滤波

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


def main():

    img = cv.imread('lenaNoise.png')
    assert img is not None, "file could not be read, check with os.path.exists()"

    # 自定义滤波,对图像进行卷积运算:
    # 先定义卷积核,再参与计算,ddepth=-1表示和源图像深度一致
    # 此外还有个参数anchor,默认值为(-1,-1)表示锚点位于内核中心
    kernel = np.ones((5, 5), np.float32)/25
    result = cv.filter2D(img, ddepth=-1, kernel=kernel)

    # 显示图像
    titles = ['origin image', 'filter2d filter',]
    images = [img, result]
    for i in range(len(images)):
        plt.subplot(
            1, len(images), i+1), plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
        plt.title(titles[i])
        plt.axis('off')
    plt.show()
    cv.waitKey(0)

    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_23_2d_filter

三、高通滤波

3.1 Sobel

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


def sobel(img):
    # Sobel 使用Sobel算子计算一阶、二阶、三阶或三者混合 图像导数梯度
    # ddepth 输出图像的深度,计算图像的梯度会有浮点数,负数,所以后面会取绝对值
    # dx,dy  X和Y方向的梯度
    # ksize  参与图像卷积操作的核,大小可以是1、3、5或7,用于不同精度的边缘检测
    grad_x = cv.Sobel(img, ddepth=cv.CV_64F, dx=1, dy=0, ksize=3)
    abs_grad_x = cv.convertScaleAbs(grad_x)

    grad_y = cv.Sobel(img, ddepth=cv.CV_64F, dx=0, dy=1, ksize=3)
    abs_grad_y = cv.convertScaleAbs(grad_y)

    # 分别计算x和y,再求和
    sobel = cv.addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0)

    return abs_grad_x, abs_grad_y, sobel


def main():

    img = cv.imread('res2.jpg')
    img_lena = cv.imread('lena.png', cv.IMREAD_GRAYSCALE)

    assert img is not None and img_lena is not None, "file could not be read, check with os.path.exists()"

    # 显示图像
    titles = ['origin ', 'sobel_x', 'sobel_y', 'sobel_x+sobel_y', 'lena ',
              'lena_sobel_x', 'lena_sobel_y', 'lena_sobel_x+lena_sobel_y']
    images = [img, *sobel(img), img_lena, *sobel(img_lena)]
    for i in range(len(images)):
        plt.subplot(2, 4, i+1)
        plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
        plt.title(titles[i])
        plt.axis('off')
    plt.show()
    cv.waitKey(0)
    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_26_sobel

3.2 Scharr

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']


def main():

    img = cv.imread('lena.png', cv.IMREAD_GRAYSCALE)
    assert img is not None, "file could not be read, check with os.path.exists()"

    scharrx = cv.Scharr(img, ddepth=cv.CV_64F, dx=1, dy=0)
    scharrxAbs = cv.convertScaleAbs(scharrx)

    scharry = cv.Scharr(img, ddepth=cv.CV_64F, dx=0, dy=1)
    scharryAbs = cv.convertScaleAbs(scharry)

    # 分别计算x和y,再求和
    scharrxy = cv.addWeighted(scharrxAbs, 0.5, scharryAbs, 0.5, 0)

    # 显示图像
    titles = ['origin ', 'scharrx', 'scharry', 'scharrx + scharry']
    images = [img, scharrxAbs, scharryAbs, scharrxy]
    for i in range(len(images)):
        plt.subplot(2, 2, i+1)
        plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
        plt.title(titles[i])
        plt.axis('off')
    plt.tight_layout()
    plt.show()

    cv.waitKey(0)
    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_27_scharr

3.3 Laplacian

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']


def main():

    img = cv.imread('lena.png', cv.IMREAD_GRAYSCALE)
    assert img is not None, "file could not be read, check with os.path.exists()"

    result = cv.Laplacian(img, cv.CV_16S, ksize=3)
    resultAbs = cv.convertScaleAbs(result)

    # 显示图像
    titles = ['origin ', 'Laplacian']
    images = [img, resultAbs]
    for i in range(len(images)):
        plt.subplot(1, 2, i+1)
        plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
        plt.title(titles[i])
        plt.axis('off')
    plt.show()
    cv.waitKey(0)
    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_28_laplacian

3.4 Canny

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# plt.rcParams['font.sans-serif'] = ['SimHei']


def main():

    img = cv.imread('lena.png')
    assert img is not None, "file could not be read, check with os.path.exists()"

    # canny 是一个多步算法,先用5*5核高斯滤波过滤噪声,然后用Sobel算法查找图像梯度,最后去除任何可能不构成边缘的、不需要的像素
    # threshold1 较小值 低于这个值的肯定不是边
    # threshold2 较大值 高于这个值的肯定是边
    # 位于两者之间的需要进行连通性判断
    img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    img_result_1 = cv.Canny(img_gray, threshold1=100, threshold2=200)
    img_result_2 = cv.Canny(img_gray, threshold1=50, threshold2=240)

    # 显示图像
    titles = ['origin ', 'gray', 'canny 100,200', 'canny 50,240']
    images = [img, img_gray, img_result_1, img_result_2]
    for i in range(len(images)):
        plt.subplot(2, 2, i+1)
        plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
        plt.title(titles[i])
        plt.axis('off')
    plt.tight_layout()
    plt.show()
    cv.waitKey(0)
    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_29_canny

四、图像金字塔

通常,我们通常处理恒定大小的图像。但在某些情况下,我们需要处理不同分辨率的(相同的)图像。例如,当在图像中搜索某个东西时,比如人脸,我们不确定物体将在该图像中出现在什么大小。在这种情况下,我们将需要创建一组具有不同分辨率的相同图像,并在所有这些图像中搜索对象。这些不同分辨率的图像集被称为图像金字塔(因为当它们被保存在一个堆栈中,顶部是最高分辨率的图像时,它看起来就像一个金字塔)。

金字塔的一个应用是图像混合。

4.1 高斯金字塔

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']


def main():

    img = cv.imread('lena.png')
    assert img is not None, "file could not be read, check with os.path.exists()"

    # 模糊图像向下采样
    img_down = cv.pyrDown(img)
    img_down_down = cv.pyrDown(img_down)
    img_down_down_down = cv.pyrDown(img_down_down)

    # 显示图像
    titles = ['origin ', '向下采样1', '向下采样2', '向下采样3']
    images = [img, img_down, img_down_down, img_down_down_down]
    for i in range(len(images)):
        plt.subplot(2, 2, i+1)
        plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
        plt.title(titles[i])
        plt.axis('off')
    plt.tight_layout()
    plt.show()
    cv.waitKey(0)
    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_30_gaussian_pyramid

4.2 拉普拉斯金字塔

拉普拉斯金字塔是由高斯金字塔形成的。拉普拉斯金字塔图像像边缘图像,它的大多数元素都是零,常被用于图像压缩。拉普拉斯金字塔的水平是由高斯金字塔的水平与高斯金字塔的扩展水平的差异形成的

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# plt.rcParams['font.sans-serif'] = ['SimHei']


def main():

    img = cv.imread('lena.png')
    assert img is not None, "file could not be read, check with os.path.exists()"

    # pyrDown和pyrUp并不是可逆的
    img_down = cv.pyrDown(img)
    img_down_up = cv.pyrUp(img_down)

    img_laplacian = img - img_down_up

    # 显示图像
    titles = ['origin ', 'img_laplacian']
    images = [img, img_laplacian]
    for i in range(len(images)):
        plt.subplot(1, 2, i+1)
        plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
        plt.title(titles[i])
        plt.axis('off')
    plt.show()
    cv.waitKey(0)
    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_30_laplacian_pyramid

五、形态学

5.1 腐蚀

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# plt.rcParams['font.sans-serif'] = ['SimHei']


def main():

    img = cv.imread('j.png')
    assert img is not None, "file could not be read, check with os.path.exists()"

    kernel3 = np.ones((3, 3), np.uint8)
    img_erode_3 = cv.erode(img, kernel3, iterations=1)

    kernel5 = np.ones((5, 5), np.uint8)
    img_erode_5 = cv.erode(img, kernel5, iterations=1)

    cross = cv.getStructuringElement(cv.MORPH_CROSS, (5, 5))
    img_erode_by_cross = cv.erode(img, cross)

    ellipse = cv.getStructuringElement(cv.MORPH_ELLIPSE, (5, 5))
    img_erode_by_ellipse = cv.erode(img, ellipse)

    # 显示图像
    titles = ['origin ', 'erode_3', 'erode_5', 'cross', 'ellipse']
    images = [img, img_erode_3, img_erode_5,
              img_erode_by_cross, img_erode_by_ellipse]
    for i in range(len(images)):
        plt.subplot(2, 3, i+1)
        plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
        plt.title(titles[i])
        plt.axis('off')
    plt.tight_layout()
    plt.show()
    cv.waitKey(0)
    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_31_erode

5.2 膨胀

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# plt.rcParams['font.sans-serif'] = ['SimHei']


def main():

    img = cv.imread('j.png')
    assert img is not None, "file could not be read, check with os.path.exists()"

    kernel3 = np.ones((3, 3), np.uint8)
    img_dilate_3 = cv.dilate(img, kernel3, iterations=1)

    kernel5 = np.ones((5, 5), np.uint8)
    img_dilate_5 = cv.dilate(img, kernel5, iterations=1)

    cross = cv.getStructuringElement(cv.MORPH_CROSS, (5, 5))
    img_dilate_by_cross = cv.dilate(img, cross)

    ellipse = cv.getStructuringElement(cv.MORPH_ELLIPSE, (5, 5))
    img_dilate_by_ellipse = cv.dilate(img, ellipse)

    # 显示图像
    titles = ['origin ', 'dilate_3', 'dilate_5', 'cross', 'ellipse']
    images = [img, img_dilate_3, img_dilate_5,
              img_dilate_by_cross, img_dilate_by_ellipse]
    for i in range(len(images)):
        plt.subplot(2, 3, i+1)
        plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
        plt.title(titles[i])
        plt.axis('off')
    plt.tight_layout()
    plt.show()
    cv.waitKey(0)
    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_33_dilate

5.3 运算

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# plt.rcParams['font.sans-serif'] = ['SimHei']


def main():

    img = cv.imread('j.png')
    assert img is not None, "file could not be read, check with os.path.exists()"

    # 形态学通常用于二值化图像
    # 开操作:先腐蚀后膨胀
    # 闭操作:先膨胀后腐蚀
    # 形态学梯度:膨胀减去腐蚀。
    # 顶帽:原图像与开操作图像之间的差值图像。
    # 黑帽:闭操作图像与原图像之间的差值图像。

    kernel = np.ones((3, 3), np.uint8)

    img_opening = cv.morphologyEx(img, cv.MORPH_OPEN, kernel)
    img_closing = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel)
    img_gradient = cv.morphologyEx(img, cv.MORPH_GRADIENT, kernel)
    img_tophat = cv.morphologyEx(img, cv.MORPH_TOPHAT, kernel)
    img_blackhat = cv.morphologyEx(img, cv.MORPH_BLACKHAT, kernel)

    # 显示图像
    titles = ['origin ', 'open', 'close', 'gradient', 'tophat', 'blackhat']
    images = [img, img_opening, img_closing,
              img_gradient, img_tophat, img_blackhat]
    for i in range(len(images)):
        plt.subplot(2, 3, i+1)
        plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
        plt.title(titles[i])
        plt.axis('off')
    plt.tight_layout()
    plt.show()
    cv.waitKey(0)
    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_34_morphology

六、直方图

6.1 计算

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# plt.rcParams['font.sans-serif'] = ['SimHei']


def main():

    img = cv.imread('lena.png')
    assert img is not None, "file could not be read, check with os.path.exists()"

    img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    img_hist = cv.calcHist([img], [0], None, [256], [0, 256])

    # 显示图像
    titles = ['gray', 'origin']
    images = [img_gray, img]
    for i in range(len(images)):
        plt.subplot(2, 2, i+1)
        plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
        plt.title(titles[i])
        plt.axis('off')

    plt.subplot(2, 2, 3)
    plt.plot(img_hist)
    plt.title('histogram')
    plt.xlim([0, 256])

    color = ('b', 'g', 'r')
    plt.subplot(2, 2, 4)
    for i, col in enumerate(color):
        histr = cv.calcHist([img], [i], None, [256], [0, 256])
        plt.plot(histr, color=col)
        plt.xlim([0, 256])
    plt.title('color histogram')
    plt.tight_layout()
    plt.show()
    cv.waitKey(0)
    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_35_histpgram

6.2 均衡

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# plt.rcParams['font.sans-serif'] = ['SimHei']


def main():

    img = cv.imread('lena.png')
    assert img is not None, "file could not be read, check with os.path.exists()"

    img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    img_hist = cv.calcHist([img_gray], [0], None, [256], [0, 256])
    # 均衡灰度图像
    img_gray_equ = cv.equalizeHist(img_gray)
    img_equ_hist = cv.calcHist([img_gray_equ], [0], None, [256], [0, 256])

    clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
    img_clahe = clahe.apply(img_gray)

    # 显示图像
    titles = ['origin ', 'gray', 'equ', 'clahe']
    images = [img, img_gray, img_gray_equ, img_clahe]
    for i in range(len(images)):
        plt.subplot(3, 2, i+1)
        plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
        plt.title(titles[i])
        plt.axis('off')

    plt.subplot(3, 2, 5)
    plt.plot(img_hist)
    plt.title('orgin hist')
    plt.xlim([0, 256])

    plt.subplot(3, 2, 6)
    plt.plot(img_equ_hist)
    plt.title('equ hist')
    plt.xlim([0, 256])

    plt.show()
    cv.waitKey(0)
    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_36_histpgram_equalize

6.3 反向投影

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# plt.rcParams['font.sans-serif'] = ['SimHei']


def main():

    img = cv.imread('lena.png')
    img_2 = cv.imread('lena.png')
    assert img is not None, "file could not be read, check with os.path.exists()"

    img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    img_hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)

    img_hist = cv.calcHist([img_hsv], [0], None, [256], [0, 256])
    cv.normalize(img_hist, img_hist, 0, 255, cv.NORM_MINMAX)

    # 直方图反投影 将每个像素用概率表示 经常用于图像分割或在图像中查找感兴趣的对象, 和 camshift meanshift等算法一起使用
    dst = cv.calcBackProject([img_hsv], [0, 1], img_hist, None, 1)

    # 显示图像
    titles = ['origin ', 'gray', 'backProject']
    images = [img, img_gray, dst]
    for i in range(len(images)):
        plt.subplot(2, 2, i+1)
        plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
        plt.title(titles[i])
        plt.axis('off')

    plt.show()
    cv.waitKey(0)
    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_37_histpgram_backprojection

七、轮廓

7.1 查找显示

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# plt.rcParams['font.sans-serif'] = ['SimHei']


def main():

    img = cv.imread('box.jpg')
    img_2 = img.copy()
    assert img is not None, "file could not be read, check with os.path.exists()"

    img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    ret, thresh = cv.threshold(img_gray, 127, 255, 0)

    # 进行查找轮廓的图片应该是二值化图片,黑色背景中找白色物体轮廓
    contours, hierarchy = cv.findContours(
        thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

    cv.drawContours(img_2, contours, -1, (0, 255, 0), 3)
    # cv.drawContours(img_2, contours, 3, (0, 255, 0), 3)
    # cnt = contours[4]
    # cv.drawContours(img_2, [cnt], 0, (0, 255, 0), 3)

    # 显示图像
    titles = ['origin ', 'binary', 'cornor']
    images = [img, thresh, img_2]
    for i in range(len(images)):
        plt.subplot(2, 2, i+1)
        plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
        plt.title(titles[i])
        plt.axis('off')

    plt.show()
    cv.waitKey(0)
    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_38_contour_find_draw

7.2 常用特征

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# plt.rcParams['font.sans-serif'] = ['SimHei']


def main():

    img = cv.imread('g.png')
    assert img is not None, "file could not be read, check with os.path.exists()"

    img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    ret, thresh = cv.threshold(img_gray, 127, 255, 0)

    # 进行查找轮廓的图片应该是二值化图片,黑色背景中找白色物体轮廓
    contours, hierarchy = cv.findContours(
        thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
    cnt = contours[0]

    M = cv.moments(cnt)

    cx = int(M['m10'] / M['m00'])
    cy = int(M['m01'] / M['m00'])
    print('重心:', cx, cy)

    area = cv.contourArea(cnt)
    print('面积:', area)

    perimeter = cv.arcLength(cnt, True)
    print('周长:', perimeter)

    # 轮廓近似图像
    img_approx = img.copy()
    epsilon = 0.01*cv.arcLength(cnt, True)
    approx = cv.approxPolyDP(cnt, epsilon, True)
    cv.drawContours(img_approx, [approx], -1, (0, 255, 0), 2)

    # 外接矩形
    img_rect = img.copy()
    x, y, w, h = cv.boundingRect(cnt)
    cv.rectangle(img_rect, (x, y), (x+w, y+h), (0, 255, 0), 2)

    # 最小矩形
    img_min_rect = img.copy()
    rect = cv.minAreaRect(cnt)
    box = cv.boxPoints(rect)
    box = np.int0(box)
    cv.drawContours(img_min_rect, [box], 0, (0, 0, 255), 2)

    # 外接圆
    img_circle = img.copy()
    (x, y), radius = cv.minEnclosingCircle(cnt)
    center = (int(x), int(y))
    radius = int(radius)
    cv.circle(img_circle, center, radius, (0, 255, 0), 2)

    # 凸包
    img_hull = img.copy()
    hull = cv.convexHull(cnt)
    cv.drawContours(img_hull, [hull], 0, (0, 255, 0), 2)

    # 椭圆
    img_ellipse = img.copy()
    ellipse = cv.fitEllipse(cnt)
    cv.ellipse(img_ellipse, ellipse, (0, 255, 0), 2)

    # 线
    img_line = img.copy()
    rows, cols = img.shape[:2]
    [vx, vy, x, y] = cv.fitLine(cnt, cv.DIST_L2, 0, 0.01, 0.01)
    lefty = int((-x*vy/vx) + y)
    righty = int(((cols-x)*vy/vx)+y)
    cv.line(img_line, (cols-1, righty), (0, lefty), (0, 255, 0), 2)

    cv.drawContours(img, contours, -1, (0, 255, 0), 2)

    # 显示图像
    titles = ['binary', 'cornor', 'approx',
              'rect', 'min_rect', 'circle', 'hull', 'ellipse', 'line']
    images = [thresh, img, img_approx, img_rect,
              img_min_rect, img_circle, img_hull, img_ellipse, img_line]
    for i in range(len(images)):
        plt.subplot(3, 3, i+1)
        plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))
        plt.title(titles[i])
        plt.axis('off')
    plt.tight_layout()
    plt.show()
    cv.waitKey(0)
    cv.destroyAllWindows()


if __name__ == '__main__':
    main()

demo_38_contour_feature

参考

  1. https://github.com/LeBron-Jian/ComputerVisionPractice

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/681238.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

眼底照 + OCT图 + 精神状态 ,预测阿尔兹海默症

眼底照片和OCT图像&#xff0c;预测阿尔兹海默症 数据多模态网络模型集成可视化分析 论文&#xff1a;https://www.ophthalmologyretina.org/action/showPdf?piiS2468-6530%2824%2900045-9 目前&#xff0c;认知障碍的诊断依赖于血清和蛋白质生物标志物的检测、脑脊液检查和正…

充电宝哪款质量好性价比高?精选四大宝藏款充电宝分享

在这个快节奏的数字时代&#xff0c;智能手机、平板电脑等电子设备已成为我们日常生活与工作中不可或缺的伙伴。然而&#xff0c;电量焦虑似乎也如影随形&#xff0c;时刻考验着我们的耐心与行程安排。于是&#xff0c;一款质量上乘、性价比高的充电宝便成了许多人的随身必备“…

超实用!新手必看的色彩设计指南

在UI设计中&#xff0c;色彩设计扮演着非常重要的角色&#xff0c;它不仅可以为用户带来视觉上的愉悦体验&#xff0c;还可以影响用户的情绪、行为和注意力。通过运用不同的色彩搭配和调性&#xff0c;设计师可以引导用户的注意力&#xff0c;突出重点内容或功能&#xff0c;提…

告别鼠标:蓝牙无线安卓模拟鼠标,绘图板,手写板操作电脑PC端,卡卡罗特也说好,儿童节快乐

家人们&#xff0c;上链接了&#xff1a;https://download.csdn.net/download/jasonhongcn/89387887 横屏模式&#xff1a; 竖屏模式&#xff1a; 操作说明&#xff1a; 1. 手势滑动模拟鼠标移动 2. 界面如果有滚动条&#xff0c;右手指按紧&#xff0c;通过左手指移动实现…

Spring Security 注册过滤器关键点与最佳实践

在 Spring Security 框架中&#xff0c;注册过滤器是实现身份验证和授权的关键组件。正确配置和使用注册过滤器对于确保应用程序的安全性至关重要。以下是一些关于 Spring Security 注册过滤器的注意事项和最佳实践。 过滤器链顺序&#xff1a; 注册过滤器通常位于过滤器链的末…

揭秘业务系统数据安全三大核心问题:“谁在用”、“用什么”和“怎么用”

数据库宛如一座坚固的宝库&#xff0c;守护着无尽的智慧与财富—数据&#xff0c;如同熠熠生辉的金币。当宝库的门紧闭时&#xff0c;金币得以安然无恙。 然而&#xff0c;在业务系统的广阔天地中&#xff0c;这些数据金币被精心挑选、流通使用&#xff0c;每一枚都承载着无尽…

eNSP学习——RIP路由协议基础配置

目录 主要命令 原理概述 实验内容 实验目的 实验拓扑 实验编址 实验步骤 1、基本配置 2、使用RIPv1搭建网络 开启 RIP调试功能 3、使用RIPv2搭建网络 RIPv1和RIPv2的不同 需要eNSP各种配置命令的点击链接自取&#xff1a;华为&#xff45;NSP各种设备配置命令大全PD…

栈排序00

题目链接 栈排序 题目描述 注意点 对栈进行排序使最小元素位于栈顶最多只能使用一个其他的临时栈存放数据不得将元素复制到别的数据结构&#xff08;如数组&#xff09;中栈中的元素数目在[0, 5000]范围内 解答思路 本题是要实现一个小顶堆&#xff0c;可以直接使用Priori…

Linux C语言: 数据类型

一、 为什么要引入数据类型 • 计算机中每个字节都有一个地址&#xff08;类似门牌号&#xff09; • CPU通过 地址 来访问这个字节的空间 0x20001103 1 0 0 1 0 0 1 1 0x20001102 1 1 1 0 1 1 1 0 0x20001101 1 1 1 1 0 1 0 1 0x20001100 0 …

掌握ChatGPT的正确打开方式

引言 随着人工智能技术的飞速发展&#xff0c;自然语言处理&#xff08;NLP&#xff09;领域取得了显著的突破。其中&#xff0c;聊天生成预训练变换器&#xff08;ChatGPT&#xff09;作为一种新型的对话式AI模型&#xff0c;引起了广泛关注。本文将详细介绍ChatGPT的正确使用…

linux业务代码性能优化点

planning优化的一些改动----------> 减少值传递&#xff0c;多用引用来传递 <---------- // ----------> 减少值传递&#xff0c;多用引用来传递 <---------- // 例1&#xff1a; class A{}; std::vector<A> v; // for(auto elem : v) {} // 不建议&#xff…

视频监控汇聚平台LntonCVS国标GB28181协议实现语音对讲功能

在当今这个智能技术飞速发展的时代&#xff0c;人工智能已经成为了电子产品领域的一股不可忽视的热门趋势。随着科技的不断进步&#xff0c;越来越多的电子产品开始融入人工智能技术&#xff0c;从而为其开拓了全新的发展路径。在这个大背景下&#xff0c;安防摄像头无插件直播…

Mitmproxy作为瑞士军刀可拦截、检查、修改和重放网络流量可用于渗透测试。

Mitmproxy是一个开源的中间人代理工具&#xff0c;用于拦截、修改和查看HTTP和HTTPS流量。它可以用于调试、测试和分析网络应用程序和移动应用程序的通信。 Mitmproxy可以在本地计算机上作为一个代理服务器运行&#xff0c;将所有流量导向到它&#xff0c;然后可以查看和修改这…

CA到TA的调用流程是什么?如何实现的?

快速链接: . &#x1f449;&#x1f449;&#x1f449;Trustzone/TEE/安全 面试100问-目录 &#x1f448;&#x1f448;&#x1f448; 付费专栏-付费课程 【购买须知】:联系方式-加入交流群 ----联系方式-加入交流群 个人博客笔记导读目录(全部) 简单一点来说&#xff0c;CA…

电器公司2套PROE如何满足20人使用?

电器公司的日常运营高度依赖于各类软件工具&#xff0c;其中PROE作为广泛应用于产品设计领域的软件&#xff0c;在电器厂公司的生产流程中扮演着举足轻重的角色。如何合理配置和管理PROE软件资源&#xff0c;以满足20人同时使用的需求&#xff0c;是许多电器厂公司面临的实际问…

比瓴科技以何魅力吸引安全大牛?

今年4月&#xff0c;专注于软件供应链安全的行业领导厂商比瓴科技宣布&#xff0c;与元豚科技战略合并&#xff0c;元豚科技创始人唐誉聪加入比瓴&#xff0c;担任合伙人及研发副总裁一职。唐誉聪表示&#xff0c;将携手比瓴共同推动持续应用安全平台(ASPM)的发展&#xff0c;将…

深度学习论文: DINOv2: Learning Robust Visual Features without Supervision

深度学习论文: DINOv2: Learning Robust Visual Features without Supervision DINOv2: Learning Robust Visual Features without Supervision PDF: https://arxiv.org/abs/2304.07193 PyTorch代码: https://github.com/shanglianlm0525/CvPytorch PyTorch代码: https://githu…

【产品面对面】deepin 办公升级:打印管理器全功能解析及驱动资源汇总

内容来源&#xff1a;deepin&#xff08;深度&#xff09;社区 如果你想要或者正在使用 deepin 进行办公&#xff0c;那么一定会使用到 “打印管理器”。打印管理器作为一款管理打印机的工具&#xff0c;将成为你办公得力助手之一。近期&#xff0c;我们会在 deepin 应用商店发…

【学习心得】算法刷题心得分享

一、为什么要刷题&#xff1f; 提升编程能力&#xff0c;强化对数据结构的理解&#xff0c;熟练掌握常用的算法等为竞赛、考试做准备找实习、找工作需要&#xff08;上机考试面试手撕代码&#xff09;提升自信心&#xff0c;放松一下 二、刷题前应该有哪些知识储备&#xff1f;…

Web 网页性能优化

Web 网页性能及性能优化 一、Web 性能 Web 性能是 Web 开发的一个重要方面&#xff0c;侧重于网页加载速度以及对用户输入的响应速度 通过优化网站来改善性能&#xff0c;可以在为用户提供更好的体验 网页性能既广泛又非常深入 1. 为什么性能这么重要&#xff1f; 1. 性能…