package FFT; import javax.swing.*; import javax.swing.border.BevelBorder; import javax.swing.event.MouseInputListener; import java.awt.*; import java.awt.event.*; /** * Bei diesem Applet soll die Diskrete Fouriertransformation und deren * Einsatz bei der Bildverarbeitung veranschaulicht werden. * Diese Klasse stellt die graphische Oberflaeche und die * Logistik fur das fft Applet bereit. Die Oberflaeche besteht aus * zwei Panels. Im oberen Bereich befindet sich das Operationpanel,in dem alle * Werkzeuge zu finden sind. Im zweiten Panel (fftViewer) sind die * Bilder zu sehen. Dies ist auch die eigentliche Arbeitsflaeche des * Benutzers. * * Zum programminternen Ablauf einer Bildmanipulation: * Wird vom Benutzer die Fouriertransformierte bearbeitet,so wird die Operation * zwecks visueller Darstellung * zunaechst an den iRPImage Objekten filteredAmplitude und filteredPhase * durchgefuehrt. Diese beiden iRPImage Objekte sind auf der Ober- * flaeche als Amplitude bzw. als Phase sichtbar. Damit die Operation dann * auch bei der Ruecktransformation wirksam wird, wird diese noch bei * den Objekten filteredImage1 und filteredImage2 durchgefuehrt. filteredImage1 * stellt den Realteil und filteredImage2 den Imaginaerteil der Fouriertransformation * dar. Beide sind doubleiRPImage Objekte und werden bei der * Ruecktransformation benoetigt. Dies sind allerdings nur Kopien * der Fouriertransformation,damit alle Aenderungen wieder rueckgaengig * gemacht werden koennen. Die Kopien werden angefertigt,wenn ein * neues Bild ausgewaehlt oder auf den reset-Button geklickt wird. * * @author Rene Iser, Behrang Karmimibabak, Simon Winkelbach */ public class fftApplet extends JApplet implements MouseInputListener{ // Die iRPImage Objekte sind fur die Manipulation der Bilder. // filteredAmplitude und filteredPhase sind fuer die Visuelle // darstellung von Betrag und Phase zustaendig. protected iRPImage A, B, C, D,filteredInputImage,filteredAmplitude; protected iRPImage filteredPhase; protected doubleiRPImage D1, D2, temp1, temp2, temp3, temp4; protected doubleiRPImage filteredImage1,filteredImage2; protected JPanel operationPanel,messagePanel; protected JPanel[] toolMainPanel,toolSubPanel; protected JDialog pictureDialog,toolDialog; protected fftViewer viewer; // Hier werden die Bilder untergebracht. protected JButton sample; //startet die Abtastung protected JButton clear; protected JButton cordSystem,choosePicture,chooseTool; protected JButton circleButton,rectButton,invCircButton,invRectButton,lineButton,pointPairButton; protected JButton[] pictureButtons; protected fft ft = new fft(); protected ImageWindow input,output,amplitude,phase; protected JLabel circleToolLabel,pointToolLabel,rectToolLabel; protected JLabel message1,message2,invCircToolLabel,invRecToolLabel,lineToolLabel; protected final String[] pictures={"Punkte","Clown","Face","box","Empty"}; protected final String[] tools={"circle","rect","inverse circle","inverse rect","line","points"}; protected final String[] sampling={"2","3","4","5","6","7","8","9","10","11","12"}; protected String plaf,imageToLoad; protected int startX,startY,endX,endY,width,height,radius; // Definition von Kreisen,linien,etc.. protected int sRate; // die Abtastrate protected ImageIcon dialogIcon; protected DialogImageProvider imgProv; protected Image[] dialogImg; protected String[] dialogImgNames; /** * Die boolschen Variablen sind fuer die diversen Fallunterscheidungen innerhalb * des Systems. line,rect usw. unterscheiden das ausgewaehlte Tool. * firstMousePress ist dazu da einen Startpunkt fuer die geometrischen Figuren * zu markieren. Diese wird immer dann auf 'false' gesetzt sobald zum ersten * Mal die mouseDragged-Methode aufgerufen wird(Bzw. wieder auf 'true' bei * mouseReleased). * Die Picture-Variablen unterscheiden welches bild gerade bearbeitet werden soll. */ boolean line,point,rect,circle,inverseRect,inverseCircle; boolean firstMousePress,cutedOut,chooseCordSystem; boolean amplitudePicture,inputPicture,outputPicture,phasePicture; public void init() { ////////////////////////////////////////////// line=false;point=false;rect=false;circle=true; inverseRect=false;inverseCircle=false; cutedOut=false; firstMousePress=true; chooseCordSystem=false; sRate=2; imgProv = new DialogImageProvider(); dialogImg = imgProv.getImages(); dialogImgNames = imgProv.getImageNames(); Image dialogImage = Toolkit.getDefaultToolkit().getImage(getClass().getResource("dialogIcon.gif")); dialogIcon=new ImageIcon(dialogImage); this.initializeStartImages(); this.initializeButtons(); this.initializeLabels(); this.initialzeDialog(); messagePanel=new JPanel(); messagePanel.setPreferredSize(new Dimension(220,50)); messagePanel.setBorder(BorderFactory.createEtchedBorder()); messagePanel.add(message1); messagePanel.add(message2); Dimension d = new Dimension(250,120); operationPanel = new JPanel(); operationPanel.setLayout(new FlowLayout(FlowLayout.LEFT,10,10)); operationPanel.setPreferredSize(d); operationPanel.setBorder(BorderFactory.createLineBorder(Color.GRAY)); operationPanel.add(choosePicture); operationPanel.add(chooseTool); operationPanel.add(sample); operationPanel.add(cordSystem); operationPanel.add(clear); operationPanel.add(messagePanel); viewer = new fftViewer(input,amplitude,phase,output); viewer.setLayout(new FlowLayout(FlowLayout.LEFT,10,15)); viewer.add(operationPanel); getContentPane().add(viewer); this.changeLookAndFeel(); this.initializeActionListeners(); operationPanel.addMouseMotionListener(this); operationPanel.addMouseListener(this); addMouseListener(this); addMouseMotionListener(this); } /** * Initialisierung der Dialogboxen,welche aufgerufen werden, * wenn man das Bild oder das Tool wechselt. */ public void initialzeDialog(){ JOptionPane picturePane = new JOptionPane(); pictureButtons=new JButton[dialogImg.length]; String buttonName; /* *Hier werden die Buttons zur Bildauswahl initialisiert. *In 'buttonName' wird der Name des zu ladenen Bildes gespeichert. *Hier wird davon ausgegangen, dass die kleinen Bilder fur die Icons *auf den Buttons auf '..Dialog.jpg' oder 'Dialog.gif' enden. *Daher auch die -10 in dem substring(..)- Aufruf. *Es ist Voraussetzung, dass das Iconbild und das grobe Bild, welches *hier geladen werden soll, dasselbe Dateiformat, also '.gif' oder 'jpg' *haben. */ for(int i=0;i1){ if(amplitudePicture){ filteredAmplitude.SetPixel(xPos+i,yPos+j,0); filteredImage1.SetPixel(xPos+i,yPos+j,0); filteredImage2.SetPixel(xPos+i,yPos+j,0); } else{ re=filteredImage1.GetPixel(xPos+i,yPos+j); im=filteredImage1.GetPixel(xPos+i,yPos+j); absolut= (Math.sqrt(re*re+im*im)); filteredImage1.SetPixel(xPos+i,yPos+j,absolut); filteredPhase.SetPixel(xPos+i,yPos+j,0); filteredImage2.SetPixel(xPos+i,yPos+j,0); } } } } } for (int i=0;i1){ filteredInputImage.SetPixel(xPos+i,yPos+j,0); } } } } for (int i=0;ia2) delta=-1; else delta=1; for(a = a1; a != a2+delta; a+=delta)//for(a = a1; a < a2; a++) { b = (double)b1 + ((double)(b2-b1)* ((double)a-(double)a1)/((double)a2-(double)a1)); //Die Abfrage ist zufallig wegen ArrayindexofBoundexception!! if(((int)b != A.sizeY) && ((int)a !=A.sizeX)) { if(amplitudePicture){ phase=Math.toRadians(filteredPhase.GetPixel((int)a,(int)b)); filteredImage1.SetPixel((int)a,(int)b,absolut*Math.cos(phase)); filteredImage2.SetPixel((int)a,(int)b,absolut*(-1)*Math.sin(phase)); } else{ re=filteredImage1.GetPixel((int)a,(int)b); im=filteredImage2.GetPixel((int)a,(int)b); absolut=Math.sqrt(re*re+im*im); filteredImage1.SetPixel((int)a,(int)b,absolut); filteredImage2.SetPixel((int)a,(int)b,0); } } } } else { if (b1>b2) delta=-1; else delta=1; for(b = b1; b != b2+delta; b+=delta) { a =(double)a1 + ((double)(a2-a1)* ((double)b-(double)b1)/((double)b2-(double)b1)); if((int)b != A.sizeY && ((int)a != A.sizeX)) { if(amplitudePicture){ phase=Math.toRadians(filteredPhase.GetPixel((int)a,(int)b)); filteredImage1.SetPixel((int)a,(int)b,absolut*Math.cos(phase)); filteredImage2.SetPixel((int)a,(int)b,absolut*(-1)*Math.sin(phase)); } else{ re=filteredImage1.GetPixel((int)a,(int)b); im=filteredImage2.GetPixel((int)a,(int)b); absolut=Math.sqrt(re*re+im*im); filteredImage1.SetPixel((int)a,(int)b,absolut); filteredImage2.SetPixel((int)a,(int)b,0); } } } } } /** * Die Methode setzt die Punkte in das Bild, wenn das Tool 'Punkt' * gewaehlt wurde. * Die Methode wird von mouseClicked(..) aufgerufen. * Bei der Amplitude wird der Betrag auf max gesetzt,bzw. bei * der Phase der Winkel auf 2*PI(oder 0) gesetzt und entsprechend * Real-und Imaginaerteil neu gesetzt. * @param x die x-Koordinate der Maus * @param y die y-Koordinate der Maus */ public void drawPoint(int x,int y){ int xPos=x; int yPos=y; double absolut,re,im; double phase; absolut= filteredAmplitude.GetPixel(filteredAmplitude.GetMax()); if(absolut==0){ absolut=255; } if(inputPicture){ filteredInputImage.SetPixel(xPos-10,yPos-160,255); setPixelMirror(xPos-10,yPos-160,filteredInputImage); manipulateInputImage(); } else if(amplitudePicture){ phase=filteredPhase.GetPixel(xPos-380,yPos-20); phase=Math.toRadians(phase); filteredAmplitude.SetPixel(xPos-380,yPos-20,255); setPixelMirror(xPos-380,yPos-20,filteredAmplitude); filteredImage1.SetPixel(xPos-380,yPos-20,absolut*Math.cos(phase)); filteredImage2.SetPixel(xPos-380,yPos-20,absolut*(-1)*Math.sin(phase)); setPixelMirror(xPos-380,yPos-20); manipulateTransformedImage(); } else if(phasePicture){ phase=Math.PI*2; re=filteredImage1.GetPixel(xPos-380,yPos-320); im=filteredImage2.GetPixel(xPos-380,yPos-320); absolut=Math.sqrt(re*re+im*im); filteredPhase.SetPixel(xPos-380,yPos-320,255); filteredImage1.SetPixel(xPos-380,yPos-320,absolut); filteredImage2.SetPixel(xPos-380,yPos-320,0); setPixelMirror(xPos-380,yPos-320); manipulateTransformedImage(); } } /** * Liefert den Radius des Kreises um den * Vektor (x,y). */ public int getRadius(int x,int y){ double r; r = Math.sqrt(x*x+y*y); return (int)r; } /** * Ist die Maus ueber dem Amplituden Bild? * @param x x-Koordinate des Punktes * @param y y-Koordinate des Punktes */ public boolean mouseOverAmplitudePicture(int x,int y){ if (x>=380 && x<380+B.sizeX && y>=20 && y<20+B.sizeY) return true; else return false; } /** * Ist die Maus ueber dem Eingangs Bild? * @param x x-Koordinate des Punktes * @param y y-Koordinate des Punktes */ public boolean mouseOverInputPicture(int x,int y){ if (x>=10 && x<10+A.sizeX && y>=160 && y<160+A.sizeY) return true; else return false; } /** * Ist die Maus ueber dem Phasen Bild? * @param x x-Koordinate des Punktes * @param y y-Koordinate des Punktes */ public boolean mouseOverPhasePicture(int x,int y){ if (x>=380 && x<380+C.sizeX && y>=320 && y<320+C.sizeY) return true; else return false; } /** * Ist die Maus ueber dem Ausgangs Bild? * Die Methode wird z.Z. nicht gebraucht. * @param x x-Koordinate des Punktes * @param y y-Koordinate des Punktes */ public boolean mouseOverOutputPicture(int x,int y){ if (x>=760 && x<760+C.sizeX && y>=160 && y<160+C.sizeY) return true; else return false; } /** *Ist der 'Point'-Operator aktiv,wird ein *Komplexes Punktpaar in das entsprechende Bild gesetzt. */ public void mouseClicked(MouseEvent e) { amplitudePicture = mouseOverAmplitudePicture(e.getX(),e.getY()); phasePicture=mouseOverPhasePicture(e.getX(),e.getY()); inputPicture=mouseOverInputPicture(e.getX(),e.getY()); int xPos=e.getX(); int yPos=e.getY(); if(point) drawPoint(xPos,yPos); } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mousePressed(MouseEvent e) { } /** * FirstMousePress wird auf 'true' gesetzt um ein * erneutes Zeichnen zu ermoeglichen. Dann wird * die cut-Methode aufgerufen,welche die Operation * durchfuehrt. */ public void mouseReleased(MouseEvent e){ firstMousePress=true; /* * Mit den geschachtelten if-Abfragen wird sichergestellt,dass * der Radius des Kreises,bzw. das Rechteck nicht ueber den Rand * des Bildes hinausgeht. * Die Abfrage startX>0.. ist noetig,da bei einem mouse click diese * Methode ebenfalls aufgerufen wird. Wird z.b. irgendwo eine Linie * eingezeichnet,dann der reset-button gedrueckt und anschiebend * wieder irgendwo ins Bild geklickt wird die alte Linie nochmal * eingezeichnet,da sich die Variablen startX,startY etc. noch * nicht veraendert haben. Dies wird mit dieser Abfrage verhindert,da * startX bzw. startY am Ende auf null gesetzt werden. */ if(startX>0 && startY>0){ if(!(point || line)){ if(amplitudePicture){ if(startX-380-radius >=0 && startX-380+radius=0 && startY-20+radius=0 && startX-380+radius=0 && startY-320+radius=0 && startX-10+radius=0 && startY-160+radius=0 && startX-380+radius=0 && startY-20+radius=0 && startX-380+radius=0 && startY-320+radius=0 && startX-10+radius=0 && startY-160+radius