美文网首页Python
OpenCV-Python学习(十一):直方图

OpenCV-Python学习(十一):直方图

作者: 星光下的胖子 | 来源:发表于2020-06-26 15:18 被阅读0次

    目录:

    • 1.绘制直方图
      • 1)一维直方图
      • 2)2D直方图
    • 2.直方图均衡化
      • 1)全局直方图均衡化
      • 2)CLAHE(限制对比度的自适应直方图均衡化)-->局部
    • 3.直方图反向投影

    一、绘制直方图

    直方图:统计每个像素在图像矩阵中出现的次数或概率。

    OpenCV函数:

    绘制直方图
    cv2.calcHist(images, channels, mask, histSize, ranges, hist=None, accumulate=None)
    
    参数:
    img:输入图像,为列表,如[img]。
    channels: 计算的通道,为列表,如[0]表示单通道,[0, 1]统计两个通道。
    mask: 掩模,和输入图像大小一样的矩阵,为1的地方会进行统计(与图像逻辑与后再统计);无掩模时为None。
    histSize: 每一个channel对应的bins(柱子)个数,为列表,如[256]表示256个像素值。
    ranges: bins的边界,为列表,如[0,256]表示像素值范围在0-256之间。-->使用切片的原理,含前不含后。
    
    1)一维直方图

    一般将图像从BGR转换为灰度图来绘制一维直方图,也可绘制单通道的1D直方图。

    # 1)一维直方图
    import cv2
    import matplotlib.pyplot as plt
    
    img = cv2.imread("image/1.jpg")
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转化为灰度图
    
    # 绘制灰度图的直方图
    hist_gray = cv2.calcHist(images=[gray], channels=[0], mask=None, histSize=[256], ranges=[0, 256])
    # 绘制单通道B的直方图
    hist_B = cv2.calcHist([img], [0], None, [256], [0, 256])
    # 绘制单通道G的直方图
    hist_G = cv2.calcHist([img], [1], None, [256], [0, 256])
    # 绘制单通道R的直方图
    hist_R = cv2.calcHist([img], [2], None, [256], [0, 256])
    
    plt.plot(hist_gray, color="gray", label="Gray")
    plt.plot(hist_B, color="b", label="B")
    plt.plot(hist_G, color="g", label="G")
    plt.plot(hist_R, color="r", label="R")
    plt.show()
    
    一维直方图.png
    2)2D直方图

    对于彩色图片,需将图像从BGR转换为HSV,我们通过Hue (色度,范围[0, 179] )和Saturation(饱和度,范围[0, 255])两个特征来绘制2D直方图。

    # 2)2D直方图
    import cv2
    
    img = cv2.imread("image/1.jpg")
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)  # 转化为HSV图
    
    # 绘制2D直方图
    hist_hsv = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
    
    cv2.namedWindow("hist_hsv", cv2.WINDOW_NORMAL)
    cv2.imshow("hist_hsv", hist_hsv)
    cv2.waitKey(0)
    cv2.destroyWindow()
    
    二维直方图.png

    二、直方图均衡化

    直方图均衡化是利用直方图,调整图像对比度的一种方法。
    主要用于图像增强,如:图像去雾。

    1)全局直方图均衡化

    OpenCV函数:

    1)全局直方图均衡化
    dst = cv2.equalizeHist(src)
    
    参数:
    src: 图像对象矩阵,必须为单通道的uint8类型的矩阵数据
    dst: 输出图像矩阵(和src的shape一样)
    

    示例:

    # 1)全局直方图均衡化
    import cv2
    import matplotlib.pyplot as plt
    
    src = cv2.imread("image/7.jpg", cv2.IMREAD_GRAYSCALE)
    
    # 全局直方图均衡化
    dst = cv2.equalizeHist(src)
    
    # 原直方图
    hist_src = cv2.calcHist([src], [0], None, [256], [0, 256])
    # 全局均衡化后的直方图
    hist_dst = cv2.calcHist([dst], [0], None, [256], [0, 256])
    
    # 结合matplotlib展示多张图片
    plt.subplot(221), plt.imshow(src, cmap="gray"), plt.title("Src Image")
    plt.xticks([]), plt.yticks([])
    plt.subplot(222), plt.imshow(dst, cmap="gray"), plt.title("Dst Image")
    plt.xticks([]), plt.yticks([])
    plt.subplot(223), plt.plot(hist_src, color="r", label="hist_src"), plt.legend()
    plt.subplot(224), plt.plot(hist_dst, color="b", label="hist_dst"), plt.legend()
    plt.show()
    
    全局直方图均衡化.png
    2)CLAHE(限制对比度的自适应直方图均衡化)

    限制对比度的自适应直方图均衡(CLAHE,Contrast Limited Adaptive Histogram Equalization),图像被分成称为“tile”的小块(在OpenCV中,tileSize默认为8x8),然后对每一个小块进行直方图均衡化。
    但若小块内有噪声,影响很大,需要通过限制对比度来进行抑制,即限制对比度自适应直方图均衡化。如果限制对比度的阈值设置为40,在局部直方图分布中某个像素值出现次数为45,那么多出的5次像素点会被去掉,平均成其他像素值。

    OpenCV函数:

    2)CLAHE(限制对比度自适应均衡化)
    clahe = cv2.createCLAHE(clipLimit=None, tileGridSize=None)
    dst = clahe.apply(src)
    
    参数:
    clipLimit: 限制对比度的阈值,默认为40,直方图中像素值出现次数大于该阈值,多余的次数会被重新分配。
    tileGridSize: tile块的大小,如tileGridSize=(8,8),默认为(8,8)。
    

    示例:

    # 2)CLAHE(限制对比度的自适应直方图均衡化)
    import cv2
    import matplotlib.pyplot as plt
    
    src = cv2.imread("image/8.jpg", cv2.IMREAD_GRAYSCALE)
    
    # 1.全局直方图均衡化
    img_equalize = cv2.equalizeHist(src)
    
    # 2.CLAHE自适应均衡化
    # createCLAHE(clipLimit=None, tileGridSize=None)
    clahe = cv2.createCLAHE(clipLimit=40, tileGridSize=(8, 8))
    img_clahe = clahe.apply(src)
    
    # 原直方图
    hist_src = cv2.calcHist([src], [0], None, [256], [0, 256])
    # 全局均衡化后的直方图
    hist_equalize = cv2.calcHist([img_equalize], [0], None, [256], [0, 256])
    # CLAHE均衡化后的直方图
    hist_clahe = cv2.calcHist([img_clahe], [0], None, [256], [0, 256])
    
    # 结合matplotlib展示多张图片
    plt.subplot(231), plt.imshow(src, cmap="gray"), plt.title("Src Image")
    plt.xticks([]), plt.yticks([])
    plt.subplot(232), plt.imshow(img_equalize, cmap="gray"), plt.title("Image after Equalzie")
    plt.xticks([]), plt.yticks([])
    plt.subplot(233), plt.imshow(img_clahe, cmap="gray"), plt.title("Image after CLAHE")
    plt.xticks([]), plt.yticks([])
    plt.subplot(234), plt.plot(hist_src, color="b", label="hist_src"), plt.legend()
    plt.subplot(235), plt.plot(hist_equalize, color="g", label="hist_equalize"), plt.legend()
    plt.subplot(236), plt.plot(hist_clahe, color="r", label="hist_clahe"), plt.legend()
    plt.show()
    
    CLAHE自适应均衡化.png

    三、直方图反向投影

    直方图反向投影主要用于图像分割或查找图像中感兴趣的对象。

    直方图反向投影返回的图像,与输入图像具有相同的大小(但是单个通道),其中每个新的像素值对应于该像素属于ROI(感兴趣区域)的概率。越相似,概率值越大,颜色越靠近白色。

    OpenCV直方图反向投影流程:

    1)获取感兴趣对象的直方图
        calcHist(images, channels, mask, histSize, ranges, hist=None, accumulate=None)
    2)调用calcBackProject()之前,需要对直方图进行归一化。
        normalize(src, dst, alpha=None, beta=None, norm_type=None, dtype=None, mask=None)
        参数:
        src: 输入图片
        dst: 输出图片
        alpha: 阈值下限
        beta: 阈值上限
        norm_type: 归一化的类型。包括:
        NORM_INF = 1
        NORM_L1 = 2
        NORM_L2 = 4
        NORM_L2SQR = 5
        NORM_MINMAX = 32
        dtype: 为负数时,dst的大小和图像深度类型均与src一致。为正数时,由dtype属性指定dst的图像深度类型。
        mask: 掩膜
    3)反向投影
        calcBackProject(images, channels, hist, ranges, scale, dst=None)
        参数:
        images: 输入图像列表,如[img]。
        channels: 用于计算反向投影的通道列表,与hist直方图维度相匹配。
        hist: 感兴趣区域的直方图。
        ranges: 直方图中每个维度bin的取值范围。
        scale: 反向投影的图像像素的伸缩因子。
    4)圆盘卷积
        kernel = cv2.getStructuringElement(shape=cv2.MORPH_ELLIPSE, ksize=(5, 5))
        dst = cv2.filter2D(dst, -1, kernel)
    5)图像二值化
        ret, thresh = threshold(src, thresh, maxval, type, dst=None)
    6)抠出目标图像中的感兴趣部分
        thresh = cv2.merge((thresh, thresh, thresh))
        res = cv2.bitwise_and(target, thresh)
    

    示例:

    import cv2
    
    # 感兴趣对象ROI
    roi = cv2.imread("image/10.jpg")
    hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)  # 转化为HSV图
    # 目标图像
    target = cv2.imread("image/9.jpg")
    hsv_target = cv2.cvtColor(target, cv2.COLOR_BGR2HSV)  # 转化为HSV图
    
    # 1)统计ROI的直方图
    hist_roi = cv2.calcHist([hsv_roi], [0, 1], None, [180, 256], [0, 180, 0, 256])
    
    # 2)直方图归一化: 在调用calcBackProject之前,需要对hist_roi进行归一化
    cv2.normalize(hist_roi, hist_roi, 0, 255, cv2.NORM_MINMAX)
    
    # 3)反向投影: calcBackProject
    backProject = cv2.calcBackProject([hsv_target], [0, 1], hist_roi, [0, 180, 0, 256], 1)
    
    # 4)圆盘卷积
    kernel = cv2.getStructuringElement(shape=cv2.MORPH_ELLIPSE, ksize=(5, 5))
    backProject = cv2.filter2D(backProject, -1, kernel)
    
    # 5)图像二值化
    ret, thresh = cv2.threshold(backProject, 50, 255, cv2.THRESH_BINARY)
    
    # 6)抠出目标图像中的感兴趣部分
    thresh = cv2.merge((thresh, thresh, thresh))
    res = cv2.bitwise_and(target, thresh)
    
    # 展示图片
    cv2.imshow("roi", roi)
    cv2.imshow("target", target)
    cv2.imshow("backProject", backProject)
    cv2.imshow("thresh", thresh)
    cv2.imshow("res", res)
    cv2.waitKey(0)
    cv2.destroyWindow()
    
    直方图反向投影.png

    相关文章

      网友评论

        本文标题:OpenCV-Python学习(十一):直方图

        本文链接:https://www.haomeiwen.com/subject/xlsdfktx.html