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);
}
}
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?