Python+Numpy+CV2/GDAL实现对图像的Wallis匀色

news2025/1/13 10:04:12

Wallis匀色原理:

# f(x,y):Wallis匀色后结果
# g(x,y):输入的待匀色影像
# mg:待处理影像的灰度均值
# mf:参考影像的灰度均值
# sg:待处理影像和的标准偏差        
# sf:参考影像的标准偏差
f(x,y)=(g(x,y)−mg)(sf/sg)+mf

匀色代码逻辑解释:

(1)使用变异系数计算影像的分块数目;
(2)分块计算各块的均值、标准差;
(3)均值、标准差图重采样(双线性)成与输入影像相同行列数;
(4)代入Wallis匀色计算公式计算匀色后的图像数组并保存结果。

代码使用注意:

(1)输入影像与参考影像一定要行列数一致,后面采用GDAL的算法做了重采样,但是GDAL重采样要求输入的影像一定要有坐标;
(2)代码里给Wallis匀色后的值取了绝对值,因为保存成8bit的时候一些负值变成255了;
(3)处理的数据必须是8位的,输出也被固定成8位的了(band_i.astype(np.uint)),如果输入别的位深的数据需要修改一下输出时的数值转换。

算法脚本:

cv2进行Wallis匀色处理的代码

cv2适合对没有坐标、数据量小的图片进行处理,带坐标且数据量极大的卫星影像等往下看GDAL的算法。

"""Wallis匀光——cv"""
import cv2
import numpy as np
from osgeo import gdal
import matplotlib.pyplot as plt
org_file = r"输入影像.tif"
ref_file = r"参考影像.tif"
img_org = cv2.imread(org_file)
infer_img = cv2.imread(ref_file)
width,height,bands = img_org.shape
# 将影像分块进行处理
# 计算变异系数
cv_org = np.std(img_org)/np.mean(img_org)
cv_ref = np.std(infer_img)/np.mean(infer_img)
r = cv_org/cv_ref
num = int(np.ceil(8*r))
w = int(np.ceil(width/num))
h = int(np.ceil(height/num))
# mg:待处理影像的灰度均值
# mf:参考影像的灰度均值
# sg:待处理影像和的标准偏差        
# sf:参考影像的标准偏差 
mg = np.zeros((num,num,bands),dtype=np.float)
mf = np.zeros_like(mg)
sg = np.zeros_like(mg)
sf = np.zeros_like(mg)
for b in range(bands):
    for i in range(num):
        for j in range(num):
            orgin_x = i*w
            if orgin_x + w > width:orgin_x = width - w
            orgin_y = j*h
            if orgin_y + h > height:orgin_y = height - h
            end_x = orgin_x + w
            end_y = orgin_y + h
            img = img_org[orgin_x:end_x,orgin_y:end_y,b]
            ref = infer_img[orgin_x:end_x,orgin_y:end_y,b]
            mg[i,j,b] = np.mean(img)
            sg[i,j,b] = np.std(img)
            mf[i,j,b] = np.mean(ref)
            sf[i,j,b] = np.std(ref)

"""Wallis公式:f(x,y)=(g(x,y)−mg)⋅(sf/sg)+mf"""
eps = 1e-8
waillisImg = np.zeros_like(img_org)
for i in range(bands):
    mg_res = cv2.resize(mg[:,:,i],(height,width),interpolation=cv2.INTER_LINEAR)
    mf_res = cv2.resize(mf[:,:,i],(height,width),interpolation=cv2.INTER_LINEAR)
    sf_res = cv2.resize(sf[:,:,i],(height,width),interpolation=cv2.INTER_LINEAR)
    sg_res = cv2.resize(sg[:,:,i],(height,width),interpolation=cv2.INTER_LINEAR)
    band_i = np.abs((img_org[:,:,i] - mg_res) * (sf_res / (sg_res+ eps)) + mf_res)
    waillisImg[:,:,i] = band_i.astype(np.uint)
cv2.imwrite(r"waillis匀色结果.tif",waillisImg)
plt.subplot(1,3,1)
plt.imshow(img_org)
plt.subplot(1,3,2)
plt.imshow(infer_img)
plt.subplot(1,3,3)
plt.imshow(waillisImg)
plt.show()

贴一下匀色结果:
在这里插入图片描述

GDAL的Wallis匀色算法代码

GDAL的算法就没有办法像上面cv2一样把全图读完计算变异系数了(计算量太大了),采用的是经典的分块处理,将图像分成固定大小的方形切片,计算均值和标准差,并使用gdal.warp进行重采样,后面就是简单的分波段计算、保存与输出了。

"""Wallis匀光——GDAL"""

from osgeo import gdal,gdalconst
import numpy as np

org_file = r"输入影像.tif"
ref_file = r"参考影像.tif"

raster = gdal.Open(org_file)
rows = raster.RasterYSize
cols = raster.RasterXSize
bands = raster.RasterCount
print(cols,rows,bands)
OriginX,psX,_,OriginY,_,psY = raster.GetGeoTransform()
EndX = OriginX + cols * psX
EndY = OriginY + rows * psY
extent = [OriginX,EndY,EndX,OriginY]
# 分块大小定义为512
bk_size = 512
num_w = int(np.ceil(cols / bk_size))
num_h = int(np.ceil(rows/ bk_size))
print(num_w,num_h)
ref_raster = gdal.Open(ref_file)
# 输入影像对齐(对参考影像重采样成相同行列数)
if ref_raster.RasterXSize != cols and ref_raster.RasterYSize != rows:
    new_ref = ref_file[0:-4]+"_resample.tif"
    warp_ds = gdal.Warp(new_ref,ref_file,width = cols,height = rows) 
    warp_ds = None
    ref_raster = gdal.Open(new_ref)
# 计算Wallis需要的参数
# mg:待处理影像的灰度均值
# mf:参考影像的灰度均值
# sg:待处理影像和的标准偏差        
# sf:参考影像的标准偏差 
res_out = np.zeros((4,num_h,num_w,bands),dtype=np.float)
for b in range(bands):
    img_band = raster.GetRasterBand(b+1)
    ref_img = ref_raster.GetRasterBand(b+1)
    for i in range(num_h):
        for j in range(num_w):
            orgin_x = min(j*bk_size,cols -  bk_size)
            orgin_y = min(i*bk_size,rows - bk_size)
            img = img_band.ReadAsArray(orgin_x,orgin_y, bk_size, bk_size)
            ref = ref_img.ReadAsArray(orgin_x,orgin_y, bk_size, bk_size)
            res_out[0,i,j,b] = np.mean(img)#mg
            res_out[1,i,j,b] = np.std(img)#sg
            res_out[2,i,j,b] = np.mean(ref)#mf
            res_out[3,i,j,b] = np.std(ref)#sf

# 重采样
# 对输入影像重采样是为了获得采样后的Projection和GeoTransform,用来赋给mg/sg/mf/sf进行上采样
# 测试中发现gdal.warp无法对没有坐标的图像重采样
outimg = r"输入影像重采样.tif"
warp_ds = gdal.Warp(outimg,org_file,resampleAlg=gdalconst.GRA_Average,width = num_w,height = num_h) 
del warp_ds
temp_ref = gdal.Open(outimg)
in_list = []
for i in range(4):
    driver = gdal.GetDriverByName("GTiff")
    temp_out = r"temp%d.tif" % i # 过程数据 完成后可以删除
    temp_ds = driver.Create(temp_out,num_w,num_h,bands,gdal.GDT_Float32)
    temp_ds.SetGeoTransform(temp_ref.GetGeoTransform())
    temp_ds.SetProjection(temp_ref.GetProjection())
    for tb in range(bands):
        temp_ds.GetRasterBand(tb+1).WriteArray(res_out[i,:,:,tb])
    temp_ds.FlushCache()
    del temp_ds
    temp_res = r"temp_res%d.tif" % i # 过程数据 完成后可以删除
    warp_ds = gdal.Warp(temp_res,temp_out,resampleAlg=gdalconst.GRA_Bilinear,outputBounds = extent,xRes = psX,yRes =psY,targetAlignedPixels=True)                         
    del warp_ds
    in_raster = gdal.Open(temp_res)
    in_list.append(in_raster)

# 输出匀色结果
eps = 1e-8
[mean_raster,std_raster,mean_ref_raster,std_ref_raster] = in_list
driver = gdal.GetDriverByName("GTiff")
out_ds= driver.Create(r"Wallis匀色结果.tif",cols,rows,bands,gdal.GDT_Byte)
out_ds.SetGeoTransform(raster.GetGeoTransform())
out_ds.SetProjection(raster.GetProjection())
for b in range(bands):
    # 输入影像
    in_band = raster.GetRasterBand(b+1)
    mean_band = mean_raster.GetRasterBand(b+1)
    std_band = std_raster.GetRasterBand(b+1)
    # 参考影像
    mean_ref_band = mean_ref_raster.GetRasterBand(b+1)
    std_ref_band = std_ref_raster.GetRasterBand(b+1)
    # 输出影像
    out_band = out_ds.GetRasterBand(b+1)
    # 分块处理
    for i in range(num_h):
        for j in range(num_w):
            orgin_x = min(j*bk_size,cols -  bk_size)
            orgin_y = min(i*bk_size,rows - bk_size)
            # 读取输入参数
            gx = in_band.ReadAsArray(orgin_x, orgin_y, bk_size, bk_size)
            mg = mean_band.ReadAsArray(orgin_x, orgin_y, bk_size, bk_size)
            sg = std_band.ReadAsArray(orgin_x, orgin_y, bk_size, bk_size)
            mf = mean_ref_band.ReadAsArray(orgin_x, orgin_y, bk_size, bk_size)
            sf = std_ref_band.ReadAsArray(orgin_x, orgin_y, bk_size, bk_size)
            # 计算匀色影像
            wallis = np.abs((gx - mg) * (sf / (sg+ eps)) + mf)
            # 保存匀色结果
            out_band.WriteArray(wallis.astype(np.uint),orgin_x,orgin_y)
    out_band.FlushCache()
del out_band
out_ds.FlushCache()
del out_ds
print("Done")

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从阿里云“数字证书管理服务”申请免费的SSL证书

最近网站的SSL证书即将到期,之前是从FreeSSL申请的证书,而且是通过OpenSSL自己生成CSR文件的方式申请的证书,操作还是比较繁琐。(具体参考: https://blog.csdn.net/weixin_42534940/article/details/90745452 &#xf…

一、几种常用的设计模式

设计模式分类 创建者模式:对象实例化的模式,创建型模式用于解耦对象的实例化过程。 常用:单例模式、工厂方法模式、抽象工厂模式、建造者模式 。 不常用:原型模式结构型模式:把类或对象结合在一起形成一个更大的结构。…

Tilemap瓦片资源

1、Tilemap Tilemap一般称之为 瓦片地图或者平铺地图,是Unity2017中新增的功能,主要用于快速编辑2D游戏中的场景,通过复用资源的形式提升地图多样性 工作原理就是用一张张的小图排列组合为一张大地图 它和SpriteShape都是用于制作2D游戏的…

CEAC 之《企业信息化管理》1

👨‍💻个人主页:微微的猪食小窝 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 本文由 微微的猪食小窝 原创 收录于专栏 【CEAC证书】 1综合布线是智能建筑的信息高速公路。 A、正确 B、错误A2直通线的一根双绞线的两端执行不同…

Java基础实战项目-------网上订餐系统

目录 前言 项目需求 项目环境准备 技能点 实现思路 ​编辑 项目总结 完整代码: 前言 已学完Java基础部分的内容,如下 理解程序的基本概念:程序、变量、数据类型 会使用顺序、选择、循环、跳转语句编写程序 会使用数组以及Arrays的…

[附源码]SSM计算机毕业设计智慧教学平台JAVA

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

[附源码]java毕业设计生产型企业员工管理系统

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

应急响应-账户排查

用户信息排查 在服务器被入侵之后,攻击者可能会建立相关账户,方便进行远程控制。 主要采用一下几种: 直接建立一个新用户;(有时候为了混淆视听,账户名称和系统常用名相似)激活一个系统中的默认用户,但是这…

ArcGIS计算图斑四至坐标原来这么简单!可不要在走弯路哦

时常我们需要去计算图斑的四至坐标 (四至与四至点不一样哦) 很多朋友会去求个 最小边界几何 在与原始图斑相交得到点来算四至 这种方法有许多问题 是不可以取的,我们今天来介绍一下 一个简单的字段计算就解决这个问题 然后嫌麻烦 我们…

jtag调试ls1012a linux-5.3内核

1、jtag连接 OK1012A-C jtag引脚如下: 如果jlink的VCC对外输出供电,那么需要关闭,VCC对外供电导致jtag连接不上。使用引脚匹配的转接板连接开发板的jtag插座。使用交叉串口线连接开发板。 2、linux-5.3内核编译 -O0编译修改方法与树莓派4b编译修改方法一…

java基于ssm大学生社团管理系统-计算机毕业设计

系统采用了B/S结构,将所有业务模块采用以浏览器交互的模式,选择MySQL作为系统的数据库,开发工具选择My eclipse来进行系统的设计。基本实现了社团管理应有的主要功能模块,本系统有前台与后台两大功能模块,管理员&#…

【图像隐藏】基于小波变换DWT实现数字水印嵌入提取含各类攻击附matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。 🍎个人主页:Matlab科研工作室 🍊个人信条:格物致知。 更多Matlab仿真内容点击👇 智能优化算法 …

OPT(奥普特)荣摘高工锂电“2022年度创新技术奖”

日前,高工锂电年会暨金球奖颁奖典礼在深圳隆重举行,集结了锂电产业链上下游企业高层领袖,围绕行业新技术、数字工厂、极限智造等共议未来发展之道。 作为锂电行业机器视觉核心供应商,OPT(奥普特)受邀出席年…

【Java八股文总结】之面向对象

文章目录Java面向对象基础一、面向对象基础1、什么是封装?2、什么是继承?1、子类访问父类2、子类的访问修饰符3、方法重写3、什么是多态?1、Java语言如何实现多态2、什么时候使用多态?4、什么是接口?5、怎么使用接口&a…

Stream

目录 一 函数式接口 1 特点 2 核心函数式接口 1) Consumer 2) Supplier 3) Function 4) Predicate 5) 扩展:BiFunction 二 Stream 1 stream操作过程 1) 中间操作 2)终端…

[附源码]java毕业设计汽车票售票系统lunwen

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

太湖“生态度假式”年会,为您的健康守护,为您的相聚喝彩

最近几年经常听到, 有人说今年最大的目标就是活着, 历经风雨,方知岁月静好的可贵, 这特殊的一年又一年里让大家深觉“健康”的重要, 也让我们更热爱彼此、热爱生活。 倏忽间,2022已至尾声, 又到…

【ASM】字节码操作 工具类与常用类 GeneratorAdapter 介绍

文章目录 1.概述2. GeneratorAdapter2.1 class info2.2 fields2.3 构造方法2.4 方法2.5 特殊方法2.5.1 loadThis2.5.2 getArgIndex2.5.2 box &3. 案例4.总结1.概述 在上一篇文章中:【ASM】字节码操作 工具类与常用类 AdviceAdapter 介绍 打印方法进入 和 方法退出 的参数…

[附源码]SSM计算机毕业设计远程在线教育平台JAVA

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

【蓝桥杯物联网赛项学习日志】Day4 关于USART/UART

关键词:USART UART 串口通信 理论基础 USART/UART USART(Universal Synchronous/Asynchronous Receiver/Transmitter) 通用 同步/异步 串行 接收/发送器是一种串行通信接口。USART最多有5个信号,分别是TX,RX,nCTS.nRTS,SCLK TX串行输出信号RX串行输…