Monday, June 24, 2013

Creating windows and capturing webcam with Java and OpenCV

As we saw here, we can load a picture and display it, all in java. Now we want to use OpenCV for some of this so that we can apply some signal processing to the image down the road... The trick is explained here... Basically how to "cast" the image from OpenCV (in Mat) in an Image object that works with drawImage.We found some answers in the topic but nothing was too clear:
  1. Android has a library that allows from Bitmap to Mat and viceversa: org.opencv.android.Utils. This probably would work for us as finally we want to run this on Android, but still, not for the time being (we are in PC...).
  2. http://stackoverflow.com/questions/14958643/converting-bufferedimage-to-mat-in-opencv
  3. http://stackoverflow.com/questions/15670933/opencv-java-load-image-to-gui
Did a further search for "java opencv convert mat into image -android -IplImage" and got this two that match:
  1. http://answers.opencv.org/question/10344/opencv-java-load-image-to-gui/
  2. http://enfanote.blogspot.com/2013/06/converting-java-bufferedimage-to-opencv.html
That solved! Geeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee!! Somehow, seems to be done by hand conversion, which is not very nice, but looks like there is not library call for this...

UPDATE: please see the code on the first comment below, that ngeen left. I have not tried it in here, but I used it in this other example and it works nicely!!
UPDATE2: triggered by another nice way to do this Mat to BufferedImage conversion, I decided to benchmark all these methods. See here this post for the results.

 // Import the basic graphics classes.  
 // The problem here is that we read the image with OpenCV into a Mat object.  
 // But OpenCV for java doesn't have the method "imshow", so, we got to use  
 // java for that (drawImage) that uses Image or BufferedImage (?)  
 // So, how to go from one the other...  
 import java.awt.*;  
 import java.awt.image.BufferedImage;  
 import javax.swing.*;  
 //import org.opencv.core.Core;  
 import org.opencv.core.Mat;  
 import org.opencv.highgui.Highgui;  
 public class Panel extends JPanel{  
   private static final long serialVersionUID = 1L;  
   String pic_name="resources/DSC01638.jpg";  
   Mat picture;  
   BufferedImage image;  
   /**  
    * Converts/writes a Mat into a BufferedImage.  
    *  
    * @param matrix Mat of type CV_8UC3 or CV_8UC1  
    * @return BufferedImage of type TYPE_3BYTE_BGR or TYPE_BYTE_GRAY  
    */  
   public static BufferedImage matToBufferedImage(Mat matrix) {  
     int cols = matrix.cols();  
     int rows = matrix.rows();  
     int elemSize = (int)matrix.elemSize();  
     byte[] data = new byte[cols * rows * elemSize];  
     int type;  
     matrix.get(0, 0, data);  
     switch (matrix.channels()) {  
       case 1:  
         type = BufferedImage.TYPE_BYTE_GRAY;  
         break;  
       case 3:  
         type = BufferedImage.TYPE_3BYTE_BGR;  
         // bgr to rgb  
         byte b;  
         for(int i=0; i<data.length; i=i+3) {  
           b = data[i];  
           data[i] = data[i+2];  
           data[i+2] = b;  
         }  
         break;  
       default:  
         return null;  
     }  
     BufferedImage image = new BufferedImage(cols, rows, type);  
     image.getRaster().setDataElements(0, 0, cols, rows, data);  
     return image;  
   }  
   // Create a constructor method  
   public Panel(){  
     super(); // Calls the parent constructor  
     picture = Highgui.imread(pic_name);  
     // Got to cast picture into Image  
     image=matToBufferedImage(picture);  
   }  
   public void paintComponent(Graphics g){  
      g.drawImage(image,50,10,400,400, this);  
   }  
   public static void main(String arg[]){  
    // Load the native library.  
    System.loadLibrary("opencv_java245");    
    JFrame frame = new JFrame("BasicPanel");  
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
    frame.setSize(400,400);  
    Panel panel = new Panel();  
    frame.setContentPane(panel);       
    frame.setVisible(true);           
  }  
 }  

Then, we want to display the webcam. So, not read from file...
 // Import the basic graphics classes.  
 // The problem here is that we read the image with OpenCV into a Mat object.  
 // But OpenCV for java doesn't have the method "imshow", so, we got to use  
 // java for that (drawImage) that uses Image or BufferedImage.  
 // So, how to go from one the other... Here is the way...  
 import java.awt.*;  
 import java.awt.image.BufferedImage;  
 import javax.swing.*;  
 import org.opencv.core.Mat;  
 import org.opencv.highgui.VideoCapture;  
 public class Panel extends JPanel{  
   private static final long serialVersionUID = 1L;  
   private BufferedImage image;  
   // Create a constructor method  
   public Panel(){  
     super();  
   }  
   private BufferedImage getimage(){  
     return image;  
   }  
   private void setimage(BufferedImage newimage){  
     image=newimage;  
     return;  
   }  
   /**  
    * Converts/writes a Mat into a BufferedImage.  
    *  
    * @param matrix Mat of type CV_8UC3 or CV_8UC1  
    * @return BufferedImage of type TYPE_3BYTE_BGR or TYPE_BYTE_GRAY  
    */  
   public static BufferedImage matToBufferedImage(Mat matrix) {  
     int cols = matrix.cols();  
     int rows = matrix.rows();  
     int elemSize = (int)matrix.elemSize();  
     byte[] data = new byte[cols * rows * elemSize];  
     int type;  
     matrix.get(0, 0, data);  
     switch (matrix.channels()) {  
       case 1:  
         type = BufferedImage.TYPE_BYTE_GRAY;  
         break;  
       case 3:  
         type = BufferedImage.TYPE_3BYTE_BGR;  
         // bgr to rgb  
         byte b;  
         for(int i=0; i<data.length; i=i+3) {  
           b = data[i];  
           data[i] = data[i+2];  
           data[i+2] = b;  
         }  
         break;  
       default:  
         return null;  
     }  
     BufferedImage image2 = new BufferedImage(cols, rows, type);  
     image2.getRaster().setDataElements(0, 0, cols, rows, data);  
     return image2;  
   }  
   public void paintComponent(Graphics g){  
      BufferedImage temp=getimage();  
      g.drawImage(temp,10,10,temp.getWidth(),temp.getHeight(), this);  
   }  
   public static void main(String arg[]){  
    // Load the native library.  
    System.loadLibrary("opencv_java245");    
    JFrame frame = new JFrame("BasicPanel");  
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
    frame.setSize(400,400);  
    Panel panel = new Panel();  
    frame.setContentPane(panel);       
    frame.setVisible(true);       
    Mat webcam_image=new Mat();  
    BufferedImage temp;  
    VideoCapture capture =new VideoCapture(0);  
    if( capture.isOpened())  
     {  
      while( true )  
      {  
        capture.read(webcam_image);  
        if( !webcam_image.empty() )  
         {  
           frame.setSize(webcam_image.width()+40,webcam_image.height()+60);  
           temp=matToBufferedImage(webcam_image);  
           panel.setimage(temp);  
           panel.repaint();  
         }  
         else  
         {  
           System.out.println(" --(!) No captured frame -- Break!");  
           break;  
         }  
        }  
       }  
       return;  
   }  
 }  

And as we are here, let's finish with the tracking of face and eyes... Tomorrow :)
PS.: Click here to see the index of these series of posts on OpenCV

Sunday, June 23, 2013

Creating windows in Java and drawing in them

A very basic one (note that I am just learning, so, some of the usage may not be very correct):
 import java.awt.event.*;  
 import javax.swing.*;  
 public class Main {  
   /**  
    * @param args  
    */  
   public static void main(String s[]) {       
     JFrame f = new JFrame("Jumbled Image");  
     f.addWindowListener(new WindowAdapter() {  
       public void windowClosing(WindowEvent e) {System.exit(0);}  
     });  
     f.pack();  
     f.setSize(200,200);  
     f.setVisible(true);  
   }  
  }  

Nice explanation on JFrame (heavyweight) and JPanel (lightweight) here
Follow those links to understand why you need both...
 import java.awt.*;  
 import javax.swing.*;  
 public class Panel extends JPanel{  
   // Create a constructor method  
   public Panel(){  
     super(); // Calls the parent constructor  
   }  
   public void paintComponent(Graphics g){  
    g.drawLine(10,10,150,150); // Draw a line from (10,10) to (150,150)  
   }  
   public static void main(String arg[]){  
    JFrame frame = new JFrame("BasicPanel");  
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
    frame.setSize(200,200);  
    Panel panel = new Panel();  
    frame.setContentPane(panel);       
    frame.setVisible(true);           
  }  
 }  

Basically, you also create a frame here (heavyweight) but then add inside a panel (lightweight) that gets drawn automatically by the GUI when needed (like when created, or moved...) by calling paintComponent. If you want to force it draw you can do "repaint()".

Now we load an image and present it in the window:
 //Import the basic graphics classes.  
 import java.awt.*;  
 import javax.swing.*;  
 public class Panel extends JPanel{  
   String image_name="resources/IMAG0107.jpg";  
   Image image;  
   // Create a constructor method  
   public Panel(){  
     super(); // Calls the parent constructor  
     image = Toolkit.getDefaultToolkit().getImage(image_name);  
   }  
   public void paintComponent(Graphics g){  
      g.drawImage(image,50,10,200,200, this);  
   }  
   public static void main(String arg[]){  
    JFrame frame = new JFrame("BasicPanel");  
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
    frame.setSize(200,200);  
    Panel panel = new Panel();  
    frame.setContentPane(panel);       
    frame.setVisible(true);           
  }  
 }  

We had the picture inside the "resources" directory. We can do the same with Java io library, not the toolkit:
 //Import the basic graphics classes.  
 import java.awt.*;  
 import javax.imageio.ImageIO;  
 import javax.swing.*;  
 import java.io.File;  
 import java.io.IOException;  
 public class panel extends JPanel{  
   private static final long serialVersionUID = 1L;  
   String image_name="resources/DSC01642.jpg";  
   Image image;  
   // Create a constructor method  
   public panel(){  
     super(); // Calls the parent constructor  
     //image = Toolkit.getDefaultToolkit().getImage(image_name);  
     try {  
       image=ImageIO.read(new File(image_name));  
     } catch (IOException e) {  
       // TODO Auto-generated catch block  
       System.out.println("Error loading the image");  
       e.printStackTrace();  
     }      
   }  
   public void paintComponent(Graphics g){  
      g.drawImage(image,50,10,200,200, this);  
   }  
   public static void main(String arg[]){  
    JFrame frame = new JFrame("BasicPanel");  
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
    frame.setSize(200,200);  
    panel panel = new panel();  
    frame.setContentPane(panel);       
    frame.setVisible(true);           
  }  
 }  

On the next post, we will learn how to do some of this with OpenCV, so, that we can start applying some image processing to it... Also, click here to see the index of these series of posts on OpenCV

Saturday, June 22, 2013

Firefox plugins

A list of some of the ones I love. They were very easy to start with, so, didn't bother with more fancy ones... If you use them, consider donating something :)
  1. DownThemAll You downloading some long file and the connection breaks... no problem :)
  2. Google Translator for Firefox Helps you translate in line, in the same page... Simple, does what it needs to do...
  3. DownloadHelper Do you want to get/save a cool video from a website (youtube...)?
  4. Forecastfox The weather on your status bar
  5. SessionManager Saves and restores the state of all your browsing windows

Saturday, June 8, 2013

From ATX to bench power supply

Tons of these tutorials on the web. Here is one:
http://jumperone.com/2011/06/atx-power-supply-tutorial/
http://jumperone.com/2012/12/converting-atx-power-supply-to-bench-power-supply-faq/#Q3

Anyhow, this is just to say that if you don't put the load resistor, it can (and it did, on my case) blow up. In my case, I think it was an electrolytic cap... FYI, I blew it before I read anything. When it blew then I went looking for the reason... It is not that I was suicidal :) Anyhow, PSUs are so cheap that I don't feel like spending time fixing it.

Thursday, June 6, 2013

OpenCV in C/Eclipse - Quick install guide

We are going to setup now OpenCV in Eclipse. For that, we will follow the tutorial in: 
http://docs.opencv.org/doc/tutorials/objdetect/cascade_classifier/cascade_classifier.html#cascade-classifier

We start by creating a project. Follow these instructions.
http://docs.opencv.org/doc/tutorials/introduction/linux_eclipse/linux_eclipse.html

Nevertheless, we got stuck in several places, so, here are the tips. First place was because I was selecting the wrong project, to start with.


I was going with GNU Autotools which, it seems, needs to be setup, etc... The right choice is "Executable" and the I picked the MinGW GCC. Found the solution here.

Also got stuck because I didn't know how to properly add the libraries in Eclipse. For details, read this and this. But even with that, I was doing some mistakes, so, here is the basics: 
  1. Add the path to the include (header files) directory. In our case it was (C:/eclipse/opencv/build/include). The individual paths are listed in the code, respect to this root... FYI, I did this in the C++ compiler options. Not in the C compiler.
  2. Add the path to the lib (compiled libraries) AND the libraries themselves. When adding their name, do not add the extension.
  3. Remember to use fwd slash "/" on the paths although I think it is ok because Eclipse will put it between "".
  4. Also, watch how the C libraries are defined. I didn't really have to add the path for them, but some examples didn't work when used without the .h. For instance, use #include <stdio.h> and not #include <stdio>.
Here is a screen shot of the whole thing, in case it helps with this or something else:


Notice that if you download the Opencv code of the link above is slightly different than the listed... They have few more includes, like:
#include "opencv2/core/utility.hpp"
#include "opencv2/highgui/highgui_c.h"

But I didn't need those to build.

Not sure why I need to use the x86 >> This may be because we may have selected this version of eclipse because of Qt?? Compiling with the libraries on x64 will not generate an exe but we don't get more errors than the one we get with x86 (make: *** No rule to make target `all'.). This error is weird because everything else works. And anyhow, I shouldn't need to create a rule because we have it in auto. On that sense, looking into the directories, notice that I don't have a makefile. I think that is normal. The tool has that internal but does not share it with us.

Another thing was that the program didn't start because libpencv_highgui245.dll is missing from your computer. That was just the first one that he looked for. All of them were missing.It basically has to do with dynamic linking. The dll is not included in the code (like it would with static), so, at run time needs to look for it and can't find it. See http://qt-project.org/forums/viewthread/12525. I solved by moving the 4 dlls to the debug directory.

GEEEE! Almost there! Just a last one... Remember to get the xmls. I put them in resources, following a procedure like the one described in the java tutorial. I had to add resources/ in front of the text. Works now from run. If you want to execute the exe, you then have to move it to the root of the project with all its dlls...

DONE!

PS.: Click here to see the index of these series of posts on OpenCV

Saturday, June 1, 2013

Transferring the contacts from Blackberry to Android phone

Shoot, I tried everything, see below, but this was it:
http://www.youtube.com/watch?feature=player_embedded&v=eIg0c3ovQLY

Ultra easy!!!

******************************

If I would have thought twice before doing things, maybe it would have been easier, but did not. Here few things I tried and why they didn't work for me. Skip to the bottom to see what worked...
  1. I had actually made a back up of the phone with the Blackberry Desktop Manager, but that seemed of little utility unless somebody knows how to grab that into an Android (I didn't find out).
  2. Google Sync. I had not done this before my new phone got here. By the time I activated the new one, the old was out of service and installing anything was not an option. Somehow, couldn't do it even through WiFi...
  3. Using pairing of the two phones through BT. That was close. Even when my Blackberry was not listed on the Android phone to import contacts, it did connect but when it tried to get the list, it asked to change the settings on the Blackberry to unencrypted and I just couldn't do that. It is lock on that setting since I got it.
So, what worked? I use the Blackberry Desktop Manager to import all the contacts from the phone into Outlook. Then, through the enterprise server, my Android got updated when I connected my laptop to the company network. So, it looked like I got many of these in, but not all! I can't see why not all! One of my contact folders was not getting updated @@

https://sites.google.com/site/ipdparse/downloads
https://sites.google.com/site/ipdbbbextract/home

http://www.ziva-vatra.com/index.php?aid=58&id=U29mdHdhcmU=