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));
Related
I would like to save a file (avi) of some frames (in this case, 600) from my webcam using java opencv, but i have no idea how to do that, the code below gives me the avi file specified but with size 0, no frames inside whatsover, also in the directory i have those 600 frames in jpeg's.
It's important to use java for that, no python.
Mat frame = new Mat();
VideoWriter writer = new VideoWriter("c:/opencv/vid.avi", VideoWriter.fourcc('X','2','6','4'), 30 ,frame.size(), true);
videoCapture = new VideoCapture();
videoCapture.open(0);
videoCapture.set(Videoio.CAP_PROP_FRAME_WIDTH, 1280);
videoCapture.set(Videoio.CAP_PROP_FRAME_HEIGHT, 720);
while (true){
videoCapture.read(frame);
if (!frame.empty())
break;
}
int frameNo = 0;
while (frameNo < 600){
videoCapture.read(frame);
writer.write(frame);
Imgcodecs imageCodecs = new Imgcodecs();
String file = "c:/opencv/i" + frameNo + ".jpg";
Imgcodecs.imwrite(file,frame);
frameNo++;
}
videoCapture.release(); // release device
You didn't mention which openCV version are you using, I use OpenCV-3.4.2
AVI container use DIVX codec reference: https://wiki.videolan.org/DivX/
I modify a bit your code:
Mat frame = new Mat();
VideoWriter writer = new VideoWriter("c:/opencv/vid.avi", VideoWriter.fourcc('D', 'I', 'V', 'X'), 30, new Size(videoCapture.get(Videoio.CAP_PROP_FRAME_WIDTH), videoCapture.get(Videoio.CAP_PROP_FRAME_HEIGHT)));
while(runnable)
{
if(videoCapture.grab())
{
try
{
//Decodes and returns the grabbed video frame.
videoCapture.retrieve(frame);
//encode to .jpg the frame to a MatOfByte
Imgcodecs.imencode(".jpg", frame, mem);
//read into an Image
Image im = ImageIO.read(new ByteArrayInputStream(mem.toArray()));
//Draw image to a Jpanel
BufferedImage buff = (BufferedImage) im;
Graphics g = jPanel1.getGraphics();
g.drawImage(buff, 0, 0, getWidth(), getHeight(), 0, 0, buff.getWidth(), buff.getHeight(), null);
//record the frame
writer.write(frame);
}
catch(Exception ex)
{
System.out.println("Error");
ex.printStackTrace();
}
}
}
videoCapture.release(); // release device
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
How to blur a portion of an image, to hide some privates parts like credit card informations.
I try to use ConvolveOp.class like :
float[] matrix = new float[400];
for (int i = 0; i < 400; i++)
matrix[i] = 1.0f/500.0f;
BufferedImage sourceImage = (BufferedImage) image; ;
BufferedImage destImage = null ;
BufferedImageOp op = new ConvolveOp( new Kernel(20, 20, matrix), ConvolveOp.EDGE_NO_OP, null );
BufferedImage blurredImage = op.filter(sourceImage, destImage);
it seems to work, except that the image is completely blurred.
In the case you want to focus on the application and not on the specifics of image processing, you can use an image processing framework like Marvin. Thus, you can do more with less code.
Input image:
Output image:
Source code:
import static marvin.MarvinPluginCollection.*;
public class PortionBlur {
public PortionBlur(){
// 1. Load image
MarvinImage image = MarvinImageIO.loadImage("./res/credit_card.jpg");
// 2. Create masks for each blurred region
MarvinImageMask mask1 = new MarvinImageMask(image.getWidth(), image.getHeight(), 38,170,345,24);
MarvinImageMask mask2 = new MarvinImageMask(image.getWidth(), image.getHeight(), 52,212,65,24);
MarvinImageMask mask3 = new MarvinImageMask(image.getWidth(), image.getHeight(), 196,212,65,20);
MarvinImageMask mask4 = new MarvinImageMask(image.getWidth(), image.getHeight(), 38,240,200,20);
// 3. Process Image with each mask
GaussianBlur gaussianBlur = new GaussianBlur();
gaussianBlur.load();
gaussianBlur.attributes.set("radius",15);
gaussianBlur.process(image.clone(), image, mask1);
gaussianBlur.process(image.clone(), image, mask2);
gaussianBlur.process(image.clone(), image, mask3);
gaussianBlur.process(image.clone(), image, mask4);
// 4. Save the final image
MarvinImageIO.saveImage(image, "./res/credit_card_out.jpg");
}
public static void main(String[] args) {
new PortionBlur();
System.exit(0);
}
}
Gaussian blur algorithm source code:
https://github.com/gabrielarchanjo/marvinproject/blob/master/marvinproject/dev/MarvinPlugins/src/org/marvinproject/image/blur/gaussianBlur/GaussianBlur.java
I don't know whether this can be done by changing the matrix values, but this should definitely be possible by filtering a subimage, since, according to the BufferedImage.getSubimage() documentation:
The returned BufferedImage shares the same data array as the original image.
So the original BufferedImage should change with code like this:
BufferedImage image = /* ... */;
BufferedImage subImage = image.getSubimage(10, 20, 30, 40); // x, y, width, height
new ConvolveOp(new Kernel(20, 20, matrix), ConvolveOp.EDGE_NO_OP, null).filter(subImage, subImage);
I didn't test this though, and I can imagine that filter doesn't work as expected if source and destination are the same, in which case you could use a copy of the subimage, using the solution from this question:
BufferedImage image = /* ... */;
BufferedImage dest = image.getSubimage(10, 20, 30, 40); // x, y, width, height
ColorModel cm = dest.getColorModel();
BufferedImage src = new BufferedImage(cm, dest.copyData(dest.getRaster().createCompatibleWritableRaster()), cm.isAlphaPremultiplied(), null).getSubimage(0, 0, dest.getWidth(), dest.getHeight());
new ConvolveOp(new Kernel(20, 20, matrix), ConvolveOp.EDGE_NO_OP, null).filter(src, dest);
After that, continue working with image (not subImage, src or dest!)
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'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();
}
}