# Barcodes in Bild erkennen



## data89 (7. Okt 2009)

Hallo,

zu dem Geburtstag vom Barcode (siehe Google-Logo: http://www.google.de/logos/barcode09.gif) habe ich auch eine Frage, die Barcode betrifft:

Wie kann ich einen Barcode auf einem Bild finden? Das Auslesen des Barcodes ist eine andere Sache, um die man sich kümmern muss, sobald man erst einmal einen Barcode gefunden hat. Super wäre es, wenn man dann nur noch einen Ausschnitt des Bildes hätte; dann kann man den Barcode aus diesem "Scannerstreifen" auslesen - wäre super. Hier noch ein Beispiel:




Das zu erkennende Bild.




Es wurde der Barcode erkannt und nur ein Streifen herausgefiltert.

Aber wie ich den Barcode am Besten aus einem Bild erkenne, ist mir zweifelhaft ....

Vielen Dank für's lesen,
data89


----------



## Geeeee (7. Okt 2009)

Über Korrelation könnte man die Elemente herausfinden. Natürlich müsste man dann noch die einzelnen Bars auslesen, wenn man sie eingegrenzt hat. Stelle mir da einen schönen Umfang vor 
Leider kann ich gerade deine Bilder nicht sehen (proxy) und schauen was du da gezeigt hast.


----------



## data89 (7. Okt 2009)

Wie machen die das hier: ||| | ||| | || CODECHECK.INFO : Login

Es gibt einen Bereich, in dem der Strichcode ist. Drin wird er erkannt. Aber was ist die Logik dahinter?


----------



## ARadauer (7. Okt 2009)

Wie viel Erfahrung hast du mit Bildverarbeitung?

Ich würds mal mit dem einfachen Erkennen der senkrechten Linien versuchen. Also mit einfacher Kantenerkennung kommt man sicher schon weit.

Wenn nicht, mal ein paar mal ein Opening und Closing anwenden und mal schaun, was man mit Korrelation findet...


----------



## data89 (7. Okt 2009)

ARadauer hat gesagt.:


> Wie viel Erfahrung hast du mit Bildverarbeitung?


Ich habe mich bereits erfolgreich mit der Erkennung von Gesten von Personen beschäftigt. D.h. Positionsbestimmung der Hände und des Kopfes, Dreieck durchgelegt und erkannt, wenn eine Hand oder so gehoben wird ...



ARadauer hat gesagt.:


> Ich würds mal mit dem einfachen Erkennen der senkrechten Linien versuchen. Also mit einfacher Kantenerkennung kommt man sicher schon weit.


Höre ich immer wieder, aber hab immer noch nicht wirklich verstanden was das ist. Bei meinem ersten (und einizigen Projekt; Erkennung von Gesten) habe ich einfach nur die Hautfarbenen Pixel rausgefischt und dann Punktwolken zusammengefasst, die dann die Punkte waren.

Wer googeln kann ist klar im Vorteil - hab rausgefunden was es bedeutet!



ARadauer hat gesagt.:


> Wenn nicht, mal ein paar mal ein Opening und Closing anwenden und mal schaun, was man mit Korrelation findet...


Was ist das?

Danke,
data89


----------



## data89 (7. Okt 2009)

Anbei findet Ihr einen Versuch, der jedoch nicht funktioniert! Es kommt irgend ein wirrer Kram raus. Grundidee: Alle Farbwerte für jede Spalte mitteln und daraus eine "Linie" erstellen. Dann abgrenzen was ausgefüllt und was nicht ausgefüllt ist und in ein boolean-Array schreiben. Dann daraus die 43 Blöcke extrahieren, anhand der Prüfgruppen (Anfang, Mitte, Ende) die Breite vom weißen Bereich für 1 LE bestimmen und auf die anderen 8 Gruppen (mit jeweils 4 Blöcken) anwenden und die Zahl nach schauen.

Wie kann man das besser machen?

*Irgendwie bin ich von diesem Scanner http://www.codecheck.info/images/Scanner.swf fasiziert! Der liest ja wirklich viele EAN-8 Codes ein ... das gibt's ja gar nicht ( - doch bei Roller .... das war was anderes ;-))*
Wie funktioniert der wohl?

Danke für Eure Hilfe vorab,
beste Grüße,
data89

P.S.: Achso, ich arbeite mit *EAN-8*.


----------



## Gast2 (7. Okt 2009)

prinzipell sollte nur der Barcode auf dem Bild sein ... pauschal ein Binärfilter verwenden ... dann kannst Du mittig auf Y anfangen und X durchlaufen bis Du einen Punkt erwischt hast ... nur erstellst Du von dem Punkt aus eine Punktwolke ... über diese Punktwolke erstellst Du eine Regressionsgerade ... anhand dieser Gerade kannst Du das Bild drehen das es korrekt ausgerichtet ist ... nun kannst Du den Barcode auslesen


----------



## data89 (8. Okt 2009)

Aber wie werde ich die einzelnen Graustufen los? Ich muss ja die richtigen Abstände einlesen!


----------



## Gast2 (8. Okt 2009)

data89 hat gesagt.:


> Ich habe mich bereits erfolgreich mit der Erkennung von Gesten von Personen beschäftigt.



die Aussage wiederspricht sich mit 



data89 hat gesagt.:


> Aber wie werde ich die einzelnen Graustufen los? Ich muss ja die richtigen Abstände einlesen!



die Fehlen da einfache Grundlagen ... eine Hand zu erkennen ist schon der etwas gehobenere Ansatz ... werde mich aber nochmal selber Quoten



mogel hat gesagt.:


> ... pauschal ein Binärfilter verwenden ...



vieleicht hilfts, mogel


----------



## Geeeee (8. Okt 2009)

Will einfach nochmal das Wort Sobeloperator für die Kantenerkennung in den Thread werfen.
EDIT: argh, sehe gerade, dass du Sobel bei dir in einem Editgrund angegeben hast


----------



## data89 (8. Okt 2009)

Geeeee hat gesagt.:


> Will einfach nochmal das Wort Sobeloperator für die Kantenerkennung in den Thread werfen.
> EDIT: argh, sehe gerade, dass du Sobel bei dir in einem Editgrund angegeben hast


Wenn ich den anwende bekomme ich an der Stelle wo der Barcode ist ein "Kantengewuschel"!

===========================
EDIT:

Ich habe diese Seite hier gefunden: BaToo - Bar Code Toolkit : Documentation - Algorithm browse Dort wird der Algorithmus beschrieben. Teile verstehe ich (und habe ich mir auch so in etwa gedacht) aber andere Teile verstehe ich nicht:


> By applying slightly different recognition parameters along each individual scanline (i.e., the binarization threshold that categorizes pixels into either black or white), the overall recognition accuracy can also be improved.


Was ist hier gemeint? Die Festsetzung des Wertes zur Entscheidung was schwarz und was weiß ist? Und wie setzt man den Wert fest?

Hier ist der Kommentar des Algorithmusses (zwei 's'?):

```
/** 
 *  This class manages the recognition of a barcode, using several scanlines.
 *  It runs the recognition along several scanlines and combines the results of
 *  the different runs.
 *  <p>
 *  Central to the combination of the results of the different scanlines is a three dim. array,
 *  referenced as "possible_numbers", containing information about the occurence of a certain 
 *  digit at a specific position in the EAN13 code.
 *  <p>	         
 *  The first dimension has 13 entries and represents the position in the EAN13 code.
 *  The second dimension has 10 entries and works like a stack for the digits recognized
 *  at that position in the EAN13 code. <br>
 *  The third dimension has two elements: <br> 0 = specifies the digit itself (0..9), 
 *                                        <br> 1 = the amount of this digit's occurence  
 *                                                  at that position in the EAN13 code (0..#scanlines)
 *  <p><p>                                          
 *  Here is an example. Assume, we have 19 scanlines, and along these scanline the following 
 *  information is recognized: (This has been a pretty blurry barcode image... :-)
 *  <p>
 *   Scanline 0 result: ????????????<br>
 *   Scanline 1 result: ????????????<br>
 *   Scanline 2 result: ????????????<br>
 *   Scanline 3 result: ????????????<br>
 *   Scanline 4 result: ????????????<br>
 *   Scanline 5 result: ????????????<br>
 *   Scanline 6 result: 3?6???3?????<br>
 *   Scanline 7 result: ????????????<br>
 *   Scanline 8 result: ?????4??????<br>
 *   Scanline 9 result: ????????????<br>
 *   Scanline 10 result: ????????????<br>
 *   Scanline 11 result: 612?97017840<br>
 *   Scanline 12 result: ???7????8???<br>
 *   Scanline 13 result: 6122970178?0<br>
 *   Scanline 14 result: ????????????<br>
 *   Scanline 15 result: ????????????<br>
 *   Scanline 16 result: ????????????<br>
 *   Scanline 17 result: ????????????<br>
 *   Scanline 18 result: ????????????<br>
 *   Scanline 19 result: ????????????<br>
 *   <p><p>
 *   The possible_numbers-array will contain the following information.
 *   (Index of third dim. = 0 => Here we see information about the recognized digits.)
 *   The array has already been sorted using the sortDigits() method. This means
 *   that the digits that have been detected most at a certain position are on top.
 *   <p>
 *   detected digits: possible_numbers[][][0]
 *   <p>
 *   0 :   6  1  2  7  9  7  0  1  7  8  4  0 <br> 
 *   1 :   3  x  6  2  x  4  3  x  8  x  x  x <br>
 *   2 :   x  x  x  x  x  x  x  x  x  x  x  x <br> 
 *   3 :   x  x  x  x  x  x  x  x  x  x  x  x <br> 
 *   4 :   x  x  x  x  x  x  x  x  x  x  x  x <br> 
 *   5 :   x  x  x  x  x  x  x  x  x  x  x  x <br> 
 *   6 :   x  x  x  x  x  x  x  x  x  x  x  x <br> 
 *   7 :   x  x  x  x  x  x  x  x  x  x  x  x <br> 
 *   8 :   x  x  x  x  x  x  x  x  x  x  x  x <br> 
 *   9 :   x  x  x  x  x  x  x  x  x  x  x  x <br> 
 *   <p>
 *   Index of third dim. = 1 => Here we see information about the occurence of the
 *   digits.
 *   <p>
 *   # of their occurence: possible_numbers[][][1]
 *   <p>
 *   0 :   2  2  2  1  2  2  2  2  2  2  1  2 <br>  
 *   1 :   1  0  1  1  0  1  1  0  1  0  0  0 <br> 
 *   2 :   0  0  0  0  0  0  0  0  0  0  0  0 <br> 
 *   3 :   0  0  0  0  0  0  0  0  0  0  0  0 <br> 
 *   4 :   0  0  0  0  0  0  0  0  0  0  0  0 <br> 
 *   5 :   0  0  0  0  0  0  0  0  0  0  0  0 <br> 
 *   6 :   0  0  0  0  0  0  0  0  0  0  0  0 <br> 
 *   7 :   0  0  0  0  0  0  0  0  0  0  0  0 <br> 
 *   8 :   0  0  0  0  0  0  0  0  0  0  0  0 <br> 
 *   9 :   0  0  0  0  0  0  0  0  0  0  0  0 <br> 
 *   <p> 
 *   Below is a run of the detectValidBarcode() method that tries to detect a valid
 *   barcode. If no code can be recognized directly, we are trying all possible
 *   combinations of the recognized digits starting with the "most likely" combination.
 *   This is intended as a last try. The need to try different combinations of the recognized digits
 *   should occur very seldom, or at least with only very few alternatives for 
 *   specific digits. As a prositive effect, we get the chance to recognize a barcode that
 *   couldn't be recognized before, as a negative consequence, we can get a EAN13 number
 *   that is correct, according to the checksum, but that doesn't match the 
 *   barcode on the image.
 *   <p>
 *   Trying to find a valid code: (detectValidBarcode()-method)
 *   <p>
 *   CHECK: 6 1 2 7 9 7 0 1 7 8 4 0  ckecksum_digit:5 <br>
 *   CHECK: 6 1 2 7 9 7 0 1 8 8 4 0  ckecksum_digit:2 <br>
 *   CHECK: 6 1 2 7 9 7 3 1 7 8 4 0  ckecksum_digit:6 <br>
 *   CHECK: 6 1 2 7 9 7 3 1 8 8 4 0  ckecksum_digit:3 <br>
 *   CHECK: 6 1 2 7 9 4 0 1 7 8 4 0  ckecksum_digit:8 <br>
 *   CHECK: 6 1 2 7 9 4 0 1 8 8 4 0  ckecksum_digit:5 <br>
 *   CHECK: 6 1 2 7 9 4 3 1 7 8 4 0  ckecksum_digit:9 <br>
 *   CHECK: 6 1 2 7 9 4 3 1 8 8 4 0  ckecksum_digit:6 <br>
 *   CHECK: 6 1 2 2 9 7 0 1 7 8 4 0  ckecksum_digit:0 <br>
 *   <p>
 *   RESULT: 612297017840                                                                         
 *   <p>            
 *   
 *  @author Robert Adelmann
 *  @version 1.0
 */
```

*Also was ist in dem 3-D-Array?*


----------



## Gast2 (8. Okt 2009)

data89 hat gesagt.:


> Wenn ich den anwende bekomme ich an der Stelle wo der Barcode ist ein "Kantengewuschel"!


ist auch klar ... Du hast keine Kanten sondern Flächen ... da durchaus 2 (oder auch 3) Bits nebeneinander gesetzt sind im Barcode ... mal abgesehen davon - ein einfaches Bit würde Dir auch 2 Kanten Liefern (Flankenübergang von 0->1 und 1->0) ... damit hast Du aber immer noch nichts gewonnen - im Gegenteil nun hast Du doppelt soviele Linien



> Was ist hier gemeint? Die Festsetzung des Wertes zur Entscheidung was schwarz und was weiß ist? Und wie setzt man den Wert fest?



ich quote mich mal pauschal selber



mogel hat gesagt.:


> ... pauschal ein Binärfilter verwenden ...



letzter Versuch, mogel


----------



## data89 (8. Okt 2009)

mogel hat gesagt.:


> letzter Versuch, mogel


In dem Beispiel wird ja auch mit einem Binärfilter gearbeitet: erst in Grauwerte umwandeln und dann Thresholding benutzen. Fertig ist die Scannerlinie.

Wenn ich das auf mein Webcambild anwende, kommt das heraus:






Jetzt muss ich mehrere Scannerlinien drüberlegen, den EAN mehrmals einlesen und dann abgleichen und eine Mehrheitsentscheidung vornhemen. Wenn ich das gemacht habe, dann muss ich noch ein bisschen Code/Performance verbessern.

So müsste es jetzt aber funktionieren, oder???

data89


----------



## Geeeee (8. Okt 2009)

Ich wollte in die Richtung Kantenerkennung nur gehen, damit er den Barcode richtig rotiert bekommt und dann auslesen kann.


----------



## data89 (8. Okt 2009)

Okay, aber das mit dem Rotieren lasse ich weg. Der benutzer sieht später auf dem Bildschirm ein Visier (roter Bereich mit Mittellinie) und muss dann den Barcode dort zentrieren und einmal ablichten. Ich denke, dass man so viel vom Benutzer verlangen kann ...

Wenn man den Barcode auf einem statischen Bild sucht, dann benötigt man das. Außerdem sieht mein Testbild scheußlich aus und eignet sich eher weniger (durch die Verzerrungen):





data89


----------



## Gast2 (8. Okt 2009)

data89 hat gesagt.:


> So müsste es jetzt aber funktionieren, oder???



ja ... im Idealfall nicht X-mal über die selber Zeile sondern mal oben mal unten ... allerdings wirst Du mit Deinem Beispiel Probleme bekommen - es ist verzerrt ... wenn Du jetzt x-mal über die gleiche Zeile gehst (dann ist die Zerrung egal), bekommst Du auch x-mal exakt das gleiche raus ... damit reicht es wenn Du nur 1 mal den Scanner bemühst


----------



## data89 (8. Okt 2009)

*Also hier mein Ergebnis. Aber irgendwie klappt das immer noch nicht ...*

BcodeReader.java

```
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;


public class BcodeReader {

	public BcodeReader(int[][] image, int scanlines) {
		
		// check the size of scanlines
		if (scanlines > image.length) {
			scanlines = image.length;
		}
		
		int[][] barcodes = new int[scanlines][8];
		int bcnt = 0;
		
		// scan the complete barcode
		for (int i = 0; i < scanlines; i++) {
			int height = (image.length/scanlines)*i;
		
			// get the line of colors
			int[] scanline = BcodeReader.getColorFromRGB(image[i]);
			// read the fields
			int[][] fields = BcodeReader.getFields(scanline);
			
			int[] code = new EAN8().recognize(fields, 1, fields.length-1);
			
			if (code != null) {
				System.out.println(java.util.Arrays.toString(code));
					
				barcodes[bcnt] = code;
				bcnt++;
				
			}
		}
		
		int[] eanFinal = new int[8];
		
		for (int i = 0; i < eanFinal.length; i++) {
			
			int[] alleDieserStelle = new int[barcodes.length];
			for (int j = 0; j < barcodes.length; j++) {
				alleDieserStelle[j] = barcodes[j][i];
			}
			
			eanFinal[i] = BcodeReader.getNumber(alleDieserStelle);
			
			
		}
		
		System.out.println(java.util.Arrays.toString(eanFinal));
		
	}
	
	private static int getNumber(int[] candidates) {
		
		int[][] bewertung = new int[candidates.length][2];
		int bewcnt = 0;
		
		for (int i = 0; i < candidates.length; i++) {
			
			boolean contains = false;
			for (int j = 0; j < bewertung.length; j++) {
				if (bewertung[j][0] == candidates[i]) {
					bewertung[j][1]++;
					contains = true;
				}
			}
			
			if (!contains) {
				bewertung[bewcnt][0] = candidates[i];
				bewertung[bewcnt][1] = 1;
				bewcnt++;
			}
			
		}
		
		int highestIndex = 0;
		int highestNumber = 0;
		
		for (int i = 0; i < bewertung.length; i++) {
			
			if (bewertung[i][0] > highestNumber) {
				highestNumber = bewertung[i][0];
				highestIndex = i;
			}
			
		}
		
		
		return bewertung[highestIndex][0];
	}
	
	private static int[][] getFields(int[] scanline) {
		
		// check 
		if (scanline.length < 1) {
			return null;
		}
		
		/*
		 * temp contains on
		 * 	0: the value (0 or 255)
		 *  1: the number of fields
		 */
		int[][] temp = new int[scanline.length][2];
		
		int fcnt = 0;
		int last_value = scanline[0];
		int last_fields = 1;
		for (int i = 1; i < scanline.length; i++) {
			if ((scanline[i] == last_value) && (i < scanline.length - 1)) {
				last_fields++;
			} else {
				
				temp[fcnt][0] = last_value;
				temp[fcnt][1] = last_fields;
				
				fcnt++;
				last_value = scanline[i];
				last_fields = 0;
			}
		}
		
		int[][] fields = new int[fcnt][2];
		for (int i = 0; i < fields.length; i++) {
			fields[i] = temp[i];
		}
		
		return fields;
	}
	
	private static int[] getColorFromRGB(int[] rgb_array) {
		
		int[][] line = new int[rgb_array.length][3];
		
		for (int i = 0; i < rgb_array.length; i++) {
			Color c = new Color(rgb_array[i]);
			
			line[i][0] = c.getRed();
			line[i][1] = c.getGreen();
			line[i][2] = c.getBlue();
		}
		
		return BcodeReader.transformPathToBW(line);
	}
	
	
	
	
	
	
	private static int[] transformPathToBW(int[][] line) {

		int w = line.length;
		int bw_line[] = new int[w];
		bw_line[0] = 255;

		// create greyscale values:
		int grey_line[] = new int[w];
		int average_illumination = 0;
		for (int x = 0; x < w; x++) {
			grey_line[x] = (line[x][0] + line[x][1] + line[x][2]) / 3;
			average_illumination = average_illumination + grey_line[x];
		}
		average_illumination = average_illumination / w;

		// perform the binarization:
		int range = w / 20;

		// temp values:
		int moving_sum;
		int moving_average;
		int v1_index = -range + 1;
		int v2_index = range;
		int v1 = grey_line[0];
		int v2 = grey_line[range];
		int current_value;
		int comparison_value;

		// initialize the moving sum:
		moving_sum = grey_line[0] * range;
		for (int i = 0; i < range; i++)
			moving_sum = moving_sum + grey_line[i];

		// apply the adaptive thresholding algorithm:
		for (int i = 1; i < w - 1; i++) {
			if (v1_index > 0) v1 = grey_line[v1_index];
			if (v2_index < w) v2 = grey_line[v2_index];
			else v2 = grey_line[w - 1];
			moving_sum = moving_sum - v1 + v2;
			moving_average = moving_sum / (range << 1);
			v1_index++;
			v2_index++;

			current_value = (grey_line[i - 1] + grey_line[i]) >>> 1;

			// decide if the current pixel should be black or white: 
			comparison_value = (3 * moving_average + average_illumination) >>> 2;
			if ((current_value < comparison_value - 3)) bw_line[i] = 0;
			else bw_line[i] = 255;
		}

		// filter the values: (remove too small fields)    		

		if (w >= 640) {
			for (int x = 1; x < w - 1; x++) {
				if ((bw_line[x] != bw_line[x - 1]) && (bw_line[x] != bw_line[x + 1])) bw_line[x] = bw_line[x - 1];
			}
		}
		return bw_line;
	}
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	

	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	public static void main(String[] args) {
		
		try {
			
			BufferedImage image = ImageIO.read(new File("barcode.png"));
			
			int w = image.getWidth();
			int h = image.getHeight();
			int[] rgbs = new int[w*h];
			image.getRGB(0, 0, w, h, rgbs, 0, w);
			
			int[][] img = new int[h][w];
			int totcnt = 0;
			for (int i = 0; i < h; i++) {
				for (int j = 0; j < w; j++) {
					img[i][j] = rgbs[totcnt];
					totcnt++;
				}
			}
			
			new BcodeReader(img, 1);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		
	}
	
}
```
EAN8.java

```
public class EAN8 implements Barcode {

	public static int FIELD_LENGTH = 43;

	public static int[] NUMBERSPACE = new int[]{
		3211,
		2221,
		2122,
		1411,
		1132,
		1231,
		1114,
		1312,
		1213,
		3112
	};
	
	
	@Override
	public int[] recognize(int[][] fields, int start, int end) {

		// check
		
		int[] result = new int[8];
		
		if ((end - start) != FIELD_LENGTH ||
				start < 0 || end > (fields.length - 1)) {
			return null;
		}

		int white_length = 0;
		int black_length = 0;
		

		black_length = Math.round(((float)fields[start + 0][1] + fields[start + 2][1] + fields[end - 0][1] 
		                   + fields[end - 2][1] + fields[start + 20][1] + fields[start + 22][1])/6.0f);
		white_length = Math.round(((float)fields[start + 0][1] + fields[end - 1][1] + fields[start + 19][1]
		                   + fields[start + 21][1] + fields[start + 23][1])/5.0f);

		result[0] = Integer.parseInt(((String)
				(Math.round(((double)fields[start + 3][1])/white_length) + "")+
				(Math.round(((double)fields[start + 4][1])/black_length) + "")+
				(Math.round(((double)fields[start + 5][1])/white_length) + "")+
				(Math.round(((double)fields[start + 6][1])/black_length) + "")
		));
		
		result[1] = Integer.parseInt(((String)
				(Math.round(((double)fields[start + 7][1])/white_length) + "")+
				(Math.round(((double)fields[start + 8][1])/black_length) + "")+
				(Math.round(((double)fields[start + 9][1])/white_length) + "")+
				(Math.round(((double)fields[start + 10][1])/black_length) + "")
		));
		
		result[2] = Integer.parseInt(((String)
				(Math.round(((double)fields[start + 11][1])/white_length) + "")+
				(Math.round(((double)fields[start + 12][1])/black_length) + "")+
				(Math.round(((double)fields[start + 13][1])/white_length) + "")+
				(Math.round(((double)fields[start + 14][1])/black_length) + "")
		));
		
		result[3] = Integer.parseInt(((String)
				(Math.round(((double)fields[start + 15][1])/white_length) + "")+
				(Math.round(((double)fields[start + 16][1])/black_length) + "")+
				(Math.round(((double)fields[start + 17][1])/white_length) + "")+
				(Math.round(((double)fields[start + 18][1])/black_length) + "")
		));
		
		result[4] = Integer.parseInt(((String)
				(Math.round(((double)fields[start + 24][1])/white_length) + "")+
				(Math.round(((double)fields[start + 25][1])/black_length) + "")+
				(Math.round(((double)fields[start + 26][1])/white_length) + "")+
				(Math.round(((double)fields[start + 27][1])/black_length) + "")
		));
		
		result[5] = Integer.parseInt(((String)
				(Math.round(((double)fields[start + 28][1])/white_length) + "")+
				(Math.round(((double)fields[start + 29][1])/black_length) + "")+
				(Math.round(((double)fields[start + 30][1])/white_length) + "")+
				(Math.round(((double)fields[start + 31][1])/black_length) + "")
		));
		
		result[6] = Integer.parseInt(((String)
				(Math.round(((double)fields[start + 32][1])/white_length) + "")+
				(Math.round(((double)fields[start + 33][1])/black_length) + "")+
				(Math.round(((double)fields[start + 34][1])/white_length) + "")+
				(Math.round(((double)fields[start + 35][1])/black_length) + "")
		));
		
		result[7] = Integer.parseInt(((String)
				(Math.round(((double)fields[start + 36][1])/white_length) + "")+
				(Math.round(((double)fields[start + 37][1])/black_length) + "")+
				(Math.round(((double)fields[start + 38][1])/white_length) + "")+
				(Math.round(((double)fields[start + 39][1])/black_length) + "")
		));
		

		int[] eanCode = new int[8];
		for (int i = 0; i < eanCode.length; i++) {
			eanCode[i] = this.lookUpNumber(result[i]);
		}
		
		return eanCode;
	}

	
	public int lookUpNumber(int ean) {
		
		for (int i = 0; i < EAN8.NUMBERSPACE.length; i++) {
			if (EAN8.NUMBERSPACE[i] == ean) {
				return i;
			}
		}
		return -1;
	}
	
	
}
```
Barcode.java

```
public interface Barcode {

	public int[] recognize(int[][] fields, int start, int end);

}
```


----------



## data89 (10. Okt 2009)

Hallo,

ich habe das jetzt mit dem Barcode hinbekommen und das funktioniert auch via JMF mit meiner Webcam. Aber: da das Bild so groß ist werden manchmal auch Barcodes erkannt, wo garkeine vorhanden sind.

*Gibt es einen einfachen Mechanismus, mit dem man feststellen kann, ob ein Barcode im Bild befindlich ist?*

data89 :-(


----------

