Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Method getImage() return images referencing the same raster bytes #182

Closed
humber1000 opened this issue Feb 21, 2014 · 9 comments
Closed
Labels

Comments

@humber1000
Copy link

First, let me congratulate you for your work. Your Webcam Capture library is awesome! Very effective and much more easy to use than the JMF from sun-oracle. Secondly, forgive me for my bad english, if it is. It's not my native language.
Well, now... the issue... I'm making and application that shows the images of several webcams in a window (JFrame), and if you select one of them, it is shown in the main windows (a JFrame too). Everything was going well, the webcams was shown in the selection window, and the selected webcam was shown in the main window. But when I get to the moment of taking a picture (using the getImage() method) in the main window, the problem comes out. Every picture that I take is stored in a Vector, which is passed as the argument for a viewer window (JFame), and when I open it, it turns out that every image in the sequence of the viewer window is the same, the last one. It seems as if the last picture taken replaces the earlier ones in the vector.
But there's more. Whenever I clik a button in the viewer window, the webcam takes a snapshot and replaces the central image of the viewer panel (the bigger one) with the new one.

So we have two issues in here:

  1. The last image taken using the getImage() method replaces all those stored in the images vector.
  2. Whenever I click a button in the viewer window, the webcam takes a snapshot and replaces the central image.

I would be very thankful if help me out with this. You'll see, this is part of my thesis, and if you take some time for helping out to solve this issues I would really appreciate it.

I'm going to show you the relevant parts of my code so you can understand the way I'm doing the things.

For detecting the several webcams connected I use the following code:

    java.util.List<Webcam> webCamList = null;

try{
    webCamList = (java.util.List<Webcam>)Webcam.getDiscoveryService().getWebcams(10, TimeUnit.SECONDS);
}catch(TimeoutException toe) {
    toe.printStackTrace();
}

In the selection window, the several webcams are showing through a square that extends from JToggleButton. This is the constructor for the squares:

    Webcam cam;

    public CamSquare(Webcam webCam) {

        //................ Some code

        cam = webCam;

        cam.setViewSize(cam.getViewSizes()[1]);

        cam.open(true);

        cam.getLock().unlock();    // So I can have both, the square view and the main window view, playing at the same time. I suppose this is what it is used for.

        WebcamPanel webCamPanel = new WebcamPanel(cam);

        //.............. Some code

    }

Now, once I do click over any square, the image appears immediately in the main window, with a bigger size. The main window implements the ActionListener interface, and this is the relevant part of the actionPerformed method:

    public void actionPerformed(ActionEvent ae) {

            //......... Some code

            if(ae.getSource() instanceof CamSquare)
    {
        square = (CamSquare)ae.getSource();

        webCam = square.getWebCam();

        webCam.open(true);

        WebcamPanel webCamPanel = new WebcamPanel(webCam);
        webCamPanel.setFillArea(true);

        videoPanel.removeAll();

        videoPanel.add(webCamPanel, BorderLayout.CENTER);

                    videoPanel.revalidate();
        videoPanel.repaint();

                    //............ Some other code.

            }

            if(ae.getSource()==captureButton)
    {
        Image image = (Image)webCam.getImage();

        if(image!=null)
        {
            imagesVector.addElement(image);    // This is the vector I was telling you about, properly initialized in the main window constructor (new Vector<Image>(0,1)).

            //...... Some other code
        }
    }

            //......... Some code

    }

Well, as I told you before, I would be very grateful if you help me solve this problems.
Thanks in advanced.
AH!... And my OS is Windows 7 (32-bit), and I'm usin webcam-capture-0.3.10-RC6-dist. My webcmas are Genius ISlim 300X.

@sarxos
Copy link
Owner

sarxos commented Feb 21, 2014

Hi @humber1000,

This hack with unlocking webcam to open it in parallel may lead you to many problems, including Java crash, especially when the webcam is closed, and this method will work only on Windows (because of the bug in the videoinput library actually). On Linux or Mac OS you will simply get an error.

Just wanted to explain this - opening single webcam in parallel is fundamentally wrong and you should avoid this. If you want more details I can explain you later because now I have to catch the last bus to my apartment or I will have to go 13 km by foot at night.

In regards to the image replacement - I guess this may be caused by the fact you are using non-blocking mode where image is buffered (open method with arg true), but I have to verify this. Try opening webcam with open(false) and check again. Seems like the images are not really replaced, but by the fact that you are always getting the same image. Please correct me if I'm wrong.

@humber1000
Copy link
Author

Hi, sarxos.
Thanks for you soon reply.
I tried what you said and the code for the CamSquare constructor looked like this:

Webcam cam;

public CamSquare(Webcam webCam) {

    //................ Some code

    cam = webCam;

    cam.setViewSize(cam.getViewSizes()[1]);

    cam.open(false);

    WebcamPanel webCamPanel = new WebcamPanel(cam);

    //.............. Some code

}

As you can see, I opened the webCam with the 'false' argument, and I removed the line where I unlocked it... but the result was the same.
By the way, although I removed the unlock line and I used the 'false' argument to open the webCam, I still can have two webCamPanel of the same webCam playing in diferent panels of the application. But as I told you... the problem regards the getImage() method persists.
What about if we do this... for you must be very easy and quick to make... Create a WebcamPanel in the usual way, creating its Webcam as you always do, and try this: get several images using the getImage() method and store them in a Vector at the same time you are getting them, one by one. Then, use the vector to display the images in a diferente window, and you'll see that they all will be the same.
And don't forget the most weird issue... when I press any button in the viewer panel, which has nothing to do with the main window, where the getImage() method stays, all images change into a new captured image. As if the webcam took an snapshot alone, just by pressing any button. I could think in a logic error if it happened in the main window, where the getImage() method stays, but, in the viewer panel?... Why? I don't understand.

I hope you don't bother for helping me out. Your library is very good, and I'd like to use it properly.
Thanks in advanced, sarxos.

@sarxos
Copy link
Owner

sarxos commented Feb 26, 2014

@humber1000,

You are absolutely correct. The image instances are actually completely different objects, but the data beneath the raster references the same byte[][] array (see this commit) containing image data. Damn, I was so happy year ago when I was able to drop down the memory consumption... Sadly, seems like we need to increase it again because my "enhancement" actually introduced a bug you've discovered.

@sarxos sarxos closed this as completed in 3bcd742 Feb 26, 2014
@sarxos
Copy link
Owner

sarxos commented Feb 26, 2014

I uploaded newest JAR into Sonatype repo, you can download it from here:

https://oss.sonatype.org/content/repositories/snapshots/com/github/sarxos/webcam-capture/0.3.10-SNAPSHOT/webcam-capture-0.3.10-20140226.212407-23.jar

I already confirmed it's fixing problem you've found, but please confirm it as well.

In regards to the problem with button... It's pretty weird since WebcamPanel does not expose any camera controls for mouse or keyboard - it's just a plain area where image is being drawn. I suppose this may be side effect of the bug, so please try with new JAR.

As for the parallel playing, I haven't said it's not possible - you can of course play image from one webcam in unlimited number of panels (as long as you have resources for that), but you cannot open it twice (the webcam device). This is because when you open camera, it allocates native instance which is using DirectShow on Windows, libv4l on Linux and QuickTime on Mac. The problem arose because Windows allows two separate instances to use the same camera device (Linux and Mac does not allow such operation) via the same capture graph, and when you close one instance, it will destroy capture graph, so when second instance will try to read it, it will most likely crash because of segmentation fault, or with some strange error in console (if you are lucky enough).

Here is the small program I used to debug the problem (as you suggested). I moved it into examples:

https://github.com/sarxos/webcam-capture/blob/master/webcam-capture/src/example/java/TakePicturesAndPlayExample.java

Thank you very much for finding this bug :)

Take care!

@sarxos sarxos added the bug label Feb 26, 2014
@humber1000
Copy link
Author

Thanks to you, for your great collaboration.
I'm going to try with the new .jar.
Take care.

@humber1000
Copy link
Author

sarxos... I'm sorry for bringing you bad news... but the new .jar works the same than the old one. The problem persists.
In other way, I wanted to ask you something. The driver OpenIMAJGrabber.dll found in Webcam Capture\webcam-capture-0.3.10...\com\github\sarxos\webcam\ds\buildin\lib\win32 should be placed in some folder? If I remember well you didn't leave instructions about that driver. Where should I put it?
And what about the OpenIMAJGrabber.class? Which cases should it be used in?

@sarxos
Copy link
Owner

sarxos commented Feb 27, 2014

The OpenIMAJGrabber.dll should not put it in any folder. It's automatically extracted by BridJ. Just replace RC6 JAR in the classpath with the new one and you should be fine. This is default driver, embedded in Webcam Capture JAR, which should work fine as it is, so it doe not require any specific instructions.

When you say "it works the same", what do you actually mean? I used the simple example I prepared to test issue you've described (images replaced in vector) and confirmed it was there. After I fixed the bug, the same code confirmed it does not persist any more.

Have you removed previous Webcam Capture JAR from classpath and replaced by new one, or you just added new one without removing previous? Also, are you using Maven? In such case, JAR replacement will not work since you have to change dependency in your POM if this is the case.

@humber1000
Copy link
Author

Maven? I'm not using nothing with such a name, as far as I know. I'm only using your .jar files.
And when I said "I works the same", I ment that the problem persisted. The images stored in the vector are replaced for the last one taken, which by the way, is taken (I realized that later) when I press the button to open the viewer window. As if the getImage() method executes by itself when I press any buton. Because, remember what I told you, anytime I pressed a button in the viewer window, which is a class apart (that has NOTHING to do with the getImage() method) the camera takes a snapshot and replaces the central image.
And as for the procedure you are telling me regard the .jar files, I did just like what you said. I removed the old .jar and replaced for the new one, and configured my IDE (JCreator) to use the new .jar file. But it didn't help me.
But, you know something?... I just test your TakePicturesAndPlayExample.java code and with the new .jar it works fine. But it doesn't in my code. So I realized that something in my code or in my configuration must be wrong.
Could you help me figure out what could it be?
Thanks in advanced.

@sarxos
Copy link
Owner

sarxos commented Mar 1, 2014

I can help you with the code (just drop it somewhere or put on Github), but not with the configuration, since I'm completely unfamiliar with JCreator (I'm using Eclipse IDE).

Maven is a dependency manager. In small projects dependencies managing problem does not usually exist, but when the project grows, you found that number of dependencies (JARs) you have to use use in code, constantly grows, and you realize in one moment that some classes are missing, some methods does not exits, etc - this is because of wrong or missing JARs included in classpath. Maven takes this burden from you and create dependency tree which contains all required JARs and download them from the Central Repository which contains more than half million of officially released files. It knowns what JARs are required by other JARs because their creators declared this when they put them in Maven Central.

Learning Maven may be a little hard for the beginning, but after you are familiar with this tool, it's like a blessing in your everyday programming life. All my projects I created in several years back from now, are using Maven and I cannot imagine managing all required JARs manually.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants