Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Barcode aus Bild auslesen (https://www.delphipraxis.net/160487-barcode-aus-bild-auslesen.html)

DSCHUCH 15. Mai 2011 19:41

Barcode aus Bild auslesen
 
Hallo,

kennt jemand eine Komponenten, mit der man aus einem Bild Barcodes auslesen kann? Derzeit verwenden wir BarcodeReader als Active-X, funktioniert eigentlich gut und ich habe auch nichts anderes gefunden, aber vielleicht auch etwas übersehen.

http://www.imagesinfo.com/products/barcode-reader/

Schönen Abend.

Sir Rufo 15. Mai 2011 21:17

AW: Barcode aus Bild auslesen
 
Da gäbe es noch http://www.qualitysoft.de/

DSCHUCH 16. Mai 2011 08:35

AW: Barcode aus Bild auslesen
 
sehr gut, sogar deutsch. ^^

Andreas Schilling 16. Mai 2011 09:10

AW: Barcode aus Bild auslesen
 
Wir arbeiten damit.
http://www.java4less.com/barcodedelp...odesdelphi.php

Coffeecoder 16. Mai 2011 09:14

AW: Barcode aus Bild auslesen
 
Zitat:

Zitat von Andreas Schilling (Beitrag 1101034)

Sieht sehr interessant aus :)

Mfg Coffeecoder

generic 16. Mai 2011 12:26

AW: Barcode aus Bild auslesen
 
Zitat:

Zitat von Andreas Schilling (Beitrag 1101034)

Das erzeugt nur Barcodes - Erkennung kann ich dort nicht finden.

Andreas Schilling 16. Mai 2011 12:35

AW: Barcode aus Bild auslesen
 
Stimmt, aber der Anbieter war schon richtig. Ich hatte auf die Schnelle den ersten Link ausgewählt wo das Wort Barcode drinnen vorkam. Hier also der richtige Link.
http://www.java4less.com/vision/vision.php

squetk 16. Mai 2011 14:06

AW: Barcode aus Bild auslesen
 
Eine Open Source Variante wäre unter
http://zbar.sourceforge.net/index.html zu finden.
Ist zwar keine Delphi-Komponente, steuern wir aber mit Delphi.

himitsu 29. Jun 2011 14:40

AW: Barcode aus Bild auslesen
 
@qsquetk: Wie macht ihr das denn?

Ich hab's ja schon geschafft die ZBar-DLL anzusprechen, aber die Ergebnisse lassen zu Wünschen übrig.
Von 6 ausreichend guten Strichcodes auf einem eingescannten A4 Bild (~1600x2300 Pixelchen) werden nur 1 bis 5 erkannt + ein paar "nichtexistierende" Codes :lol:
Und das auch erst, wenn ich das Bild in kleineren Schritten um bis zu 90° drehe.
(die Nichtexistierende kann man bestimmt/vermutlich noch über dernen "Quallitätsangabe" rausfiltern)

Deren vorkompilierte EXE erkennt aber wesentlich mehr und zuverlässiger nur das, was auch drauf ist.
Auch ohne das Bild zu drehen und einfach nur wagerecht+senkrecht zu scannen.


[add]Achtung, das ist der nichtfunktionierende Code ... der Richtige wurde später gepostet :zwinker:[/add]
Delphi-Quellcode:
bmp := TBitmap.Create;
bmp.PixelFormat := pf8bit;
try
  bmp.Width := Source.Width;
  bmp.Height := Source.Height;
  bmp.Canvas.Draw(0, 0, Source);
  bmp.Width := (bmp.Width + 3) and not 3; // damit die Scannlines direkt aneinander liegen und alles zusammen übergeben werden kann
  bytesPerLine := (bmp.Width + 3) and not 3;
  p := bmp.ScanLine[bmp.Height - 1]; // die Bildzeilen gehen von unten nach oben
//for i := (bytesPerLine * bmp.Height) - 1 downto 0 do
//  if p[i] > 200 then p[i] := 255 else p[i] := 0;
  scanner := zbar_image_scanner_create;
  image := zbar_image_create;
  try
    zbar_image_set_format(image, 'Y800');
    zbar_image_set_size(image, bmp.Width, bmp.Height);
    zbar_image_set_data(image, p, bmp.Height * bytesPerLine, nil);

    // Disable all symbologies?
    zbar_image_scanner_set_config(scanner, ZBAR_NONE, ZBAR_CFG_ENABLE, 0);

    // Set the resolution of the scanner to 4 pixels.  Helps with skewed and poor quality bar codes.
    stat := zbar_image_scanner_set_config(scanner, ZBAR_NONE, ZBAR_CFG_X_DENSITY, Density);
    if stat <> 0 then raise Exception.Create('set config failed');

    stat := zbar_image_scanner_set_config(scanner, ZBAR_NONE, ZBAR_CFG_Y_DENSITY, Density);
    if stat <> 0 then raise Exception.Create('set config failed');

    for stype in BarType do begin
      // Enable the requested symbology
      stat := zbar_image_scanner_set_config(scanner, stype, ZBAR_CFG_ENABLE, 1);
      if stat <> 0 then raise Exception.Create('set config failed');

      // Enable the use of a check digit is requested
      if CheckDigit then
        zbar_image_scanner_set_config(scanner, stype, ZBAR_CFG_ADD_CHECK, 1);
    end;

    //
    count := zbar_scan_image(scanner, image);
    if count > 0 then begin
      symbol := zbar_image_first_symbol(image);
      while Assigned(symbol) do begin
        if AddBarType then
          Codes.Add(zbar_get_symbol_name(zbar_symbol_get_type(symbol)) + Codes.NameValueSeparator + zbar_symbol_get_data(symbol))
        else
          Codes.Add(zbar_symbol_get_data(symbol));

        // für's Debuggen markieren, was wo gefunden wurde
        SetLength(points, zbar_symbol_get_loc_size(symbol));
        if points <> nil then begin
          for i := 0 to Length(points) - 1 do begin
            points[i].X := zbar_symbol_get_loc_x(symbol, i);
            points[i].Y := bmp.Height - zbar_symbol_get_loc_y(symbol, i) - 1;
          end;
          bmp.Canvas.Brush.Style := bsDiagCross;
          bmp.Canvas.Brush.Color := clFuchsia;
          bmp.Canvas.Pen.Color := clFuchsia;
          bmp.Canvas.Pen.Width := 1;
          bmp.Canvas.Polyline(points);
          bmp.Canvas.Pen.Width := 4;
          bmp.Canvas.Ellipse(points[0].X - 15, points[0].Y - 15, points[0].X + 16, points[0].Y + 16);
          bmp.Canvas.Brush.Style := bsClear;
          bmp.Canvas.Font.Color := clRed;
          bmp.Canvas.Font.Size := 20;
          bmp.Canvas.TextOut(points[0].X + 14, points[0].Y + 14, zbar_symbol_get_data(symbol));
        end;

        symbol := zbar_symbol_next(symbol);
      end;
    end;

    // ebenfalls für's Debuggen
    bmp.SaveToFile(...);
  finally
    zbar_image_destroy(image);
    zbar_image_scanner_destroy(scanner);
  end;
finally
  bmp.Free;
end;

Die DLL wäre ja eigentlich recht schön, aber aktuell bin ich eher der Meinung, da es besser ist, wenn ich deren EXE aufrufe und dessen Ausgabe auslese. :?

himitsu 30. Jun 2011 13:21

AW: Barcode aus Bild auslesen
 
Liste der Anhänge anzeigen (Anzahl: 3)
So, hat mich etwas nerven gekostet, aber jetzt geht's :firejump:

Delphi-Quellcode:
uses
  ZBar;

type
  TZbarSymbolTypes = set of zbar_symbol_type_e;

procedure ReadBarcode(Codes: TStrings; Source: TGraphic; AddBarType: Boolean = False;
  BarTypes: TZbarSymbolTypes = []; CheckDigit: Boolean = True; Density: Integer = 1);
var
  bmp: TBitmap;
  bytesPerLine, count, i: Integer;
  p, pg: PByte;
//processor: zbar_processor_t;
  scanner: zbar_image_scanner_t;
  image: zbar_image_t;
  stype: zbar_symbol_type_e;
  symbol: zbar_symbol_t;
  symboltype: zbar_symbol_type_t;
begin
  if BarTypes = [] then BarTypes := [ZBAR_EAN8, ZBAR_UPCE, ZBAR_ISBN10, ZBAR_UPCA, ZBAR_EAN13, ZBAR_ISBN13, ZBAR_I25, ZBAR_CODE39, ZBAR_CODE128];

  bmp := TBitmap.Create;
  bmp.PixelFormat := pf32bit;;
  try
    bmp.Width := Source.Width;
    bmp.Height := Source.Height;
    bmp.Canvas.Draw(0, 0, Source);

  //processor := zbar_processor_create(0);
  //Assert(Assigned(processor), 'zbar-processor');
  //try
  //  if zbar_processor_init(processor, nil, Ord(False)) <> 0 then begin
  //    zbar_processor_error_spew(processor, 0);
  //    Assert(False, 'zbar-processor_init');
  //  end;
  //  zbar_processor_set_visible(processor, 0);

      scanner := zbar_image_scanner_create;
      Assert(Assigned(scanner), 'zbar-scanner');
      try
        zbar_image_scanner_set_config(scanner, ZBAR_NONE, ZBAR_CFG_ENABLE, 0);

        i := zbar_image_scanner_set_config(scanner, ZBAR_NONE, ZBAR_CFG_X_DENSITY, Density);
        Assert(i = 0, 'zbar-set_config');

        i := zbar_image_scanner_set_config(scanner, ZBAR_NONE, ZBAR_CFG_Y_DENSITY, Density);
        Assert(i = 0, 'zbar-set_config');

        for stype in BarTypes do begin
          i := zbar_image_scanner_set_config(scanner, stype, ZBAR_CFG_ENABLE, 1);
          Assert(i = 0, 'zbar-set_config');

          if CheckDigit then
            zbar_image_scanner_set_config(scanner, stype, ZBAR_CFG_ADD_CHECK, 1);
        end;

        image := zbar_image_create;
        Assert(Assigned(image), 'zbar-image');
        try
          bytesPerLine := bmp.Width;
          p := bmp.ScanLine[bmp.Height - 1]; // die Bildzeilen gehen von unten nach oben
          pg := GetMemory(bmp.Height * bytesPerLine);
          try
            for i := bmp.Height * bytesPerLine downto 0 do
              pg[i] := Round(p[i*4]*0.3 + p[i*4+1]*0.59 + p[i*4+2]*0.11);

            zbar_image_set_format(image, 'Y800');
            zbar_image_set_size(image, bmp.Width, bmp.Height);
            zbar_image_set_data(image, pg, bmp.Height * bytesPerLine, nil);

            count := zbar_scan_image(scanner, image);
          //zbar_process_image(processor, image); count := 1;
          finally
            FreeMemory(pg);
          end;

          if count > 0 then begin
            symbol := zbar_image_first_symbol(image);
            while Assigned(symbol) do begin
              symboltype := zbar_symbol_get_type(symbol);
              if AddBarType then
                Codes.Add(String(AnsiString(zbar_get_symbol_name(symboltype)) + AnsiString(zbar_get_addon_name(symboltype)))
                  + Codes.NameValueSeparator + String(AnsiString(zbar_symbol_get_data(symbol))))
              else
                Codes.Add(String(AnsiString(zbar_symbol_get_data(symbol))));

              symbol := zbar_symbol_next(symbol);
            end;
          end;
        finally
          zbar_image_destroy(image);
        end;
      finally
        zbar_image_scanner_destroy(scanner);
      end;
  //finally
  //  zbar_processor_destroy(processor);
  //end;
  finally
    bmp.Free;
  end;
end;
Wer schräge Barcodes einscännen will/muß, der braucht einfach nur das Bild zu drehen, denn die ZBar-Barcode-Komponente scännt nur in 90°-Winkeln (wagerecht und senkrecht).
z.B. von 0° bis <90° in 10°-Schritten
oder einfach nur noch einmal 45°
oder 0°, 22°, 45° und 68°

Da könnte man z.B. direkt in den Block nach
Delphi-Quellcode:
image := zbar_image_create;
eine entsprechende Schleife einbauen.
Eventuell dann auch noch die StringListe mit .Sort:=True und .Duplicates:=dupIgnore .

Delphi-Quellcode:
procedure RotateBitmap(Dest, Source: TBitmap; Winkel: Double; Hintergrund: TColor = clWhite; GroesseAnpassen: Boolean = True);
type
//TArray = array[0..0] of Byte; {pf8bit}
//TArray = array[0..0] of array[0..1] of Byte; {pf16bit}
//TArray = array[0..0] of array[0..2] of Byte; {pf24bit}
  TArray = array[0..0] of array[0..3] of Byte; {pf32bit}
  PArray = ^TArray;
var
  rw: Boolean;
  CT, ST: Double;
  I, J, X, Y, SrcW, SrcH, SrcWD, SrcHD, SrcWD2, SrcHD2: Integer;
  ScanS, ScanD: array of PArray;
  XCT, XST: Integer;
  YCT, YST: array of Integer;
begin
//Source.PixelFormat := pf8bit;
//Source.PixelFormat := pf16bit;
//Source.PixelFormat := pf24bit;
  Source.PixelFormat := pf32bit;
  Dest.PixelFormat := Source.PixelFormat;
  Winkel := 360 - Winkel;
  while Winkel > 360 do Winkel := Winkel - 360;
  while Winkel < 0 do Winkel := Winkel + 360;
  Winkel := Winkel * PI / 180;
  ST := Sin(Winkel);
  CT := Cos(Winkel);
  rw := Frac(Winkel / 90) = 0;
  if not GroesseAnpassen then begin
    Dest.Width := Source.Width;
    Dest.Height := Source.Height;
  end else if ST * CT < 0 then begin
    Dest.Width := Round(Abs(Source.Width * CT - Source.Height * ST));
    Dest.Height := Round(Abs(Source.Width * ST - Source.Height * CT));
  end else begin
    Dest.Width := Round(Abs(Source.Width * CT + Source.Height * ST));
    Dest.Height := Round(Abs(Source.Width * ST + Source.Height * CT));
  end;
  with Dest.Canvas do begin
    Brush.Style := bsSolid;
    Brush.Color := Hintergrund;
    FillRect(ClipRect);
  end;
  SrcWD := Source.Width;
  SrcHD := Source.Height;
  SrcWD2 := Source.Width div 2;
  SrcHD2 := Source.Height div 2;
  if CT < 0 then Dec(SrcWD2);
  if ST < 0 then Dec(SrcHD2);
  SetLength(ScanS, Source.Height);
  SetLength(ScanD, Dest.Height);
  for I := Source.Height - 1 downto 0 do ScanS[I] := Source.ScanLine[I];
  for I := Dest.Height  - 1 downto 0 do ScanD[I] := Dest.ScanLine[I];
  SetLength(YCT, Dest.Height);
  SetLength(YST, Dest.Height);
  for J := 0 to Dest.Height - 1 do begin
    if rw then
      Y := Trunc(J - Dest.Height / 2 + 0.5)
    else
      Y := J - Dest.Height div 2;
    YCT[J] := Round(Y * CT * 4 + 2);
    YST[J] := Round(Y * ST * 4 + 2);
  end;
  for I := 0 to Dest.Width - 1 do begin
    if rw then
      X := Trunc(I - Dest.Width / 2)
    else
      X := I - Dest.Width div 2;
    XCT := Round((X * CT + SrcWD2) * 4);
    XST := Round((X * ST + SrcHD2) * 4);
    for J := 0 to Dest.Height - 1 do begin
      SrcW := (XCT - YST[J]) shr 2; {... div 4}
      SrcH := (XST + YCT[J]) shr 2;
      if (SrcH >= 0) and (SrcH < SrcHD) and (SrcW >= 0) and (SrcW < SrcWD) then
        ScanD[J][I] := ScanS[SrcH][SrcW];
    end;
  end;
end;
Benötigt wird nur die angehängte Zbar.pas und die libzbar-0.dll von zbar.sourceforge.net, bzw. aus dem Anhang.


Das die Zbar.pas wurde natürlich auch gleich mit auf Unicode angepaßt ... läuft aber weiterhin auch mit ANSI.


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:02 Uhr.
Seite 1 von 3  1 23      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz