시소당
이미지 프로세스에 놀랄만한 높은 성능을 부여하는 Java Advanced Imaging(JAI) API가 자바 플랫폼에
추가되었다. 이번 테크팁에서는 이 API를 사용하는 3가지 기본 기능에 대해 배우고, 이를 확장하여 복잡한 작업도 구현해보도록
한다. 사용자의 하드 드라이브에서 이미지를 로드하여 이미지 변경사항을 적용하고, 변경된 이미지를 사용자의 하드 드라이브에 다른
포맷으로 저장해본다. 이미지를 골라 test.jpg로 변경하자. 사용자의 하드에 이미지가 없다면 다운로드 받기 바란다. 이
페이지에서는 예전 테크팁의 이미지를 사용하도록 한다.
이 API가 사용자의 자바 플랫폼에 들어있지 않으면 JAI download 페이지를 통해 다운로드할 수 있다. 현재 1.1.3 alpha가 출시되어있다
이번 테크팁에서는 다음 메소드를 사용하여 대부분의 JAI 기능에 접근한다:
JAI.create(String opName, ParameterBlock args)
JAI.create(String opName, ParameterBlock args,
RenderingHints hints);
ParameterBlock 은 opName으로 레퍼런스된 메소드로 전달되는 모든 소스와 매개변수를 hold하도록 설계된
오브젝트이다. ParameterBlock은 소스의 Vector와 파라매터의 Vector로 구성되어있다.
ParameterBlock에서 가장 유용한 두 메소드는 addSource() 와add() 이다. addSource() 는 소스
리스트의 마지막에 이미지를 추가할 때 사용하며, add()는 매개변수 리스트의 마지막에 Object 타입의 오브젝트나 원시타입의
랩퍼(wrapper)를 추가할 때 사용한다. ParameterBlock의 다른 메소드들은 소스이나 매개 변수 콜렉션으로부터
요소에 접근, 조작, 제거할 수 있는 기능을 한다.
예를 들어 test.jpg 이미지를 불러내기 위해 다음과 같이 할 수 있다:
ParameterBlock pb = new ParameterBlock();
pb.add("test.jpg);
image = JAI.create("fileload", pb);
이 "FileLoad" 연산은 JAI가 제공하는 코덱을 사용한다. 대신 별도의 JAI Image I/O 툴 패키지에
포함된"ImageRead" 연산을 사용할 수도 있다. ImageRead를 사용하려면 추가적인 패키지를 설치해야 하므로 이번
테크팁에서는 다루지 않는다.
또한 test.jpg가 사용자의 로컬 디렉토리에 있지 않으면 이 패스(path)를 적절히 수정해 주어야 한다.
이 코드에서 이미지는 PlanarImage 타입이다. 이것은 JAI에서 2차원 이미지를 위한 기본 클래스이며, 픽셀들의
집합이라고 여겨질 수 있다. JAI.create() 메소드는 RenderedOp 타입의 오브젝트를 리턴한다.
RenderedOp는 PlanarImage를 상속하며, 이미지에 방금 수행된 연산의 정보를 포함하고 있다. 일련의 연산들을
엮으면, 이 RenderedOp 노드에 이런 연산들의 기록을 갖게되는 것이다.
어떤 연산들을 이용할 수 있고, 해당하는 ParameterBlock에 어떤 매개변수들이 반드시 포함되어야하는 지 어떻게 알 수
있을까? javax.media.jai.operator 패키지의 클래스들을 보자( class 리스트 보기). Descriptor로
끝나는 클래스들을 살펴보면, 모두 OperationDescriptor를 구현하고 있다. 예를 들어,
이름이FileLoadDescriptor인 클래스를 보자. 이 클래스의 JavaDoc에서 fileload로
리스트된GlobalName을 찾을 수 있으며, 이는JAI.create() 메소드로 전달된 것들이다. 또한 예정된 매개변수들
리스트와 그 매개변수들의 디폴트 값 리스트도 찾을 수 있다.
일반적으로 javax.media.jai.OperationDescriptor 의 이러한 구현들은 Descriptor 형식의 이름을 갖는다. JAI.create()에 첫번째 매개변수로 전달된 해당 연산명은이다. 백 개 이상의 가능한 연산이 있다. 이번 테크팁의 나머지 부분에서는 jpeg 이미지에 convolution를 적용하고 수정된 이미지를 tiff로 저장해보도록 하자.
2004년 2월 19일자 테크팁 " CONVOLVEOP를 이용해서 디지털 이미지에 효과주기 "에서는 convolution을
사용하여 이미지를 흐리고 선명하게 처리하는 방법에 대해 배웠다. 그 테크팁을 따라하면, convolution에 대한 3*3
커널을 생성하게된다. Convolution은 한 픽셀과, 그 픽셀과 edge를 공유하는 4개의 픽셀, corner를 공유하는
4개의 픽셀들의 표준화된 직선 조합을 기반으로 했다. 이번 테크팁에서도 이와 같지만, 다음과 같이 상응하는 JAI 클래스인
javax.media.jai.KernelJAI를 사용할 것이다.
import javax.media.jai.KernelJAI;
public class My3x3JAIKernels {
private static final float[] IDENTITY = {0, 0, 0,
0, 1, 0,
0, 0, 0};
private static final float[] EDGE = {0, 1, 0,
1, 0, 1,
0, 1, 0};
private static final float[] CORNER = {1, 0, 1,
0, 0, 0,
1, 0, 1};
public static KernelJAI getkernel(int corner,
int edge,
int identity) {
float[] kernel = new float[9];
int sum = corner * 4 + edge * 4 + identity;
if (sum == 0) sum = 1; // to avoid dividing by zero
for (int i = 0; i < 9; i++) {
kernel[i] = (corner * CORNER[i]
+ edge * EDGE[i]
+ identity * IDENTITY[i]) / sum;
}
return new KernelJAI(3, 3, kernel);
}
}
이제, CORNER, EDGE, IDENTITY 배열의 계수를 나타내는 3개의 값을 가지는 어느 세트이던KernelJAI 오브젝트를 생성할 수 있다.:
My3x3JAIKernels.getkernel(corner, edge, identity));
그 후 리턴된 KernelJAI 오브젝트는 convolution을 실행시키는 다음 메소드에 전달될 수 있다:
private void convolveImage(KernelJAI kernel) {
ParameterBlock pb = new ParameterBlock();
pb.addSource(image);
pb.add(kernel);
image = JAI.create("convolve", pb, null);
}
ParameterBlock을 위한 소스들의 리스트에 PlanarImage를 추가하고 매개변수들의 리스트에 KernelJAI
오브젝트를 추가해야했음을 주의하자. 수정한 이미지를 Tiff로 저장하기 위해서는 "filestore" 연산이 필요하다. 또한,
convolve된 이미지를 소스로 전달하고, 이를 저장하기 위해 이름과 형식에 대한 정보를 전달해야한다.
"FileLoad" 연산을 사용할 때와 같이, 개별적인 JAI Image I/O 툴 패키지를 다운로드 할 경우 "FileStore" 을 "ImageWrite"로 변경해야한다.
private void writeImageAsTiff(){
ParameterBlock pb = new ParameterBlock();
pb.addSource(image);
pb.add("target.tiff");
pb.add("tiff");
pb.add(null);
pb.add(true);
image = JAI.create("filestore", pb, null);
}
수정 전의 이미지를 나타낸 후, 수정 후의 이미지로 교체하는 다음의 JAIConvolve프로그램으로 이를 완성해보자.
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.media.jai.PlanarImage;
import javax.media.jai.JAI;
import javax.media.jai.KernelJAI;
import java.awt.image.BufferedImage;
import java.awt.image.renderable.ParameterBlock;
import java.awt.Graphics;
public class JAIConvolve extends JPanel {
private BufferedImage buffImage;
private PlanarImage image;
JAIConvolve(int corner, int edge, int identity) {
createBufferedImages();
setUpJFrame();
// you can introduce a delay here to view the initial
// image before the convolution is applied
convolveImage(My3x3JAIKernels.getkernel(corner,
edge,
identity));
writeImageAsTiff();
}
private void createBufferedImages() {
ParameterBlock pb = new ParameterBlock();
pb.add("test.jpg");
image = JAI.create("fileload", pb);
drawImage();
}
private void setUpJFrame() {
JFrame myFrame = new JFrame("3 x 3 Convolution");
myFrame.setSize(buffImage.getWidth(),
buffImage.getHeight());
myFrame.add(this);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setVisible(true);
}
private void convolveImage(KernelJAI kernel) {
ParameterBlock pb = new ParameterBlock();
pb.addSource(image);
pb.add(kernel);
image = JAI.create("convolve", pb, null);
drawImage();
}
private void writeImageAsTiff(){
ParameterBlock pb = new ParameterBlock();
pb.addSource(image);
pb.add("target.tiff");
pb.add("tiff");
pb.add(null);
pb.add(true);
image = JAI.create("filestore", pb, null);
}
private void drawImage() {
buffImage
= image.getAsBufferedImage();
Graphics g = buffImage.createGraphics();
g.drawImage(buffImage, 0, 0, null);
g.dispose();
repaint();
}
public void paintComponent(Graphics g) {
g.drawImage(buffImage, 0, 0, this);
}
public static void main(String[] args) {
if (args.length != 3) {
System.out.println("Usage: java Convolve" +
" corner edge identity");
System.out.println("where corner, edge, " +
"and identity are ints");
System.exit(0);
}
int corner = Integer.parseInt(args[0]);
int edge = Integer.parseInt(args[1]);
int identity = Integer.parseInt(args[2]);
new JAIConvolve(corner, edge, identity);
}
}
서로 다른 효과를 보여주는 값을 사용하는 JAIConvolve를 컴파일하고 실행한다. 예를 들어 다음 이미지는 흐림효과를 사용하였다.:
java JAIConvolve 1 0 0
"판화(etching)" 효과를 주려면 매개변수 -1 -1 8을 전달한다. 이제, 사용자의 로컬 디렉토리에는 또한 사용자의
convolution을 검색하여 사용하는 다른 것들과 공유할 수 있는 tiff인 target.tiff 파일이 있어야한다

출처 :
http://www.50001.com/tt/board/ttboard.cgi?act=read&db=10103&idx=930