Swing Bildbearbeitung unter Java

mac21

Aktives Mitglied
Hallo zusammen,

Wer meine diversen Threads mal verfolgt hat (oder falls diese ihn im Traum verfolgt haben) weiß, dass ich ein OCR-Programm für Fahrzeugscheine entwickelt habe.

KEINE SORGE, es geht jetzt. Dazu brauche ich keine Hilfe ;)

Beinahe...
Mein Programm ist darauf ausgelegt, dass nur Bilder (als BMP, JPG etc) in der genauen Größe des Fahrzeugscheins funktionieren. Das Bildverhältnis (x:y) ist ziemlich genau 2:1

Nun liegen den Kunden aber oft Scans im A4-Format vor.
Logisch, da diese die Fahrzeugscheine in den Scanner werfen und "Scannen"-Drücken.

Somit muss manuell der "weiße Rand" um den eigentlichen Schein weggeschnitten werden.
Endkunden + Paint = chaos.

Nach diesem langen Text nun endlich die Aufgabenbeschreibung:

Ich würde gern ein Programm schreiben, mit dem man die Bilder zuschneiden kann, indem man die Grenzen des Fahrzeugscheins bestimmt. Wie beim Rechteckauswahl-Tool in paint, photoshop etc.

Bei schlechten Scans sind die Kanten des Scheins kaum vom "Hintergrund" (also weiße Fläche / Scannerabdeckung) zu unterscheiden, weshalb hingezoomt werden muss.

Ihr könnt euch das so vorstellen wie in Photoshop:
Es liegt eine Bearbeitungsfläche vor, in der ich rein- und rauszoomen können will.
Beim Reinzoomen brauche ich evtl. Scrollbars.

Nun kommen meine Fragen:

- Wie realisiere ich das "zoomen"? Per Google kam ich auf die Idee: vergrößere das BufferedImage ( dann musst du aber einen Faktor anpassen: Größe Bilddatei in Pixel - Größe Bufferedimage in Pixel)
Gibt es denn keine einfachere "Zoomfunktion" für JPanels/JFrames?
- Wie könnte ich das Auswahlrechteck implementieren? Einfach an Rectangle2D? Ich hätte gerne an den Ecken und in der Mitte jeder Kante einen Nippel zum vergrößeren/verkleinern dieses Rechteckts.
 

Thallius

Top Contributor
Blöde Frage aber die Größe und das Aussehen eines Fahrzeugscheins sind doch genormt. Du hast ein OCR Programm geschrieben, dass dir die Inhalte ausliest. Was hindert dich alsio jetzt daran einen beliebigen fixen Text auf dem A4 Blatt zu finden und diesen dann als Fixpunkt zu nehmen wo alles andere steht?

Gruß

Claus
 

mac21

Aktives Mitglied
Danke für eure Antworten!

@androbin: wie meinst du das? Die Dichte bestimmen?

@Thallius: Die Scheine liegen teils um 90, 180 oder 270 Grad verdreht vor.
Mein Programm geht ja von einer fixen Größe aus und "sucht" somit die benötigten Schlüsselfelder in prozentualer Abhängigkeit vom Gesamtbild.
Auch durch die Verdrehung muss das Bild manuell angepasst werden..

Nun kam mir ein Problem dazwischen:

Mein GUI sieht manchmal anders aus... ich beschreibe es im Anhang mal mit Bildern,
hier der Code

Java:
package de.systeccomputer.tools;

import java.awt.Color; 
import java.awt.Dimension;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;

public class resizeFrame {
	
	JFrame frame;
	JMenuBar menubar;
	JMenu menu1;
	JMenuItem menuitem1;
	JMenu menu2;
	JMenuItem menuitem2;
	JScrollPane scrollpane;
	
	public resizeFrame() {
		
		init();
		createMenu();
		addListeners();		
	}
	
	public void init() {
		
		frame = new JFrame("resizeFrame");
		frame.setLayout(null);
		frame.setDefaultCloseOperation(2);
		frame.getContentPane().setBackground(Color.RED);
		frame.setBounds(100,100,1200,800);
		frame.setMinimumSize(new Dimension(800,500));
		frame.setVisible(true);
		
		JTextArea a = new JTextArea(5, 30);
		
		scrollpane = new JScrollPane(a, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		scrollpane.setBounds(50,50,frame.getContentPane().getWidth()-100,frame.getContentPane().getHeight()-100);		
		scrollpane.setVisible(true);
		frame.add(scrollpane);
		
	}
	
	public void createMenu() {
		
		menubar = new JMenuBar();
		
		menu1 = new JMenu("a menu");
		menuitem1 = new JMenuItem("long button");
		menu1.add(menuitem1);		
		menubar.add(menu1);
		
		menu2 = new JMenu("one more");
		menuitem2 = new JMenuItem("loooonger button");
		menu2.add(menuitem2);		
		menubar.add(menu2);
		
		frame.setJMenuBar(menubar);		
		
	}
	
	public void addListeners() {
		frame.addComponentListener(new ComponentListener() {
			   public void componentHidden(ComponentEvent e) {
			   }
			   public void componentMoved(ComponentEvent e) {
			   }
			   public void componentResized(ComponentEvent e) {
				   scrollpane.setBounds(50,50,frame.getContentPane().getWidth()-100,frame.getContentPane().getHeight()-100);
			   }
			   public void componentShown(ComponentEvent e) {
			   }
			});
		
		
	}
	
	public static void main(String[] args) {
		new resizeFrame();
	}

}

Hier die Bilder: Anhang anzeigen 7067
Anhang anzeigen 7068
 

Thallius

Top Contributor
Also trotzdem glaube ich nicht das es besonders schwer ist Anhand der Schrift zu erkennen wo sich der Schein befindet und wie er gedreht ist. Ich denke ich würde da eine automatische Erkennung hinbekommen

Gruß

Claus
 

mac21

Aktives Mitglied
Hallo Claus,

wäre das ein Ansatz:
Ich nehme einen Anhaltspunkt, zB. Anhang anzeigen 7083
Wenn dieser nicht gefunden wurde wird das Bild um 90 Grad gedreht,
usw. Wenn nach 3 Mal Drehen nichts gefunden wurde, öffnet sich ein Fenster zur manuellen Korrektur.

Also suche ich quasi ein Subimage in einem Image?
Nur habe ich die Angst, dass der Schein wenige Grad verdreht vorliegt.
Falls dem so ist finde ich den Anhaltspunkt bestimmt, jedoch kann ich dann nicht vorgeben:
"Das Feld A.1 befindet sich 12% (von der Gesamtbreite) weiter rechts und auf gleicher Höhe."
Durch die Drehung ist dort vielleicht nur das halbe Feld zu sehen...

Die Feldbezeichner auf dem Schein (A, B, P.1 etc.) kann ich nicht als Anhaltspunkt nehmen, da diese auch bei manueller Festlegung des Erkennungsraums nicht (richtig) erkannt werden.
 

Thallius

Top Contributor
Ich habe mir mal gerade meinen Fahrzeugschein angesehen. Bei mir sind die Felder für die Daten ja immer abwechselnd weiß und grün hinterlegt. Könnte man da nicht ansetzen? Sagen wir du untersuchst einen Bereich mit XxX Pixeln der einen gewissen maximalen durchschnittlichen Grünwert Y aller Pixel X in dem Beriech hat. Wenn du so einen gefunden hast, dann gehst du waagerecht und senkrecht weiter und findest heraus wo dieser Bereich dann anfängt weniger grün zu werden. Daran müßte man erkennen können wie genau das Schein ausgerichtet ist oder? Das Ganze muss natürlich ein wenig mit Try and Error ausprobiert werden bis du brauchbare Werte für die Größe Deines Bereiches und dem Farbwert hast nach dem du suchst.

Verständlich?

Gruß

Claus
 

mac21

Aktives Mitglied
Hallo Thallius,

vielen Dank für den Vorschlag.
Einen ähnlichen Ansatz hatte ich auch schon verfolgt.
Jedoch wurde unserem Kunden die Anforderung gestellt, die Fahrzeugscheine in s/w oder grau zu übermitteln...

Und das ganze farbtechnisch zu behandeln fand ich als unnötig/fehleranfällig,
da verschiedene Scanner verschiedene Ergebnisse abliefern.

Ich danke dir vielmals für deinen Vorschlag aber würde auf die ganze Farben-Erkennen-Vorgehensweise verzichten.
 

Foxei

Bekanntes Mitglied
Hi diese Methode ist ursprünglich mal dafür da gewesen Bild farben zu manipulieren sie geht alle pixel durch und liefert dir die RGBA anteile. Mein Ansatz wäre jetzt das du bei deinem Bild diese RGBA anteile abspeicherst in einer Liste. Und dann einfach von außen nach innen mit Rechtecken vor gehst und der letzt rechteckige Ramen wo noch alle Pixel weiß sind ist dann dein Auswahl Bereich.
Java:
public void test(BufferedImage img) throws IOException{
		int width=img.getWidth();
		int height=img.getHeight();
		
		for(int y=0;y<height;y++){
			for(int x=0;x<height;x++){
				int rgb=img.getRGB(x, y);
				int alpha = (rgb >> 24) & 0xFF;
	            int r = (rgb >> 16) & 0xFF;
	            int g = (rgb >> 8) & 0xFF;
	            int b = (rgb) & 0xFF;
	            
	            if(r!=255&&g!=255&&b!=255){
	            	r=30;b=30;g=30;
	            	img.setRGB(x, y, (int)(alpha<<24|r<<16|g<<8|b));
	            }
	            
			}
		}
		
	}

LG Simon
 

mac21

Aktives Mitglied
Hallo Foxei,

danke für deinen Denkanstoß. Ich glaube ich habe das verstanden :p
Beipsiel: Bild mit 1000x1000 Pixel.
Pseudo:
Code:
- Zeichne Rechteck von Punkt P1(0/0) bis Punkt P2(1000/1000)
- Alle Pixel weiß? 
Nein: Bild gefunden
JA: Zeichne Rechteck von Punkt P1(1/1) bis Punkt P2(999/999)
usw.

Probleme, die ich erkenne:
Somit wird mein Rechteck in jeden Durchgang um 1 Pixel pro Seite kleiner.
D.h. x von P und y von Punkt P sind jeden Durchlauf gleich groß. 
Somit würde ein Fahrzeugschein mit den Koordinaten
P1(223/247)
und P2(453/898) gar nicht gefunden werden...
 
Außerdem:
Befindet sich "Dreck" im Scanner oder wird der Scannerdeckel nicht KOMPLETT Weiß gescannt so wird das Rechteck nicht nur Weiße Pixel enthalten...
 

Foxei

Bekanntes Mitglied
Nicht ganz das was ich meinte aber ich glaube ich habe mich ungenau aus gedrückt. :/ Ich mache es einmal von Oben und Unten bzw von Rechts nach Links und bekomme die Bounds des Bildes inklusive Position. Dieses kleine Programm macht genau das mit der "test.jpeg" die im selben Ordner liegt. Und zeigt dir das Ergebnis auf einer Frame an.

Achtung Verarbeitung dauert bis zu 10 sec!!!
NEEDED_HITS bestimmt die anzahl an nicht weißen Pixeln es geben muss damit er die Zeile als zum Bild gehörig erkennt.
Der Code ist nicht sauber geschrieben nur mal eben so geschrieben bitte verzeiht.
Java:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class BildAusschnitt {
	private int NEEDED_HITS=400;
	private HashMap<Point, Color> pixel=new HashMap<Point, Color>();
	private BufferedImage img;
	public static void main(String[] args) {
		new BildAusschnitt();
	}
	public BildAusschnitt() {
		
		try {
			img=ImageIO.read(new File("test.jpeg"));
			
		} catch (IOException e) {
			e.printStackTrace();
			return;
		}
		readPixel(img);
		int y=getYTop();
		int height=getYBot()-y;
		int x=getXLeft();
		int width=getXRight()-x;
		
		System.out.println("Position: "+x+"|"+y+" Size: "+width+"|"+height);
		
		JFrame frame=new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.add(new JLabel(new ImageIcon(img.getSubimage(x, y, width, height))),BorderLayout.CENTER);
		frame.pack();
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
	}
	public int getXLeft(){
		int firstHit=-1;
		for(int x=0;x<img.getWidth();x++){
			int hits=0;
			for(int y=0;y<img.getHeight();y++){
				Color color=pixel.get(new Point(x,y));
				
				if(color!=null){
					hits++;
				}	
			}
			if(hits>=NEEDED_HITS){
				firstHit=x;
				break;
			}
		}
		return firstHit;
	}
	public int getXRight(){
		int firstHit=-1;
				
				for(int x=img.getWidth();x>=0;x--){
					int hits=0;
					for(int y=0;y<img.getHeight();y++){
						Color color=pixel.get(new Point(x,y));
						if(color!=null){
							hits++;
						}	
					}
					if(hits>=NEEDED_HITS){
						firstHit=x;
						break;
					}	
				}
				return firstHit;
			}
	public int getYTop(){
		int firstHit=-1;
		
		for(int y=0;y<img.getHeight();y++){
			int hits=0;
			for(int x=0;x<img.getWidth();x++){
				Color color=pixel.get(new Point(x,y));
				
				if(color!=null){
					hits++;
				}	
			}
			if(hits>=NEEDED_HITS){
				firstHit=y;
				break;
			}
				
		}
		return firstHit;
	}
	public int getYBot(){
		int firstHit=-1;
		
		for(int y=img.getHeight();y>=0;y--){
			int hits=0;
			for(int x=0;x<img.getWidth();x++){
				Color color=pixel.get(new Point(x,y));
				
				if(color!=null){
					hits++;
				}	
			}
			if(hits>=NEEDED_HITS){
				firstHit=y;
				break;
			}
				
		}
		return firstHit;
	}
	public void readPixel(BufferedImage img){
		int width=img.getWidth();
		int height=img.getHeight();
 
		for(int y=0;y<height;y++){

			for(int x=0;x<width;x++){
				int rgb=img.getRGB(x, y);
				int alpha = (rgb >> 24) & 0xFF;
	            int r = (rgb >> 16) & 0xFF;
	            int g = (rgb >> 8) & 0xFF;
	            int b = (rgb) & 0xFF;
 
	            if(r<230&&g<230&&b<230){
	            	Color color=new Color(r, g, b, alpha);
	            	Point point=new Point(x,y);
	            	pixel.put(point, color);
	            }
 
			}
		}
	}
}
 
Zuletzt bearbeitet:

Lemao

Mitglied
hier meine Idee bezüglich Auswahlrechteck. ist eigentlich simpel, man benötigt Mauslistener, die die Veränderung der Rechteckpunkte erfassen und zeichnet dann wiederholt ein normales Rechteck. anschließend kann man die finalen Eckpunkte für das Zoomen verwerten

Java:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class ZoomRectangle extends JFrame {

	ZoomArea zoomArea;

	public ZoomRectangle() {
		setFrameDefaults();
		createZoomArea();
	}

	private void createZoomArea() {
		zoomArea = new ZoomArea();
		add(zoomArea);
	}

	private void setFrameDefaults() {
		setVisible(true);
		setBounds(200, 200, 600, 600);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
	}

	public static void main(String[] args) {
		new ZoomRectangle();
	}

	class ZoomArea extends JPanel {

		int xPressed, yPressed;
		int xFrom, yFrom;
		int xTo, yTo;
		Marker[] marker = new Marker[8];
		final int LEFT_TOP = 0;
		final int RIGHT_TOP = 1;
		final int RIGHT_BOTTOM = 2;
		final int LEFT_BOTTOM = 3;
		final int TOP = 4;
		final int RIGHT = 5;
		final int BOTTOM = 6;
		final int LEFT = 7;

		public ZoomArea() {
			setLayout(null);
			provideMarker();
			addMouseListeners();
		}

		private void provideMarker() {
			for (int i = 0; i < marker.length; i++) {
				marker[i] = new Marker();
				add(marker[i]);
			}
		}

		private void addMouseListeners() {
			addZoomAreaListeners();
			addMarkerListeners();
		}

		private void addZoomAreaListeners() {
			addMouseListener(new MouseAdapter() {
				@Override
				public void mousePressed(MouseEvent e) {
					hideMarker();
					xPressed = e.getX();
					yPressed = e.getY();
				}

				@Override
				public void mouseReleased(MouseEvent e) {
					showMarker();
					locateMarker();
				}
			});
			addMouseMotionListener(new MouseMotionAdapter() {
				@Override
				public void mouseDragged(MouseEvent e) {
					int xCurrent = e.getX();
					int yCurrent = e.getY();
					xFrom = Math.min(xPressed, xCurrent);
					xTo = Math.max(xPressed, xCurrent);
					yFrom = Math.min(yPressed, yCurrent);
					yTo = Math.max(yPressed, yCurrent);
					repaint();
				}
			});
		}

		private void addMarkerListeners() {
			for (int i = 0; i < marker.length; i++) {
				final int j = i;
				marker[i].addMouseListener(new MouseAdapter() {
					@Override
					public void mousePressed(MouseEvent e) {
						hideMarker();
					}

					@Override
					public void mouseReleased(MouseEvent e) {
						showMarker();
						locateMarker();
					}

					@Override
					public void mouseEntered(MouseEvent e) {
						marker[j].setBackground(Color.blue);
					}

					@Override
					public void mouseExited(MouseEvent e) {
						marker[j].setBackground(Color.red);
					}
				});
				marker[i].addMouseMotionListener(new MouseMotionAdapter() {

					@Override
					public void mouseDragged(MouseEvent e) {
						Point markerLocation = ((JLabel) e.getSource()).getLocation();
						int xMarkerLocation = (int) markerLocation.getX();
						int yMarkerLocation = (int) markerLocation.getY();
						int xCurrent = xMarkerLocation + e.getX();
						int yCurrent = yMarkerLocation + e.getY();
						switch (j) {
							case LEFT_TOP:
								xFrom = xCurrent;
								yFrom = yCurrent;
								break;
							case RIGHT_TOP:
								yFrom = yCurrent;
								xTo = xCurrent;
								break;
							case RIGHT_BOTTOM:
								xTo = xCurrent;
								yTo = yCurrent;
								break;
							case LEFT_BOTTOM:
								xFrom = xCurrent;
								yTo = yCurrent;
								break;
							case TOP:
								yFrom = yCurrent;
								break;
							case RIGHT:
								xTo = xCurrent;
								break;
							case BOTTOM:
								yTo = yCurrent;
								break;
							case LEFT:
								xFrom = xCurrent;
								break;
						}
						repaint();
					}

				});
			}
		}

		private void locateMarker() {
			int xMiddle = xFrom + (xTo - xFrom) / 2;
			int yMiddle = yFrom + (yTo - yFrom) / 2;
			marker[LEFT_TOP].setLocation(xFrom - 5, yFrom - 5);
			marker[RIGHT_TOP].setLocation(xTo - 5, yFrom - 5);
			marker[RIGHT_BOTTOM].setLocation(xTo - 5, yTo - 5);
			marker[LEFT_BOTTOM].setLocation(xFrom - 5, yTo - 5);
			marker[TOP].setLocation(xMiddle - 5, yFrom - 5);
			marker[RIGHT].setLocation(xTo - 5, yMiddle - 5);
			marker[BOTTOM].setLocation(xMiddle - 5, yTo - 5);
			marker[LEFT].setLocation(xFrom - 5, yMiddle - 5);
		}

		private void hideMarker() {
			for (int i = 0; i < marker.length; i++) {
				marker[i].hide();
			}
		}

		private void showMarker() {
			for (int i = 0; i < marker.length; i++) {
				marker[i].show();
			}
		}

		@Override
		protected void paintComponent(Graphics g) {
			super.paintComponent(g);
			g.drawRect(xFrom, yFrom, xTo - xFrom, yTo - yFrom);
		}

		class Marker extends JLabel {

			public Marker() {
				setBackground(Color.red);
				setOpaque(true);
			}

			public void hide() {
				setSize(0, 0);
			}

			public void show() {
				setSize(10, 10);
			}
		}

	}

}
 
Zuletzt bearbeitet:

mac21

Aktives Mitglied
Hallo ihr beiden!
Diese beiden Lösung sind ja der Hammer! genau so habe ich es mir vorgestellt,
und das sieht ja nicht einmal sehr schwer aus.
Leider fehlte mir das Denken und das Konzept...

Da die Sache mit dem Bildausschnitt super funktioniert, brauche ich die "ZoomRectangle"-Klasse EIGENTLICH nicht.
Nun war das Problem: ich kann Fahrzeugscheine mit (übertrieben!!) 100px breite oder mit (übertrieben!!) 10.000px breite haben. Also ist es schwer, dem Programm die "needed_hits" vorzugeben. (evtl. prozentual berechnen...)

Ich lasse die Scheine mit der Bildausschnittklasse von Foxei finden, nur zeige ich sie nicht in einem Frame an, sondern schreibe sie per "ImageIO.write(...)" in eine eigene Datei.

Das habe ich diverse Mal getestet:
-OriginalBild ist bereits auf Größe des Fahrzeugscheins zugeschnitten (per hand, durch mich)
-dieses bild habe ich inmitten einer weißen Fläche freigestellt
-die "Bildausschnitt"-klasse erkannte die Fahrzeugscheine exakt und noch genauer als ich!

Damit Lemao sich die Arbeit nicht umsonst machte:
Sobald der Vorgang "zu lang" dauert, oder sobald weniger "needed_hits" gefunden wurden, so öffnet sich ein Frame zum manuellen Zuschneiden des Bildes per "zoomRectangle".

Habe eure Antworten als TOP! markiert!
Sobald ich mit diesem ganzen Projekt fertig bin, werde ich es wohl auf GIT hochladen und hier verlinken,
damit alle was von meiner Inkompetenz und eurer Genialität haben!

Ich dachte ehrlich gesagt nicht, dass ich dieses ganze OCR-Projekt jemals fertig stellen kann.


Ein fettes DANKE! an Alle !
 

mac21

Aktives Mitglied
Das einzige, was ich nicht so ganz nachvollziehen kann ist die "readPixel()"-Methode.

Eigentlich gehts nur um den Abschnitt
Java:
int rgb=img.getRGB(x, y);
int alpha = (rgb >> 24) & 0xFF;
int r = (rgb >> 16) & 0xFF;
int g = (rgb >> 8) & 0xFF;
int b = (rgb) & 0xFF;
 
if(r<230&&g<230&&b<230){
Color color=new Color(r, g, b, alpha);
Point point=new Point(x,y);
pixel.put(point, color);
}

Das mit dem Addieren der Hexwerte (FF ist ja 255) nach dem bitweisen verschieben um 24, 16 oder 8 stellen verstehe ich nicht.
Könnte mir das bitte jemand erklären?
Vielen Dank
 

Foxei

Bekanntes Mitglied
Ja das ist so eine Sache :D ich habe keine Ahnung wie das geht :/ eigentlich bin ich Software Entwickler mit Spezialisierung auf Swing Arbeitsoberflächen und Programm Algorithmen. Ich nehme sowas immer hin und arbeite damit aber warum das so ist kann ICH dir nicht sagen. Vielleicht ist jemand von den anderen so frei und erkläre uns beiden dass :D
 

Foxei

Bekanntes Mitglied
Und zu dem mit den Needed Pixeln ist ganz einfach. Du musst die zahl direkt am Anfang neu setzen.
Java:
readPixel(img);
		NEEDED_HITS=img.getWidth()/100*20;
		System.out.println("Needed Pixel: "+NEEDED_HITS);
		int y=getYTop();
		int height=getYBot()-y;
		int x=getXLeft();
Das hier wären z.b. 20 % der breite des Bildes.

LG Foxei
 

Lemao

Mitglied
11111111 11111111 11111111 11111111

so sieht eine integer Zahl aus, 4 8-bit Blöcke. mit der bitweisen Verschiebung um 24, 16, 8 oder gar nicht lotse ich immer einen der Blöcke ganz nach rechts. und so sieht 0xFF in Bitschreibweise aus:

11111111

wird die integer Zahl damit &-verknüpft bleibt von ihr nur das stehen was jeweils ganz nach rechts geschoben wurde, alles andere wird genullt. man liest damit also jeden der Blöcke wie eine separate Zahl. die jeweils für den rot, blau, grün und alpha Wert steht
 

mac21

Aktives Mitglied
Lemao, vielen Dank für deine Antwort!

Das Verknüpfen mit "&" war ja das mit der "bool'schen Algebra" ?
Logik, das ist die Lösung :D
habe verstanden!
Dezimal 77 = 01001101
0xFF = 11111111
--> "&" gibt an allen Bitstellen 1, wo beide Werte eine 1 haben. Ist nur eine Stelle 0 (also im Integer, 0xFF hat ja nur einsen), so wird auch eine 0 zurückgegeben.

und da "vor" dem 0xFF nur nullen stehen, werden alle Bits außer die letzten 8 "weggeschnitten".

Habe erst gestern meine Abschlussprüfung geschrieben, aber die "Bool'sche Algebra" hatten wir im 2. Lehrjahr schon.
Argh ich hätts wissen müssen.

Vielen Dank!
 

mac21

Aktives Mitglied
@Foxei:
Ich habe die Methode von dir mal folgendermaßen umgesetzt:
In einem JFrame habe ich eine Menüleiste, mit Buttons "öffnen, speichern, speichern unter, cut" (letztere wird natürlich noch umbenannt)
Sobald ich ein Bild geöffnet habe, kann ich auf den Button "cut" klicken,
dann startet dein Vorgang zum "autom. Erkennen" des Fahrzeugscheins.
Diese dauert, aufgrund der hohen Pixelzahl, aber bei einer 4,1mb-Datei (was nicht sehr viel ist) schon mehrere Minuten...
Sollte mal jemand auf die Idee kommen ein ".tiff" mit 600 oder 1200 DPI einzulesen, dann kann er gleich Feierabend machen und gehen. Und der Java-Heap-Space von 1GB läuft auch schnell voll..
Hat jemand nen Tipp, wie ich das ganze beschleunigen kann, bzw. den Heapspace entlasten kann?

Danke, hier die Codes
ResizeFrame.java
Java:
package de.systeccomputer.tools;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.filechooser.FileNameExtensionFilter;

public class resizeFrame {

	JFrame frame;
	JMenuBar menubar;
	JMenu menu1;
	JMenuItem openItem;
	JMenuItem saveItem;
	JMenuItem saveAsItem;
	JMenu menu2;
	JMenuItem cutItem;
	JScrollPane scrollpane;
	ImagePanel img;
	JFileChooser fc;
	BufferedImage orig;
	File file;
	String extension;

	public resizeFrame() {

		init();
		createMenu();
		addListeners();
		frame.setVisible(true);
	}

	public void init() {

		frame = new JFrame("resizeFrame");
		frame.setLayout(null);
		frame.setDefaultCloseOperation(2);
		frame.getContentPane().setBackground(Color.RED);
		frame.setBounds(100, 100, 1200, 800);
		frame.setMinimumSize(new Dimension(800, 500));

		img = new ImagePanel(null);
		scrollpane = new JScrollPane(img,
				ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
				ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
		scrollpane.setBounds(50, 50, frame.getContentPane().getWidth() - 100,
				frame.getContentPane().getHeight() - 100);
		scrollpane.setVisible(true);
		frame.add(scrollpane);

		fc = new JFileChooser();
		fc.setAcceptAllFileFilterUsed(false);
		fc.setFileHidingEnabled(true);
		fc.setCurrentDirectory(fc.getFileSystemView().getParentDirectory(
				new File("C:\\")));
		fc.setMultiSelectionEnabled(false);
		fc.addChoosableFileFilter(new FileNameExtensionFilter(
				"BMP, GIF, JPG/JPEG, PNG, TIF/TIFF", "bmp", "jpeg", "jpg", "png", "gif",
				"tif", "tiff"));
		
	}

	public void createMenu() {

		menubar = new JMenuBar();

		menu1 = new JMenu("Datei");
		openItem = new JMenuItem("Öffnen...");
		menu1.add(openItem);
		saveItem = new JMenuItem("Speichern...");
		saveItem.setEnabled(false);
		menu1.add(saveItem);
		saveAsItem = new JMenuItem("Speichern unter...");
		saveAsItem.setEnabled(false);
		menu1.add(saveAsItem);
		menubar.add(menu1);

		menu2 = new JMenu("Bearbeiten");
		cutItem = new JMenuItem("Cut");
		cutItem.setEnabled(false);
		menu2.add(cutItem);
		menubar.add(menu2);

		frame.setJMenuBar(menubar);

	}

	public void open(File file) {
		try {
			orig = ImageIO.read(file);
		} catch (Exception e) {}
		
		if(orig != null) {
			img.setImage(orig);
			extension = file.getName().substring(file.getName().lastIndexOf('.')+1, file.getName().length());
			saveItem.setEnabled(true);
			saveAsItem.setEnabled(true);
			cutItem.setEnabled(true);
		}
		// BufferedImage orig = ImageIO.read(new
		// File("C://OCR TEST//test.jpg"));
	}
	
	public void cut() {
		if(orig != null) {
			orig = BildAusschnitt.cut(orig);
			img.setImage(orig);
			frame.repaint();
		}
	}
	
	public void save() {
		try{
			ImageIO.write(orig, extension, file);
		}catch(Exception e){}
	}
	
	public void saveAs(File asFile) {
		try{
			ImageIO.write(orig, extension, asFile);
		}catch(Exception e){}        
	}

	public void addListeners() {
		frame.addComponentListener(new ComponentListener() {
			public void componentHidden(ComponentEvent e) {
			}

			public void componentMoved(ComponentEvent e) {
			}

			public void componentResized(ComponentEvent e) {
				scrollpane.setBounds(50, 50,
						frame.getContentPane().getWidth() - 100, frame
								.getContentPane().getHeight() - 100);
			}

			public void componentShown(ComponentEvent e) {
			}
		});

		openItem.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				int returnVal = fc.showOpenDialog(frame);

				if (returnVal == JFileChooser.APPROVE_OPTION) {
					file = fc.getSelectedFile();
					open(file);
					frame.repaint();
				}
			}

		});
		
		saveItem.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				save();
			}

		});
		
		saveAsItem.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				int returnVal = fc.showSaveDialog(frame);

				if (returnVal == JFileChooser.APPROVE_OPTION) {
					file = fc.getSelectedFile();
					saveAs(file);
				}
			}

		});
		
		cutItem.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				cut();
			}

		});
	}

	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				try {
					UIManager.setLookAndFeel(UIManager
							.getSystemLookAndFeelClassName());
					new resizeFrame();
				} catch (Exception e) {
				}
			};

		});
	}
}

ImagePanel.java
Java:
package de.systeccomputer.tools;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;

import javax.swing.JPanel;

public class ImagePanel extends JPanel {
	
	private BufferedImage image = null;

	public ImagePanel(BufferedImage image) {
		
		if(image != null) {
			setImage(image);
		}	    
	}
	
	public void setImage(BufferedImage orig) {
		this.image = orig;
	}
	
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		if (image != null) {
			g.drawImage(image, 0, 0, this.getWidth(), this.getHeight(), this);
		}
	}

}

BildAusschnitt.java
Java:
package de.systeccomputer.tools;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class BildAusschnitt {

	private static int NEEDED_HITS_X;
	private static int NEEDED_HITS_Y;
	private static HashMap<Point, Color> pixel = new HashMap<Point, Color>();
	private static BufferedImage img;

	public static BufferedImage cut(BufferedImage orig) {
		img = orig;
		NEEDED_HITS_X = 10; //img.getWidth() / 4;
		NEEDED_HITS_Y = 10; //img.getHeight() / 4;

		readPixel(img);
		int y = getYTop();
		int height = getYBot() - y;
		int x = getXLeft();
		int width = getXRight() - x;

		System.out.println("Position: " + x + "|" + y + " Size: " + width + "|"
				+ height);

		img = img.getSubimage(x, y, width, height);
		return img;
	}
	
	public static int getXLeft() {
		int firstHit = -1;

		for (int x = 0; x < img.getWidth(); x++) {
			int hits = 0;

			for (int y = 0; y < img.getHeight(); y++) {
				Color color = pixel.get(new Point(x, y));

				if (color != null) {
					hits++;
				}
			}
			if (hits >= NEEDED_HITS_Y) {
				firstHit = x;
				break;
			}
		}
		return firstHit;
	}

	public static int getXRight() {
		int firstHit = -1;

		for (int x = img.getWidth(); x >= 0; x--) {
			int hits = 0;
			for (int y = 0; y < img.getHeight(); y++) {
				Color color = pixel.get(new Point(x, y));
				if (color != null) {
					hits++;
				}
			}
			if (hits >= NEEDED_HITS_Y) {
				firstHit = x;
				break;
			}
		}
		return firstHit;
	}

	public static int getYTop() {
		int firstHit = -1;

		for (int y = 0; y < img.getHeight(); y++) {
			int hits = 0;

			for (int x = 0; x < img.getWidth(); x++) {
				Color color = pixel.get(new Point(x, y));

				if (color != null) {
					hits++;
				}
			}
			if (hits >= NEEDED_HITS_X) {
				firstHit = y;
				break;
			}
		}
		return firstHit;
	}

	public static int getYBot() {
		int firstHit = -1;

		for (int y = img.getHeight(); y >= 0; y--) {
			int hits = 0;

			for (int x = 0; x < img.getWidth(); x++) {
				Color color = pixel.get(new Point(x, y));

				if (color != null) {
					hits++;
				}
			}
			if (hits >= NEEDED_HITS_X) {
				firstHit = y;
				break;
			}
		}
		return firstHit;
	}

	public static void readPixel(BufferedImage img) {
		int width = img.getWidth();
		int height = img.getHeight();

		for (int y = 0; y < height; y++) {

			for (int x = 0; x < width; x++) {
				int rgb = img.getRGB(x, y);
				int alpha = (rgb >> 24) & 0xFF;
				int r = (rgb >> 16) & 0xFF;
				int g = (rgb >> 8) & 0xFF;
				int b = (rgb) & 0xFF;

				if (r < 230 && g < 230 && b < 230) {
					Color color = new Color(r, g, b, alpha);
					Point point = new Point(x, y);
					pixel.put(point, color);
				}
			}
		}
	}
}

Nun habe ich ein Bild:
Anhang anzeigen 7164
 
Zuletzt bearbeitet:
Ähnliche Java Themen
  Titel Forum Antworten Datum
H kleine Bildbearbeitung AWT, Swing, JavaFX & SWT 3
V Applet mit Bildbearbeitung AWT, Swing, JavaFX & SWT 3
T bildbearbeitung AWT, Swing, JavaFX & SWT 3
ToNyXXL Bildbearbeitung: Ist Java zu schlecht? oO AWT, Swing, JavaFX & SWT 12
P Tool für Bildbearbeitung AWT, Swing, JavaFX & SWT 6
MiMa JavaFX JAR unter Windows ausführen schlägt fehl? AWT, Swing, JavaFX & SWT 5
CodingBerlin JavaFX Programm läuft nur unter Eclipse AWT, Swing, JavaFX & SWT 1
S Ich bringe Code mit JavaFX unter Apache NetBeans IDE 12.6 nicht zum laufen. AWT, Swing, JavaFX & SWT 14
U Wie funktioniert das rotieren unter 2dGraphics, also wie stelle ich z. B. 90° ein? AWT, Swing, JavaFX & SWT 1
T Swing DPI-Skalierung und Java 2D unter Java 11 (und Windows 10) AWT, Swing, JavaFX & SWT 2
N JavaFX Installation unter IntelliJ IDEA AWT, Swing, JavaFX & SWT 5
temi JavaFX Problem mit IntelliJ und JavaFx 11 unter XUbuntu AWT, Swing, JavaFX & SWT 3
B JavaFX openjfx11: intelliJ unter Ubuntu 18.10 kann nicht auflösen AWT, Swing, JavaFX & SWT 4
CptK Swing Button: ImageIcon unter den Text AWT, Swing, JavaFX & SWT 4
T Java Swing - kleines Rechteck unter dem cursor AWT, Swing, JavaFX & SWT 5
Blender3D Meine Swing Anwendung läuft unter Windows 10 und Ubuntu aber nicht auf Windows 7 AWT, Swing, JavaFX & SWT 16
A Swing Gemaltes Bild über saveDialog speichern unter AWT, Swing, JavaFX & SWT 15
S Kein JFrame unter Mac? AWT, Swing, JavaFX & SWT 8
Blender3D Swing KeyBoardListener funktioniert nicht unter UBUNTU AWT, Swing, JavaFX & SWT 7
V Swing Button soll unter anderem Button sein AWT, Swing, JavaFX & SWT 2
L DoubleBuffering unter Swing AWT, Swing, JavaFX & SWT 0
L JavaFX Scene wechseln unter FX AWT, Swing, JavaFX & SWT 5
Avarion Swing JFrame unter Windows 10 kleiner ?! AWT, Swing, JavaFX & SWT 2
T ThreadPool sicher beenden unter Verwendung von swt.widgets.Display.syncExec AWT, Swing, JavaFX & SWT 1
M Layout-Probleme unter Swing AWT, Swing, JavaFX & SWT 5
S (Swing)Vollbild anzeigen unter Linux/Mac AWT, Swing, JavaFX & SWT 6
D 2D-Grafik Rechteck befindet sich unter dem Rahmen des JFrame. AWT, Swing, JavaFX & SWT 1
T JFrame Icon unter Linux/Ubuntu AWT, Swing, JavaFX & SWT 11
S JMenu unter JPanel versteckt AWT, Swing, JavaFX & SWT 5
P Verbuggte custom JButton unter Windows AWT, Swing, JavaFX & SWT 9
SexyPenny90 JLabel liegt unter meiner Turtle AWT, Swing, JavaFX & SWT 5
F LayoutManager Null-Layout unter Linux im TreeCellEditor AWT, Swing, JavaFX & SWT 3
J AWT setBackground(Color.orange) ist unter Win7 Aero nicht orange AWT, Swing, JavaFX & SWT 3
T Unter JPanel liegende Komponenten "totschalten" AWT, Swing, JavaFX & SWT 5
R Problem mit TrayIcon unter Windows/Linux AWT, Swing, JavaFX & SWT 7
M Datei Speichern unter Dialog - SWT AWT, Swing, JavaFX & SWT 3
T JButtons indexiert unter NetBeans anlegen AWT, Swing, JavaFX & SWT 7
S GUI aussehen unter Windows und Linux (und Mac) AWT, Swing, JavaFX & SWT 13
J Applet Kommunikation unter Applets AWT, Swing, JavaFX & SWT 2
I Probleme mit GWT Controls unter Firefox AWT, Swing, JavaFX & SWT 14
A Swing Probleme unter Windows 7 AWT, Swing, JavaFX & SWT 5
F AWT MouseMotionListener e.getButton() ist immer 0 unter Linux und Windows AWT, Swing, JavaFX & SWT 6
F AWT DnD von Dateien mit Sonderzeichen funktioniert unter Linux nicht AWT, Swing, JavaFX & SWT 3
J Swing Natives Menü unter OS X erstellen ? AWT, Swing, JavaFX & SWT 8
C Swing Kleines Programm mit SWING unter Verwendung von MVC AWT, Swing, JavaFX & SWT 5
G SWT-App läuft nicht unter OSX, unter Win aber problemlos AWT, Swing, JavaFX & SWT 3
H Y-Position mit get-/setLocation() unter Linux/Enlightement16 inkonsistent AWT, Swing, JavaFX & SWT 3
G SWT Linie unter transparentes Canvas zeichnen AWT, Swing, JavaFX & SWT 4
M KeyListener Problem unter Firefox AWT, Swing, JavaFX & SWT 2
G Quaqua unter Windows AWT, Swing, JavaFX & SWT 15
B LaF unter KDE AWT, Swing, JavaFX & SWT 2
SuperSeppel13 Swing Fehlende Komponenten unter Mac OS X AWT, Swing, JavaFX & SWT 8
M Swing GroupLayout unter Java 1.5 AWT, Swing, JavaFX & SWT 20
M JMenu teilweise unter einer JComponent AWT, Swing, JavaFX & SWT 4
B Button identifizieren unter MouseEvent AWT, Swing, JavaFX & SWT 7
L JPanel mit Objekten selektieren wie unter Windows / Ubuntu AWT, Swing, JavaFX & SWT 4
W WindowsLookAndFeel unter Mac AWT, Swing, JavaFX & SWT 5
A Swing LAF unter Windows: javax.swing.DebugGraphics cannot be cast to java.awt.Graphics2D AWT, Swing, JavaFX & SWT 5
N JDesktop unter Linux AWT, Swing, JavaFX & SWT 4
C JComboBox funktioniert nicht unter Mac OS X AWT, Swing, JavaFX & SWT 2
P Swing [gelöst/erledigt] Gleicher Code läuft unterschiedlich unter Linux und Windows AWT, Swing, JavaFX & SWT 5
U Grafikkontext unter JButtons? AWT, Swing, JavaFX & SWT 5
M Probleme unter Linux AWT, Swing, JavaFX & SWT 7
E Hat Netbeans unter Linux kein Designer für Swing? AWT, Swing, JavaFX & SWT 3
D Probleme mit Java Swing unter Mac OSX AWT, Swing, JavaFX & SWT 13
F Statuszeile unter Swing AWT, Swing, JavaFX & SWT 4
P Programm terminiert nicht (unter Eclipse) AWT, Swing, JavaFX & SWT 5
V Swing: System-Look&Feel unter KDE AWT, Swing, JavaFX & SWT 3
L Problem mit "setVisible" unter LINUX AWT, Swing, JavaFX & SWT 5
gieser jToggleButton: Text unter Bild AWT, Swing, JavaFX & SWT 2
G SWT Button mit Image und ohne Rand unter Linux? AWT, Swing, JavaFX & SWT 7
M Wo bring ich die datenbankanfragen unter? AWT, Swing, JavaFX & SWT 22
G Problene mt Focus unter Swing AWT, Swing, JavaFX & SWT 7
D AWT drawString funktioniert nicht unter Linux AWT, Swing, JavaFX & SWT 7
lolkind unter JPanel eine JTable auf voller Größe anzeigen lassen? AWT, Swing, JavaFX & SWT 6
G AnfängerSWING Frage Werkzeugleiste unter dem Menu AWT, Swing, JavaFX & SWT 3
Noar IllegalComponentStateException unter Gnu/Linux AWT, Swing, JavaFX & SWT 2
T % von Komponenten unter Layoutmanager AWT, Swing, JavaFX & SWT 2
S JTable: Zeile unter MouseCursor farblich hervorheben AWT, Swing, JavaFX & SWT 2
Firefork JPopupMenu unter einem Schalter darstellen AWT, Swing, JavaFX & SWT 2
D Programm läuft unter XP aber nicht unter Knoppix AWT, Swing, JavaFX & SWT 6
ARadauer jtable drucken unter java 1.3 AWT, Swing, JavaFX & SWT 2
T Pobleme beim Druck unter Java AWT, Swing, JavaFX & SWT 2
M Keine Buttons oder sonstige Objekte in JFrame unter Linux AWT, Swing, JavaFX & SWT 4
J JSlider regaiert unter Java 1.6 nicht mehr AWT, Swing, JavaFX & SWT 7
R Drucken unter jdk 1.4 mit JTable AWT, Swing, JavaFX & SWT 11
C Thread - Beendigung unter Swing abwarten AWT, Swing, JavaFX & SWT 6
T JGoodies unter Windows 98 AWT, Swing, JavaFX & SWT 4
Z Wie kann ich Text unter den Textfeldern einfügen? AWT, Swing, JavaFX & SWT 3
F AWT Programm unter Linux anders als unter Windows ! AWT, Swing, JavaFX & SWT 8
M JDialog unter win und linux unterschiedliche größe nötig? AWT, Swing, JavaFX & SWT 4
F Schriftarten unter Windows und Linux AWT, Swing, JavaFX & SWT 6
M [SOLVED]komponenten unter einem JTabbedPane AWT, Swing, JavaFX & SWT 2
S AWT unter Gnome AWT, Swing, JavaFX & SWT 2
T Tray-Icon-Menü unter Linux AWT, Swing, JavaFX & SWT 10
J JFrame Icon unter Linux AWT, Swing, JavaFX & SWT 2
M .txt unter Verwendung von JSpinner in Textfeld schreiben AWT, Swing, JavaFX & SWT 4
H AbsoluteLayout nicht nur unter Netbeans AWT, Swing, JavaFX & SWT 5
B Graues Feld unter JComboBox AWT, Swing, JavaFX & SWT 2
I Drag and Drop funktioniert unter Linux nicht AWT, Swing, JavaFX & SWT 6

Ähnliche Java Themen

Neue Themen


Oben