Hai semuanya!
Setiap orang menggunakan barcode saat ini, kebanyakan tanpa memperhatikan hal ini. Ketika kami membeli bahan makanan di toko, pengenal mereka dapatkan dari barcode. Ini juga sama dengan barang di gudang, parsel pos dan sebagainya. Tetapi tidak banyak orang yang tahu, bagaimana cara kerjanya.
Apa yang 'di dalam' barcode, dan apa yang dikodekan pada gambar ini?

Mari kita mencari tahu, dan juga mari kita menulis bar decoder kita sendiri.
Pendahuluan
Menggunakan barcode memiliki sejarah panjang. Upaya pertama untuk membuat otomatisasi dilakukan pada tahun 50-an, paten untuk sistem pembacaan kode diberikan. David Collins, yang bekerja di Pennsylvania Railroad, memutuskan untuk mempermudah proses penyortiran mobil. Idenya jelas - untuk menyandikan pengidentifikasi mobil dengan garis warna yang berbeda, dan membacanya menggunakan sel foto. Pada tahun 1962 kode semacam itu menjadi standar oleh Association of American Railroads. (sistem
KarTrak ). Pada tahun 1968 lampu diganti oleh laser, itu memungkinkan untuk meningkatkan akurasi dan mengurangi ukuran pembaca. Pada tahun 1973, Kode Produk Universal dikembangkan, dan pada tahun 1974 produk bahan makanan pertama (permen karet Wrigley - jelas di Amerika Serikat;) dijual. Pada tahun 1984, bagian ketiga dari semua toko telah menggunakan barcode, di negara lain kemudian menjadi populer.
Ada banyak jenis barcode yang berbeda untuk aplikasi yang berbeda, misalnya, string "12345678" dapat dikodekan dengan cara ini (dan tidak semuanya):

Mari kita mulai analisis. Semua informasi di bawah ini adalah tentang tipe "Code-128" - hanya karena prinsipnya mudah dipahami. Mereka yang ingin menguji mode lain, dapat menggunakan
generator barcode online dan menguji jenis lain sendiri.
Pada pandangan pertama, sebuah barcode terlihat seperti kumpulan angka acak, tetapi sebenarnya strukturnya terorganisasi dengan baik:

1 - Ruang kosong, diperlukan untuk menentukan posisi kode mulai.
2 - Mulai simbol. Tiga jenis Code-128 tersedia (disebut A, B dan C), dan simbol awal masing-masing dapat berupa 11010000100, 11010010000 atau 11010011100. Untuk jenis ini, tabel penyandian berbeda (lihat
deskripsi Code_128 untuk lebih jelasnya ).
3 - Kode itu sendiri, berisi data pengguna.
4 - Periksa jumlah.
5 - Stop simbol, untuk Code-128-nya 1100011101011.
6 (1) - Ruang kosong.
Sekarang mari kita lihat, bagaimana bit-bit tersebut dikodekan. Sangat mudah - jika kita akan mengambil lebar garis paling tipis ke "1", maka garis lebar ganda adalah "11", garis lebar tiga kali lipat adalah "111", dan seterusnya. Ruang kosong masing-masing akan "0", "00" atau "000", sesuai dengan prinsip yang sama. Mereka yang tertarik, dapat membandingkan urutan mulai pada gambar di atas, untuk melihat bahwa aturannya dihormati.
Sekarang kita bisa mulai coding.
Mendapatkan urutan bit
Secara umum, ini adalah bagian yang paling rumit, dan dapat dilakukan dengan cara yang berbeda. Saya tidak yakin bahwa pendekatan saya optimal, tetapi untuk tugas kami cukup jelas.
Pertama, mari memuat gambar, merentangkan lebar, memotong garis horizontal dari tengah, mengubahnya menjadi warna b / w dan menyimpannya sebagai array.
from PIL import Image import numpy as np import matplotlib.pyplot as plt image_path = "barcode.jpg" img = Image.open(image_path) width, height = img.size basewidth = 4*width img = img.resize((basewidth, height), Image.ANTIALIAS) hor_line_bw = img.crop((0, int(height/2), basewidth, int(height/2) + 1)).convert('L') hor_data = np.asarray(hor_line_bw, dtype="int32")[0]
Pada barcode, garis hitam berkorespondensi dengan “1”, tetapi dalam RGB hitamnya bertolak belakang, 0, sehingga array harus dibalik. Kami juga akan menghitung nilai rata-rata.
hor_data = 255 - hor_data avg = np.average(hor_data) plt.plot(hor_data) plt.show()
Mari kita jalankan program untuk memverifikasi bahwa barcode telah dimuat dengan benar:

Sekarang kita perlu menentukan lebar satu 'bit'. Untuk melakukan ini, kami akan mengekstrak urutan, menyimpan posisi persimpangan garis rata-rata.
pos1, pos2 = -1, -1 bits = "" for p in range(basewidth - 2): if hor_data[p] < avg and hor_data[p + 1] > avg: bits += "1" if pos1 == -1: pos1 = p if bits == "101": pos2 = p break if hor_data[p] > avg and hor_data[p + 1] < avg: bits += "0" bit_width = int((pos2 - pos1)/3)
Kami hanya menyimpan garis silang rata-rata, sehingga kode "1101" akan disimpan sebagai "101", cukup bit untuk mendapatkan lebar pikselnya.
Sekarang mari kita buat decoding itu sendiri. Kita perlu menemukan setiap garis rata-rata yang bersilangan, dan menemukan jumlah bit dalam interval terakhir, yang ditemukan. Angka tidak akan cocok dengan sempurna (kode dapat diregangkan atau ditekuk sedikit), jadi, kita perlu membulatkan nilainya menjadi bilangan bulat.
bits = "" for p in range(basewidth - 2): if hor_data[p] > avg and hor_data[p + 1] < avg: interval = p - pos1 cnt = interval/bit_width bits += "1"*int(round(cnt)) pos1 = p if hor_data[p] < avg and hor_data[p + 1] > avg: interval = p - pos1 cnt = interval/bit_width bits += "0"*int(round(cnt)) pos1 = p
Mungkin ada cara yang lebih baik untuk melakukan ini, pembaca dapat menulis dalam komentar.
Jika semua dilakukan dengan sempurna, kita akan mendapatkan urutan seperti ini:
11010010000110001010001000110100010001101110100011011101000111011011
01100110011000101000101000110001000101100011000101110110011011001111
00010101100011101011
Decoding
Secara umum, ini cukup mudah. Simbol dalam
Kode-128 dikodekan dengan kode 11-bit, yang dapat memiliki pengkodean yang berbeda (menurut pengkodean ini - A, B atau C, dapat berupa huruf atau angka dari 00 hingga 99).
Dalam kasus kami, awal urutannya adalah 11010010000, yang sesuai dengan "Kode B". Saya terlalu malas untuk memasukkan semua kode secara manual, jadi saya hanya menyalinnya dari halaman Wikipedia. Parsing dari baris ini juga dibuat dengan Python (petunjuk - jangan lakukan hal-hal seperti ini pada produksi).
CODE128_CHART = """ 0 _ _ 00 32 S 11011001100 212222 1 ! ! 01 33 ! 11001101100 222122 2 " " 02 34 " 11001100110 222221 3 # # 03 35 # 10010011000 121223 ... 93 GS } 93 125 } 10100011110 111341 94 RS ~ 94 126 ~ 10001011110 131141 103 Start Start A 208 SCA 11010000100 211412 104 Start Start B 209 SCB 11010010000 211214 105 Start Start C 210 SCC 11010011100 211232 106 Stop Stop - - - 11000111010 233111""".split() SYMBOLS = [value for value in CODE128_CHART[6::8]] VALUESB = [value for value in CODE128_CHART[2::8]] CODE128B = dict(zip(SYMBOLS, VALUESB))
Bagian terakhir mudah. Pertama, mari kita pisahkan urutan menjadi blok 11-bit:
sym_len = 11 symbols = [bits[i:i+sym_len] for i in range(0, len(bits), sym_len)]
Akhirnya, mari hasilkan string output dan tampilkan:
str_out = "" for sym in symbols: if CODE128A[sym] == 'Start': continue if CODE128A[sym] == 'Stop': break str_out += CODE128A[sym] print(" ", sym, CODE128A[sym]) print("Str:", str_out)
Saya tidak akan menunjukkan di sini hasil dekode dari gambar atas, biarkan itu menjadi pekerjaan rumah bagi pembaca (menggunakan aplikasi yang diunduh untuk smartphone akan dianggap curang :).
Pemeriksaan CRC tidak diterapkan dalam kode ini, mereka yang ingin, dapat melakukannya sendiri.
Yang pasti, algoritma ini tidak sempurna, itu dilakukan dalam waktu setengah jam. Untuk tugas profesional ada pustaka yang siap digunakan, misalnya,
pyzbar . Untuk mendekode gambar, 4 baris kode sudah cukup:
from pyzbar.pyzbar import decode img = Image.open(image_path) decode = decode(img) print(decode)
(pertama perpustakaan harus diinstal menggunakan perintah "pip install pyzbar")
Tambahan : pengguna situs
vinograd19 mengirim komentar menarik tentang riwayat perhitungan jumlah cek barcode.
Perhitungan angka cek itu menarik, itu berasal dari evolusi.
Jumlah cek jelas diperlukan untuk menghindari kesalahan penguraian kode. Jika barcode 1234, dan diterjemahkan sebagai 7234, kita perlu metode untuk menolak penggantian 1 hingga 7. Validasi bisa tidak sempurna, tetapi setidaknya 90% kode harus diverifikasi dengan benar.
Pendekatan 1: Mari kita ambil saja jumlah, untuk memiliki 0 sebagai sisa dari divisi. Simbol pertama berisi data, dan digit terakhir adalah demikian, sehingga jumlah semua angka dibagi dengan 10. Setelah decoding, jika jumlahnya tidak habis dibagi 10 - decoding salah, dan perlu diulang. Misalnya, kode 1234 valid - 1 + 2 + 3 + 4 = 10. Kode 1216 - juga valid, tetapi 1218 tidak.
Ini membantu untuk menghindari masalah decoding. Tetapi kode juga dapat dimasukkan secara manual, menggunakan keyboard perangkat keras. Menggunakan ini, kasus buruk lain ditemukan - jika urutan dua digit akan diubah, jumlah cek akan tetap benar, itu pasti buruk. Misalnya, jika barcode 1234 dimasukkan sebagai 2134, jumlah cek akan sama. Ditemukan, bahwa urutan angka yang salah adalah kasus umum, jika seseorang mencoba memasukkan angka dengan cepat.
Pendekatan 2. Mari kita tingkatkan algoritma checksum - mari kita hitung angka ganjil dua kali. Kemudian, jika pesanan akan diubah, jumlahnya akan salah. Misalnya, kode 2364 valid (2 + 3 * 2 + 6 + 4 * 2 = 20), tetapi kode 3264 tidak (3 + 2 * 2 + 6 + 4 * 2 = 19). Lebih baik, tetapi ada kasus lain yang muncul. Ada beberapa keyboard, memiliki 10 kunci dalam dua baris, baris pertama adalah 12345 dan yang kedua adalah 67890. Jika alih-alih "1" pengguna akan mengetik "2", cek checksum akan gagal. Tetapi jika pengguna akan memasukkan "6" dan bukannya "1" - jumlah cek mungkin terkadang benar. Itu karena 6 = 1 + 5, dan jika digit memiliki tempat ganjil, kita mendapatkan 2 * 6 = 2 * 1 + 2 * 5 - jumlahnya meningkat 10. Kesalahan yang sama akan terjadi, jika pengguna memasukkan "7 "Alih-alih" 2 "," 8 "bukannya" 3 ", dan seterusnya.
Pendekatan ke-3. Mari kita ambil jumlahnya lagi, tapi mari kita dapatkan angka ganjil ... 3 kali. Misalnya, kode 1234565 - valid, karena 1 + 2 * 3 + 3 + 4 * 3 + 5 + 6 * 3 +5 = 50.
Metode ini menjadi standar untuk kode EAN13, dengan beberapa perubahan: jumlah digit adalah tetap dan sama dengan 13, di mana 13 digit - adalah jumlah cek. Angka di tempat ganjil dihitung tiga kali, di tempat genap sekali.Ngomong-ngomong, kode EAN-13 adalah yang paling banyak digunakan dalam perdagangan dan pusat perbelanjaan, sehingga orang melihatnya lebih sering daripada jenis kode lainnya. Pengkodean bitnya sama seperti pada Code-128, struktur datanya dapat ditemukan di
artikel Wikipedia .
Kesimpulan
Seperti yang bisa kita lihat, bahkan hal yang mudah seperti barcode, bisa berisi beberapa hal keren. By the way, lifehack kecil lain untuk pembaca, yang cukup sabar untuk membaca sampai tempat ini - teks di bawah barcode sepenuhnya identik dengan data barcode. Itu dibuat untuk operator, yang dapat secara manual memasukkan kode, jika tidak dapat dibaca oleh pemindai. Jadi mudah untuk mengetahui konten barcode - cukup baca teks di bawah ini.
Terima kasih sudah membaca.