I'm developing an application using Java Opencv-2.4.4 and swing GUI. Problem is that I'm unable to find any solution, that shows efficient way how to print processed image (saved in Mat object) to java swing GUI. For this moment I'm using this clumsy solution:
javax.swing.JLabel outputImage;
outputImage.setIcon(new javax.swing.ImageIcon("/home/username/Output.png"));
private void sliderStateChanged(javax.swing.event.ChangeEvent evt) {
.
.
Mat canny; // Here is saved what I want to plot
String filename = "/home/username/Output.png";
Highgui.imwrite(filename, canny); // write to disk
outputImage.setIcon(new ImageIcon(ImageIO.read(new File(filename)))); //update Icon
.
.
}
When user changes some values, inputs etc ., in GUI I have to overwrite Output.png on disk and update jLabel with new image from disk.
Is there any more elegant / efficient solution to this ? Is it posible to plot or convert Mat object directly to Canvas or Image or anything that is printable as image in swing ?
Yes there is more elegant way to do it. You can concert Mat to BufferedImage type and then just Load it with swing. The code to convert it to Buffered image is:
Mat image_tmp = your image
MatOfByte matOfByte = new MatOfByte();
Highgui.imencode(".jpg", image_tmp, matOfByte);
byte[] byteArray = matOfByte.toArray();
BufferedImage bufImage = null;
try {
InputStream in = new ByteArrayInputStream(byteArray);
bufImage = ImageIO.read(in);
} catch (Exception e) {
e.printStackTrace();
}
And then you just can paint it in your GUI object:
g.drawImage(bufImage , 0, 0, null);
where g is of type Graphics
Hope this helps.
jpeg encoding is interesting, but there are a couple problems:
it is not a lossless format, you will lose image data when compressing
it takes quite a while (around 6 to 10 times longer than the suggested one below)
public Image toBufferedImage(Mat m){
int type = BufferedImage.TYPE_BYTE_GRAY;
if ( m.channels() > 1 ) {
type = BufferedImage.TYPE_3BYTE_BGR;
}
int bufferSize = m.channels()*m.cols()*m.rows();
byte [] b = new byte[bufferSize];
m.get(0,0,b); // get all the pixels
BufferedImage image = new BufferedImage(m.cols(),m.rows(), type);
final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
System.arraycopy(b, 0, targetPixels, 0, b.length);
return image;
}
This is a readymade solution for Imshow() equivalent in Java OpenCV Its simple to use. API will look like:
Imshow im = new Imshow("Title");
im.showImage(matimage);
Visit here https://github.com/master-atul/ImShow-Java-OpenCV
This is a better solution as you don't store the image into disk and read again. Hence it reduces the overhead of reading from a disk and thus is faster.
Using #andriy's anwser. I came up with this solution. I used JFrame instead of Graphics. Hope this helps.
public void imshow(Mat src){
BufferedImage bufImage = null;
try {
MatOfByte matOfByte = new MatOfByte();
Highgui.imencode(".jpg", src, matOfByte);
byte[] byteArray = matOfByte.toArray();
InputStream in = new ByteArrayInputStream(byteArray);
bufImage = ImageIO.read(in);
JFrame frame = new JFrame("Image");
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(new JLabel(new ImageIcon(bufImage)));
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
} catch (Exception e) {
e.printStackTrace();
}
}
Related
I'm trying to store an imageIcon bas a Base64 String.
This is what I have so far:
public ImageIcon getImageIcon() {
if(imageIcon == null || imageIcon.isEmpty()){
return null;
} else {
try {
byte[] btDataFile = Base64.decodeBase64(imageIcon);
BufferedImage image = ImageIO.read(new ByteArrayInputStream(btDataFile));
return new ImageIcon(image);
} catch (IOException ex) {
System.out.println(ex.getLocalizedMessage());
return null;
}
}
}
public void setImageIcon(ImageIcon imageIconIn) {
imageIcon = Base64.encodeBase64String(imageToByteArray(imageIconIn));
}
public static byte[] imageToByteArray(ImageIcon imageIn) {
try {
BufferedImage image = new BufferedImage(imageIn.getIconWidth(), imageIn.getIconHeight(),BufferedImage.TYPE_INT_RGB);
ByteArrayOutputStream b = new ByteArrayOutputStream();
// FIX
Graphics g;
g = image.createGraphics();
imageIn.paintIcon(null, g, 0,0);
// END FIX
ImageIO.write(image, "jpg", b );
g.dispose();
return b.toByteArray();
} catch (IOException ex) {
System.out.println(ex.getLocalizedMessage());
return null;
}
}
I get a black rectangle instead of the image.
I'm using Java 1.8 on Ubuntu 16.04.
What am I doing wrong?
Thanks for your help.
******************************** . FIXED . ******************************
I found a working solution and updated the above code.
******************************** EDIT *********************************
Added g.dispose() after painting icon.
This code creates a brand new BufferedImage, with width & height same as the given image.
BufferedImage image = new BufferedImage(
imageIn.getIconWidth(),
imageIn.getIconHeight(),
BufferedImage.TYPE_INT_RGB);
Note that the image is empty. No content has been written to it. The bytes will all be zero, and RGB 0x000000 is black.
Then, you are writing the bytes of this black image to your ByteArrayOutputStream.
ByteArrayOutputStream b = new ByteArrayOutputStream();
ImageIO.write(image, "jpg", b );
return b.toByteArray();
Of course, when you convert that byte buffer back to an image, it will be black.
You will want to draw/copy imageIn into your new image before you write out the bytes.
But if you don't mind using whatever the current image's format is, you could just write out that image instead of converting it to TYPE_INT_RGB...
Image image = imageIn.getImage();
// write image to ByteArrayOutputStream
I have a jpeg2000 image, img.jp2 on a file, and on a DataInputStream object imgobj in my project, and want to show that image on a JFrame.
The old version jai_imageio-1.1.jar recommended here and the jj2000 library are both included.
I have tried:
j2kImageReader.setInput(new FileImageInputStream(new File(fileName)));
ImageReadParam imageReadParam =
j2kImageReader.getDefaultReadParam();
imageReadParam.setSourceRegion(new Rectangle(0, 0, 300, 300));
IIOImage image = j2kImageReader.readAll(0, imageReadParam);
// This type of images is difficult to handle,
// I just don't know what to do with IIOImage,
// ImageIcon doesn't accept that type in its constructor.
And this:
Image img = ImageIO.read(new File(fileName));
ImageIcon imgIcon = new ImageIcon(img);
JLabel label = new JLabel(imgIcon);
panel1.add(label);
panel1.repaint();
//Error: Can't read input file!. The panel is still empty
The option included in JMRTD is using two decoders, and no one of them accepts .jp2:
NistDecoder dec=new NistDecoder();
WsqDecoder wdec=new WsqDecoder();
//using the last one, I tried: bitmp= wdec.decode(myDataInputStream);
//but with Error, Invalid pointer : 0!.
So the question is: what is the proper use of jj2000 or jai_imageio to read a jpeg2000 image from a file or a DataInputStream, and if it is possible, to show it on a simple panel on a JFrame?
Thank you for help.
EDIT
AS requested in comments, this is what I did:
//1
FaceImageInfo imgfn = fsinf.getFaceImageInfos().get(0);
BufferedImage bf=ImageIO.read(imgfn.getImageInputStream());
ImageIcon iconImg = new ImageIcon();
iconImg= new ImageIcon(bf);// if this fails try write it to a stream and read it back see //2
JLabel(iconImg, JLabel.CENTER);
//2
ByteArrayOutputStream baos=null;
try{
baos=new ByteArrayOutputStream();
ImageIO.write(bf, "jpg", baos);
}
finally{
try{
baos.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
try {
ByteArrayInputStream bais=new ByteArrayInputStream(baos.toByteArray());
bf2=ImageIO.read(bais) ;
iconImg= new ImageIcon(bf2);
JLabel(iconImg, JLabel.CENTER);
} catch (Exception e) {
e.printStackTrace();
}
Assuming the code otherwise reads the image like you want it, you can easily get a BufferedImage from the ImageReader like this:
try (ImageInputStream input = ImageIO.createImageInputStream(new File(fileName))) {
j2kImageReader.setInput(input));
// Not sure why/if you want to read only the upper left, but I'll leave it as is
ImageReadParam imageReadParam = j2kImageReader.getDefaultReadParam();
imageReadParam.setSourceRegion(new Rectangle(0, 0, 300, 300));
// Use read instead of readAll
BufferedImage image = j2kImageReader.read(0, imageReadParam);
// You can now create an icon and add to a component
Icon icon = new ImageIcon(image);
JLabel label = new JLabel(icon);
// Etc...
}
I am writing my first program in OpenCV in Java and I'd like to ask, is it possible to load and display image from file only using Mat?
I found solution on this website
http://answers.opencv.org/question/31505/how-load-and-display-images-with-java-using-opencv/
but it changes Mat to Image before.
I'll be grateful for any tips
This is an old question but for those who still face the same problem there is an implementation of "imshow" now in OpenCV for Java (I am using verion 4.1.1) under HighGui static object.
So you would first import it like:
import org.opencv.highgui.HighGui;
and then display the image like:
HighGui.imshow("Image", frame);
HighGui.waitKey();
Where 'frame' is your OpenCV mat object.
You can use the next code to transform a cvMat element into a java element: BufferedImage or Image:
public BufferedImage Mat2BufferedImage(Mat m) {
// Fastest code
// output can be assigned either to a BufferedImage or to an Image
int type = BufferedImage.TYPE_BYTE_GRAY;
if ( m.channels() > 1 ) {
type = BufferedImage.TYPE_3BYTE_BGR;
}
int bufferSize = m.channels()*m.cols()*m.rows();
byte [] b = new byte[bufferSize];
m.get(0,0,b); // get all the pixels
BufferedImage image = new BufferedImage(m.cols(),m.rows(), type);
final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
System.arraycopy(b, 0, targetPixels, 0, b.length);
return image;
}
And then display it with:
public void displayImage(Image img2) {
//BufferedImage img=ImageIO.read(new File("/HelloOpenCV/lena.png"));
ImageIcon icon=new ImageIcon(img2);
JFrame frame=new JFrame();
frame.setLayout(new FlowLayout());
frame.setSize(img2.getWidth(null)+50, img2.getHeight(null)+50);
JLabel lbl=new JLabel();
lbl.setIcon(icon);
frame.add(lbl);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
source: http://answers.opencv.org/question/10344/opencv-java-load-image-to-gui/
Nope, there is no imshow equivalent in java. Please refer this link.
I know we can output an Image using Jpanel using the following code:
JFrame frame = new JFrame("IMG");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(true);
frame.setLocationRelativeTo(null);
ImageIcon image = new ImageIcon(".../img.jpg");
frame.setSize(image.getIconWidth()+10,image.getIconHeight()+35);
JLabel label1 = new JLabel(" ", image, JLabel.CENTER);
frame.getContentPane().add(label1);
frame.validate();
frame.setVisible(true);
This code would assume that I have created or already have an image file in my directory. But what I want to do is output the image in the Jpanel directly without creating the image file. How do I do that using OpenCV Mat object in JAVA?
You can convert Mat object to BufferedImage object using following method:
public static BufferedImage createAwtImage(Mat mat) {
int type = 0;
if (mat.channels() == 1) {
type = BufferedImage.TYPE_BYTE_GRAY;
} else if (mat.channels() == 3) {
type = BufferedImage.TYPE_3BYTE_BGR;
} else {
return null;
}
BufferedImage image = new BufferedImage(mat.width(), mat.height(), type);
WritableRaster raster = image.getRaster();
DataBufferByte dataBuffer = (DataBufferByte) raster.getDataBuffer();
byte[] data = dataBuffer.getData();
mat.get(0, 0, data);
return image;
}
Then you can simply display image using ImageIcon:
// Load image using Highgui or create Mat object other way you want
Mat mat = Highgui.imread(".../img.jpg");
ImageIcon image = new ImageIcon(createAwtImage(mat));
I'm having problems converting a simple PNG into a JPEG format.
I'm using the following code:
...
File png = new File(filePath);
try {
SeekableStream s = new FileSeekableStream(png);
PNGDecodeParam pngParams = new PNGDecodeParam();
ImageDecoder dec = ImageCodec.createImageDecoder("png", s, pngParams);
RenderedImage pngImage = dec.decodeAsRenderedImage();
JPEGEncodeParam jparam = new JPEGEncodeParam();
jparam.setQuality(0.50f); // e.g. 0.25f
File jpeg = new File("jpeg.jpeg");
FileOutputStream out = new FileOutputStream(jpeg);
ImageEncoder encoder = ImageCodec.createImageEncoder("JPEG", out, jparam);
encoder.encode(pngImage);
s.close();
} catch (IOException e) {
ok = false;
e.printStackTrace();
}
return ok;
}
...
I end up with an JAI exception ->
java.lang.RuntimeException: Only 1, or 3-band byte data may be written.
at com.sun.media.jai.codecimpl.JPEGImageEncoder.encode(JPEGImageEncoder.java:148) ...
Ran out of options. Any suggestion?
It might be easier to use ImageIO to read the PNG into a BufferedImage and write the image out in JPEG format.
Addendum: In this approach, the conversion is handled transparently by the writer's ImageTranscoder.
BufferedImage img = ImageIO.read(new File("image.png"));
ImageIO.write(img, "jpg", new File("image.jpg"));
you probably have alpha channel in the png that you need to get rid of before trying to write the jpg.
Create a new BufferedImage with type TYPE_INT_RGB (not TYPE_INT_ARGB), and then write your source image (pngImage) onto the new blank image.
Something like this (warning, not tested code):
BufferedImage newImage = new BufferedImage( pngImage.getWidth(), pngImage.getHeight(), BufferedImage.TYPE_INT_RGB);
newImage.createGraphics().drawImage( pngImage, 0, 0, Color.BLACK, null);
I also found that reading a PNG image into a BufferedImage with ImageIO (Java 6) and writing it out to a JPG "format name" corrupted the image. The image was there, but the colors looked "solarized" and almost inverted. The JPG file was much smaller than the PNG file for sure, so a lot of compression was done. I don't see how you might control the compression or color depth.
I had corrupted file after conversion with other solutions but this method worked for me:
public static void formatConverter(String pngFile, String jpgFile) {
try {
File input = new File(pngFile);
File output = new File(jpgFile);
BufferedImage image = ImageIO.read(input);
BufferedImage result = new BufferedImage(
image.getWidth(),
image.getHeight(),
BufferedImage.TYPE_INT_RGB);
result.createGraphics().drawImage(image, 0, 0, Color.WHITE, null);
ImageIO.write(result, "jpg", output);
} catch (IOException e) {
e.printStackTrace();
}
}
I suppse that JAI reads the PNG image with an indexed colour model and is only able to write 8-bit grayscale or 24-bit colour images as JPEG files.
If you are not required to use JAI for this task, you should be able to use ImageIO instead:
ImageIO.write(ImageIO.read(new File("in.png")), "JPEG", new File("out.jpg"));
I was getting the following message in a slightly different context. Getting rid of the alpha channel solved the problem
javax.imageio.IIOException: Sample size must be <= 8
at com.sun.imageio.plugins.jpeg.JPEGImageWriter.write(JPEGImageWriter.java:435)
at javax.imageio.ImageWriter.write(ImageWriter.java:580)
at com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageWriter.write(Unknown Source)
at net.sf.basedb.util.ImageTools.tiffToJpg(ImageTools.java:98)
at net.sf.basedb.util.ImageTools.main(ImageTools.java:118)
see Converting transparent gif / png to jpeg using java
Have a look at the solution that redraws with the graphics environment posted by harmanjd. The solution with the DirectColorModel doesn't compile and should be wiped away. I don't have enough rep points to comment directly there.