본문 바로가기

IT/Image Processing

[OpenCV / Java]Webcam 영상 출력

이번 포스팅에서는 이클립스환경에서 Java와 OpenCV 이용한 웹캠영상 출력에 대해서 포스팅하겠다.

튜토리얼은 다음 링크를 참고했다.

http://michaelscarlett.blog.com/2015/01/25/opencv-java-webcam-example/


튜토리얼의 코드는 3가지 파트로 나뉜다.


1. Main.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.highgui.VideoCapture;
 
public class Main {
 
    static {
                // Load the native OpenCV library
        System.loadLibrary( Core.NATIVE_LIBRARY_NAME );
    }
 
    public static void main(String[] args) {
        // Register the default camera
        VideoCapture cap = new VideoCapture(0);
 
        // Check if video capturing is enabled
        if (!cap.isOpened()) {
            System.exit(-1);
        }
 
        // Matrix for storing image
        Mat image = new Mat();
        // Frame for displaying image
        MyFrame frame = new MyFrame();
        frame.setVisible(true);
 
        // Main loop
        while (true) {
            // Read current camera frame into matrix
            cap.read(image);
            // Render frame if the camera is still acquiring images
            if (image != null) {
                frame.render(image);
            } else {
                System.out.println("No captured frame -- camera disconnected");
                break;
            }
        }
 
    }
}
cs


2. MyFrame.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import java.awt.FlowLayout;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
 
import javax.swing.JFrame;
import javax.swing.JPanel;
 
import org.opencv.core.Mat;
 
public class MyFrame {
 
    private final JFrame frame;
    private final MyPanel panel;
 
    public MyFrame() {
                // JFrame which holds JPanel
        frame = new JFrame();
        frame.getContentPane().setLayout(new FlowLayout());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 
                // JPanel which is used for drawing image
        panel = new MyPanel();
        frame.getContentPane().add(panel);
    }
 
    public void setVisible(boolean visible) {
        frame.setVisible(visible);
    }
 
    public void render(Mat image) {
        Image i = toBufferedImage(image);
        panel.setImage(i);
        panel.repaint();
        frame.pack();
    }
 
    public static Image toBufferedImage(Mat m){
              // Code from http://stackoverflow.com/questions/15670933/opencv-java-load-image-to-gui
 
              // Check if image is grayscale or color
          int type = BufferedImage.TYPE_BYTE_GRAY;
          if ( m.channels() > 1 ) {
              type = BufferedImage.TYPE_3BYTE_BGR;
          }
 
              // Transfer bytes from Mat to BufferedImage
          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;
      }
}
cs


3. MyPanel.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
 
import javax.swing.JPanel;
 
public class MyPanel extends JPanel {
 
    private Image img;
 
    public MyPanel() {
 
    }
 
    public void setImage(Image img) {
                // Image which we will render later
        this.img = img;
 
                // Set JPanel size to image size
        Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
        setPreferredSize(size);
        setMinimumSize(size);
        setMaximumSize(size);
        setSize(size);
        setLayout(null);
    }
 
        @Override
    public void paintComponent(Graphics g) {
        g.drawImage(img, 00null);
    }
}
cs


위의 세가지 코드를 실해보면 어느때는 잘 되다가 width와 height가 0라고 실행이 안되는 경우가 발생한다.

링크된 튜토리얼은 Main.java에서 잘못된 부분들이 있다.

그 부분을 짚어보자면 다음과 같다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Matrix for storing image
Mat image = new Mat();
// Frame for displaying image
MyFrame frame = new MyFrame();
frame.setVisible(true);
 
// Main loop
while (true) {
    // Read current camera frame into matrix
    cap.read(image);
    // Render frame if the camera is still acquiring images
    if (image != null) {
        frame.render(image);
    } else {
        System.out.println("No captured frame -- camera disconnected");
        break;
    }
}
cs


반복문 while에 진입해서 if문에서 변수 image가 null값인지 아닌지 검사를 하게 되는데,

여기서 변수 image는 절대로 null값이 될 수 없다. 그리고 만약 변수 image가 null값이 되어

else로 진입해도 문제의 소지가 생긴다.

한번 곰곰히 생각해보자.

.

.

.

.

.

.

코드를 살펴보면

위에서 변수 image는 이미 선언되어있다.


1
2
// Matrix for storing image
Mat image = new Mat();
cs


이는 이미 메모리에 변수값이 초기화되어 할당되었다는 의미이다.

그러니 변수 image는 null값을 가질 수 없다.

따라서 다음처럼 바꾸는 것이 더 좋다.


1
2
3
if (!image.empty()) {
    frame.render(image);
}
cs


그리고 else에 선언된 break도 문제가 된다.

만약에 웹캠의 상태가 안좋아 연결을 하는데 몇번의 시도를 해야한다고 하면

(실제로 실행해보면 저기있는 else의 break때문에 원하지 않는 결과들이 나올 것이다.)

else의 break에 막혀 "No captured frame -- camera disconnected"라는 문자열을 출력하고

프로그램이 종료 될 것이다.

그러므로 이 부분은 다음과 같이 선언하는게 더 좋다.


1
2
3
else {
    System.out.println("No captured frame -- camera disconnected");
}
cs


따라서 Main.java의 전체적인 코드는 다음과 같다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.highgui.VideoCapture;
public class Main {
    
    static {
        // Load the native OpenCV library
        System.loadLibrary("opencv_java2411");
    }
 
    public static void main(String[] args) {
        // Register the default camera
        VideoCapture cap = new VideoCapture(0);
 
        // Check if video capturing is enabled
        if (!cap.isOpened()) {
            System.exit(-1);
        }
 
        // Matrix for storing image
        Mat image = new Mat();
        // Frame for displaying image
        MyFrame frame = new MyFrame();
        frame.setVisible(true);
 
        // Main loop
        while (true) {
            // Read current camera frame into matrix
            cap.read(image);
            // Render frame if the camera is still acquiring images
            if (!image.empty()) {
                frame.render(image);
            } else {
                System.out.println("No captured frame -- camera disconnected");
            }
        }
    }
}
cs


잘 되었다면 다음과 같이 웹캠 영상이 출력되는 것을 볼 수 있다.



자 이상으로 이클립스 환경에서 Java와 OpenCV를 이용한 웹캠 영상 출력에 대한 포스팅을 마치겠다.