0
点赞
收藏
分享

微信扫一扫

OpenCV4.3 Java 编程入门:图片中像素的遍历与映射

楠蛮鬼影 2022-04-19 阅读 74

文章目录

1 像素与颜色空间

存储像素值需要指定颜色空间和数据类型,其中颜色空间是指一个给定的颜色,如何组合颜色元素,及各元素如何编码。最简单的颜色空间时灰度空间,只处理黑色和白色,对它们进行编码组合,便可以产生不同程度的灰色。
在这里插入图片描述
对于彩色,则有多种不同类型的颜色空间,但不论哪种类型都是把颜色分成三个或四个基本元素,通过组合基本元素来表示和构成颜色空间。

例如 RGB 颜色空间就是最常用的一种颜色空间,它的基本元素是——红色,绿色,蓝色,alpha。

HSV 和 HLS 把颜色分解成色调、饱和度和亮度/明度。这种方式,更符合人类的视觉认知,比如调整图片的亮度,只需要操作 ‘亮度’ 元素的值就可以了,但是 RGB 方式,就需要三个元素一起调整。

CIE Lab 是一种在感知上均匀的颜色空间,它适合用来度量两个颜色之间的距离。

每个组成元素都有其自己的定义域,在定义域取决于其数据类型,如何存储一个元素决定了我们在其定义域上能够控制的精度。最小的数据类型是 char,占一个字节或者 8 位,可以是有符号或无符号,共 256 个值。使用 float 或 double 则能给出更加精细的颜色分辨能力。但是,增加像素元素的尺寸也会增加图像所占的内存空间。

在这里插入图片描述

2 图像在内存之中的存储方式

图像数据在内存中是以矩阵的形式存在,而矩阵的大小取决于所用的颜色空间模型和通道数。

对于多通道图像来说,矩阵中的列会包含多个子列,其子列个数与通道数相等。

单通道:

Mat mat = Mat.eye(new Size(3,4), CV_8UC1);
System.out.println(mat.dump());

在这里插入图片描述
双通道:

Mat mat = Mat.eye(new Size(3,4), CV_8UC2);
System.out.println(mat.dump());

在这里插入图片描述
三通道

Mat mat = Mat.eye(new Size(3,4), CV_8UC2);
System.out.println(mat.dump());

在这里插入图片描述

3 通过 Mat.ptr() 方法遍历像素

org.bytedeco.opencv.opencv_core.Mat

@Test
    public void test() {
        Mat mat = new Mat(new Size(3,3), CV_8UC3, new Scalar(5,4,3,0));

        System.out.println("rows = " + mat.rows());
        System.out.println("cols = " + mat.cols());
        System.out.println("channels = " + mat.channels());
        System.out.println("total = " + mat.total());
        for (int i = 0; i < mat.rows(); i++) {
            for (int j = 0; j < mat.cols(); j++) {
                byte[] values = new byte[mat.channels()];
                mat.ptr(i,j).get(values);
                System.out.println(Arrays.toString(values));
            }
            System.out.println();
        }
    }

输出:
在这里插入图片描述

org.opencv.core.Mat

    @Test
    public void test() {
        Mat mat = new Mat(new Size(3,3), CV_8UC3, new Scalar(5,4,3,0));

        System.out.println("rows = " + mat.rows());
        System.out.println("cols = " + mat.cols());
        System.out.println("channels = " + mat.channels());
        System.out.println("total = " + mat.total());
        for (int i = 0; i < mat.rows(); i++) {
            for (int j = 0; j < mat.cols(); j++) {
                double[] values = mat.get(i,j);
                System.out.print(Arrays.toString(values) + " ");
            }
            System.out.println();
        }
    }

输出:
在这里插入图片描述

4 LUT : 查找表映射

LUT 即 look up table 操作,OpenCV 官方文档推荐使用该方法进行像素操作,它用于批量进行图像元素查找、扫描、和操作。

函数原型:

/** 执行数组的查找表转换

@param src 包含 8 位元素的输入数组。
@param lut 256个元素的查找表;如果是多通道输入阵列,该表要么只有一个通道(在这种情况下,所有通道使用相同的映射),要么具有与输入数组相同的通道数。 
@param dst 输出阵列,大小和通道数与 src 相同,深度与 lut 相同。
*/
@Namespace("cv") public static native void LUT(@ByVal Mat src, @ByVal Mat lut, @ByVal Mat dst);

函数 LUT 用查找表中的值对输入元素值映射,并填充输出数组。条目的索引取自输入数组。也就是说,该函数按如下方式处理src的每个元素:
在这里插入图片描述
其中:

  1. 当 src 元素类型为 CV_8U 时,d = 0;
  2. 当 src 元素类型为 CV_8S 时,d = 128;

下面通过示例来说明 LUT 的映射过程:
在这里插入图片描述
代码:

    public void lutTest() {
    	// 1. 构建 5x5 单通道矩阵,元素初始值为 8
        Mat mat = new Mat(new Size(5,5), CV_8U, new Scalar(8));
        mat.row(3).setTo(new Mat(new Size(1, 1), CV_8U, new Scalar(9))); // 将第四行(索引为3)元素值,改为 9
        mat.col(3).setTo(new Mat(new Size(1, 1), CV_8U, new Scalar(7))); // 将第四列元素值,改为 7

		// 2. 构建 LUT 映射表: size = 256x1, 元素初始值为 1
        Mat lut = new Mat(new Size(256,1), CV_8U, new Scalar(1));
        lut.col(7).setTo(new Mat(new Size(1, 1), CV_8U, new Scalar(77))); // lut[7] == 77 
        lut.col(8).setTo(new Mat(new Size(1, 1), CV_8U, new Scalar(88))); // lut[8] == 88 
        lut.col(9).setTo(new Mat(new Size(1, 1), CV_8U, new Scalar(99))); // lut[9] == 99 

        Mat dst = new Mat();
		// 3. 调用 LUT 函数,执行映射
        opencv_core.LUT(mat, lut, dst);
        for (int i = 0; i < mat.rows(); i++) {
            for (int j = 0; j < mat.cols(); j++) {
                byte[] values = new byte[mat.channels()];
                dst.ptr(i,j).get(values);
                System.out.print(Arrays.toString(values) + " ");
            }

            System.out.println();
        }
    }

mat 矩阵的内容:
在这里插入图片描述

dst 矩阵的内容:
在这里插入图片描述

举报

相关推荐

0 条评论