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

环境: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中合成的假彩色图像非常接近

  • 15
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

juechen333

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

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

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

打赏作者

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

抵扣说明:

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

余额充值