You are on page 1of 14

Wydział Mechaniczny

Politechniki Białostockiej
Katedra Robotyki i Mechatroniki

Instrukcja do zajęć laboratoryjnych z przedmiotu:

SYSTEMY WIZYJNE

Ćwiczenie nr: 3

Kontrola kodów 1D-2D

Kod przedmiotu: MK2S22005

Instrukcję opracował: dr inż. Jakub Augustyniak

Białystok 2022
Cel ćwiczenia
Celem ćwiczenia jest stworzenie kompletnego algorytmu analizy i przetwarzania obrazu do
rozpoznawania kodów 1D oraz 2D znajdujących się obiektach umieszczonych na taśmociągu
przemysłowym wykorzystując kamerę Kinect.
1. Wprowadzenie
Kod kreskowy to informacje w postaci cyfr albo liter zawarte w znaku graficznym. Zależnie od
rodzaju kodu kreskowego wyróżniamy: kod 1D (zbudowany z pasków) oraz kod 2D
(zbudowany z kwadracików) np. kody QR. Odczyt polega na rozszyfrowaniu kombinacji
czarnych i białych elementów w symbolu, która odpowiada za konkretne znaki (cyfry i liczby).
Kombinacja określona jest za pomocą szerokości każdej z kresek lub złożoności kwadratów
w zależności od rodzaju kodu kreskowego [1].
Kody jednowymiarowe:
Kody 1D inaczej linearne, opierają się na pionowych, ciemnych oraz jasnych liniach. Procedura
odczytu kodów jednowymiarowych opiera się na określaniu różnic między szerokościami linii
w kodzie kreskowym. Odczyt ten ogranicza się wyłącznie do odczytu poziomego pionowych
linii [2].
Rodzaje kodów 1D:

• EAN – kod typu EAN występuje w dwóch wersjach: EAN – 13 (12 cyfr danych oraz
jedna kontrolna). Kod EAN 13 w USA znany jest także jako UPC. Używany również
w połączeniu z ISSN w magazynach prasowych.
• Kod 39 (Code 39) – kod kreskowy złożony z pasków, który zawiera znaki
alfanumeryczne. Jest zmiennej długości i pozwala zapisać 43 znaki. Każdy znak ma 9
elementów, 3 są znacznie szersze.
• Kod 128 (Code 128) – kod alfanumeryczny o zmiennej długości, który został
opracowany, aby rozszerzyć liczbę znaków do 128.
• Kod przeplatany 2 z 5 (Interleaved 2 of 5) –kod wyłącznie numeryczny o parzystej,
zmiennej długości. Wyróżnia się dużym zagęszczeniem – cyfry kodowane są parami
w „przeplocie” – czarne paski odpowiadają za jedną cyfrę, natomiast białe paski za
drugą.
Kody dwuwymiarowe
Kody 2D pozwalają zmieścić większą ilość informacji niż kody liniowe, ponieważ ich kodowanie
i odczyt odbywa się zarówno pionowo jak i poziomo [2].
Rodzaje kodów 2D:

• Aztec – kod alfanumeryczny o dużej gęstości. Umożliwia zapis 3832 znaków


numerycznych lub 3067 alfanumerycznych. Składa się z tarczy w środku i zbudowany
jest na kwadratowej siatce.
• DataMatrix – kod alfanumeryczny, który charakteryzuje się zmienną długością oraz
dużą gęstością. Złożony jest z kwadratów ułożonych wewnątrz obwodu symbolu.
Wyróżnia się możliwością zapisu 3116 znaków numerycznych lub 2335
alfanumerycznych.
• PDF 417 – kod alfanumeryczny, który umożliwia zapis dużej ilości danych,
przedstawionych w postaci tzw. słów kodowych. Każde ze słów składa się z 4
czarnych kresek wewnątrz 17 modułów. Umożliwia zapis 256 znaków ASCII II
zawartych w trzech zbiorach, każdy z nich zawiera 929 znaków o różnych wzorach.
• QR Code – kod alfanumeryczny o dużych możliwościach. Pozwala zapisać 7089
znaków numerycznych lub 4296 alfanumerycznych.
Kody hybrydowe
Są połączeniem kodów dwuwymiarowych oraz jednowymiarowych. Powstały w wyniku
ewolucji tych kodów [2].
Rodzaje kodów hybrydowych:

• Aztec Mesas – kod dwuwymiarowy z kodem kreskowym jednowymiarowym.


Pozwala kodować rożne ilości danych.
• RSS – pozwala zakodować dużą ilość danych na niewielkim obszarze.

Kody trójwymiarowe tzw. DPM to przeważnie dwuwymiarowe kody kreskowe wytłoczone na


płaskiej powierzchni w dowolnym materiale. Często pojawiają się na elementach metalowych
(np. przy produkcji samochodów), które tworzą określone wzór w tym wypadku kod kreskowy
[2].

2. Opis stanowiska pomiarowego

a) Kamery KINECT

Kamera Kinect (Rys. 1) to seria urządzeń wejściowych wyprodukowanych przez firmę


Microsoft i wydanych po raz pierwszy w 2010 roku. Urządzenia te zawierają kamery RGB oraz
projektory i detektory podczerwieni, które mapują głębię obrazu za pomocą obliczeń światła
strukturalnego lub czasu lotu. Zebrane dzięki nim informacje mogą być wykorzystywane do
np. rozpoznawanie gestów i wykrywanie szkieletu ciała w czasie rzeczywistym. Kamera Kinect
zawiera również mikrofony, których można używać do rozpoznawania mowy i sterowania
głosowego.
Rys. 1 Wygląd kamery Kinect: a) Kinect v1; b) Kinect v2

Technologia wykrywania głębi i ruchu stanowiąca podstawę sensora Kinect jest dostępna
dzięki czujnikowi głębi. Oryginalny sensor Kinect v1 (Rys. 2) wykorzystuje w tym celu światło
strukturalne: urządzenie używa wzoru w bliskiej podczerwieni wyświetlanego w przestrzeni
przed sensorem Kinect, podczas gdy czujnik podczerwieni wychwytuje wzór odbitego światła.
Wzór światła jest zniekształcony przez względną głębokość obiektów znajdujących się przed
nim, a do oszacowania tej głębokości można użyć zależności matematycznych związanych
z układem sprzętowym sensora Kinect. Kinect v2 (Rys. 3) używa pomiarów czasu lotu.
Projektor podczerwieni w sensorze Kinect wysyła modulowane światło podczerwone, które
jest następnie przechwytywane przez czujnik. Światło podczerwone odbijające się od bliższych
obiektów będzie miało krótszy czas lotu niż to odbite od elementów bardziej odległych. Czujnik
podczerwieni rejestruje, jak bardzo wzór modulacji został zdeformowany w zależności od
czasu lotu, piksel po pikselu. Pomiary głębokości w czasie lotu mogą być dokładniejsze
i obliczone w krótszym czasie, co pozwala na wykrycie większej liczby klatek na sekundę [3].

Tabela 1. Porównanie parametrów kamery Kinect v1 oraz Kinect v2

Parametr/Kamera Kinect v1 Kinect v2


Rozdzielczość (kolor) + fps 640×480 30fps 1920×1080 30fps
Rozdzielność (głębia) 320x240 512x424
Czujnik Światło strukturalne Czas lotu
Zdefiniowane stawy
20 26
szkieletowe
Poziome pole widzenia 57° 70°
Pionowe pole widzenia 43° 60°
Rys. 2 Budowa kamery Kinect v1

Rys. 3 Budowa kamery Kinect v2

b) Stanowisko laboratoryjne MPS 500 – FMS

Jest modułowym stanowiskiem związanym z elastycznym systemem produkcyjnym


ukazującym zachodzące procesy technologiczne szczególnie w przemyśle spożywczym lub
farmaceutycznym (Rys. 4). Poniżej przedstawione stanowisko składa się z następujących
komponentów:

1) Stanowisko napełniania i indeksowania butelek


2) Stanowisko pakowania
3) Stanowisko transportowe
4) Stanowisko rozpakowywania
5) Stanowisko odsysania i mycia
6) Stanowisko buforowania
7) Stanowisko dystrybucji
8) Stanowisko podawania
9) Stanowisko magazynowania
10) Stanowisko sortowania (wydania towaru).

Rys. 4 Stanowisko MPS 500 FMS z wyszczególnionymi modułami

Wszystkie moduły stanowiska wyposażone są w sterownik PLC S7-300, na które zostały


wgrane odpowiednie programy sterujące. Połączenie pomiędzy nimi jest realizowane za
pomocą sieci Ethernet, która umożliwia wzajemną wymianę danych.

3. Przebieg ćwiczenia
Ćwiczenie rozpocząć od dokonania kalibracji wybranego czujnika jakim jest kamera Kinect v1
lub Kinect v2.
Kolejne etapy:
1) Uzyskać podgląd obrazu na żywo;
2) Wykorzystując funkcję readBarcode znaleźć na obrazie kod QR;
msg = readBarcode(I) - wykrywa i dekoduje kod kreskowy 1-D lub 2-D w obrazie
wejściowym i zwraca komunikat skojarzony z tym kodem kreskowym.
Jeśli obraz wejściowy zawiera wiele kodów kreskowych, funkcja readBarcode dekoduje tylko
pierwszy wykryty kod kreskowy.
msg = readBarcode(I,roi) - określa prostokątny obszar zainteresowania (ROI), aby
zmniejszyć obszar, w którym funkcja szuka kodu kreskowego. Obszar zainteresowania ROI
musi być w pełni zawarty w obrazie wejściowym.
msg = readBarcode(___,format) - określa formaty kodów kreskowych w celu
zmniejszenia typów kodów kreskowych, których szuka funkcja. Określ ten argument oprócz
dowolnej kombinacji argumentów wejściowych w poprzednich składniach.
[msg,detectedFormat,loc] - dodatkowo zwraca format, detectFormat i lokalizację loc
wykrytego kodu kreskowego.
3) Dodać adnotację do obrazu za pomocą zdekodowanej wiadomości;
xyText = loc(2,:);
Imsg = insertText(I, xyText, msg, "BoxOpacity", 1, "FontSize", 25);

4) Wstawić wypełnione okręgi w lokalizacjach wykrytego szyku;


Imsg = insertShape(Imsg, "FilledCircle", [loc, ...
repmat(10, length(loc), 1)], "Color", "red", "Opacity", 1);

5) Wyświetlić wynik
W przypadku kodu 1D należy:

• Uzyskać podgląd obrazu na żywo;


• Wykorzystując funkcję readBarcode znaleźć na obrazie kod kreskowy i określić jego
format;
• Wyświetlić odczytaną wiadomość wraz z formatem;
disp("Detected format and message: " + format + ", " + msg)

• Wstawić znaczniki na krańcach kodu kreskowego;


I = insertShape(I, "FilledCircle", [locs, ...
repmat(10, length(locs), 1)], "Color", "red", "Opacity", 1);

• Wyświetlić wynik.
UWAGA:
W celu pomyślnego wykrycia kod kreskowy musi on być widoczny (niczym nie przysłonięty
oraz w polu widzenia kamery). Musi być również jak najbliżej wyrównany do pozycji poziomej
lub pionowej. Funkcja readBarcode jest z natury bardziej odporna na rotacje dla kodów 2-D
lub matrycowych niż dla 1-D lub liniowych kodów kreskowych [3].
Funkcja readBarcode wykrywa tylko jeden kod kreskowy w każdym obrazie. Aby wykryć wiele
kodów kreskowych, trzeba określić region zainteresowania (ROI). Aby określić ROI, można użyć
funkcji Drawrectangle, aby interaktywnie określić ROI. Można także użyć technik analizy
obrazu, aby wykryć ROI wielu kodów kreskowych na obrazie [3].
Wykrywanie wielu kodów na jednym obrazie:
1) Użyć funkcji drawrectangle, aby narysować i uzyskać parametry prostokąta.
roi1 = drawrectangle;
pos = roi1.Position;
2) Użyć funkcji readBarCode w celuy znalezienie kodu oraz jego formatu. Następnie
wprowadzić linie wskazujące linie rzędu skanowanego, po czym nanieść adnotację na
obraz za pomocą zdekodowanej wiadomości;
roi = […………];

imSize = size(I);
for i = 1:size(roi,1)
[msg, format, locs] = readBarcode(I, roi(i,:));
disp("Wiadomosc: " + format + ", " + msg)

xyBegin = locs(1,:);
I = insertShape(I,"Line",[1 xyBegin(2) imSize(2) xyBegin(2)], ...
"LineWidth", 5);

I = insertText(I, xyBegin, msg, "BoxOpacity", 1, "FontSize", 20);


end

W celu zautomatyzowania procesu wykrywania wielu kodów kreskowych należy posłużyć się
technikami analizy oraz przetwarzania obrazów. Wymaga to zlokalizowania wielu kodów
kreskowych na obrazie, określenia i skorygowania ich orientacji. W przypadku obrazu
zawierającego wiele obróconych kodów kreskowych należy przystąpić do wstępnego
przetwarzania obrazu w celu prawidłowego odczytania ich.

W tym celu należy:

1) Wykryć regiony kandydujące dla kodów kreskowych za pomocą MSER (ang. Maximally
stable extremal regions).
Następnie, wykryć obszary zainteresowania na obrazie za pomocą funkcji
detectMSERFeatures. Pozwoli to wyeliminować niepożądane obszary na podstawie
określonych kryteriów, takich jak współczynnik proporcji. Można użyć obrazu binarnego
z przefiltrowanych wyników do dalszego przetwarzania.

[~, cc] = detectMSERFeatures(Igray);

regionStatistics = regionprops(cc, 'MajorAxisLength', 'MinorAxisLength');


minAspectRatio = 10;
candidateRegions =
find(([regionStatistics.MajorAxisLength]./[regionStatistics.MinorAxisLength
]) > minAspectRatio);

BW = false(size(Igray));

for i = 1:length(candidateRegions)
BW(cc.PixelIdxList{candidateRegions(i)}) = true;
end

imshow(BW)
title("Kandydujace region dla kodow kreskowych")

2) Wyodrębnić segmenty linii kodu kreskowego za pomocą transformacji Hough.


Wykryć widoczne krawędzie obrazu za pomocą funkcji krawędziowej. Następnie użyć
transformaty Hough, aby znaleźć interesujące linie - możliwe pionowe kreski w kodzie
kreskowym.
BW = edge(BW,'canny');
[H,T,R] = hough(BW);

imshow(BW)

% Określ rozmiar sąsiedztwa tłumienia.


reductionRatio = 500;
nhSize = floor(size(H)/reductionRatio);
idx = mod(nhSize,2) < 1;
nhSize(idx) = nhSize(idx) + 1;

% Zidentyfikuj szczyty transformacji Hougha.


P = houghpeaks(H,length(candidateRegions),'NHoodSize',nhSize);

% Wykryj linie na podstawie wykrytych pików.


lines = houghlines(BW,T,R,P);

% Wyświetl linie wykryte za pomocą funkcji houghlines.


Ihoughlines = ones(size(BW));

% Punkty początkowe i końcowe wykrytych linii.


startPts = reshape([lines(:).point1], 2, length(lines))';
endPts = reshape([lines(:).point2], 2, length(lines))';

Ihoughlines = insertShape(Ihoughlines, 'Line', [startPts, endPts], ...


'LineWidth', 2, 'Color', 'green');

% Wyświetl oryginalny obraz z nałożonymi wykrytymi liniami.


Ibarlines = imoverlay(I, ~Ihoughlines(:,:,1));
imshow(Ibarlines)
3) Zlokalizować kody kreskowe na obrazie

Po wyodrębnieniu odcinków linii należy zlokalizować poszczególne kody kreskowych na


obrazie. W tym celu można wykorzystać jedną z dwóch metod.

Metoda 1: Technika oparta na klastrach, która wykorzystuje funkcje pakietu Statistics


i Machine Learning Toolbox™ do identyfikacji poszczególnych kodów kreskowych. Ta technika
jest bardziej odporna na wartości odstające, które zostały wykryte przy użyciu powyższych
technik analizy obrazu. Można go również rozszerzyć na szeroki zakres warunków
obrazowania bez konieczności dostrajania parametrów.

Metoda 2: Technika oparty na segmentacji w celu oddzielenia poszczególnych kodów


kreskowych. Ta metoda wykorzystuje inne techniki analizy obrazu do lokalizacji i korekcji
obrotu wyodrębnionych kodów kreskowych. Chociaż działa to całkiem dobrze, może wymagać
dostrojenia parametrów, aby zapobiec wykrywaniu wartości odstających.

Metoda 1: Technika oparty na klastrach


Ta technika składa się z dwóch kroków:
1. Określenie dwusieczne segmentów linii kodu kreskowego
Chociaż powszechną praktyką jest bezpośrednie używanie linii (uzyskanych za pomocą
przekształcenia Hougha) do lokalizacji kodu kreskowego, ta metoda wykorzystuje linie do
dalszego wykrywania dwusiecznych prostopadłych dla każdej z linii. Linie dwusieczne są
reprezentowane jako punkty w przestrzeni kartezjańskiej, dzięki temu nadają się do
identyfikacji poszczególnych kodów kreskowych. Zastosowanie dwusiecznych sprawia, że
wykrywanie poszczególnych kodów kreskowych jest bardziej niezawodne, ponieważ
skutkuje mniejszą błędną klasyfikacją linii, które są podobne, ale należą do różnych kodów
kreskowych.

2. Wykonanie grupowania na dwusiecznych, aby zidentyfikować poszczególne kody


kreskowe
Ponieważ wszystkie słupki w kodzie kreskowym są w przybliżeniu równoległe do siebie,
dwusieczne każdego z tych słupków powinny idealnie być tą samą linią, a odpowiadające
im punkty powinny zatem skupiać się wokół jednego punktu. W praktyce te dwusieczne
będą się różnić w zależności od segmentu, ale nadal będą na tyle podobne, aby umożliwić
zastosowanie algorytmu grupowania opartego na gęstości. Wynikiem wykonania tej
operacji grupowania jest zestaw klastrów, z których każdy wskazuje na osobny kod
kreskowy. W tym celu należy użyć funkcji dbscan (Statistics and Machine Learning Toolbox),
która nie wymaga wcześniejszej znajomości liczby klastrów.

Przykład sprawdza dostępność licencji Statistics and Machine Learning Toolbox™. Jeśli
zostanie znaleziona licencja, w przykładzie zostanie użyta metoda klastrowania.
W przeciwnym razie w przykładzie zastosowano metodę segmentacji.

useClustering = license('test','statistics_toolbox');

if useClustering
[boundingBox, orientation, Iclusters] = clusteringLocalization(lines,
size(I));

imshow(Iclusters)
else
disp("The clustering based workflow requires a license for the
Statistics and Machine Learning Toolbox")
end

Metoda 2: Technika oparty na segmentacji


Po usunięciu szumu tła, wykryte pionowe paski są grupowane w indywidualne kody kreskowe
przy użyciu operacji morfologicznych, takich jak imdilate. W przykładzie zastosowano funkcję
regionprops, aby określić obwiednię i orientację dla każdego z kodów kreskowych. Wyniki są
wykorzystywane do przycinania poszczególnych kodów kreskowych z oryginalnego obrazu
i orientacji ich mniej więcej poziomo.

if ~useClustering
[boundingBox, orientation, Idilated] =
segmentationLocalization(Ihoughlines);

imshow(Idilated)
end

4) Przycięcie kodów kreskowych i poprawa ich rotacji.

Kody kreskowe są przycinane z oryginalnego obrazu przy użyciu obwiedni uzyskanych z segmentacji.
Wyniki orientacji są używane do wyrównania kodów kreskowych tak, aby były w przybliżeniu poziome.

% Zlokalizuj i obróć kody kreskowe na obrazie.


correctedImages = cell(1, length(orientation));

% Przechowuj przycięte i skorygowane obrazy kodów kreskowych.


for i = 1:length(orientation)

I = insertShape(I, 'Rectangle', boundingBox(i,:), 'LineWidth',3,


'Color', 'red');
if orientation(i) > 0
orientation(i) = -(90 - orientation(i));
else
orientation(i) = 90 + orientation(i);
end

% Wykadruj kod kreskowy z oryginalnego obrazu i obróć go używając


% wykrytej orientacji. correctedImages{i} =
imrotate(imcrop(Igray,boundingBox(i,:)), orientation(i));
end

% Wyświetl obraz ze zlokalizowanymi kodami kreskowymi.


imshow(I)

5) Wykrycie kodów kreskowych w przyciętych obrazach z korekcją obrotu


Przycięte i skorygowane obrazy kodów kreskowych są następnie używane z funkcją
readBarcode do ich dekodowania.

for i = 1:length(correctedImages)
[msg, format, ~] = readBarcode(correctedImages{i}, '1D');
disp("Odczytana wiadomosc: " + format + ", " + msg)
end

Dodatkowe funkcje [3]:


clusteringLocalization wykorzystuje przepływ pracy oparty na klastrach do lokalizowania
poszczególnych kodów kreskowych.

function [boundingBox, orientation, Iclusters] =


clusteringLocalization(lines, imSize)

linesBisector = array2table(zeros(length(lines), 4), 'VariableNames',


{'theta', 'rho', 'x', 'y'});

idxNeg = find([lines.theta] < 0);


idxPos = find([lines.theta] >= 0);

negAngles = 90 + [lines(idxNeg).theta];
linesBisector.theta(idxNeg) = negAngles;

posAngles = [lines(idxPos).theta] - 90;


linesBisector.theta(idxPos) = posAngles;

midPts = zeros(length(lines),2);

for i = 1:length(lines)
midPts(i,:) = (lines(i).point1 + lines(i).point2)/2;
linesBisector.rho(i) = abs(midPts(i,2) - tand(lines(i).theta) *
midPts(i,1))/...
((tand(lines(i).theta)^2 + 1) ^ 0.5);
end
[linesBisector.x, linesBisector.y] =
pol2cart(deg2rad(linesBisector.theta),linesBisector.rho,'ro');

X = [linesBisector.x,linesBisector.y];

D = pdist2(X,X);

searchRadius = max(imSize/5);
minPoints = 10;
idx = dbscan(D,searchRadius, minPoints);

numClusters = unique(idx(idx > 0));

dataXY = cell(1, length(numClusters));

Iclusters = ones(imSize);

for i = 1:length(numClusters)
classIdx = find(idx == i);

rgbColor = rand(1,3);
startPts = reshape([lines(classIdx).point1], 2, length(classIdx))';
endPts = reshape([lines(classIdx).point2], 2, length(classIdx))';

Iclusters = insertShape(Iclusters, 'Line', [startPts, endPts], ...


'LineWidth', 2, 'Color', rgbColor);

dataXY{i} = [startPts; endPts];


end

orientation = zeros(1,length(numClusters));
boundingBox = zeros(length(numClusters), 4);

padding = 40;

for i = 1:length(numClusters)

.
x1 = min(dataXY{i}(:,1)) - padding;
x2 = max(dataXY{i}(:,1)) + padding;
y1 = min(dataXY{i}(:,2)) - padding;
y2 = max(dataXY{i}(:,2)) + padding;

boundingBox(i,:) = [x1, y1, x2-x1, y2-y1];

orientation(i) = mean(linesBisector.theta(idx == i));

end

end

segmentationLocalization wykorzystuje przepływ pracy oparty na segmentacji w celu


zlokalizowania poszczególnych kodów kreskowych.
function [boundingBox, orientation, Idilated] =
segmentationLocalization(Ihoughlines)

Ibw = ~Ihoughlines(:,:,1);
Ibw(Ibw > 0) = true;
diskRadius = 10;
se = strel('disk', diskRadius);
Idilated = imdilate(Ibw, se);

regionStatistics = regionprops(Idilated, 'Orientation', 'BoundingBox');

padding = 40;

boundingBox = zeros(length(regionStatistics), 4);

for idx = 1:length(regionStatistics)


boundingBox(idx,:) = regionStatistics(idx).BoundingBox;
boundingBox(idx,1) = boundingBox(idx,1) - padding;
boundingBox(idx,2) = boundingBox(idx,2) - padding;
boundingBox(idx,3) = boundingBox(idx,3) + 2*padding;
boundingBox(idx,4) = boundingBox(idx,4) + 2*padding;

end
orientation = [regionStatistics(:).Orientation];
end

4. Opracowanie wyników
Na podstawie przeprowadzonej kalibracji kamery Kinect oraz poszczególnych etapów
przetwarzania i analizy obrazów przedstawić graficznie poszczególne kroki pozwalające
wykryć i zidentyfikować pojedynczy kod 1D, kod 2D oraz wiele kodów na jednym obrazie.
Sprawozdanie powinno zawierać:
1. Temat ćwiczenia.
2. Datę wykonania ćwiczenia.
3. Przebieg realizacji ćwiczenia.
4. Wykresy danych odczytanych oraz wyniki kalibracji.
5. Wnioski.

5. Pytania kontrolne
1) Co to są kody kreskowe?
2) Wymień rodzaje kodów kreskowych.
3) Jakie ograniczenia mają kody kreskowe?
4) Opisz budowę kamery Kinect v1 oraz v2.

6. Literatura
[1] Gavin Weightman: The History of the Bar Code., 23.09.2015, smithsonianmag.com
[2] Kody kreskowe – rodzaje standardy sprzęt zastosowania – ILiM, Poznań 2000, ISBN 83-
87344-60-5
[3] Creusot, Clement, et al. "Real-time Barcode Detection in the Wild." IEEE Winter Conference
on Applications of Computer Vision, 2015.

You might also like