OpenCV 가 4.6.0 이 나왔네요.. 다운로드 받아서 아무데나 풀어 줍시다
자바 예제 2. 환경 설정 환경은 ... 아래 글을 참고 하시고요
https://tobee.tistory.com/entry/OpenCV%EC%99%80-%EC%9E%90%EB%B0%94-1-%ED%97%AC%EB%A1%9C-OpenCV
이제 노트북 카메라에서 입력을 받아서 화면에 뿌릴 수 있는 클래스를 만들어 보기도 하겠습니다.
이 클래스의 껍데기랑, 이력에 대해서는 언급을 했던 것으로 알고 있습니다.
그럼 다음 행동을 통해서 화면에 뿌리는 클래스에 접근 할 수 있을 것입니다.
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());
}
}
화면을 그리는 클래스를 만드는 방법은 크게는 두가지가 있을 것 같습니다.
하나는 JPanel, 그 나머지 하나는 Canvas 입니다.
그냥 두 개를 다 만들어 보기로 했습니다.
두 개를 만들기 위해서 참고 한 사이트들은 부록에 있습니다.
우선 CamPanel과 CamCanvas 에 대한 소스 입니다.
CamPanel.java
final static class CamPanel extends JPanel {
private static final long serialVersionUID = -1248475680851582365L;
// a flag to change the button behavior
private boolean cameraActive = false;
private BufferedImage bufImagew;
@Override
public void paintComponent(Graphics g)
{
try {
super.paintComponent(g);
if(bufImagew != null)
g.drawImage(bufImagew,0,0,null);
else
System.out.println("buffer is null!!!");
}
catch(Exception e){}
}
protected void startCamera() {
if (!this.cameraActive) {
// start the video capture
InnerUtil.openCam();
// is the video stream available?
if (InnerUtil.isCamOpened()) {
cameraActive = true;
// grab a frame every 33 ms (30 frames/sec)
Runnable frameGrabber = new Runnable() {
@Override
public void run() {
// effectively grab and process a single frame
Mat frame = InnerUtil.grabFrame();
// convert and show the frame
bufImagew = Utils.matToBufferedImage(frame);
//System.out.println("3 " + bufImagew.getWidth() + ":" + bufImagew.getWidth());
// updateImageView(currentFrame, imageToShow);
repaint();
// invalidate();
}
};
InnerUtil.scheduleStart(frameGrabber);
// update the button content
goCam.setText("Stop Camera");
} else {
// log the error
System.err.println("Impossible to open the camera connection...");
}
} else {
// the camera is not active at this point
this.cameraActive = false;
// update again the button content
goCam.setText("Start Camera");
// stop the timer
InnerUtil.stopAcquisition();
}
}
}
CamCanvas.java
final static class CamCanvas extends Canvas {
private static final long serialVersionUID = 1235525630469980081L;
// a flag to change the button behavior
private boolean cameraActive = false;
private BufferedImage bufImagew;
@Override
public void paint(Graphics g) {
Graphics2D g2;
g2 = (Graphics2D) g;
if (bufImagew != null)
{
g2.drawImage(bufImagew, 0, 0, getWidth(), getHeight(), null);
}
//g2.drawString ("This is is a string", 0 + 10, getHeight() - 10);
}
protected void startCamera() {
... CamPanel 과 같음
}
}
그리고 공통 메서드를 넣어 두기 위해서 유틸 클래스인 InnerUtil 을 하나 아래 와 같이 만들었습니다.
private final static class InnerUtil
{
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
// a timer for acquiring the video stream
private static ScheduledExecutorService timer;
// the OpenCV object that realizes the video capture
private static VideoCapture capture = new VideoCapture();
// the id of the camera to be used
private static int cameraId = 0;
static void openCam()
{
capture.open(cameraId);
}
static boolean isCamOpened()
{
return capture.isOpened();
}
static void scheduleStart(Runnable frameGrabber)
{
timer = Executors.newSingleThreadScheduledExecutor();
timer.scheduleAtFixedRate(frameGrabber, 0, 33, TimeUnit.MILLISECONDS);
}
static Mat grabFrame() {
// init everything
Mat frame = new Mat();
// check if the capture is open
if (capture.isOpened()) {
try {
// read the current frame
capture.read(frame);
// if the frame is not empty, process it
if (!frame.empty()) {
Imgproc.cvtColor(frame, frame, Imgproc.COLOR_BGR2GRAY);
}
} catch (Exception e) {
// log the error
System.err.println("Exception during the image elaboration: " + e);
}
}
return frame;
}
/**
* Stop the acquisition from the camera and release all the resources
*/
static void stopAcquisition() {
if (timer != null && !timer.isShutdown()) {
try {
// stop the timer
timer.shutdown();
timer.awaitTermination(33, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
// log any exception
System.err.println(
"Exception in stopping the frame capture, trying to release the camera now... " + e);
}
}
if (capture.isOpened()) {
// release the camera
capture.release();
}
}
}
이제 모든 준비는 끝난 것 같네요.
그럼 패널위에다 화면을 표출 한 것을 먼저 보도록 하겠습니다.
그 다음으로 Canvas 를 이용한 캠 기능 활성화 입니다.
두 개의 메서드가 구현 된 모양은 거의 비슷해 보이기는 하지만
paint와 paintComponent 메서드는 좀 달라 보이기는 합니다.
Canvas로 그려 놓은 것이 심하게 화면이 깜박거리네요~
거의 모든 사람들이 알겠지만 이 때 필요한 것이 바로 더블 버퍼 링이라는 거겠죠..
가만히 생각해 보면 카메라에서 쉼없이 변화되어 나오는 그림 파일을 계속 실시간으로 그려 준다는 것이 아마 이런 깜박임이 나타나는 현상이기 때문이겠죠.
그럼, 일단 그려 놓고 다 그려 지면 보여 주면 되겠네? 라는 것이 이 더블 퍼버링의 주된 의미가 되겠습니다.
CamCanvas.java 파일을 다음 처럼 좀 바꿔 주면 되겠습니다.
final static class CamCanvas extends Canvas {
private static final long serialVersionUID = 1235525630469980081L;
// a flag to change the button behavior
private boolean cameraActive = false;
private BufferedImage bufImagew;
//for duble buffering...
@Override
public void update(Graphics g) {
Graphics2D g2;
g2 = (Graphics2D) g;
Graphics offgc;
Image offscreen;
if (bufImagew != null) {
offscreen = createImage(bufImagew.getWidth(), bufImagew.getHeight());
offgc = offscreen.getGraphics();
// clear the exposed area
offgc.setColor(getBackground());
offgc.drawImage(bufImagew, 0, 0, getWidth(), getHeight(), null);
offgc.setColor(getBackground());
g2.drawImage(offscreen, 0, 0, getWidth(), getHeight(), null);
//invalidate();
}
//g2.drawString ("This is is a string", 0 + 10, getHeight() - 10);
}
protected void startCamera() {
... 생략
}
}
그러고 나서 다시 한번 볼까요?
심하게 떨리던 화면을 더블 버퍼링으로 잡아 보았습니다.
간단하게(🥲) OpenCV 를 이용해서 할 수 있는 예제를 살펴 보았습니다.
많은 이야기가 나올 수도 있겠지만...
다음으로 미루기로 하고 이 정도면 뭔가 이 라이브러리를 사용하고 있다는 느낌이 들어가는 군요~
이상.
부록 1. 참고 사이트들
'프로그래밍 > [Java] OpenCV' 카테고리의 다른 글
OpenCV와 자바 - 4.1. 이미지 조작 - 1 (0) | 2022.09.14 |
---|---|
OpenCV와 자바 - 4. 동영상과 이미지 UI-1 (1) | 2022.09.13 |
OpenCV와 자바 - 3. 프로세싱-2 (0) | 2022.09.12 |
OpenCV와 자바 - 3. 프로세싱 (2) | 2022.09.11 |
OpenCV와 자바 - 1. 헬로 OpenCV (3) | 2022.09.08 |