Background:
I'm working on creating an OpenCV Java command line app to tease out some information from some particle streak images. In particular, I would like to know the dimensions of the smallest possible bounding box which will fit over each particle streak. First I have to find the particles, so I use Simple Blob feature detection.
Code:
package com.bostonwalker;
import org.opencv.core.Mat;
import org.opencv.core.MatOfKeyPoint;
import org.opencv.features2d.FeatureDetector;
import org.opencv.features2d.KeyPoint;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;
import java.util.List;
public class Main {
public static void main(String[] args)
{
System.loadLibrary("opencv_java247");
String sourcePath = "C:\\path_to_image\\05.png";
Mat srcImgMat = Highgui.imread(sourcePath);
if (srcImgMat == null)
{
System.out.println("Failed to load image at " + sourcePath);
return;
}
System.out.println("Loaded image at " + sourcePath);
MatOfKeyPoint matOfKeyPoints = new MatOfKeyPoint();
FeatureDetector blobDetector = FeatureDetector.create(FeatureDetector.SIMPLEBLOB);
blobDetector.detect(srcImgMat, matOfKeyPoints);
System.out.println("Detected " + matOfKeyPoints.size()+ " blobs in the image");
List<KeyPoint> keyPoints = matOfKeyPoints.toList();
}
}
Error:
Unfortunately, the returned matOfKeyPoints is always empty (size always equals 1x0). I have scoured the web, but opencv for desktop Java is not an extremely popular library, and my problem doesn't seem to be that common. I have tried using other feature detector algorithms just to see if I can return any key points whatsoever (the answer is no).
My gut instinct tells me that the color channel scheme of the image is not supported by the Simple Blob algorithm. I have exported the .png files from Photoshop as 8 bits/channel Grayscale and 8 bits/channel RGB Color. It's hard to know what's actually going on in the Highgui.imread() call, and what the Mat data actually looks like.
Questions:
What is causing the call to detect to return an empty matOfKeyPoints?
Is there an easier way to do the image processing I want done?
More information:
OpenCV version 2.4.7
Image included below
RESOLVED:
Found the problem. Namely, a small typo in the source path. It looks like Highgui.imread() returns an empty Mat when an incorrect source path is used, instead of returning null like I assumed it would.
Related
I'm having some problems with transparency.
I'm using the snippet provided in https://stackoverflow.com/a/27453793, but while on Windows it works, on Mac it does not.
On further investigation the different appears to be the value returned from getPixel.
Take the below example, using a 1x1 pixel transparent image I created.
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
public class ImageTest {
public static void main(final String[] args) throws MalformedURLException, IOException {
try (InputStream stream = new URL("https://i.imgur.com/BFlkniE.png").openStream()) {
final Path path = Files.createTempFile(null, ".png");
Files.copy(stream, path, StandardCopyOption.REPLACE_EXISTING);
final ImageDescriptor element = ImageDescriptor.createFromFile(null, path.toString());
final Image image = element.createImage();
final ImageData imageData = image.getImageData();
System.out.println(imageData.getPixel(0, 0));
}
}
}
On Windows, the output is 0, on Mac it's 16711680. What's the reason for this?
The value returned by ImageData.getPixel is not necessarily a RGB value, it is just a value for the current colour table. You must use the PaletteData in the ImageData to get the RGB value:
RGB rgb = imageData.palette.getRGB(imageData.getPixel(0, 0));
This is happening because you open an InputStream and then you proceed to completely ignore it and create your ImageDescriptor from a temp file instead.
According to the documentation of Files.createTempFile(), this temp file is empty, so trying to create an image from it is guaranteed to fail, no matter what your operating system is.
Apparently the implementation of ImageDescriptor.createFromFile() behaves differently between the two operating systems in the erroneous situation of trying to read an image from an empty file.
I suppose what is happening is that in both cases they are trying to act in a supposedly error-tolerant way, failing silently instead of throwing an exception. However, the underlying operating systems apparently fail slightly differently, so the initialization of ImageDescriptor ends up being incomplete in different ways.
If it appears to you that it is working under Windows, then this is either due to pure coincidence, or, more likely, you are not determining correctly whether it fails or not. You appear to regard that the zero pixel value returned under windows indicates success; I would not be so sure about that.
I can't help it but think I've missed just the Thread to answer my question but I've been looking for a long time now and can't seem to find the help I need.
My problem is quite simple:
I've created a game (or rather I'm in the process of it) and I'm trying to add sprites (png files for the enemies and such) to it. Loading them in the IDE works just fine but when I create a jar file and try to open it, it simply says "A Java Exception has occurred". Further investigation revealed the problem is that it can't find the files I told it to load.
Through the threads I've read I gathered this much:
It's either that I'm not loading the images properly, meaning that I don't use the proper code for it, or
my MANIFEST.mf does not contain a "Class-Path" (meaning that the arguments are blank, which in fact they are)
Finding other code didn't work out for me. People suggested to use a ClassLoader which I could't manage to get working. Trying it out gave me nullpointer exceptions.
Trying to look into the latter didn't do much help, because I couldn't find any helping information, or I'm just not understanding anything.
package platformer.resources;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.imageio.*;
public class ImageLoader
{
static String spritePath = "src/platformer/resources/";
public static BufferedImage loadImage(String path)
{
BufferedImage img = null;
try{img= ImageIO.read(new File(spritePath+path));
}catch(IOException e){System.out.println("Couldn't load File: "+spritePath+path);}
return img;
}
public static BufferedImage flipImage(BufferedImage bufferedImage)
{
AffineTransform tx = AffineTransform.getScaleInstance(-1, 1);
tx.translate(-bufferedImage.getWidth(null), 0);
AffineTransformOp op = new AffineTransformOp(tx,
AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
bufferedImage = op.filter(bufferedImage, null);
return bufferedImage;
}
}
This is the code I used so far.
Other classes would use "loadImage" or "flipImage" and in the IDE it works fine but as a .jar it fails to find the .png.
For example the class "platformer/entities/walker.class" would try to open the "Idle.png". In order to do that it uses the "loadImage("/entities/enemy/walker/Idle.png")" method. Note that in the method the actual path would end up being "src/platformer/resources/entities/enemy/walker/Idle.png".
Again, I'm terribly sorry if this has already been answered but I appreciate your help nonetheless.
Michael
When your files are inside a jar they can only be taken out as a resource stream so you will want to use something like:
ImageLoader.class.getResourceAsStream("nameoffile").
This is because a jar is actually a zipped up directory structure and files are not really files they are hidden amongst a compressed zip formatting as binary.
I want put a barcode in my page and can preview it. The barcode generator is google.zxing and my reporting tool is iReport.
But i dont know, how to configure Image Expression and Expression Class of an image in iReport.
The two key ideas are first to write a bit of Java code to create the relevant image and then to design the report to reference this code appropriately. Perhaps the simplest way to generate the image is in a scriptlet like this:
package com.jaspersoft.alliances.mdahlman;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import net.sf.jasperreports.engine.JRDefaultScriptlet;
import net.sf.jasperreports.engine.JRScriptletException;
public class QRCodeScriptlet extends JRDefaultScriptlet {
public void afterDetailEval() throws JRScriptletException {
QRCodeWriter writer = new QRCodeWriter();
BitMatrix matrix = null;
try {
matrix = writer.encode(getFieldValue("barcode_text").toString(), BarcodeFormat.QR_CODE, 256, 256);
this.setVariableValue("BarCodeImage", MatrixToImageWriter.toBufferedImage(matrix) );
} catch (WriterException e) {
e.printStackTrace();
}
}
}
That's full of hard-coded ugliness, but the key ideas are all shown. Then you need to define the report like this:
Sample query: select 'some text' as barcode_text
I included this only to reinforce the point that my scriptlet hard-codes the field name barcode_text. (This is bad.)
Variable: BarCodeImage of type java.awt.image.BufferedImage with calculation System.
This name is hard-coded in the scriptlet too. (This is equally bad.)
Add to iReport's classpath:
The compiled scriptlet .jar file
core.jar (from ZXing)
javase.jar (from ZXing)
Add an Image element to the report with Expression $V{BarCodeImage}.
The result is a happy happy QR-code in your generated JasperReport:
I recall a sample that I have seen which does things much more cleanly. It actually included a nice plug-in so you could easily install this functionality into iReport with minimal effort. If I can track that down, then I'll update this post. But until then this at least covers all of the critical points.
The image expression should return any subclass of java.awt.Image. The easiest way to achieve this is to use your own helper class to generate the Image. You can create a static method that generates a barcode from a Stringand call that method from IReport.
In the case of ZXing I don't know the method to use, but I can tell what I use as ImageExpression using the Barbecue library.
net.sourceforge.barbecue.BarcodeImageHandler.getImage(
MyBarcodeGenerator.getFromString($F{field})
MyBarcodeGenerator class contains the method getFromString(...) that returns a net.sourceforge.barbecue.Barcode in my case a net.sourceforge.barbecue.linear.code39.Code39Barcode
The Expression Class is ignored.
--Edited:
To encode an Image in zxing you should use MatrixToImageWriter
The following code will encode a QRCode into a BufferedImage which you can use in the Image Expression field:
MatrixToImageWriter.toBufferedImage(new QRCodeWriter().encode("BARCODE CONTENT", BarcodeFormat.QR_CODE, 400 /*Width*/, 400/*Height*/));
I'm on OS X 10.7.1. I've downloaded the latest JavaCV binaries, and built OpenCV from a current subversion checkout. The cvLoadImage() function returns null, no matter what I pass it. I have verified that I am passing it a valid path to a valid jpg image. Other JavaCV functions seem to return reasonable values, but since I can't load images, I can't really check.
I think I may have an error somewhere, but I'm not familiar with how JavaCV reports errors, so I can't check.
EDIT: I can verify that the overall JavaCV installation is valid and functioning, in that if I use Java's ImageIO to load an image, it works and I can subsequently operate on the loaded image, and save an image out (again, through ImageIO). SSCE follows:
import static com.googlecode.javacv.cpp.opencv_core.*;
import static com.googlecode.javacv.cpp.opencv_imgproc.*;
import static com.googlecode.javacv.cpp.opencv_objdetect.*;
import static com.googlecode.javacv.cpp.opencv_highgui.*;
import java.io.IOException;
import javax.imageio.ImageIO;
import java.io.File;
import java.awt.image.BufferedImage;
import com.googlecode.javacv.cpp.*;
import com.googlecode.javacpp.Loader;
class ImgLoadTest {
public static void main(String[] args) {
//comment out EITHER the BufferedImage bit OR the cvLoadImage portion.
//works
BufferedImage img = ImageIO.read(new File(args[0]));
IplImage origImg = IplImage.createFrom(img);
//returns null
//IplImage origImg = cvLoadImage(args[0]);
System.out.println("origImg is" + origImg);
}
}
Since I can make it work via ImageIO, I'm not overly concerned about this bug anymore, but solving it may be of use to others working with JavaCV.
OpenCV only works well with ASCII filenames. If you have i18n characters in the path, it may very well choke. Also, at the moment, JavaCV maps all String objects to UTF-8, and it does not seem like Mac OS X uses UTF-8 by default.
So, if i18n is important to your application, keep on using ImageIO...
Has anyone successfully used the Transform SWF for Java library from [Flagstone Software][1]
[1]: http://www.flagstonesoftware.com/transform/index.html to edit an existing swf file. Mainly what I want to accomplish is load a swf file and replace images or texts dynamically. Thank you.
I know it is a little bit late, but google searchers will still land here :-) This code will color the first text span of all text elements to red.
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.zip.DataFormatException;
import com.flagstone.transform.Movie;
import com.flagstone.transform.MovieTag;
import com.flagstone.transform.datatype.Color;
import com.flagstone.transform.text.DefineText;
public class Flash {
public static void main(String args[]) throws MalformedURLException, DataFormatException, IOException {
Movie m = new Movie();
m.decodeFromFile(new File("C:\\tmp\\Movie.swf"));
for (MovieTag mt : m.getObjects()) {
System.out.println(mt.getClass() + " " + mt.toString());
if (mt instanceof DefineText) {
((DefineText) mt).getSpans().get(0).setColor(new Color(255, 0, 0));
}
}
m.encodeToFile(new File("C:\\tmp\\foo.swf"));
}
}
Yes, I am working on a desktop application that generates swf files. It is a little tricky but the samples in the Cookbook will help you a lot. Just go through the samples and you will find almost anything that you need.One thing is that, the developer stopped working on the framwork but it still works fine. Transform library only supports Flash 10 and Translate supports ActionScript 1.0. I had to change the ActionScript 2 and 3 code to AS1 for the framework to work which was for me to only replace the variable types when declaring variables.