OpenCV的直方图

本文使用python实现

图像直方图

图像直方图是不同像素值范围的像素个数统计图:

在这里插入图片描述

# matplotlib.pyplot.hist()函数
def hist(x: Any,                            # 输入的数据
         bins: Any = None,                  # 条形数
         range: Any = None,                 # x轴的范围,范围之外的将被舍弃,数组元组类型(起,终)
         density: bool = False,             # 是否以密度形式显示
         weights: Any = None,
         cumulative: bool = False,
         bottom: Any = None,                # y轴的起始位置
         histtype: str = 'bar',             # 线条类型:‘bar’,方形;“barstacked”:柱形,“step”:“未填充线条”;“stepfilled”:“填充线条”
         align: str = 'mid',
         orientation: str = 'vertical',
         rwidth: Any = None,
         log: bool = False,
         color: Any = None,
         label: Any = None,
         stacked: bool = False,
         *,
         data: Any = None,
         **kwargs: Any) -> Any

 

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


def plot_demo(image):
    plt.hist(image.ravel(), 256, [0, 256])    # #ravel功能是将多维数组降为一维数组
    plt.title("image1")
    plt.show()


src = cv.imread("C:/Users/admin/Desktop/14.jpg")  # 打开一张图片
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)  # 设置图片尺寸,自动
cv.imshow("input image", src)  # 显示图像
plot_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()

 opencv里面函数如下

# OpenCV中函数
cv2.cv2 def calcHist(images: Any,        # 输入的图像或数组,必须用方括号括起来
             channels: Any,              # 用于计算直方图的通道
             mask: Any,                  # 
             histSize: Any,
             ranges: Any,                # 这个直方图分成多少份(即多少个直方柱)
             hist: Any = None,           # 表示直方图中各个像素的值,[0.0, 256.0]表示直方图能表示像素值从0.0到256的像素。
             accumulate: Any = None)     # 一个布尔值,用来表示直方图是否叠加

示例代码

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


def image_hist(image):
    color = ('blue', 'green', 'red')
    for i, color in enumerate(color):    # 这是python语法
        hist = cv.calcHist([image], [i], None, [256], [0, 256])
        plt.plot(hist, color=color)
        plt.xlim([0, 256])
    plt.title("image2")
    plt.show()


src = cv.imread("C:/Users/admin/Desktop/14.jpg")  # 打开一张图片
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)  # 设置图片尺寸,自动
cv.imshow("input image", src)  # 显示图像
image_hist(src)
cv.waitKey(0)
cv.destroyAllWindows()

 

直方图均衡化

import cv2 as cv
import numpy as np


def equal_hist_demo(image):
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)    # 转成灰度
    dst = cv.equalizeHist(gray)                     # 将灰度图像进行直方图均衡化,是图像增强的一个手段
    cv.imshow("equal_hist_demo image", dst)


src = cv.imread("C:/Users/admin/Desktop/6.jpg")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
equal_hist_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()

这种方法可以提高图像的亮度:

 

局部直方图均衡化,可以调节参数来改变效果

def clahe_demo(image):  # 局部直方图均衡化
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
    dst = clahe.apply(gray)
    cv.imshow("clahe_demo image", dst)

直方图比较,将以上两张米粒的图片拿来作直方图比较:

def create_rgb_hist(image):     # 创建rgb直方图
    h, w, c = image.shape
    rgbHist = np.zeros([16*16*16, 1], np.float32)
    bsize = 256/16
    for row in range(h):
        for col in range(w):
            b = image[row, col, 0]
            g = image[row, col, 1]
            r = image[row, col, 2]
            index = np.int(b/bsize)*16*16 + np.int(g/bsize)*16 + np.int(r/bsize)
            rgbHist[np.int(index), 0] = rgbHist[np.int(index), 0] + 1
    return rgbHist


def hist_compare(image1, image2):   # 直方图比较
    hist1 = create_rgb_hist(image1) # 创建直方图
    hist2 = create_rgb_hist(image2)
    match1 = cv.compareHist(hist1, hist2, cv.HISTCMP_BHATTACHARYYA) # 巴氏距离
    match2 = cv.compareHist(hist1, hist2, cv.HISTCMP_CORREL)        # 相关性,越大越相似
    match3 = cv.compareHist(hist1, hist2, cv.HISTCMP_CHISQR)        # 卡方,越大越不相似
    print("巴氏距离:%s,相关性:%s,卡方:%s"%(match1, match2, match3))

结果

巴氏距离:0.2635654174726917,相关性:0.9962298431258823,卡方:91208.7069553576

直方图反向投影

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


def hist2d_demo(image):
    hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)
    hist = cv.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
    # [0, 1]表示两个通道:0通道和1通道
    # [180, 256]0通道180,1通道256
    # [0, 180, 0, 256]0通道范围[0, 180],1通道范围[0, 256]
    '''
    def calcHist(images: Any,       # 必须用方括号括起来
             channels: Any,         # 用于计算直方图的通道
             mask: Any,             # 没有使用
             histSize: Any,         # 表示这个直方图分成多少份(即多少个直方柱)
             ranges: Any,           # 表示直方图中各个像素的值,[0.0, 256.0]表示直方图能表示像素值从0.0到256的像素。
             hist: Any = None,
             accumulate: Any = None)
    '''
    plt.imshow(hist, interpolation='nearest')
    plt.title("2D Histogram")
    plt.show()


src = cv.imread("C:/Users/admin/Desktop/14.jpg")  # 打开一张图片
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)  # 设置图片尺寸,自动
cv.imshow("input image", src)  # 显示图像
hist2d_demo(src)
back_projection_demo()
cv.waitKey(0)
cv.destroyAllWindows()

直方图反向投影

def back_projection_demo():    # 直方图反向投影
    sample = cv.imread("C:/Users/admin/Desktop/sample.jpg")
    target = cv.imread("C:/Users/admin/Desktop/14.jpg")
    roi_hsv = cv.cvtColor(sample, cv.COLOR_BGR2HSV)     # 转换为hsv
    target_hsv = cv.cvtColor(target, cv.COLOR_BGR2HSV) 
    cv.imshow("sample", sample) # 显示图片
    cv.imshow("target", target)
    roiHist = cv.calcHist([roi_hsv], [0, 1], None, [32, 32], [0, 180, 0, 256])    # 可通过调节[32, 32]来调节输出效果
    cv.normalize(roiHist, roiHist, 0, 255, cv.NORM_MINMAX)  # 归一化
    '''
    def normalize(src: Any,             # 输入数据
              dst: Any,                 # 输出数据
              alpha: Any = None,        # range normalization模式的最小值
              beta: Any = None,         # range normalization模式的最大值
              norm_type: Any = None,    # 归一化的类型
              dtype: Any = None,        # dtype为负数时,输出数组的type与输入数组的type相同;否则,输出数组与输入数组只是通道数相同,而tpye=CV_MAT_DEPTH(dtype).
              mask: Any = None) -> None # 操作掩膜,用于指示函数是否仅仅对指定的元素进行操作
    '''
    dst = cv.calcBackProject([target_hsv], [0, 1], roiHist, [0, 180, 0, 256], 1)
    '''
    def calcBackProject(images: Any,    # 输入图像,图像深度必须位CV_8U,CV_16U或CV_32F中的一种,尺寸相同,每一幅图像都可以有任意的通道数
                    channels: Any,      # 通道
                    hist: Any,          # 输入的直方图
                    ranges: Any,        # 直方图中每个维度bin的取值范围 
                    scale: Any,         # 可选输出反向投影的比例因子
                    dst: Any = None) -> None
    '''
    cv.imshow("back_projection_demo", dst)

其中cv.normalize()函数中归一化类型norm_type有如下取值:

NORM_MINMAX: 数组的数值被平移或缩放到一个指定的范围,线性归一化,一般较常用。

NORM_INF: 此类型的定义没有查到,根据OpenCV1的对应项,可能是归一化数组的C - 范数(绝对值的最大值)

NORM_L1: 归一化数组的L1 - 范数(绝对值的和)

NORM_L2: 归一化数组的(欧几里德)L2 - 范数

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瑟寒凌风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值