2

I use JavaCV (not OpenCV). My goal is to obtain a Mat object from an image that is stored as a Resource. Then I'm going to pass this Mat into opencv_imgproc.matchTemplate method. I've managed to write this bad code:

    InputStream in = getClass().getResourceAsStream("Lenna32.png");
    BufferedImage image = ImageIO.read(in);
    Frame f = new Java2DFrameConverter().getFrame(image);
    Mat mat = new OpenCVFrameConverter.ToMat().convert(f);

This works in some cases. The problems are:

  1. For png images that has transparency channel (that is 32BPP), it shifts channels, so that R=00 G=33 B=66 A=FF turns to R=33 G=66 B=FF Lenna 32BPP color shift

  2. On my target environment, I can't use ImageIO

  3. There are too many object conversions InputStream -> BufferedImage -> Frame -> Mat. I feel like there should be a simple and effective way to do this.

What is the best way to create Mat from a Resource?

berak
  • 39,159
  • 9
  • 91
  • 89
al0
  • 374
  • 1
  • 7
  • 20

2 Answers2

5

I resolved this by reading bytes from InputStream and passing them into imdecode function:

InputStream is = context.getResourceAsStream("Lenna32.png");
int nRead;
byte[] data = new byte[16 * 1024];
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
while ((nRead = is.read(data, 0, data.length)) != -1) {
    buffer.write(data, 0, nRead);
}
byte[] bytes = buffer.toByteArray();
Mat mat = imdecode(new Mat(bytes), CV_LOAD_IMAGE_UNCHANGED);
al0
  • 374
  • 1
  • 7
  • 20
  • 1
    If you can use Apache Commons IO you can convert the input stream directly to a byte array with a one-liner with IOUtils.toByteArray(is); – Semaphor Dec 20 '18 at 14:40
  • ...or simply use built-in `inputStream.readAllBytes()` extension function in kotlin – ruX Feb 21 '21 at 18:07
1

Just for reference, in order to convert InputStream to Mat, @Kotlin:

val bytes = inputStream.readBytes()
val mat = Mat(1, bytes.size, CvType.CV_8UC1)
mat.put(0, 0, bytes)
return Imgcodecs.imdecode(mat, Imgcodecs.IMREAD_UNCHANGED)
Octav
  • 443
  • 3
  • 9