Multi-Camera Color Correction via Hybrid Histogram Matching直方图映射

文章目录

  • Multi-Camera Color Correction via Hybrid Histogram Matching
    • 1. 计算直方图, 累计直方图, 直方图均衡化
    • 2. 直方图规定化,直方图映射。
    • 3. 实验环节
      • 3.1 输入图像
      • 3.2 均衡化效果
      • 3.3 映射效果
    • 4. 针对3实验环节的伪影 做处理和优化,就是HMM这篇论文的目的

Multi-Camera Color Correction via Hybrid Histogram Matching

这是一篇直方图匹配的论文,通过直方图匹配达到颜色转换的目的。
主要分为2个步骤:
1个是全局的直方图匹配
2是局部颜色的调整(把累计直方图的直角展开)

1. 计算直方图, 累计直方图, 直方图均衡化

直方图
在这里插入图片描述

累计直方图
在这里插入图片描述

直方图均衡化后的直方图
在这里插入图片描述


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


def cal_hist(img):
    '''

    :param img: single channel image
    :return: hist
    '''
    hist, hist_edge = np.histogram(img, bins=256, range=[0, 256])
    # for i in range(256):
    #     hist[i] = np.count_nonzero(img==i)
    # print(hist_edge)
    return hist
def cal_cum_hist(hist):
    cum_hist = np.zeros_like(hist)
    for i in np.arange(1, 256):
        cum_hist[i] = cum_hist[i-1] + hist[i]
    return cum_hist

def cal_hist_equalize(img):
    '''

    :param img: single channel image
    :return:
    '''
    h, w = img.shape
    hist = cal_hist(img)
    cum_hist = cal_cum_hist(hist)
    lut = 255 * cum_hist / (h * w)
    lut = (lut + 0.5).astype(np.uint8)

    out = lut[img]
    return out, lut

2. 直方图规定化,直方图映射。

即将图像一 的直方图 映射为 图像二的直方图,使图像一的色彩接近图像二


def cal_hist_map(img, tgt_img):
    out1, lut1 = cal_hist_equalize(img)

    out2, lut2 = cal_hist_equalize(tgt_img)
    lut_invert = np.zeros_like(lut2)

    # 反转
    lut_invert = np.ones_like(lut2) * -1
    for i in range(0, 256):
        i = 255 - i # lut2[i]可能对应很多重复的i, 赋值为最小的一个。
        lut_invert[lut2[i]] = i
    # lut_invert 可能会有一些空缺点, 通过插值填充。
    if lut_invert[0] == -1:
        lut_invert[0] = lut_invert.min()
    if lut_invert[255] == -1:
        lut_invert[255] = lut_invert.max()
    xx = []
    yy = []
    xxx = []
    for i in range(0, 256):
        if lut_invert[i] != -1:
            xx.append(i)
            yy.append( lut_invert[i])
        else:
            xxx.append(i)
    
    lut_invert[lut_invert==-1] = np.interp(xxx, xx, yy)
    # 通过插值填充 或这 直接赋值
    # for i in range(1, 256):
    #     if lut_invert[i] == -1:
    #         lut_invert[i] = lut_invert[i-1]

    
    lut = np.zeros_like(lut1)
    for i in range(256):
        lut[i] = lut_invert[lut1[i]]

    out = lut[img]
    return out, lut

3. 实验环节

3.1 输入图像

来源:原论文仓库
在这里插入图片描述

3.2 均衡化效果

直方图均衡化本文代码和opencv效果对比,基本一致:
在这里插入图片描述

3.3 映射效果

直方图映射效果:看起来还行
在这里插入图片描述

实际应用到大图的时候出现伪影:
在这里插入图片描述

4. 针对3实验环节的伪影 做处理和优化,就是HMM这篇论文的目的

复现的效果:
左中右分别为, 图1,图2,映射后的图1(色调接近图2)
在这里插入图片描述

过滤噪声(数目比较少的值,累计直方图可能出现横线的地方)后,插值前的查找表:
在这里插入图片描述

插值后:
在这里插入图片描述

更多实验图像可以运行下面的代码:

import cv2
import numpy as np
from matplotlib import pyplot as plt
from scipy.signal import savgol_filter

from python.hist_equalize import cal_hist_equalize, cal_hist, cal_cum_hist


def cal_noisy_index(hist1, h1, w1):
    '''找出 噪声的 index,这些值需要重新插值'''
    ts = [] # remove noise index

    sort_index = np.argsort(hist1)
    #print('sort value:', hist1[sort_index])
    s = 0
    for i in range(len(sort_index)):
        t = sort_index[i]
        s += hist1[t]
        if s < 0.05 * (h1 * w1):
            ts.append(t)
    #print('ts num:', len(ts))
    return ts
def cal_hist_map2(img, tgt_img):
    h1, w1 = img.shape
    h2, w2 = tgt_img.shape

    hist1 = cal_hist(img)
    cum_hist1 = cal_cum_hist(hist1)

    hist2 = cal_hist(tgt_img)
    cum_hist2 = cal_cum_hist(hist2)

    lut1 = 255 * cum_hist1 / (h1 * w1)
    lut1 = (lut1 + 0.5).astype(np.uint8)
    lut2 = 255 * cum_hist2 / (h2 * w2)
    lut2 = (lut2 + 0.5).astype(np.uint8)

    print('lut2:', lut2)
    lut_invert = np.ones_like(lut2) * -1
    for i in range(0, 256):
        i = 255 - i # lut2[i]可能对应很多重复的i, 赋值为第一个。
        lut_invert[lut2[i]] = i
    # lut_invert 可能会有一些空缺点, 通过插值填充。
    if lut_invert[0] == -1:
        lut_invert[0] = lut_invert.min()
    if lut_invert[255] == -1:
        lut_invert[255] = lut_invert.max()
    xx = []
    yy = []
    xxx = []
    for i in range(0, 256):
        if lut_invert[i] != -1:
            xx.append(i)
            yy.append(lut_invert[i])
        else:
            xxx.append(i)
    lut_invert[lut_invert == -1] = np.interp(xxx, xx, yy)
    # 通过插值填充 或这 直接赋值
    # for i in range(1, 256):
    #     if lut_invert[i] == -1:
    #         lut_invert[i] = lut_invert[i-1]

    lut = np.zeros_like(lut1)
    for i in range(256):
        lut[i] = lut_invert[lut1[i]]

    # min_val = tgt_img.min()
    # max_val = tgt_img.max()
    # lut = np.clip(lut, min_val, max_val)


    '''找出 噪声的 index,这些值需要重新插值'''
    ts = cal_noisy_index(hist1, h1, w1)
    ts += cal_noisy_index(hist2, h2, w2)
    ts = np.unique(ts)

    xx = []
    yy = []
    xx.append(0)
    yy.append(lut[0]) # xx, yy的选择也很重要, 可以设为0
    lut_ret = lut.copy()
    for i in range(1, 255):
        if i not in ts:
            xx.append(i)
            yy.append(lut[i])
    xx.append(255)
    yy.append(lut[-1])  # xx, yy的选择也很重要, 也可以设为255看下效果

    lut_ret[ts] = np.interp(ts, xx, yy )
    lut_ret2 = (np.array(lut_ret).astype(np.int16) + np.array(lut)) / 2 + 0.5
    lut_ret = lut_ret.astype(np.uint8)
    for i in range(len(lut)):
        print(lut[i], lut_ret[i])
    plt.figure()
    x = range(256)
    plt.title('origin lut and interp lut')
    plt.plot(x, lut, 'r.', x, lut_ret, 'b-', x, ((lut_ret.astype(np.int16) + lut) / 2), 'y')
    plt.show()
    # smooth with savgol_filter
    lut_ret = savgol_filter(lut_ret, 15, 1)

    out = lut_ret[img]

    return out, lut_ret, xx, yy

def process(file1, file2, file3, file4):
    # file1 = r'D:\code_color\HHM-master\6to7\6to7.png'
    # file2 = r'D:\code_color\HHM-master\6to7\7to6.png'
    img1 = cv2.imread(file1, 1)
    img = img1.copy()
    img2 = cv2.imread(file2, 1)
    out, lut0, xx0, yy0 = cal_hist_map2(img1[..., 0], img2[..., 0])
    out, lut1, xx1, yy1 = cal_hist_map2(img1[..., 1], img2[..., 1])
    out, lut2, xx2, yy2 = cal_hist_map2(img1[..., 2], img2[..., 2])

    plt.figure()
    x = np.arange(256)
    plt.plot(x, lut0, 'b+')
    plt.plot(x, lut1, 'g+')
    plt.plot(x, lut2, 'r+')
    plt.show()
    plt.figure()
    plt.plot(xx0, yy0, 'b+')
    plt.plot(xx1, yy1, 'g+')
    plt.plot(xx2, yy2, 'r+')
    plt.show()
    
    # file3 = r'D:\code_color\HHM-master\6to7\6.png'
    # file4 = r'D:\code_color\HHM-master\6to7\7.png'
    img1 = cv2.imread(file3, 1)
    img = img1.copy()
    img2 = cv2.imread(file4, 1)
    img1[..., 0] = lut0[img1[..., 0]]
    img1[..., 1] = lut1[img1[..., 1]]
    img1[..., 2] = lut2[img1[..., 2]]
    cv2.imwrite(file3[:-4] + '_my.png', img1)
    plt.figure()
    plt.imshow(np.hstack((img, img2, img1))[..., ::-1])
    plt.show()
if __name__ == "__main__":
    file2 = r'D:\code_color\HHM-master\data1\4to5.png'
    file1 = r'D:\code_color\HHM-master\data1\5to4.png'
    file4 = r'D:\code_color\HHM-master\data1\4.png'
    file3 = r'D:\code_color\HHM-master\data1\5.png'

    # file2 = r'D:\code\3dlut\lut1.png'
    # file1 = r'D:\code\3dlut\lut2.png'
    # file4 = r'D:\code\3dlut\lut1.png'
    # file3 = r'D:\code\3dlut\lut2.png'

    file2 = r'D:\code_color\HHM-master\6to7\6to7.png'
    file1 = r'D:\code_color\HHM-master\6to7\7to6.png'
    file4 = r'D:\code_color\HHM-master\6to7\6.png'
    file3 = r'D:\code_color\HHM-master\6to7\7.png'
    process(file1, file2, file3, file4)

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

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

相关文章

ChatGPT研究分析:GPT-4做了什么

前脚刚研究了一轮GPT3.5&#xff0c;OpenAI很快就升级了GPT-4&#xff0c;整体表现有进一步提升。追赶一下潮流&#xff0c;研究研究GPT-4干了啥。本文内容全部源于对OpenAI公开的技术报告的解读&#xff0c;通篇以PR效果为主&#xff0c;实际内容不多。主要强调的工作&#xf…

九种跨域方式实现原理(完整版)

前言 前后端数据交互经常会碰到请求跨域&#xff0c;什么是跨域&#xff0c;以及有哪几种跨域方式&#xff0c;这是本文要探讨的内容。 一、什么是跨域&#xff1f; 1.什么是同源策略及其限制内容&#xff1f; 同源策略是一种约定&#xff0c;它是浏览器最核心也最基本的安…

如何发布自己的npm包

一、什么是npm npm是随同nodejs一起安装的javascript包管理工具&#xff0c;能解决nodejs代码部署上的很多问题&#xff0c;常见的使用场景有以下几种&#xff1a; ①.允许用户从npm服务器下载别人编写的第三方包到本地使用。 ②.允许用户从npm服务器下载并安装别人编写的命令…

K_A18_001 基于STM32等单片机采集MQ2传感参数串口与OLED0.96双显示

K_A18_001 基于STM32等单片机采集MQ2传感参数串口与OLED0.96双显示一、资源说明二、基本参数参数引脚说明三、驱动说明IIC地址/采集通道选择/时序对应程序:四、部分代码说明1、接线引脚定义1.1、STC89C52RCMQ2传感参模块1.2、STM32F103C8T6MQ2传感参模块五、基础知识学习与相关…

Vue3之插槽(Slot)

何为插槽 我们都知道在父子组件间可以通过v-bind,v-model搭配props 的方式传递值&#xff0c;但是我们传递的值都是以一些数字&#xff0c;字符串为主&#xff0c;但是假如我们要传递一个div或者其他的dom元素甚至是组件&#xff0c;那v-bind和v-model搭配props的方式就行不通…

让你少写多做的 ES6 技巧

Array.of 关于奇怪的 Array 函数&#xff1a; 众所周知&#xff0c;我们可以通过Array函数来做以下事情。 初始化一个指定长度的数组。 设置数组的初始值。 // 1. Initialize an array of the specified length const array1 Array(3) // [ , , ] // 2. Set the initial value…

Spring Cloud学习笔记【负载均衡-Ribbon】

文章目录什么是Spring Cloud RibbonLB&#xff08;负载均衡&#xff09;是什么Ribbon本地负载均衡客户端 VS Nginx服务端负载均衡区别&#xff1f;Ribbon架构工作流程Ribbon Demo搭建IRule规则Ribbon负载均衡轮询算法的原理配置自定义IRule新建MyRuleConfig配置类启动类添加Rib…

SQLMap 源码阅读

0x01 前言 还是代码功底太差&#xff0c;所以想尝试阅读 sqlmap 源码一下&#xff0c;并且自己用 golang 重构&#xff0c;到后面会进行 ysoserial 的改写&#xff1b;以及 xray 的重构&#xff0c;当然那个应该会很多参考 cel-go 项目 0x02 环境准备 sqlmap 的项目地址&…

学习java——②面向对象的三大特征

目录 面向对象的三大基本特征 封装 封装demo 继承 继承demo 多态 面向对象的三大基本特征 我们说面向对象的开发范式&#xff0c;其实是对现实世界的理解和抽象的方法&#xff0c;那么&#xff0c;具体如何将现实世界抽象成代码呢&#xff1f;这就需要运用到面向对象的三大…

从ChatGPT与New Bing看程序员为什么要学习算法?

文章目录为什么要学习数据结构和算法&#xff1f;ChatGPT与NEW Bing 的回答想要通关大厂面试&#xff0c;就不能让数据结构和算法拖了后腿业务开发工程师&#xff0c;你真的愿意做一辈子CRUD boy吗&#xff1f;对编程还有追求&#xff1f;不想被行业淘汰&#xff1f;那就不要只…

2023年网络安全比赛--CMS网站渗透中职组(超详细)

一、竞赛时间 180分钟 共计3小时 二、竞赛阶段 1.使用渗透机对服务器信息收集,并将服务器中网站服务端口号作为flag提交; 2.使用渗透机对服务器信息收集,将网站的名称作为flag提交; 3.使用渗透机对服务器渗透,将可渗透页面的名称作为flag提交; 4.使用渗透机对服务器渗透,…

一个Bug让人类科技倒退几十年?

大家好&#xff0c;我是良许。 前几天在直播的时候&#xff0c;问了直播间的小伙伴有没人知道「千年虫」这种神奇的「生物」的&#xff0c;居然没有一人能够答得上来的。 所以&#xff0c;今天就跟大家科普一下这个人类历史上最大的 Bug 。 1. 全世界的恐慌 一个Bug会让人类…

jQuery《一篇搞定》

今日内容 一、JQuery 零、 复习昨日 1 写出至少15个标签 2 写出至少7个css属性font-size,color,font-familytext-algin,background-color,background-image,background-sizewidth,heighttop,bottom ,left ,rightpositionfloatbordermarginpadding 3 写出input标签的type的不…

flex布局左边宽度固定,右边宽度动态扩展问题

我们希望在一个固定宽度的容器中&#xff0c;分左右两边&#xff0c;左边宽度固定大小&#xff0c;右边占满&#xff0c;使用flex布局时&#xff0c;如下&#xff1a; 对应代码如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta…

LeetCode - 198 打家劫舍

目录 题目来源 题目描述 示例 提示 题目解析 算法源码 题目来源 198. 打家劫舍 - 力扣&#xff08;LeetCode&#xff09; 题目描述 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装…

【华为机试真题 Python实现】2023年1、2月高频机试题

文章目录2023年1季度最新机试题机考注意事项1. 建议提前刷题2. 关于考试设备3. 关于语言环境3.1. 编译器信息3.2. ACM 模式使用sys使用input&#xff08;推荐&#xff09;3. 关于题目分值及得分计算方式4. 关于做题流程5. 关于作弊2023年1季度最新机试题 两个专栏现在有200博文…

2023还有人不知道kubernetes?| 初步理解kubernetes

文章目录Kubernetes(K8s)一、Openstack&VM1、**认识虚拟化****1.1**、什么是虚拟化**1.2、虚拟化分类**2、OpenStack与KVM、VMWare2.1、OpenStack2.2、KVM2.3、VMWare二、容器&编排技术1、容器发展史1.1、Chroot1.2、FreeBSD Jails1.3、Solaris Zones1.4、LXC1.5、Dock…

深度学习 Day26——使用Pytorch实现猴痘病识别

深度学习 Day26——使用Pytorch实现猴痘病识别 文章目录深度学习 Day26——使用Pytorch实现猴痘病识别一、前言二、我的环境三、前期工作1、设置GPU导入依赖项2、导入猴痘病数据集3、划分数据集四、构建CNN网络五、训练模型1、设置超参数2、编写训练函数3、编写测试函数4、正式…

【LeetCode】1544. 整理字符串、LCP 44. 开幕式焰火

作者&#xff1a;小卢 专栏&#xff1a;《Leetcode》 喜欢的话&#xff1a;世间因为少年的挺身而出&#xff0c;而更加瑰丽。 ——《人民日报》 目录 1544. 整理字符串 LCP 44. 开幕式焰火 1544. 整理字符串 1544. 整理字符串 题目描述…

金三银四、金九银十 面试宝典 Spring、MyBatis、SpringMVC面试题 超级无敌全的面试题汇总(超万字的面试题,让你的SSM框架无可挑剔)

Spring、MyBatis、SpringMVC 框架 - 面试宝典 又到了 金三银四、金九银十 的时候了&#xff0c;是时候收藏一波面试题了&#xff0c;面试题可以不学&#xff0c;但不能没有&#xff01;&#x1f941;&#x1f941;&#x1f941; 一个合格的 计算机打工人 &#xff0c;收藏夹里…