环境: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格式的相互转换
目录
一、认识OpenCV中的Mat类
1、定义及使用方法
Mat可以保存图片,根据所读入的图片为其分配相应大小的内存空间 ,也能利用构造方法自己定义大小,下面是两种创建方法:
Mat mat1 = new Mat(2,2, CvType.CV_8UC3);
Mat mat2 = Imgcodecs.imread("img\\5.png");
用println()试一试打印mat会出现什么
System.out.println(mat1);
System.out.println(mat2);
结果:
这些代表什么意思呢?
2*2*CV_8UC3:2像素×2像素×数据类型
isCont:是否联系存储
isSubmat:是否为子矩阵
nativeObj:本地对象地址
dataAddr:存储的图片的地址
2、OpenCV数据类型简介
如图(图片来源于CSDN@UU果)
解释2*2*CV_8UC3:下划线后的数字表示图片的位数、数字后的第一个字母表示用于储存像素的类型、后面的符号表示通道数
U:unsigned int ,无符号整型
S:signed int ,有符号整型
F:float,单精度浮点型,float类型本身即有符号
Cx:图像的通道数
Mat如何存储像素?
System.out.println(mat1.dump());
System.out.println(mat2.dump());
我们所定义的大小是 2行2列,2行即两行,2列就是两个红色矩形框的内容,每一列都包括 【B,G,R 】三个通道(3个数据)
我们之前所输出的信息为20行18列,18列总共有54个通道数,因为图片大小有限,仅展示行数。
二、密度分割简介
单波段图像的伪彩色合成中的密度分割是一种图像处理技术,它通过将单波段图像的不同灰度级别映射到不同的颜色上,来增强图像的视觉效果和信息表达能力。
在单波段图像中,所有像素值通常都是灰度级的,这意味着每个像素只有一个亮度值,没有色彩信息。为了提高这些图像的可读性和解释性,可以采用伪彩色合成的方法,其中密度分割是常用的一种技术。
具体来说,密度分割的过程包括以下几个步骤:
1、确定分割级别:根据图像的灰度直方图或其他方法确定分割的级别,即将整个灰度范围分成若干个区间。
2、分配颜色:为每个灰度区间分配一种颜色,这样不同的灰度级别就会对应不同的颜色。
3、应用颜色映射:使用图像处理软件或编程库(如OpenCV)将颜色映射应用到图像上,使得每个像素根据其灰度值显示相应的颜色。
通过这种方式,原本单调的灰度图像就被转换成了色彩丰富的图像,有助于观察者区分不同的特征和细节。这在遥感图像处理、医学影像分析等领域尤为重要,因为人眼对灰度的辨别能力有限,密度分割技术能够利用影像灰度的细微差别来提取特征信息。
三、实现过程
1、简述原理
将单波段的灰度值分级赋予不同的颜色,例如,将灰度值为0-85的赋予B蓝色通道,86-170的赋予G绿色通道,171-255的赋予R红色通道,(怎么分级可按具体情况自己决定),其余两个通道均赋予0值。
2、代码实现
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;
/**
* @Author: HNUST_jue_chen
* @Date: 2022/10/22/ 9:44
* @Attention: 转载, 引用请注明出处
*/
//伪彩色合成
public class CalPseudoColor {
//加载本地动态链接库
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
public void graySplit(String path) {
try {
gdal.AllRegister();//支持所有驱动
//以只读方式读取数据存入Dataset类型里
Dataset dataset = gdal.Open(path, gdalconstConstants.GA_ReadOnly);
//图像的大小
int iYSize = dataset.getRasterYSize();
int iXSize = dataset.getRasterXSize();
//获取图像的灰度波段
Band band = dataset.GetRasterBand(1);
//定义灰度值数组
int[][] bandArr = new int[iYSize][iXSize];
//将图像灰度值存入灰度值数组
for (int i = 0; i < bandArr.length; i++) {
band.ReadRaster(0, i, iXSize, 1, bandArr[i]); //一次读取一行灰度值数据
}
//灰度图的伪彩色合成(密度分割)
//OpenCV三通道存储图像的像素是按照B,G,R顺序存储的
//单通道转多通道算法:
//原图像灰度值为0-85的赋予B蓝色通道,86-170的赋予G绿色通道,171-255的赋予R红色通道,其余两个通道均赋予0
//定义二维数组存储三通道的像素值
int[][] bandArrThreeChannel = new int[iYSize][iXSize * 3];
for (int i = 0; i < iYSize; i++) {
for (int j = 0; j < iXSize; j++) {
if (bandArr[i][j] >= 170) {
//灰度值为171-255的赋予红色通道,其余两个通道赋予0
bandArrThreeChannel[i][3 * j + 2] = bandArr[i][j];
bandArrThreeChannel[i][3 * j] = 0;
bandArrThreeChannel[i][3 * j + 1] = 0;
} else if (bandArr[i][j] >= 85) {
//灰度值为86-170的赋予绿色通道,其余两个通道赋予0
bandArrThreeChannel[i][3 * j + 1] = bandArr[i][j];
bandArrThreeChannel[i][3 * j] = 0;
bandArrThreeChannel[i][3 * j + 2] = 0;
} else if (bandArr[i][j] >= 0) {
//灰度值为0-85的赋予蓝色通道,其余两个通道赋予0
bandArrThreeChannel[i][3 * j] = bandArr[i][j];
bandArrThreeChannel[i][3 * j + 1] = 0;
bandArrThreeChannel[i][3 * j + 2] = 0;
}
}
}
//定义伪彩色图像的大小及数据类型
//CV_32SC3:32表示32位,S表示有符号整型,C3表示3个通道
Mat img_cpc = new Mat(bandArr.length, bandArr[0].length, CvType.CV_32SC3);
for (int i = 0; i < bandArrThreeChannel.length; i++) {
img_cpc.put(i, 0, bandArrThreeChannel[i]); //一次放入一行三通道像素值数据
}
//存储伪彩色图像
Imgcodecs.imwrite("D:\\Project\\IDEA_Project\\RS01\\src\\rs01\\img\\2_cpc.png", img_cpc);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
CalPseudoColor img_gray = new CalPseudoColor();
img_gray.graySplit("D:\\Project\\IDEA_Project\\RS01\\src\\rs01\\img\\2_gray.png");
}
}