Javacv: Load image from jar.

Created on 24 Sep 2016  路  6Comments  路  Source: bytedeco/javacv

I found this code and made some updates to it.
It allows for easily loading an image from the package to a Mat.
I haven't tested the part where it reverts to use JavaIO to load the bytes.
The issue i think i was getting from loading images was a leading slash and this fixes that.

The constants for color v grey should probably be set with constants from JavaCv but i didn't want to dig thru source at that time. I'm not sure if you want to integrate this or if it's likely to break from updates, or if i may have missed this functionality somewhere else.
Thank you.

//http://answers.opencv.org/question/10236/opencv-java-api-highguiimread-and-paths-pointing-to-files-in-a-jar/
//credit to Lucky Luke 
//i made some updates but i'm not sure about the JavaIO part 
//  as nothing i've loaded used that code yet

import org.bytedeco.javacpp.opencv_core.Mat;
import org.bytedeco.javacpp.indexer.ByteIndexer;

import static org.bytedeco.javacpp.opencv_imgcodecs.*;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;

public final class OpenCVUtils {
    private OpenCVUtils() {}
     /**
    * 8bit, 3-channel image.
    * @see Highgui.CV_LOAD_IMAGE_COLOR
    */
    public static final int LOAD_COLOR = 3;

    /**
    * 8bit, 1-channel image.
    * @see Highgui.CV_LOAD_IMAGE_GRAYSCALE
    */
    public static final int LOAD_GRAYSCALE = 1;

    public static Mat readImage(String name, int flags) {
        URL url = ClassLoader.getSystemResource(name);

        // make sure the file exists
        if (url == null) {
            System.out.println("ResourceNotFound: " + name);
            return new Mat();
        }

        String path = url.getPath();

        // not sure why we (sometimes; while running unpacked from the IDE) end 
        // up with the authority-part of the path (a single slash) as prefix,
        // ...anyways: Highgui.imread can't handle it, so that's why.
        if (path.startsWith("/")) {
            path = path.substring(1);
        }

        Mat image = imread(path,flags);
        if (image.empty()) {
            System.out.println("normal loading failed WHYYY???");
            BufferedImage buf;

            try {
                buf = ImageIO.read(url);
            } catch (IOException e) {
                System.out.println("IOException: " + e.getMessage());
                return image;
            }

            int height = buf.getHeight();
            int width = buf.getWidth();
            int rgb, type, channels;

            switch (flags) {
                case LOAD_GRAYSCALE:
                    type = CV_LOAD_IMAGE_GRAYSCALE;
                    channels = 1;
                    break;
                case LOAD_COLOR:
                default:
                    type = CV_LOAD_IMAGE_COLOR;
                    channels = 3;
                    break;
            }

            byte[] px = new byte[channels];
            image = new Mat(height, width, type);
            ByteIndexer bi = image.createIndexer();


            for (int y=0; y<height; y++) {
                for (int x=0; x<width; x++) {
                    rgb = buf.getRGB(x, y);
                    px[0] = (byte)(rgb & 0xFF);
                    if (channels==3) {
                        px[1] = (byte)((rgb >> 8) & 0xFF);
                        px[2] = (byte)((rgb >> 16) & 0xFF);
                    }
                    bi.put(y, x, px);

                }
            }            
        }

        return image;

    }

    public static Mat readImage(String name) {
        return readImage(name, LOAD_COLOR);
    }

}
enhancement help wanted

All 6 comments

Using ImageIO isn't OpenCV, so I wouldn't call this class OpenCV anything. Also, FrameConverter already has more efficient methods to convert BufferedImage<->Mat.

In short, if you could refactor that to use FrameConverter, and then place these methods in say the JavaCV util class, I'll be happy to merge that! Thanks

Please send a pull request when you are ready to merge this! Thanks

Any updates on this?

very sorry about this. being more familiar with this now, let me try something over the weekend and if not able to get it done i'll close.

So it turns out i only used that method when i was running locally. if i built to jar and deployed web app it could not load the images from the class path with that method.
i ended up using this to get from file->Mat not sure if there is something that will already do file -> Frame i guess. :

public static Mat matFromJar(String path, int flags) {
        InputStream is = OpenCVUtils.class.getClassLoader().getResourceAsStream(path);
        if (is == null) {
                       System.out.println("ResourceNotFound: " + path);
                        return new Mat();
                }
        int nRead;
        byte[] data = new byte[16 * 1024];
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        try {
            while ((nRead = is.read(data, 0, data.length)) != -1) {
                buffer.write(data, 0, nRead);
            }
        } catch (IOException e) {
            log.error("something happened",e);
        }
        byte[] bytes = buffer.toByteArray();
        Mat mat = imdecode(new Mat(bytes), flags);
        return mat;
    }

i also have some convenience methods

 public static Mat getROICopy(Mat m,Rect r){        
        Mat roi = new Mat(r.size(),m.type());
        m.rowRange(r.y(),r.y()+r.height()).colRange(r.x(), r.x()+r.width()).copyTo(roi);
        return roi;

    }

    public static Mat getROI(Mat m,Rect r){
              // Changes to the returned mat show on the original image     
        return m.rowRange(r.y(),r.y()+r.height()).colRange(r.x(), r.x()+r.width());

    }
        // m: the matching strength output from template matching
        // t: threshold value to count as a match
    public static List<Point> getPointsFromMatAboveThreshold(Mat m, float t){
        List<Point> matches = new ArrayList<Point>();
        FloatIndexer indexer = m.createIndexer();
        for (int y = 0; y < m.rows(); y++) {
            for (int x = 0; x < m.cols(); x++) {
                if (indexer.get(y,x)>t) {
                    System.out.println("(" + x + "," + y +") = "+ indexer.get(y,x));
                    matches.add(new Point(x, y));                   
                }
            }           
        }       
        return matches;
    }   
    // Given source image and template to match return max score
    public static float matchScore(Mat src,Mat tmp){

        Size size = new Size(src.cols()-tmp.cols()+1, src.rows()-tmp.rows()+1);
        Mat result = new Mat(size, CV_32FC1);
        matchTemplate(src, tmp, result, TM_CCORR_NORMED);
        DoublePointer minVal= new DoublePointer();
        DoublePointer maxVal= new DoublePointer();
        Point min = new Point();
        Point max = new Point();
        FloatIndexer fi = result.createIndexer();
        minMaxLoc(result, minVal, maxVal, min, max, null);      
        return fi.get(max.y(),max.x());
    } 

Looks useful! Could you put all that together and send a pull request to get this merged?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

The-Crocop picture The-Crocop  路  5Comments

Bahramudin picture Bahramudin  路  3Comments

newstarbka picture newstarbka  路  5Comments

kongqw picture kongqw  路  4Comments

fif10 picture fif10  路  3Comments