OpenCV와 자바 - 1. 헬로 OpenCV

2022. 9. 8. 12:47프로그래밍/[Java] OpenCV

728x90

 

OpenCV 가 4.6.0 이 나왔네요..

다운로드 받아서 아무데나 풀어 줍시다

 

1. 자바 예제

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;

public class HelloCV {
        public static void main(String[] args){
                System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
                Mat mat = Mat.eye(3, 3, CvType.CV_8UC1);
                System.out.println("mat = " + mat.dump());
        }
}
 

2. 환경 설정

환경은 이런 거겠죠?

 

  • 자바 JDK
  • OpenCV 자바 라이브러리
  • OpenCV 자바 네이티브 라이브러리

 

위의 환경 설정 말고 뭐가 있는 지 알아 보도록 하겠습니다.

우선 다음과 같이 환경 변수를 잡겠죠?

SET JAVA_HOME=C:\DEV\SDK\JDK\jdk-11.0.9
SET OPENCV_HOME=C:\DEV\SDK\opencv
SET CLASSPATH=%OPENCV_HOME%\build\java\opencv-460.jar;.

SET PATH=%JAVA_HOME%\BIN;.;%OPENCV_HOME%\build\java\x64;%PATH%
 

자바는 1.8 에서 너무 놀았던 것 같아서 11 로 올려 보겠습니다.

자바 11 다음과 같은 특징이 있다고 하네요...

https://www.geeksforgeeks.org/the-complete-history-of-java-programming-language/

음... 뭔가 아는 체 하기에는 생소한 단어가 넘 많으네요~

그런 다음 HelloCV.java 라는 파일을 만들고, 위의 코드를 복사해 넣으면 ? 되겠지만...

다음 디렉토리에 거의 비슷하게 있으니

C:\DEV\SDK\opencv\sources\samples\java\eclipse\HelloCV\src\Main.java
 

위에 껄 사용 해 보도록 하죠.

 

3. 헬로우 OpenCV

소스 코드를 컴파일 하고 실행을 한 번 해 보면 될 것 같습니다.

어떻게 되는 지는 아래 동영상으로 확인 하시면 될 듯 하네요...

 

OpenCV 자바 예제 파일을 돌려 보아요~

 3. 헬로우 OpenCV 카메라

3.1 소스의 재구성

JavaFX 로 만들어 진 것인데.. 별로 안 친해서 그냥 코드를 좀 빌려 쓰도록 해 보겠습니다.

젤 손에 익은 Swing 으로 만들까 합니다.

 

Swing으로 왜 만드냐고 물어보는 사람은 없겠지만,

 

옛날 이야기 하나 하자면

이 Java 1.2가 나왔을 때, 선 마이크로 시스템즈(?) 에서는 이를 JAVA 2 로 명명하며 엄청나다고 자랑을 했던 기억이 납니다. 그 중심에 이 Swing 이란 게 있었던 것으로 기억이 나네요...

더 깊이 들어가면 잘 알지도 못하지만,

쓰기도 쉽지도 않고,

만들기도 쉽지 않지만,

만들놔도 예쁘지도 않고,

업그레이드 하기도 애매하고

UI 그리기 위한 통합 개발 환경도 거의 없고 등등

그렇게 초창기 내 코딩 인생에 들어와 박히고 나니, 몸이 기억하고 특히나 손가락이 기억을 하네요.

하지만, 처음 부터 만들라면 손사래를 치겠지만 어디서 원하는 껍데기(여기서는 GUI 화면 ㅋ~) 하나 구하면

오히려 하나 씩 만들어가는 재미도 있다능 ~😅

 

우선 껍데기 코드는 스택 오버플로우에서~~

(전체 코드는 부록 1에서 확인 하십시오)

 

 

Speeding up webcam access in Java OpenCV

I am porting part of my C++ OpenCV-based code to Java OpenCV. I am using the Java wrappers prepared by Willow Garage, i.e., the group behind c++ OpenCV. I am not using javacv (hosted at googlecode).

stackoverflow.com

 

 

위 코드를 바탕으로 github의 아래 소스 코드를 이용 하도록 합니다.

3.2 사용자 UI

사용자 UI 에 대한 개념은 아래 처럼 하는 게 저자의 생각인 듯 합니다.

4. 소스 만들기

그럼 소스를 만들어 볼까 합니다.

우선 진입부, 진입 부는 이건 순전한 내 생각입니다만 공식 같은 거죠~

public static void main(String[] args) {
	SwingUtilities.invokeLater(new Runnable() {
		public void run() {
			try {
				UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
			} catch (Exception useDefault) {
			}
			initGui();
		}
	});
}
 

위의 코드에서 아래 부분은 있어도 되고 없어도 됩니다.

try {
	UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
 

 

위의 코드가 있으면

이렇게 될꺼고, 없으면

이렇게 될테니까요...😁

그럼 initGui 메서드를 만들어 볼까요?

public static void initGui() {
	final HelloCamera hellcam = new HelloCamera();
	
	JFrame f = new JFrame("HelloCamera");
	// Let the OS handle the positioning!
	f.setLocationByPlatform(true);
	f.setLayout(new BorderLayout());
	f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
	//f.setVisible(true);
	f.add(hellcam, BorderLayout.CENTER);
	f.pack();
	//f.setSize(new Dimension(800, 600));

	f.setVisible(true);

	f.addWindowListener(new WindowAdapter() {
		@Override
		public void windowClosing(WindowEvent e) {
			System.out.println("Closed");
			hellcam.stopCam();
			e.getWindow().dispose();
		}
	});

}
 

위의 코드를 수행 하면, 이미 이렇게 저렇게 만들어 본 위의 윈도우가 나옵니다.

아주 단순해 보이는 말이죠.

 

문득, 메서드라는 말이 나와서 말인 데 보통 우리는 함수라고도 말을 합니다.

메서드는 방법, 함수는 기능 이라는 영어 단어 인 것으로 보이고

우리는 소프트웨어 공학 중에 OO 로 말하는 것을 방법론이라고 합니다.

그래서 내 생각에는 C 에서는 함수, 그 외에 Object Oriented Programming 을 할 때는 메서드가 아닐까 하는 데요. 자바는 OOP 를 하기 최적화 된 언어 였기 때문에(그때는 😊) 자바는 메서드라고 해도 되지 않을까 하는 순전한 나만의 생각입니다.

그럼 이런 생각이 들기도 하지요. OO 의 개념으로 짜면 메서드, 아니면 함수?

 

그럼 HelloCamera 클래스를 만들어 볼 차례 입니다.

이 클래스의 뼈대는 다음 처럼 구성이 됩니다. 짜다 보니 아래 같은 뼈대가 되었습니다.

일단, 아무 생각이 없다고 봐야죠~

public class HelloCamera extends JPanel {
	private static JButton goCam = new JButton("Go camera~");
	private static CamPanel camPane = new CamPanel();
	private static CamCanvas camCavs = new CamCanvas();

	public HelloCamera(final boolean isCanvas) {
		setSize(new Dimension(600, 450));
		setPreferredSize(new Dimension(600, 450));
		
		initCamPanel(isCanvas);
		
		setVisible(true);
	}
	
	private void initCamPanel(final boolean isCanvas)
	{
		
		if(!isCanvas)
		{
			camPane.setSize(new Dimension(600, 450));
			camPane.setPreferredSize(new Dimension(600, 450));
			setLayout(new BorderLayout());
			add(camPane, BorderLayout.CENTER);
			add(goCam, BorderLayout.SOUTH);
			goCam.setActionCommand("goCamPanel");
			goCam.addActionListener(new CamButtonClickListener());
		}
		else
		{
			camCavs.setSize(new Dimension(600, 450));
			camCavs.setPreferredSize(new Dimension(600, 450));
			setLayout(new BorderLayout());
			add(camCavs, BorderLayout.CENTER);
			add(goCam, BorderLayout.SOUTH);
			goCam.setActionCommand("goCamCanvas");
			goCam.addActionListener(new CamButtonClickListener());
		}
	}
	
	class CamButtonClickListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			if (e.getActionCommand().equals("goCamPanel")) {
				camPane.startCamera();
			}
			else if (e.getActionCommand().equals("goCamCanvas")) {
				camCavs.startCamera();
			}
		}

	}
	
	protected void stopCam(final boolean isCanvas) {
		if(!isCanvas)
		{
			camPane.stopAcquisition();
		}
		else
		{
			camCavs.stopAcquisition();
		}
		
	}
	
	
	final static class CamCanvas extends Canvas {
		...
	}
	
	final static class CamPanel extends JPanel {
		...

	}

	public static void initGui(final boolean isCanvas) {
		...

	}

	public static void main(String[] args) {
		...
	}
}
 

위의 코드를 보면,

private static JButton goCam = new JButton("Go camera~");
private static CamPanel camPane = new CamPanel();
private static CamCanvas camCavs = new CamCanvas();
 

위와 같이 Panel과 Canvas가 두개 구성 되어 있는 것이 보이 실 겁니다.

이건 카메라에서 받아온 이미지를 그리는 방법이

패널 위에다 그리는 방업과 캔버스에 그리는 방법 두개가 있어서 따로 선언 한 부분입니다.

그리는 방법에 대한 상세한 설명은 공부를 안해봐서 모르겠습니다만,

패널에다 그리는 것은 내부적인 자바 라이브러리를 좀 더 써서 편하게 그리겠다는 의미이고,

캔버스에다 그리는 것은 좀 더 개발자가 자신의 임의 대로 섬세한(?) 그리기를 해 보겠다는 의미로

저는 받아 들입니다.

 

isCanvas 라는 불리언 매개 변수는 그래서 나온 것이라 생각 하면 됩니다.

 

여기까지 하겠습니다~아

 

 

부록 1.

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;

import java.io.InputStream;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.highgui.Highgui;
import org.opencv.highgui.VideoCapture;


public class Robot extends JPanel implements Runnable {

    static BufferedImage bufImagew = null;
    public Robot() {

        JFrame f=new JFrame();
        f.setVisible(true);
        f.add(this);
        f.setSize(new Dimension(640,500));

    }

    @Override
    public void run() {

        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        VideoCapture camera = new VideoCapture(0);
        // 1 for next camera
        int i = 0;
        try {

            Mat frame = new Mat();
            while (true) {
                    camera.read(frame);
                    Mat image_tmp = frame;

                    MatOfByte matOfByte = new MatOfByte();
                    BufferedImage bufImage = null;

                    if(image_tmp!=null)
                    Highgui.imencode(".jpg", image_tmp, matOfByte); 


                    byte[] byteArray = matOfByte.toArray();
                    try {

                        InputStream in = new ByteArrayInputStream(byteArray);
                        bufImage = ImageIO.read(in);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }


                    bufImagew=bufImage;
                    this.repaint();
                    if(i==5)
                        i=0;
                } 

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void paintComponent(Graphics g)
    {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        DetectFaceDemo d=new DetectFaceDemo();
        try {

        super.paintComponent(g);
        g.drawImage(bufImagew,0,0,null);

        }
        catch(Exception e){}
    }

    public static void main(String[] args) {
        Robot gs = new Robot();
        Thread th = new Thread(gs);
        th.start();
    }
}
 

부록 2.

 

 

 

 

728x90