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.
 
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
 
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
 
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
 
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.
 
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
 
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.
 
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
 
Hallo Foxei,

danke für deinen Denkanstoß. Ich glaube ich habe das verstanden 😛
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...
 
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:
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:
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 !
 
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
 
Ja das ist so eine Sache 😀 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 😀
 
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
 
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
 
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 😀
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!
 
@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:

Neue Themen


Zurück
Oben