【问题标题】:OpenCV java implementaiton of Mat.dump() returns inaccurate dataMat.dump() 的 OpenCV java 实现返回不准确的数据
【发布时间】:2020-06-02 06:09:47
【问题描述】:

我正在寻找将图像像素数据提取到整数列表(或任何数字表示)中。例如,具有 2 x 2 白色图像,结果将是 [255,255,255,255]。如果图像是代码生成而不是从磁盘读取,则 Mat.dump() 方法会准确打印图像像素值:

    Mat m = new Mat(5, 10, CvType.CV_8UC1, new Scalar(0));
    System.out.println("OpenCV Mat: " + m);
    Mat mr1 = m.row(1);
    mr1.setTo(new Scalar(1));
    Mat mc5 = m.col(5);
    mc5.setTo(new Scalar(5));
    System.out.println("OpenCV Mat data, "+m.total()+" elements:\n" + 
    m.dump());

打印准确=>

    OpenCV Mat: Mat [ 5*10*CV_8UC1, isCont=true, isSubmat=false, 
    nativeObj=0x1415d50, dataAddr=0x13a6880 ]
    OpenCV Mat data, 50 elements:
    [  0,   0,   0,   0,   0,   5,   0,   0,   0,   0;
       1,   1,   1,   1,   1,   5,   1,   1,   1,   1;
       0,   0,   0,   0,   0,   5,   0,   0,   0,   0;
       0,   0,   0,   0,   0,   5,   0,   0,   0,   0;
       0,   0,   0,   0,   0,   5,   0,   0,   0,   0]

但如果我在磁盘上写入 Mat "m" 内容,然后我再次读取它,dump() 方法会吐出奇怪的输出:

    Imgcodecs.imwrite(TRAIN_PATH_PROC+"m.jpg",m);

    m = null;
    m = Imgcodecs.imread(TRAIN_PATH_PROC+"m.jpg");
    System.out.println("Fresly read m, "+m.total()+" elements:\n"+m.dump());

打印

Fresly read m, 50 elements:
[  0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   1,   1,   0,   0,   0,   
5,   5,   5,   1,   1,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0;
1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   
5,   5,   5,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1;
0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   1,   1,   0,   0,   0,   5,   
5,   5,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0;
0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   4,   
4,   4,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0;
0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   1,   1,   0,   0,   0,   
5,   5,   5,   1,   1,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0]

由于我需要从读取的图像中提取 int 值,并依赖 dump() 来表示字符串,这给我带来了麻烦。

编辑:

我已经设法简单地使用来提取数据

    List<Integer> values = new ArrayList<>();

    for (int i = 0; i < m.rows(); i++) {
        for (int j = 0; j < m.cols(); j++) {
            values.add((int)m.get(i,j)[0]);
        }
    }

【问题讨论】:

  • 另外,我忘了说,dump() 方法会扭曲任何磁盘读取的图像数据,而不仅仅是通过 Imgcodecs.imwrite() 编写代码的图像
  • JPEG 是一种有损文件格式。您不一定会取回您编写的相同数据。
  • @AndyTurner 可能是这样,但为什么 .total() 只返回 50 个元素?另外,重读前后图片的字节大小是一样的

标签: java opencv


【解决方案1】:

Mat.dump() 是我们的朋友,打印垫子名称以显示其属性。 (问题标题应更改为不贬低 dump()。) imread 自动假定转换为 BGR,因此 3 个数据通道而不是预期的 1 个通道。 imwrite JPEG 会自动压缩一些。您可以控制 imread 转换并减少压缩,但它仍然有点有损。

MatOfInt imwrite_flags = new MatOfInt();
imwrite_flags.fromArray(Imgcodecs.IMWRITE_JPEG_QUALITY , 100);
Imgcodecs.imwrite(TRAIN_PATH_PROC+"m.jpg",m, imwrite_flags);

m = Imgcodecs.imread(TRAIN_PATH_PROC+"m.jpg", Imgcodecs.IMREAD_UNCHANGED);

您需要的是无压缩或无损压缩,因此请使用 TIFF 格式 - 以下示例均使用 TIFF。 (见Is there a way to set specific compression scheme when saving tiff file in opencv?

String TRAIN_PATH_PROC = "";

Mat m = new Mat(5, 10, CvType.CV_8UC1, new Scalar(0));
System.out.println("OpenCV Mat: " + m);
Mat mr1 = m.row(1);
mr1.setTo(new Scalar(1));
Mat mc5 = m.col(5);
mc5.setTo(new Scalar(5));
System.out.println("OpenCV Mat data, "+m.total()+" elements:\n" + 
m.dump());

MatOfInt imwrite_flags = new MatOfInt();
imwrite_flags.fromArray(Imgcodecs.IMWRITE_TIFF_COMPRESSION , 1); // no compression
Imgcodecs.imwrite(TRAIN_PATH_PROC+"m2.tif",m, imwrite_flags);// note name change so both examples can run
// OR
Imgcodecs.imwrite(TRAIN_PATH_PROC+"m.tif",m); // default compression LZW grayscale but lossless, I think

m = null;
m = Imgcodecs.imread(TRAIN_PATH_PROC+"m.tif", Imgcodecs.IMREAD_UNCHANGED);
System.out.println("OpenCV Mat: " + m);
System.out.println("Fresly read m, "+m.total()+" elements:\n"+m.dump());

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-19
    • 1970-01-01
    • 1970-01-01
    • 2011-12-13
    • 2020-09-08
    • 1970-01-01
    相关资源
    最近更新 更多