Witam. Piszę aplikację w JAVIE, nakładającą filtry na wczytany obraz, działającą na wątkach. Ogólny szkielet aplikacji mam, ale działający na jednym wątku (zapisu do pliku nie implementowałem jeszcze, bo nie wiem, co zostanie z kodu po dodaniu wątków). Podział wczytanego obrazka jest realizowany przez funkcję getSubimage (podział na 4 równe części w pionie), ale niestety nie mam pojęcia, jak przechwycić wynik podziału i zastosować na uzyskanych częściach zdefiniowane filtry. Bez wątków program był banalny, ale z wątkami okazał się być ciężki dla mnie do ukończenia. Moje przemyślenia są widoczne częściowo w komentarzach w kodzie. Zwracam się teraz z prośbą do osób znających JAVĘ o pomoc w skończeniu tego przykładu.
Aktualnie kod wygląda tak:
FiltryGraficzne.java
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ByteLookupTable;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.awt.image.LookupOp;
import java.awt.image.RescaleOp;
import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class FiltryGraficzne {
public static void main(String[] args) {
JFrame frame = new Okno();
frame.setVisible(true);
}
}
/////////////////////////////////////////////
//~~~~~~~~~~~~~~~~klasa Okno~~~~~~~~~~~~~~~//
/////////////////////////////////////////////
class Okno extends JFrame implements ActionListener {
/**
*
*/
private static final long serialVersionUID = 2800017321906936650L;
public Okno() {
setTitle("Filtry Graficzne");
setSize(300, 400);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
Container contentPane = getContentPane();
panel = new Operacje();
contentPane.add(panel, "Center");
JMenu fileMenu = new JMenu("Plik");
openItem = new JMenuItem("Otwórz");
openItem.addActionListener(this);
fileMenu.add(openItem);
// saveItem = new JMenuItem("Save");
// saveItem.addActionListener(this);
// fileMenu.add(saveItem);
exitItem = new JMenuItem("Zakończ");
exitItem.addActionListener(this);
fileMenu.add(exitItem);
JMenu editMenu = new JMenu("Edycja");
blurItem = new JMenuItem("Rozmycie (Blur)");
blurItem.addActionListener(this);
editMenu.add(blurItem);
sharpenItem = new JMenuItem("Wyostrzenie (Sharpen)");
sharpenItem.addActionListener(this);
editMenu.add(sharpenItem);
brightenItem = new JMenuItem("Rozjaśnienie (Brighten)");
brightenItem.addActionListener(this);
editMenu.add(brightenItem);
edgeDetectItem = new JMenuItem("Wykrywanie krawędzi (Edge detect)");
edgeDetectItem.addActionListener(this);
editMenu.add(edgeDetectItem);
negativeItem = new JMenuItem("Negatyw");
negativeItem.addActionListener(this);
editMenu.add(negativeItem);
rotateItem = new JMenuItem("Obrót (Rotate)");
rotateItem.addActionListener(this);
editMenu.add(rotateItem);
JMenu helpMenu = new JMenu("Pomoc");
infoItem = new JMenuItem("O programie");
infoItem.addActionListener(this);
helpMenu.add(infoItem);
JMenuBar menuBar = new JMenuBar();
menuBar.add(fileMenu);
menuBar.add(editMenu);
menuBar.add(helpMenu);
setJMenuBar(menuBar);
}
public void actionPerformed(ActionEvent evt) {
Object source = evt.getSource();
if (source == openItem) {
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new File("."));
chooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
public boolean accept(File f) {
String name = f.getName().toLowerCase();
return name.endsWith(".gif") || name.endsWith(".jpg")
|| name.endsWith(".jpeg") || name.endsWith(".png")
|| name.endsWith(".bmp") || f.isDirectory();
}
public String getDescription() {
return "Pliki graficzne";
}
});
int r = chooser.showOpenDialog(this);
if (r == JFileChooser.APPROVE_OPTION) {
String name = chooser.getSelectedFile().getAbsolutePath();
panel.loadImage(name);
}
} else if (source == exitItem)
System.exit(0);
else if (source == blurItem)
panel.blur();
else if (source == sharpenItem)
panel.sharpen();
else if (source == brightenItem)
panel.brighten();
else if (source == edgeDetectItem)
panel.edgeDetect();
else if (source == negativeItem)
panel.negative();
else if (source == rotateItem)
panel.rotate();
else if (source == infoItem)
panel.authors();
}
private Operacje panel;
private JMenuItem openItem;
private JMenuItem exitItem;
private JMenuItem blurItem;
private JMenuItem sharpenItem;
private JMenuItem brightenItem;
private JMenuItem edgeDetectItem;
private JMenuItem negativeItem;
private JMenuItem rotateItem;
private JMenuItem infoItem;
}
/////////////////////////////////////////////////
//~~~~~~~~~~~~~~~~klasa Operacje~~~~~~~~~~~~~~~//
/////////////////////////////////////////////////
class Operacje extends JPanel {
/**
*
*/
private static final long serialVersionUID = 350570824125187877L;
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null)
g.drawImage(image, 0, 0, null);
}
public void loadImage(String name) {
Image loadedImage = Toolkit.getDefaultToolkit().getImage(name);
MediaTracker tracker = new MediaTracker(this);
tracker.addImage(loadedImage, 0);
try {
tracker.waitForID(0);
} catch (InterruptedException e) {
}
image = new BufferedImage(loadedImage.getWidth(null), loadedImage
.getHeight(null), BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = image.createGraphics();
g2.drawImage(loadedImage, 0, 0, null);
repaint();
}
private void filter(BufferedImageOp op) {
// dzielenie obrazu na n-czesci
// robione met. getSubimage()
final int N = 4;
//~~~~podział~~~//
BufferedImage tab[] = new BufferedImage[N];
for (int i = 0; i < N; i++) {
// tab[i] = image.getSubimage((i/N)*image.getWidth(), 0, ((i/N)*image.getWidth())+1/N, image.getHeight()) ;
}
//~~~~koniec podziału~~~//
// trzeba zrobic tablice na wyniki (N obrazkow)
BufferedImage filteredImage = new BufferedImage(image.getWidth(), image
.getHeight(), image.getType());
// przetwarzanie rownolegle czesci obrazu
Thread watki[] = new Thread[N];
for (int i = 0; i < N; i++) {
watki[i] = new Thread(new Runnable() {
public void run() {
// op.filter(image, filteredImage);
}
});
watki[i].start();
}
// poczekac na wszystkie watki az zakoncza
for (int i = 0; i < N; i++) {
try {
watki[i].join();
} catch (Exception e) {
}
}
image = filteredImage;
repaint();
}
private void convolve(float[] elements) {
Kernel kernel = new Kernel(3, 3, elements);
ConvolveOp op = new ConvolveOp(kernel);
filter(op);
}
public void blur() {
float weight = 1.0f / 9.0f;
float[] elements = new float[9];
for (int i = 0; i < 9; i++)
elements[i] = weight;
convolve(elements);
}
public void sharpen() {
float[] elements = { 0.0f, -1.0f, 0.0f, -1.0f, 5.f, -1.0f, 0.0f, -1.0f,
0.0f };
convolve(elements);
}
void edgeDetect() {
float[] elements = { 0.0f, -1.0f, 0.0f, -1.0f, 4.f, -1.0f, 0.0f, -1.0f,
0.0f };
convolve(elements);
}
public void brighten() {
float a = 1.5f;
float b = -20.0f;
RescaleOp op = new RescaleOp(a, b, null);
filter(op);
}
void negative() {
byte negative[] = new byte[256];
for (int i = 0; i < 256; i++)
negative[i] = (byte) (255 - i);
ByteLookupTable table = new ByteLookupTable(0, negative);
LookupOp op = new LookupOp(table, null);
filter(op);
}
void rotate() {
AffineTransform transform = AffineTransform.getRotateInstance(Math
.toRadians(5), image.getWidth() / 2, image.getHeight() / 2);
AffineTransformOp op = new AffineTransformOp(transform,
AffineTransformOp.TYPE_BILINEAR);
filter(op);
}
public void authors () {
final String ABOUT_TEXT =
"<html>" +
"Wielowątkowe przetwarzanie pliku graficznego<br><br>" +
"Program nakłada filtry na wczytany plik graficzny wykorzystując w tym celu wątki" +
"</html>";
JOptionPane.showMessageDialog(Operacje.this, ABOUT_TEXT);
}
private BufferedImage image;
// private BufferedImage lastImage;
}
Jeśli ktoś ma jakiś pomysł jak to skończyć, to niech pisze śmiało, jestem otwarty na wszelkie propozycje.