4
$\begingroup$

I would like a path or way to find barcodes in an image and read more of them and ideally quicker (It is very slow for an image).

So, BarcodeRecognize[] already recognizes multiple barcodes in an image and reads them. But I would not say that it is partically great by itself. I have 4 examples. Also, near the bottom I have the code to generate multiple barcodes in a collage which can be used to make real stickers or be an ideal digital image only.

For example, it only calculates 4 of the barcodes,{VF0olZI14,u7QuPYD7uD3J5W,hEOAqfV1,whmVd9rHfYh0}, from the image below but clearly there are many more than 4:

This is a collage of random barcodes in a png file.

when I used real barcodes, it only calculated, aI8F2lFt, from:

3 barcodes. They are rotated and real ones on a box.

and it only gave Z13 for: This has fewer barcodes with some cut off. But several of them are clear.

This being said, I think it worked perfectly for the one below by giving the five values {044000033385,4000033382,VF0olZI14,4000033382,044000033382} for:

This is an image with 5 barcodes. It was read perfectly.

And here is the code for making a sticker collage:

barcodeFormats={"Aztec","Codabar","Code128","Code39","Code93","DataMatrix","EAN13","EAN8","ITF","PDF417","QR","UPC","UPCE"};
allowedColorCombinations={
{RGBColor[0,0,0], RGBColor[1,1,1]},{RGBColor[1,0,0], RGBColor[0,1,1]},
{RGBColor[0,1,0], RGBColor[1,0,1]},{RGBColor[0,0,1], RGBColor[1,1,0]},
{RGBColor[1,1,1], RGBColor[0,0,0]},{RGBColor[0,1,1], RGBColor[1,0,0]},
{RGBColor[1,0,1], RGBColor[0,1,0]},{RGBColor[1,1,0], RGBColor[0,0,1]}
};

barCodeGenerator[format_,chosenColorCombination_] :=
Module[
  {numericList, alphaNumericList,alphaNumericCapitalList ,alphaNumericSpecialList,fullSpecialCharacterList, partialSpecialCharacterList, level, barcode,string1,string2},
  
numericList = CharacterRange["0", "9"];
alphaNumericList = Join[CharacterRange["0", "9"], CharacterRange["A", "Z"], CharacterRange["a", "z"]];
alphaNumericCapitalList = Join[CharacterRange["0", "9"], CharacterRange["A", "Z"]];
alphaNumericSpecialList=Join[CharacterRange["0", "9"], CharacterRange["A", "Z"], CharacterRange["a", "z"],{ "-", ".", "$", "/", "+", "%", " "}];
fullSpecialCharacterList ={ "-", ".", "$", "/", "+", "%", " "};
 partialSpecialCharacterList={"-","$",".","/","+"};
   

  Switch[format,
    "Aztec" | "PDF417" | "QR",
    barcode = StringJoin[RandomChoice[alphaNumericSpecialList, RandomInteger[{8, 200}]]];
    level = RandomInteger[{0, 8}];
    ColorReplace[BarcodeImage[barcode, {format, level}],{Black->chosenColorCombination[[1]],White->chosenColorCombination[[2]]}],
    
 "Code39" ,
 string1=StringJoin[RandomChoice[alphaNumericCapitalList, RandomInteger[{1, 66}]]];
 string2=StringJoin[RandomChoice[fullSpecialCharacterList, RandomInteger[{1, 14}]]];
 barcode=StringJoin[RandomSample[Join[Characters[string1], Characters[string2]]]];
   ColorReplace[BarcodeImage[barcode, format],{Black->chosenColorCombination[[1]],White->chosenColorCombination[[2]]}],
    
 "Code93" ,
 string1=StringJoin[RandomChoice[alphaNumericCapitalList, RandomInteger[{1, 66}]]];
 string2=StringJoin[RandomChoice[fullSpecialCharacterList, RandomInteger[{1, 14}]]];
 barcode=StringJoin[RandomSample[Join[Characters[string1], Characters[string2]]]];
   ColorReplace[BarcodeImage[barcode, format],{Black->chosenColorCombination[[1]],White->chosenColorCombination[[2]]}],
    
    "Code128"  ,
    barcode = StringJoin[RandomChoice[alphaNumericSpecialList, RandomInteger[{1, 80}]]];
    ColorReplace[BarcodeImage[barcode, format],{Black->chosenColorCombination[[1]],White->chosenColorCombination[[2]]}],
    
 "Codabar",
 string1=StringJoin[RandomChoice[numericList, RandomInteger[{1, 100}]]];
 string2=StringJoin[RandomChoice[partialSpecialCharacterList, RandomInteger[{1, 14}]]];
 barcode=StringJoin[RandomSample[Join[Characters[string1], Characters[string2]]]];
 ColorReplace[BarcodeImage[barcode, format],{Black->chosenColorCombination[[1]],White->chosenColorCombination[[2]]}],
 
 "DataMatrix",
 barcode = StringJoin[RandomChoice[alphaNumericList, RandomInteger[{8, 14}]],RandomChoice[{"-","$",":","/","."}]];
    ColorReplace[BarcodeImage[barcode, format],{Black->chosenColorCombination[[1]],White->chosenColorCombination[[2]]}],
    
    "ITF",
    barcode = StringJoin[RandomChoice[numericList, RandomChoice[Table[2*i, {i, 3, 40}]]]];
    ColorReplace[BarcodeImage[barcode, format],{Black->chosenColorCombination[[1]],White->chosenColorCombination[[2]]}],
    
    "EAN13",
    barcode = StringJoin[RandomChoice[numericList, 13]];
    ColorReplace[BarcodeImage[barcode, format],{Black->chosenColorCombination[[1]],White->chosenColorCombination[[2]]}],
    
    "UPC",
    barcode = StringJoin[RandomChoice[numericList, 12]];
    ColorReplace[BarcodeImage[barcode, format],{Black->chosenColorCombination[[1]],White->chosenColorCombination[[2]]}],
    
   "EAN8" ,
  barcode = StringJoin[RandomChoice[numericList, 8]];
     ColorReplace[BarcodeImage[barcode, format],{Black->chosenColorCombination[[1]],White->chosenColorCombination[[2]]}],
    
  "UPCE",
    barcode = StringJoin[Join[{RandomChoice[{"0","1"}]},RandomChoice[numericList, RandomChoice[{6,7}]]]];
    ColorReplace[BarcodeImage[barcode, format],{Black->chosenColorCombination[[1]],White->chosenColorCombination[[2]]}]
   
  ]
  
  (*barcode*)
]

(* Initialize an empty list for successful barcode generations *)
successfulBarcodes = {};
(* Desired number of successful barcode generations *)
desiredSuccesses = 20;
(* Counter for successful generations *)
successCount = 0;
(* Maximum number of attempts to avoid infinite loop *)
maxAttempts = 100;
attempts = 0;
While[successCount < desiredSuccesses && attempts < maxAttempts,
  (* Attempt to generate a barcode, suppressing warnings/errors *)
  result = Quiet[Check[
    barCodeGenerator[RandomChoice[barcodeFormats], RandomChoice[allowedColorCombinations]],
    "Error"
  ]];
  
  (* Check if the generation was successful *)
  If[result =!= "Error",
    (* If successful, append to the list and increment the counter *)
    AppendTo[successfulBarcodes, result];
    successCount++;
  ];
  
  (* Increment the attempts counter *)
  attempts++;
]
(* successfulBarcodes now contains the successful barcode generations, up to the desired number or the attempt limit *)

Rasterize[ImageCollage[successfulBarcodes,"Stretch",{825 , 1150},ImagePadding->10,Background->RGBColor[.5,.5,.5]]]

Lastly, this is a photo of a wooden pallet with empty boxes on them with stickers made from Mathematica in my garage. While I don't expect it to be able to be read, I thought this was a good place for Show & Tell. I call this sculpture, "Empty Boxes on a Pallet". Some people play the guitar as a hobby, but I do this...

Empty Boxes on a Pallet

$\endgroup$

1 Answer 1

6
$\begingroup$

Here is a partial answer. Hopefully someone else can improve it.

BarcodeRecognize seems to work better with isolated barcodes. This can be accomplished using MorphologicalComponents, if the barcodes are well separated.

img2 = ColorNegate[Binarize[img, .5]]

enter image description here

img3 = Dilation[img2, DiskMatrix[5]]

enter image description here

comps = MorphologicalComponents[img3, .01, Method -> "BoundingBox"];
comps // Colorize

enter image description here

ComponentMeasurements can now be used to extract each barcode

barcodes = ComponentMeasurements[{img, comps}, "Image"][[All, 2]]

enter image description here

For some barcodes, BarcodeRecognize returns the same result for the original and color inverted images, and for some only the inverted one works. This decodes 26 of the 40 barcodes:

BarcodeRecognize /@ ColorNegate[barcodes] /. {} -> Nothing

{"Z20aHSN1q-", "XXc5EIsPc-", "RsEMPkIXP-", "cxWXUX5pmKAWh",
"ZzFgrlIX", "OgYFuUdue", "RRS4K2kvV", "LOT4qMeOK", "5839218585789",
"VF0olZI14", "Yu8up3lWEzQt8U/", "JVqusjCx3GSN3Y/", "eB7npKSnBJZH-",
"Vg6W92475Tv0y", "sUhAv0yLSGb/", "SKlJDYqEWgOcQ4", "uIf471MW/",
"cEucOXc90", "aZVZYcYx3PAjTL", "XqRf07XAtzm", "aI8F2lFt", "hEOAqfV1",
"F8V0Kin1xvIK18", "Z1PUfv5Uq9", "whmVd9rHfYh0", "u7QuPYD7uD3J5W"}

Edited to show which barcodes worked

BarcodeRecognize performance appears to be worse with 1D and high-density 2D barcodes.

SortBy[Transpose[{barcodes, 
    BarcodeRecognize /@ ColorNegate[barcodes]}], Last] // Column

enter image description here

$\endgroup$
2
  • $\begingroup$ Thanks. I didn't know about ComponentMeasurements. I am curious now about which types it reads better or worse for now. $\endgroup$
    – Teg Louis
    Commented Feb 26 at 2:18
  • 1
    $\begingroup$ @TegLouis - Edited answer to show which ones worked $\endgroup$
    – MelaGo
    Commented Feb 26 at 15:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.