(五)图像的标准假彩色合成

news2025/1/22 11:57:49

环境:Windows10专业版 + IDEA2021.2.3 + jdk11.0.1 + GDAL(release-1928-x64-gdal-3-5-2-mapserver-8-0-0) + OpenCV-460.jar

系列文章:

(一)Python+GDAL实现BSQ,BIP,BIL格式的相互转换

(二)BSQ,BIL,BIP存储格式的相互转换算法

(三)单波段图像的伪彩色合成:密度分割(含介绍OpenCV中的Mat类)

(四)图像的%2线性拉伸

(五)图像的标准假彩色合成

(六)图像的直方图均衡化

(七)图像的均值滤波

(八)图像的中值滤波

(九)图像的高斯低通滤波

(十)图像的梯度倒数加权平滑

(十一)图像的罗伯特梯度锐化

(十二)图像的Sobel梯度锐化

(十三)图像的拉普拉斯梯度锐化

目录

一、标准假彩色合成简介

二、算法流程

三、代码实现

四、实验结果

1、原图像

2、假彩色合成结果

3、ENVI中标准假彩色的合成结果


一、标准假彩色合成简介

标准假彩色合成是一种遥感影像处理技术,用于增强图像的视觉效果和地物信息的提取

标准假彩色合成通常涉及以下几个关键步骤:

1、波段选择:从多光谱遥感图像中选择三个不同的波段。这些波段通常是根据能够最大化地物特征差异的原则来选择的。

2、颜色赋予:将选定的波段分别赋予红、绿、蓝三种颜色。由于这些波段的波长与对应的颜色波长不同,因此合成后的图像颜色并不是地物的真实颜色。

3、图像合成:利用加色法原理,将赋予颜色的波段合成一张彩色图像。这种方法可以使得某些地物特征在视觉上更加突出,便于分析和识别。

4、应用:标准假彩色合成广泛应用于植被信息提取、土地利用分类、环境监测等领域。例如,在ENVI软件中,可以通过加载CIR(Color Infrared)功能快速实现标准假彩色合成。

二、算法流程

1、利用GDAL读取landset图像波段4,波段3,波段2的像素并存放在数组中

2、一张16位的图像,图像的每个像素点的像素值都由16位的二进制数表示,每个像素点的颜色有 2^16 = 65536 种可能,也就是说,图像的颜色区间被划分成了 65536份;同理,8位图像,图像的颜色区间被划分成了2^8 = 256份。

因为TIFF图像的颜色存储位数为16位,需要进行线性拉伸转换为8位,将16位转换成8位,即为将区间 [0,65535] 映射到 [0,255] ,算出每个波段像素的最大值和最小值,进行线性拉伸,

​将最小值 pmin 映射到1,这样不会造成像素丢失,最后得到像素值范围在[1,255]的图像

3、将拉伸后的4,3,2波段的像素数组分别赋予R,G,B通道利用OpenCV合成图像并存储

三、代码实现

import org.gdal.gdal.Band;
import org.gdal.gdal.Dataset;
import org.gdal.gdal.gdal;
import org.gdal.gdalconst.gdalconstConstants;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;

import java.util.ArrayList;

/**
 * @Author: HNUST_jue_chen
 * @Date: 2022/10/28/ 11:01
 * @Attention: 转载, 引用请注明出处
 */

//假彩色合成
public class FalseColorSynthesis {
    //加载本地动态链接库
    static {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    }

    //获得波段4,3,2
    public ArrayList<int[][]> getBands(String path) {
        //支持所有驱动
        gdal.AllRegister();
        //以只读方式读取数据存入Dataset类型里
        Dataset dataset = gdal.Open(path, gdalconstConstants.GA_ReadOnly);
        //获得图像的大小
        int rows = dataset.getRasterYSize();
        int cols = dataset.getRasterXSize();
        int count = dataset.getRasterCount();
        System.out.println(rows);
        System.out.println(cols);
        System.out.println(count);

        //获得需要的三个波段
        Band band4 = dataset.GetRasterBand(4);
        Band band3 = dataset.GetRasterBand(3);
        Band band2 = dataset.GetRasterBand(2);

        //定义波段三个二维数组存放三个波段的像素
        int[][] band4_arr = new int[rows][cols];
        int[][] band3_arr = new int[rows][cols];
        int[][] band2_arr = new int[rows][cols];

        //将三个波段的像素的像素存放入二维数组
        for (int i = 0; i < rows; i++) {
            //一次读取一行像素值
            band4.ReadRaster(0, i, cols, 1, band4_arr[i]);
            band3.ReadRaster(0, i, cols, 1, band3_arr[i]);
            band2.ReadRaster(0, i, cols, 1, band2_arr[i]);
        }

        //将三个二维数组存放在集合中
        ArrayList<int[][]> band_arr = new ArrayList<>();
        band_arr.add(band4_arr);
        band_arr.add(band3_arr);
        band_arr.add(band2_arr);

        return band_arr;
    }

    //获得本图像像素的最大值和最小值
    public int[] getMinMaxPixel(int[][] arr) {
        //先将数组的第一个数赋予最大值和最小值
        int min = arr[0][0];
        int max = arr[0][0];
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[0].length; j++) {
                //更新最小值
                if (arr[i][j] < min) {
                    min = arr[i][j];
                }
                //更新最大值
                if (arr[i][j] > max) {
                    max = arr[i][j];
                }
            }
        }

        //将最大值和最小值存入数组
        int[] minMaxArr = new int[2];
        minMaxArr[0] = min;
        minMaxArr[1] = max;
        return minMaxArr;
    }

    //将16位像素转换为8位像素,线性拉伸[a,b]到[c,d]
    //a=min,b=max,c=1,d=255
    //新像素值=(d-c)/(max-min)*(原像素值-min)+1
    public int[][] linearTo8Bit(int[][] arr, int min, int max) {
        //定义线性拉伸后的数组
        int[][] arr_linear = new int[arr.length][arr[0].length];
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[0].length; j++) {
                arr_linear[i][j] = (int) ((double) (255 - 1) / (max - min) * (arr[i][j] - min) + 1);
            }
        }
        return arr_linear;
    }

    //将三个波段合成为假彩色图像
    public Mat falseColorSynthesis(ArrayList<int[][]> arrayList) {
        //获得三个波段的数组
        int[][] band4_arr = arrayList.get(0);
        int[][] band3_arr = arrayList.get(1);
        int[][] band2_arr = arrayList.get(2);

        //定义存储三个波段的三通道数组
        int[][] image_arr = new int[band4_arr.length][band4_arr[0].length * 3];

        //Mat类三通道的的顺序为B,G,R,在标准假彩色合成中应该分别赋予band2,band3,band4
        for (int i = 0; i < image_arr.length; i++) {
            //将波段2赋予蓝色通道
            for (int j = 0; j < band2_arr[0].length; j++) {
                image_arr[i][3 * j] = band2_arr[i][j];
            }
            //将波段3赋予绿色通道
            for (int j = 0; j < band3_arr[0].length; j++) {
                image_arr[i][3 * j + 1] = band3_arr[i][j];
            }
            //将波段4赋予红色通道
            for (int j = 0; j < band4_arr[0].length; j++) {
                image_arr[i][3 * j + 2] = band4_arr[i][j];
            }
        }

        //定义假彩色图像
        Mat mat = new Mat(band2_arr.length, band2_arr[0].length, CvType.CV_32SC3);
        //将像素放入图像
        for (int i = 0; i < image_arr.length; i++) {
            //一次放入一行三通道像素值
            mat.put(i, 0, image_arr[i]);
        }
        return mat;
    }

    public static void main(String[] args) {
        FalseColorSynthesis fsc = new FalseColorSynthesis();
        ArrayList<int[][]> band_arr = fsc.getBands("D:\\Project\\IDEA_Project\\RS01\\src\\rs01\\img\\13.tif");

        //得到波段4的最小最大像素值
        int[][] band4_arr = band_arr.get(0);
        int[] band4_minMax = fsc.getMinMaxPixel(band4_arr);
        int band4_min = band4_minMax[0];
        int band4_max = band4_minMax[1];

        //得到波段3的最小最大像素值
        int[][] band3_arr = band_arr.get(1);
        int[] band3_minMax = fsc.getMinMaxPixel(band3_arr);
        int band3_min = band3_minMax[0];
        int band3_max = band3_minMax[1];

        //得到波段2的最小最大像素值
        int[][] band2_arr = band_arr.get(2);
        int[] band2_minMax = fsc.getMinMaxPixel(band2_arr);
        int band2_min = band2_minMax[0];
        int band2_max = band2_minMax[1];

        //波段4线性拉伸
        int[][] band4_arrLinear = fsc.linearTo8Bit(band4_arr, band4_min, band4_max);
        //波段3线性拉伸
        int[][] band3_arrLinear = fsc.linearTo8Bit(band3_arr, band3_min, band3_max);
        //波段2线性拉伸
        int[][] band2_arrLinear = fsc.linearTo8Bit(band2_arr, band2_min, band2_max);

        //将线性拉伸后的数组存放在集合中
        ArrayList<int[][]> band_arrLinear = new ArrayList<>();
        band_arrLinear.add(band4_arrLinear);
        band_arrLinear.add(band3_arrLinear);
        band_arrLinear.add(band2_arrLinear);

        //合成假彩色图像
        Mat mat = fsc.falseColorSynthesis(band_arrLinear);
        //将假彩色图像写入文件
        Imgcodecs.imwrite("D:\\Project\\IDEA_Project\\RS01\\src\\rs01\\img\\13_fsc.png", mat);
    }
}

四、实验结果

1、原图像

TIFF格式的图像为16位深度的颜色,直接在Window里打开一张16位tif格式的图片是无法获得有效信息甚至无法打开,所以在ENVI中进行查看。

2、假彩色合成结果

3、ENVI中标准假彩色的合成结果

和ENVI中合成的假彩色图像非常接近

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

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

相关文章

pear-admin 项目结构讲解

上一篇文章介绍了pear-admin用到flask的技术&#xff0c; 深入代码后发现其结构也是令人眼前一亮&#xff0c; 结构化&#xff0c;模块化&#xff0c; 解耦做得非常优秀。 整个项目数据库使用migrate做了版本管理&#xff0c; 使用marshmallow做了序列化&#xff0c;这样数据库…

STL —— string(3)

目录 1. 使用 1.1 c_str() 1.2 find() & rfind() 1.3 substr() 1.4 打印网址的协议域名等 1.5 find_first_of() 2. string() 模拟实现 2.1 构造函数的模拟实现 2.2 operator[] 和 iterator 的模拟实现 2.3 push_back() & append() & 的模拟实现 2.4 ins…

C语言运算符优先级介绍

1. 引言 什么是运算符 运算符是编程中用于执行算术、比较和逻辑操作的符号。它们是构建表达式的基本工具&#xff0c;类似于数学中的加、减、乘和除。 程序片段示例: 简单的算术运算符使用 #include <stdio.h>int main() {int a 5, b 2;int sum a b; // 使用加法…

发车,易安联签约某新能源汽车领军品牌,为科技创新保驾护航

近日&#xff0c;易安联成功签约某新能源汽车领军品牌&#xff0c;为其 数十万终端用户 建立一个全新的 安全、便捷、高效一体化的零信任终端安全办公平台。 随着新能源汽车行业的高速发展&#xff0c;战略布局的不断扩大&#xff0c;技术创新不断引领其市场价值走向高点&am…

计算机网络——数据链路层(差错控制)

计算机网络——数据链路层&#xff08;差错控制&#xff09; 差错从何而来数据链路层的差错控制检错编码奇偶校验码循环冗余校验&#xff08;CRC&#xff09;FCS 纠错编码海明码海明距离纠错流程确定校验码的位数r确定校验码和数据位置 求出校验码的值检错并纠错 我们今年天来继…

C#打印50*30条码标签

示例图&#xff1a; 源码下载地址&#xff1a;https://download.csdn.net/download/tiegenZ/89035407?spm1001.2014.3001.5503

【Java程序设计】【C00379】基于(JavaWeb)Springboot的旅游服务平台(有论文)

【C00379】基于&#xff08;JavaWeb&#xff09;Springboot的旅游服务平台&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;已经做了六年的毕业设计程序开发&#xff0c…

STM32F103 CubeMX 使用USB生成键盘设备

STM32F103 CubeMX 使用USB生成键盘设备 基础信息HID8个数组各自的功能 生成代码代码编写添加申明信息main 函数编写HID 修改1. 修改报文描述符2 修改 "usbd_hid.h" 中的申明文件 基础信息 软件版本&#xff1a; stm32cubmx&#xff1a;6.2 keil 5 硬件&#xff1a;…

【剑指offer】顺时针打印矩阵

题目链接 acwing leetcode 题目描述 输入一个矩阵&#xff0c;按照从外向里以顺时针的顺序依次打印出每一个数字。 数据范围矩阵中元素数量 [0,400]。 输入&#xff1a; [ [1, 2, 3, 4], [5, 6, 7, 8], [9,10,11,12] ] 输出&#xff1a;[1,2,3,4,8,12,11,10,9,5,6,7] 解题 …

MySQL【三】操作数据库基础

库、表、记录的概念 库&#xff08;Database&#xff09;&#xff1a;库是一个容器&#xff0c;用于存储表和其他对象&#xff08;如视图、存储过程等&#xff09; 表&#xff08;Table&#xff09;&#xff1a;表是一个由列和行组成的矩阵&#xff0c;其中每列都定义了表中的…

MQTT.fx和MQTTX 链接ONENET物联网提示账户或者密码错误

参考MQTT.fx和MQTTX 链接ONENET物联网开发平台避坑细节干货。_mqttx和mqttfx-CSDN博客 在输入password和username后还是提示错误&#xff0c;是因为在使用token的时候&#xff0c;key填写错误&#xff0c;将设备的密钥填入key中

webpack练习之手写loader

手写一个style-loader来把样式文件插入head里面&#xff0c;准备工作 vue webpack就自己弄了&#xff0c;webpack的一些配置也自己配置好 一、创建index.css文件 .box{width: 100px;height: 100px;background-color: red; }然后在vue的main.js文件中引入它 二、创建自定义l…

MyBatis-Plus分页接口实现教程:Spring Boot中如何编写分页查询

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

港大新工作 HiGPT:一个模型,任意关系类型 !

论文标题&#xff1a; HiGPT: Heterogeneous Graph Language Model 论文链接&#xff1a; https://arxiv.org/abs/2402.16024 代码链接&#xff1a; https://github.com/HKUDS/HiGPT 项目网站&#xff1a; https://higpt-hku.github.io/ 1. 导读 异质图在各种领域&#xf…

云原生靶场kebernetesGoat、Metarget

靶场 文章目录 靶场kebernetesGoat靶场安装Docker in DockerSSRF漏洞容器逃逸到主系统Docker CIS 基线分析Kubernetes CIS 安全基线分析分析被部署挖矿软件的容器镜像获取环境信息Hidden in layersRBAC最低权限配置错误使用 Sysdig Falco 进行运行时安全监控和检测 Metarget ke…

UE5、CesiumForUnreal实现海量POI撒点显示与聚合功能

1.实现目标 POI是UE+GIS三维场景中经常需要展示的要素,在UE中常用的表示POI方法有两种。一种是Mesh,即空间的方式;另一种是Widget,即屏幕上的方式,本文这里使用的是Widget屏幕展示的形式来表示POI。 本文这里使用的POI点位数量共3.3w+,采用直接网格聚合算法,并进行性能优…

ROS机器人入门第四课:话题通信

文章目录 ROS机器人入门第四课&#xff1a;话题通信一、话题通信概述&#xff08;一&#xff09;概念&#xff08;二&#xff09;作用 二、话题通信基本操作需求:分析:流程:&#xff08;一&#xff09;发布方解释一些关键的ROS函数和概念&#xff1a; &#xff08;二&#xff0…

2024年福建事业单位招聘详细流程

2024年福建事业单位招聘详细流程&#xff0c;速速查收&#xff01;

湖北汽车工业学院 实验一 关系数据库标准语言SQL

头歌 实验一 关系数据库标准语言SQL 制作不易&#xff01;点个关注呗&#xff01;为大家创造更多的价值&#xff01; 目录 头歌 实验一 关系数据库标准语言SQL**制作不易&#xff01;点个关注呗&#xff01;为大家创造更多的价值&#xff01;** 第一关&#xff1a;创建数据库第…

简单服务器通信、IO多路复用(select、poll、epoll)以及reactor模式。

网络编程学习 简单服务器通信TCP三次握手和四次挥手三次握手&#xff08;如下图&#xff09;常见问题&#xff1f; 四次挥手 client和server通信写法server端client端 通信双方建立连接到断开连接的状态转换怎么应对多用户连接&#xff1f;缺点 IO多路复用select优缺点 pollpol…