环境:IDEA2021.2.3+jdk11.0.1+GDAL(release-1928-x64-gdal-3-5-2-mapserver-8-0-0)+OpenCV-460.jar
一、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:存储的图片的地址
那么数据类型包括哪些呢?如图(图片来源于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列就是两个矩形框,每一列都包括B,G,R三个通道
我们之前所输出的信息为20行18列,18列总共有54个通道数,因为图片大小有限,仅展示行数
现在我们清楚了Mat类的存储格式,来看看伪彩色图像是怎么生成的。
二、实现过程
原理:将单波段的灰度值分级赋予不同的颜色,例如,将灰度值为0-85的赋予B蓝色通道,86-170的赋予G绿色通道,171-255的赋予R红色通道,(怎么分级可按具体情况自己决定),其余两个通道均赋予0值
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");
}
}
三、结果
输入的灰度图像为:
输出为伪彩色图像为: