OpenCV와 자바 - 4. 동영상과 이미지 UI-1

2022. 9. 13. 12:10프로그래밍/[Java] OpenCV

728x90

그래서 왼쪽에다 버튼 붙이고, 각 이미지 프로세싱을 위한 기능을 두 개 살펴 본 것 같습니다.

그런 다음은 동영상이 아닐까 하는 데요.

동영상은 오히려 쉽지 않을까 하는 생각이 왠지 드네요

우선 카메라 켜는 버튼 밖에 없으니까 옆에다가

 

  1. 버튼 하나 만들고 'go clip' 해 볼까요?
  2. 이 'go clip' 버튼을 누르면 동영상을 하나 선택 하면 좋을 거예요
  3. 동영상을 선택하면, 카메라 영상 나오는 위치에 동영상을 틀면

될 것 같아요~ 모양은 이렇게

그럼 갑자기 이렇게 된 거, 이미지 로딩 버튼도 만들어 보아요~

'go image' 좋으네요

아래 처럼...🤤

private void initCamPanel(final boolean isCanvas) {
	setLayout(new BorderLayout());
	
	JPanel btnPane = new ButtonPanel();
	
	JPanel btnCtrlPane = new JPanel();
	btnCtrlPane.add(goCam);
	btnCtrlPane.add(goClip);
	btnCtrlPane.add(goImage);
	
	if (!isCanvas) {
		camPane.setSize(new Dimension(600, 450));
		camPane.setPreferredSize(new Dimension(600, 450));
		
		add(camPane, BorderLayout.CENTER);
		add(btnCtrlPane, BorderLayout.SOUTH);
		add(btnPane, BorderLayout.WEST);

		goCam.setActionCommand("goCamPanel");
		goClip.setActionCommand("goClipPanel");
		goImage.setActionCommand("goImagePanel");
	} else {
		camCavs.setSize(new Dimension(600, 450));
		camCavs.setPreferredSize(new Dimension(600, 450));
		
		add(camCavs, BorderLayout.CENTER);
		add(btnCtrlPane, BorderLayout.SOUTH);
		add(btnPane, BorderLayout.WEST);
		goCam.setActionCommand("goCamCanvas");
		goClip.setActionCommand("goClipCanvas");
		goImage.setActionCommand("goImageCanvas");
	}
	
	goCam.addActionListener(btnListener);
}
 

그럼, 이런 모양이 되겠죠?

그런데 뭐 클립 보다는 비디오가 나을 듯 해서 'Go video~' 가 나을 것 같으네요

그럼 그렇게 다시 정하는 것으로 합니다.

그럼 액션리스너를 MainButtonClickListener 로 바꾸어야 한다고 봅니다

class MainButtonClickListener implements ActionListener {

	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getActionCommand().equals("goCamPanel")) {
			camPane.startCamera();
		} else if (e.getActionCommand().equals("goCamCanvas")) {
			camCavs.startCamera();
		}else if (e.getActionCommand().equals("goMoviePanel")) {
			// 코드를 넣어야 해요~
		}else if (e.getActionCommand().equals("goMovieCanvas")) {
			// 코드를 넣어야 해요~
		}else if (e.getActionCommand().equals("goImagePanel")) {
			// 코드를 넣어야 해요~
		}else if (e.getActionCommand().equals("goImageCanvas")) {
			// 코드를 넣어야 해요~
		}
	}
}
 

이젠 정말 코드를 넣어야 해요~ 코드를 넣기 위해선 이런 클래스들이 있으면 해서 만들었습니다.

이렇게(🤔~)

private static MoviePanel moviePane = new MoviePanel();
private static ImagePanel imagePane = new ImagePanel();
	
private static MovieCanvas movieCanvas = new MovieCanvas();
private static ImageCanvas imageCanvas = new ImageCanvas();
 

MoviePanel은 CamPanel과 비슷하겠죠?

MovieCanvas는 CamCanvas 랑 비슷 할 것이구요~~

그렇게 생각해 보면 InnerUtil 클래스의 openCam과 isCamOpened 메서드를 약간 변경 하면 될 것 같아요...

static void openMovie(String moviepath) {
	capture.open(moviepath);
}

static boolean isMovieOpened() {
	return capture.isOpened();
}
 

모든 것이 거의 복 붙 수준이니까. 위 메서드를 사용 할 클래스 중 하나만 본다면,

final static class CamCanvasDubleBuffer 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);
		}
	}

	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);
	
						repaint();
					}
				};
				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();
		}
	}

	protected void startCamera(int drawingStyle) {

		startCamera(drawingStyle, null);
	}
	
	protected void startCamera(int drawingStyle, CannyOption cannyOpt) {

		if (this.cameraActive) {

			// 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(drawingStyle, cannyOpt);
						// 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();
		}
	}
}
 

예쁘게 나왔네요~(😁~)

ImagePanel 이나 ImageCanvas 는 좀 있다가 생각 하는 것으로 하고

둘 다, 껍데기만 만들어 놓아요~

 

그런 다음, 액션리스너 인 MainButtonClickListener를 살짝 다음처럼 수정 합니다.

@Override
public void actionPerformed(ActionEvent e) {
	if (e.getActionCommand().equals("goCamPanel")) {
		camPane.startCamera();
	} else if (e.getActionCommand().equals("goCamCanvas")) {
		camCavs.startCamera();
	}else if (e.getActionCommand().equals("goMoviePanel")) {
		String moviePath = movieGui();
		moviePane.startMovie(moviePath);
	}else if (e.getActionCommand().equals("goMovieCanvas")) {
		String moviePath = movieGui();
		movieCanvas.startMovie(moviePath);
	}else if (e.getActionCommand().equals("goImagePanel")) {
		imagePane.startImageProc("");
	}else if (e.getActionCommand().equals("goImageCanvas")) {
		imageCanvas.startImageProc();
	}
}
 

movieGui 는 동영상 경로만 받으면 될꺼에요

이렇게~

 

private String movieGui() {
	String moviePath = null;
	JPanel panel = new JPanel();
	panel.setLayout(new GridLayout(3, 0));
	panel.setBackground(new Color(0, 0, 0));
	panel.setSize(new Dimension(250, 100));
	panel.setPreferredSize(new Dimension(250, 100));
	// panel.setLayout(null);

	JTextField txtMoviePath = new JTextField();
	txtMoviePath.setForeground(new Color(0, 0, 0));
	txtMoviePath.setHorizontalAlignment(SwingConstants.CENTER);
	txtMoviePath.setFont(new Font("Arial", Font.BOLD, 11));
	txtMoviePath.setBounds(0, 0, 250, 32);

	
	JButton btnChooseMovie = new JButton("select movie");
	btnChooseMovie.setForeground(new Color(0, 0, 0));
	btnChooseMovie.setHorizontalAlignment(SwingConstants.CENTER);
	btnChooseMovie.setFont(new Font("Arial", Font.BOLD, 11));
	btnChooseMovie.setBounds(0, 0, 250, 32);

	//JPanel MoviePane = new JPanel();
	JLabel lblMoviePath = new JLabel("Movie Selection : Movie Path");
	lblMoviePath.setForeground(new Color(255, 255, 255));
	lblMoviePath.setHorizontalAlignment(SwingConstants.CENTER);
	lblMoviePath.setFont(new Font("Arial", Font.BOLD, 11));

	txtMoviePath.setSize(new Dimension(170, 25));
	txtMoviePath.setPreferredSize(new Dimension(170, 25));

	// panel.add(new JLabel("Low: "));
	panel.add(lblMoviePath);
	panel.add(txtMoviePath);
	panel.add(btnChooseMovie);

	UIManager.put("OptionPane.minimumSize", new Dimension(270, 120));

	int result = JOptionPane.showConfirmDialog(HelloCamera.this, panel, "Select Movie",
			JOptionPane.OK_CANCEL_OPTION);

	if (result == JOptionPane.OK_OPTION) {
		try {
			moviePath = txtMoviePath.getText();
			
		} catch (Exception ne) {
			JOptionPane.showMessageDialog(null, "동영상이 설정이 안되면 진행 할 수 없어요!", "동영상 위치부족",
					JOptionPane.INFORMATION_MESSAGE);
		}
	}
	else
	{
		startCam(mIsCanvasDrawing, CANNY_DRAWING);
	}
	
	return moviePath;
}
 

그럼 아래 같은 사용자 입력 창이 뜨겠죠?

근데 버튼에다가 파일 다이얼로그를 붙혀야 하는 게 남았네요~(이러니 UI 작업은 누구나 싫어하죠..😭)

그건 이렇게 붙혀 볼까요?

 

btnChooseMovie.addActionListener(new ActionListener() {
	@Override
	public void actionPerformed(ActionEvent e) {
		FileDialog fileDialogOpen = new FileDialog(mJFrame, "파일 열기", FileDialog.LOAD);
		fileDialogOpen.setVisible(true);
		String filePath = fileDialogOpen.getDirectory() == null ? "":fileDialogOpen.getDirectory() + fileDialogOpen.getFile() == null ? "":fileDialogOpen.getFile();
		txtMoviePath.setText(filePath);
	}
});
 

예상대로 라면... 이렇게 되겠죠?

 

예상대로 네요...

아닐 수도 있고~~~

 

오늘은 여기까지

728x90