그럼 이제 왼쪽 버튼 기능을 활성화 해서 이미지를 조작 해 볼 차례인 것 같습니다.
왼쪽 버튼을 그리는 클래스는 FuncButtonPanel 입니다.
액션 커맨드를 하나씩 붙히고, 리스너를 등록 해 주었습니다.
final class FuncButtonPanel extends JPanel {
private static final long serialVersionUID = 1101056225940013101L;
FuncButtonPanel() {
setLayout(new GridLayout(4, 0));
setSize(new Dimension(100, 450));
setPreferredSize(new Dimension(100, 450));
initButtonPane();
}
void initButtonPane() {
JButton btnRGB = new JButton("RGB");
btnRGB.setActionCommand("ConvBGR");
JButton btnGrayscal = new JButton("Gray scale");
btnGrayscal.setActionCommand("ConvGray");
JButton btnBlackWhite = new JButton("Black&White");
btnBlackWhite.setActionCommand("ConvBlackWhite");
JButton btnCanny = new JButton("Canny");
btnCanny.setActionCommand("ConvCanny");
// Add controls to set up horizontal and vertical gaps
add(btnRGB);
add(btnGrayscal);
add(btnBlackWhite);
add(btnCanny);
btnRGB.addActionListener(btnFuncListener);
btnGrayscal.addActionListener(btnFuncListener);
btnBlackWhite.addActionListener(btnFuncListener);
btnCanny.addActionListener(btnFuncListener);
}
}
각 버튼들은 동일 한 FunctionButtonClickListener 를 등록 했죠.
이 클래스도 역시나 UsrSelectOptions 클래스를 들고 다닐 겁니다.
class FunctionButtonClickListener implements ActionListener {
final UsrSelectOptions usrOptions;
public FunctionButtonClickListener(final UsrSelectOptions usrOptions) {
this.usrOptions = usrOptions;
}
@Override
public void actionPerformed(ActionEvent e) {
if(usrOptions.isCanvas) imageCanvas.stopTimer();
else imagePanel.stopTimer();
if (e.getActionCommand().equals("ConvGray")) {
if(usrOptions.isCanvas)
imageCanvas.loadImage(GRAY_SCALE_DRAWING);
else
imagePanel.loadImage(GRAY_SCALE_DRAWING);
} else if (e.getActionCommand().equals("ConvCanny")) {
cannyGui();
} else if (e.getActionCommand().equals("ConvBlackWhite")) {
if(usrOptions.isCanvas)
imageCanvas.loadImage(GRAY_SCALE_DRAWING);
else
imagePanel.loadImage(BLACK_AND_WHITE_DRAWING);
} else if (e.getActionCommand().equals("ConvBGR")) {
if(usrOptions.isCanvas)
imageCanvas.loadImage(RGBA_DRAWING);
else
imagePanel.loadImage(RGBA_DRAWING);
}
}
내용 상으로는 usrOptions을 사용 해서 패널인지 캔버스에 그리고 있는 지를 판단 해서 loadImage 메서드를 호출 하는 것입니다.
이 메서드는 세개가 있습니다. 저번 글에서 언급 했는 데 젤 중요한 게 젤 앞에 있죠 ㅋ
abstract void loadImage(String imagePath, boolean isStop);
abstract void loadImage(int drawingStyle);
abstract void loadImage(int drawingStyle, CannyOption cannyOption);
이미지 경로를 받는 메서드는 좀 중요 한대요
public void loadImage(String imagePath, boolean isStop) {
if(!isStop && StringUtil.isNullOrEmpty(imagePath))
{
JOptionPane.showMessageDialog(null, "이미지 경로가 없습니다", "경로 없음",
JOptionPane.INFORMATION_MESSAGE);
return;
}
else
{
if(!isStop && !new File(imagePath).exists())
{
JOptionPane.showMessageDialog(null, "이미지 파일을 찾을 수 없습니다 [" + imagePath + "]", "파일 없음",
JOptionPane.INFORMATION_MESSAGE);
return;
}
}
initMat(imagePath);
// grab a frame every 33 ms (30 frames/sec)
Runnable frameGrabber = new Runnable() {
@Override
public void run() {
Mat imageMat = grabImage();
// convert and show the frame
bufImagew = Utils.matToBufferedImage(imageMat);
repaint();
}
};
scheduleStart(frameGrabber);
// update the button content
mThemeButton.setText("UnLoad Image");
}
바로 initMat 부분이 있다는 것이죠...
initMat(imagePath);
이 메서드는 다음과 같이 구현 되어 있습니다.
BufferedImage 에서 먼저 Mat 클래스를 생성해 놓고 있습니다.
private void initMat(final String imagePath)
{
// convert and show the frame
try {
bufImagew = ImageIO.read(new File(imagePath));
cvMat = Utils.bufferedImageToMat(bufImagew);
} catch (IOException e) {
System.err.println("Exception during the image elaboration: " + e);
}
}
이렇게 생성 된 Mat 클래스를 계속 재 사용 하게 되는 대요.
최종 적으로 사용 하는 메서드인 grabImage 를 보면,
Mat grabImage(int drawingStyle, CannyOption cannyOpt) {
Mat matImage = new Mat();
try {
cvMat.copyTo(matImage);
switch (drawingStyle) {
case GRAY_SCALE_DRAWING:
Imgproc.cvtColor(matImage, matImage, Imgproc.COLOR_BGR2GRAY);
break;
case CANNY_DRAWING:
if(cannyOpt !=null)
{
CannyFunction.SetCannyLoLimit(cannyOpt.getLowVal());
CannyFunction.SetCannyHiLimit(cannyOpt.getHighVal());
CannyFunction.SetInverted(cannyOpt.isInv());
}
matImage = CannyFunction.Canny(matImage);
break;
case BLACK_AND_WHITE_DRAWING:
matImage = CannyFunction.BlackAndWhite(matImage, 3);
break;
case RGBA_DRAWING:
// Nothing to do...
// Imgproc.cvtColor(frame,frame,Imgproc.COLOR_GRAY2BGR);
}
} catch (Exception e) {
// log the error
System.err.println("Exception during the image elaboration: " + e);
}
return matImage;
}
생성 된 cvMat 를 사용해서 이미지를 조작 할 때마다 복사해 쓰도록 했습니다.
그렇지 않으면 오류가 나더랍니다~ 삽질을 좀 했네요.
그리고 grabImage 이미지 메서드는 이미지 조작의 가장 중요한 메서드 입니다~~
원래는 위의 loadImage 이미지 메서드 처럼 쓰레드 상에서 구현 하려고 하였는 데요.
가만 생각 해 보니까.. 연속적인 이미지가 아니라 이미지 하나 쓰는 것이라서 이미지를 계속적으로 읽어 들여서 표출 할 필요가 없더라구요
그리고 Mat 클래스를 재 사용 하면서 별로 의미도 없어지고 말았던 것이죠.
이미지 하나의 조작에 대해서는 이것으로 마쳐도 될 것 같네요..
다음에는 동영상을 올려서 이미지 조작 할 수 있는 지를 알아 볼 수 있도록 하겠습니다.
이상.
'프로그래밍 > [Java] OpenCV' 카테고리의 다른 글
OpenCV와 자바 - 4.3. 카메라 조작 (0) | 2022.09.17 |
---|---|
OpenCV와 자바 - 4.2. 동영상 조작 (0) | 2022.09.16 |
OpenCV와 자바 - 4.1. 이미지 조작 - 1 (0) | 2022.09.14 |
OpenCV와 자바 - 4. 동영상과 이미지 UI-1 (1) | 2022.09.13 |
OpenCV와 자바 - 3. 프로세싱-2 (0) | 2022.09.12 |