NO.3 机器视觉 直方图&帧提取

零蚀


直方图

  • 直方图的构建
    • 我们一般会用直方图来直观的统计像素的分布,直方图可以帮助我们分析和修正图片(直方图一般是对一个色值进行统计,所以大部分的样例都是灰度图)。具体的代码如下:
    import matplotlib.pyplot as plt
    src = cv.imread("../source/android.png", cv.IMREAD_GRAYSCALE)
    
    height = src.shape[0]
    width = src.shape[1]
    
    count = np.zeros(256, np.int)
    # 遍历每一个灰度图
    for rows in range(height):
        for cols in range(width):
            gray = src[rows, cols]
            count[gray] = count[gray] + 1
    
    # 绘制直方图
    # 构建x轴的数据 ,param 起始值 0 ,终止值 255 ,总数 256
    x = np.linspace(0, 255, 256)
    y = count
    
    plt.bar(x, y, width=10, alpha=0.8, color="blue", label="灰度")
    plt.show()
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fKDubXiS-1601124405892)(media/16006001095056/16006921888928.jpg)]

    • 使用直方图API,使用直方图API方式 有两种,第一种是通过opencv的方式。
    import cv2 as cv
    import matplotlib.pyplot as plt
    
    src = cv.imread("../source/collapse.jpg")
    src2 = cv.imread("../source/android.png")
    """
    直方图API
    images  资源
    channel 需要绘制的通道
    mask 遮罩(只绘制白色区域,不绘制黑色区域)
    histSize 颜色值总数(对应的channel的每一个总数)
    range 范围
    """
    hist = cv.calcHist([src], [0], None, [256], [0, 255])
    plt.plot(hist, color="blue")
    plt.show()
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H1Uxtl1r-1601124405895)(media/16006001095056/16010875570604.jpg)]

    • 另外一种是通过降维的方式,来将数据保存在一个数组中,来显示数据的变化。
    import cv2 as cv
    import matplotlib.pyplot as plt
    
    src = cv.imread("../source/collapse.jpg")
    """
    直方图API
    ravel 将二维数据降到一维数组中
    bins 设置变量范围
    """
    
    plt.hist(src.ravel(),bins=256)
    plt.show()
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DiVTwRWK-1601124405896)(media/16006001095056/16010879735837.jpg)]

  • 直方图均衡化(gray)
    • 由于直方图的点像一个个离散的点,这里所说的均衡化,就是将直方图的离散点,按照函数的线形变化规律,来让直方图有一定的变化坡度,从而使得图像更加具有柔和的变化。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WuDCWxhf-1601124405897)(media/16006001095056/16010887457052.jpg)]

    import cv2 as cv
    import numpy as np
    import matplotlib.pyplot as plt
    
    # 直方图
    from numpy.core._multiarray_umath import ndarray
    
    src = cv.imread("../source/collapse.jpg")
    gray = cv.cvtColor(src, cv.COLOR_BGRA2GRAY)
    
    x = np.linspace(0, 255, 256)
    y = np.zeros(256, np.int)
    
    for row in range(gray.shape[0]):
        for col in range(gray.shape[1]):
            gray_value = gray[row, col]
            y[gray_value] = y[gray_value] + 1
    
    # 累计概率直方图
    
    radio = np.zeros(256, np.float)
    
    for index, value in enumerate(y):
        radio[index] = value / (gray.shape[0] * gray.shape[1])
    
    plt.bar(x, radio, 0.9, color="green")
    plt.show()
    
    # 显示 累加概率直方图
    # 累加 概率就是逐级将概率直方图的值相加,
    
    sum_value = 0
    sum_radio = np.zeros(256, np.float)
    for index, value in enumerate(radio):
        sum_value += value
        sum_radio[index] = sum_value
    
    plt.bar(x, sum_radio, 0.9, color="blue")
    plt.show()
    
    # 累计概率计算当前的颜色值
    dst = np.zeros(gray.shape, np.uint8)
    for m in range(gray.shape[0]):
        for n in range(gray.shape[1]):
            old_color = gray[m,n]
            # 获取像素对应的累计概率
            radio_obtain = sum_radio[old_color]
            # 输入累计概率对应的值
            dst[m, n] = 255 * radio_obtain
    cv.imshow("dst",dst)
    cv.imshow("gray",gray)
    cv.waitKey()
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fr0CjCq1-1601124405898)(media/16006001095056/16011041424978.jpg)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nwfmuLnl-1601124405899)(media/16006001095056/16011042790125.jpg)]

    • 灰度图直方图API
    import cv2 as cv
    
    src = cv.imread("../source/android.png",cv.IMREAD_GRAYSCALE)
    # 直方图均衡化API
    dst = cv.equalizeHist(src)
    cv.imshow("hist",dst)
    cv.waitKey()
    
    • 彩色图片的直方图,分别绘制每个渠道的直方图
    import cv2 as cv
    import matplotlib.pyplot as plt
    
    src = cv.imread("../source/collapse.jpg")
    # 获取每个渠道的数据
    channel_data = cv.split(src)
    colors = ["red", "green", "blue"]
    for i in range(len(channel_data)):
        channel = channel_data[i]
        # channel.ravel = rows * cols
        plt.hist(channel.ravel(), bins=256, color=colors[i])
        plt.show()
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EeNcYqHI-1601124405900)(media/16006001095056/16011187860336.jpg)]

    • 彩色直方图的均衡化,彩色图片的均衡化,就是将图像的每个通道进行均衡化之后,将数据合并成原来的数值。可以看出均衡化后的色彩比原色彩没有那么鲜亮了,整体暗淡了一些。
    import cv2 as cv
    
    src = cv.imread("../source/collapse.jpg")
    # 获取每个渠道的数据
    channel_data = cv.split(src)
    colors = ["red", "green", "blue"]
    channel = []
    for i in range(len(channel_data)):
        channel.append(cv.equalizeHist(channel_data[i]))
    
    # 合并每个渠道的数据
    dst = cv.merge(channel)
    cv.imshow("dst", dst)
    cv.waitKey()
    

    在这里插入图片描述

  • 直方图规定化
    • 直方图的规定化,是将我们当前的图像的直方图,和目标的直方图的直方图一致,比如说我想将当前的图像的色调,改成目标图像的色调。下面将卡通图的色映射到女团的图片背景。
    import cv2 as cv
    import matplotlib.pyplot as mp
    import numpy as np
    
    """
    计算原图的累计直方图
    计算目标的累计直方图
    计算两个直方图,灰度差异
    根据最小差异,进行映射
    """
    
    
    def get_plot(src):
        # 普通的直方图
        hist = cv.calcHist([src], [0], None, [256], [0, 255])
        # mp.plot(hist)
        # mp.show()
    
        # 累计概率
        width = src.shape[1]
        height = src.shape[0]
        rate = hist / (width * height)
        # 绘制累计直方图
        sum_ratio = np.zeros(256, np.float)
        sum_value = 0
        for i in range(256):
            sum_value = sum_value + rate[i]
            sum_ratio[i] = sum_value
        mp.plot(sum_ratio)
        mp.show()
        return sum_ratio
    
    
    src = cv.imread("../source/aaaa.png", cv.COLOR_BGR2GRAY)
    src_radios = get_plot(src)  # 原图的累计概率直方图
    aim = cv.imread("../source/ashin.jpg", cv.COLOR_BGR2GRAY)
    aim_radios = get_plot(aim)  # 目标的累计概率
    
    origin1 = cv.imread("../source/aaaa.png", cv.COLOR_BGR2GRAY)
    origin2 = cv.imread("../source/ashin.jpg", cv.COLOR_BGR2GRAY)
    
    #  比较两个直方图的的灰度差异最小值
    
    indexColor = np.zeros(256, np.uint8)
    for i, src_v in enumerate(src_radios):
        min_v = 256
        index = 0
        for j, aim_v in enumerate(aim_radios):
            distance = np.abs(aim_v - src_v)
            if distance < min_v:
                min_v = distance
                index = j
        indexColor[i] = index
    
    w = src.shape[1]
    h = src.shape[0]
    
    for row in range(h):
        for col in range(w):
            gray_color = src[row, col]
            refer = indexColor[gray_color]
            src[row, col]=refer
    
    cv.imshow("origin1",origin1)
    cv.imshow("origin2",origin2)
    cv.imshow("src",src)
    cv.waitKey(0)
    
    

    在这里插入图片描述
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z8GPsSgM-1604831883524)(media/16006001095056/16048316268932.jpg)]

    • 如果想对彩色图进行直方图的映射,那么我们就需要进行channle的融合。大体的逻辑和上面的一样。

帧提取

  • 相机
    • 摄像头的打开,如果是ubuntu的话,我们可以使用以下的方式打开摄像头。
    # 打开摄像头(ubuntu)
    sudo cheese
    
    • 通过opencv的方式打开摄像头
    import cv2 as cv
    
    # 调用摄像头(0是前置,1是后置,如果传入路径就是打开视频)
    camera = cv.VideoCapture(0)
    print("是否打开摄像头=", camera.isOpened())
    
    # 获取宽,高,帧率
    width = camera.get(cv.CAP_PROP_FRAME_WIDTH)
    height = camera.get(cv.CAP_PROP_FRAME_HEIGHT)
    fps = camera.get(cv.CAP_PROP_FPS)
    while True:
        flag, frame = camera.read()
        if flag:
            cv.imshow("camera", frame)
    
        # 设置帧率为20
        key = cv.waitKey(50)
    
        # 设置点击"空格键"来跳出循环
        if key == 32:
            break
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0SsGQwvz-1601124405901)(media/16006001095056/16011224269614.jpg)]

    • 其实我们获取的这个frame就是对应着的src数据,我们可以对应的修改。(比如像下面一下,对图像进行均衡化)
    channel_data = []
    while True:
       flag, frame = camera.read()
       if flag:
       	split = cv.split(frame)
       	channel = len(split)
       	channel_data.clear()
       	for i in range(channel):
    
           	data = cv.equalizeHist(cv.equalizeHist(split[i]))
           	channel_data.append(data)
    
       	dst = cv.merge(channel_data)
       	cv.imshow("camera", dst)
    
    • 视频的解析
    camera = cv.VideoCapture("../source/earth.mp4")
    print(camera.isOpened())
    w = camera.get(cv.CAP_PROP_FRAME_WIDTH)
    h = camera.get(cv.CAP_PROP_FRAME_HEIGHT)
    fps = camera.get(cv.CAP_PROP_FPS)
    while True:
       flag, frame = camera.read()
       if flag:
           cv.imshow("earth", frame)
           # 将视频的图片每一帧输出
           cv.imwrite("picture{}".format(time.time()))
       key = cv.waitKey(int(1000 / fps))
       if key == 32:
           break
    

🔗 前言
🔗 机器人视觉篇
🔗 NO.1 机器视觉 前言
🔗 NO.2 机器视觉 几何变化 & 特效处理
🔗 NO.4 机器视觉 人脸识别&色彩过滤
🔗 NO.5 机器人视觉 二值化 & 卷积
🔗 NO.6 机器人视觉 霍夫检测 & 边缘查找
🔗 NO.7 C++中使用Opencv
🔗 NO.8 C++ 直方图 & 卷积
🔗 NO.9 C++ 匹配 & 变化
🔗 NO.10 C++ 图像算法

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

零蚀zero eclipse

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

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

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

打赏作者

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

抵扣说明:

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

余额充值