В этом примере показано, как использовать readBarcode функция из Toolbox™ Computer Vision для обнаружения и декодирования 1-D и 2-D штрихкодов в изображении. Штрих-коды широко используются для кодирования данных в визуальном машиночитаемом формате. Они полезны во многих приложениях, таких как идентификация номенклатуры, отслеживание складских запасов и отслеживание соответствия нормативным требованиям. Для 1-D штрихкодов readBarcode функция возвращает местоположение конечных точек штрихкода. Для 2-D штрихкодов функция возвращает местоположения шаблонов поиска. В этом примере используются два подхода для локализации нескольких штрихкодов в изображении. Одним из подходов является кластеризация, которая является более надежной к различным условиям визуализации и требует Toolbox™ статистики и машинного обучения. Второй подход использует рабочий процесс на основе сегментации и может потребовать настройки параметров на основе условий визуализации.
readBarcode ФункцияСчитывание QR-кода из изображения.
I = imread("barcodeQR.jpg"); % Search the image for a QR Code. [msg, ~, loc] = readBarcode(I); % Annotate the image with the decoded message. xyText = loc(2,:); Imsg = insertText(I, xyText, msg, "BoxOpacity", 1, "FontSize", 25); % Insert filled circles at the finder pattern locations. Imsg = insertShape(Imsg, "FilledCircle", [loc, ... repmat(10, length(loc), 1)], "Color", "red", "Opacity", 1); % Display image. imshow(Imsg)

Считывание штрихкода 1-D из изображения.
I = imread("barcode1D.jpg"); % Read the 1-D barcode and determine the format.. [msg, format, locs] = readBarcode(I); % Display the detected message and format. disp("Detected format and message: " + format + ", " + msg)
Detected format and message: EAN-13, 1234567890128
% Insert a line to show the scan row of the barcode. xyBegin = locs(1,:); imSize = size(I); I = insertShape(I,"Line",[1 xyBegin(2) imSize(2) xyBegin(2)], ... "LineWidth", 7); % Insert markers at the end locations of the barcode. I = insertShape(I, "FilledCircle", [locs, ... repmat(10, length(locs), 1)], "Color", "red", "Opacity", 1); % Display image. imshow(I)

Для успешного обнаружения штрих-код должен быть хорошо виден. Штрих-код также должен быть максимально приближен к горизонтальному или вертикальному положению. readBarcode функция по своей сути более устойчива к вращениям для 2-D или матричных кодов, чем к 1-D или линейным штрихкодам. Например, штрих-код не может быть обнаружен в этом изображении.
I = imread("rotated1DBarcode.jpg"); % Display the image. imshow(I)

% Pass the image to the readBarcode function.
readBarcode(I)ans = ""
Поверните изображение с помощью imrotate чтобы штрих-код был примерно горизонтальным. Использовать readBarcode на повернутом изображении.
% Rotate the image by 30 degrees clockwise. Irot = imrotate(I, -30); % Display the rotated image. imshow(Irot)

% Pass the rotated image to the readBarcode function.
readBarcode(Irot)ans = "012345678905"
readBarcode функция обнаруживает только один штрих-код в каждом изображении. Для обнаружения нескольких штрихкодов необходимо указать область, представляющую интерес (ROI). Для определения ROI можно использовать drawrectangle функция для интерактивного определения значений ROI. Для определения окупаемости инвестиций в несколько штрихкодов изображения можно также использовать методы анализа изображений.

I = imread("multiple1DBarcodes.jpg");Используйте drawrectangle функция для рисования и получения параметров прямоугольника.
roi1 = drawrectangle;
pos = roi1.Position;
% ROIs obtained using drawrectangle roi = [180 100 330 180 180 320 330 180 180 550 330 180]; imSize = size(I); for i = 1:size(roi,1) [msg, format, locs] = readBarcode(I, roi(i,:)); disp("Decoded format and message: " + format + ", " + msg) % Insert a line to indicate the scan row of the barcode. xyBegin = locs(1,:); I = insertShape(I,"Line",[1 xyBegin(2) imSize(2) xyBegin(2)], ... "LineWidth", 5); % Annotate image with decoded message. I = insertText(I, xyBegin, msg, "BoxOpacity", 1, "FontSize", 20); end
Decoded format and message: UPC-A, 012345678905 Decoded format and message: EAN-13, 4567891324562 Decoded format and message: CODE-39, ABC-123
imshow(I)

Используйте методы анализа изображений для автоматизации обнаружения нескольких штрихкодов. Это требует локализации нескольких штрихкодов в изображении, определения их ориентации и корректировки для ориентации. Без предварительной обработки штрихкоды не могут быть обнаружены в изображении, содержащем несколько повернутых штрихкодов.
I = imread("multiple1DBarcodesRotated.jpg"); Igray = im2gray(I); % Display the image. imshow(I)

% Pass the unprocessed image to the readBarcode function. readBarcode(Igray, '1D')
ans = ""
Обнаружение необработанного изображения не привело к обнаружению.
Шаг 1: Определение областей-кандидатов для штрихкодов с помощью MSER
Обнаружение областей, представляющих интерес для изображения, с помощью detectMSERFeatures функция. Затем можно исключить интересующие области на основе определенных критериев, таких как соотношение сторон. Для дальнейшей обработки можно использовать двоичное изображение из отфильтрованных результатов.
% Detect MSER features. [~, cc] = detectMSERFeatures(Igray); % Compute region properties MajorAxisLength and MinorAxisLength. regionStatistics = regionprops(cc, 'MajorAxisLength', 'MinorAxisLength'); % Filter out components that have a low aspect ratio as unsuitable % candidates for the bars in the barcode. minAspectRatio = 10; candidateRegions = find(([regionStatistics.MajorAxisLength]./[regionStatistics.MinorAxisLength]) > minAspectRatio); % Binary image to store the filtered components. BW = false(size(Igray)); % Update the binary image. for i = 1:length(candidateRegions) BW(cc.PixelIdxList{candidateRegions(i)}) = true; end % Display the binary image with the filtered components. imshow(BW) title("Candidate regions for the barcodes")

Шаг 2: Извлечение сегментов линии штрихкода с помощью преобразования
Обнаружение выдающихся кромок в изображении с помощью edge функция. Затем используйте преобразование Каф, чтобы найти интересующие строки. Линии представляют возможные кандидаты для вертикальных полос в штрихкоде.
% Perform hough transform. BW = edge(BW,'canny'); [H,T,R] = hough(BW); % Display the result of the edge detection operation. imshow(BW)

% Determine the size of the suppression neighborhood. reductionRatio = 500; nhSize = floor(size(H)/reductionRatio); idx = mod(nhSize,2) < 1; nhSize(idx) = nhSize(idx) + 1; % Identify the peaks in the Hough transform. P = houghpeaks(H,length(candidateRegions),'NHoodSize',nhSize); % Detect the lines based on the detected peaks. lines = houghlines(BW,T,R,P); % Display the lines detected using the houghlines function. Ihoughlines = ones(size(BW)); % Start and end points of the detected lines. startPts = reshape([lines(:).point1], 2, length(lines))'; endPts = reshape([lines(:).point2], 2, length(lines))'; Ihoughlines = insertShape(Ihoughlines, 'Line', [startPts, endPts], ... 'LineWidth', 2, 'Color', 'green'); % Display the original image overlayed with the detected lines. Ibarlines = imoverlay(I, ~Ihoughlines(:,:,1)); imshow(Ibarlines)

Шаг 3: Локализация штрихкодов в изображении
После извлечения отрезков линии представлены два способа локализации отдельных штрихкодов на изображении:
Метод 1: Метод кластеризации, который использует функциональные возможности Toolbox™ статистики и машинного обучения для идентификации отдельных штрихкодов. Этот метод является более устойчивым к отклонениям, которые были обнаружены с использованием описанных выше методов анализа изображения. Он также может быть расширен до широкого диапазона условий формирования изображения без необходимости настройки параметров.
Метод 2: Основанный на сегментации рабочий процесс для разделения отдельных штрихкодов. Этот метод использует другие методы анализа изображений для локализации и коррекции поворота извлеченных штрихкодов. Хотя это работает достаточно хорошо, может потребоваться некоторая настройка параметров для предотвращения обнаружения отклонений.
Метод 1: Поток операций на основе кластеризации
В этом рабочем процессе есть два шага:
1. Определение биссекторов отрезков штрихкода
Хотя обычная практика заключается в непосредственном использовании линий (которые были получены с помощью преобразования Хафа) для локализации штрихкода, этот метод использует линии для дальнейшего обнаружения перпендикулярных биссектрисов для каждой из линий. Линии биссектрисы представлены в виде точек в декартовом пространстве, что делает их пригодными для идентификации отдельных штрихкодов. Использование биссектрисов делает обнаружение отдельных штрихкодов более надежным, поскольку это приводит к меньшим ошибкам в классификации линий, которые похожи, но принадлежат к различным штрихкодам.
2. Выполнить кластеризацию биссекторов для идентификации отдельных штрихкодов
Поскольку все стержни в штрихкоде приблизительно параллельны друг другу, биссектрисы каждого из этих стержней в идеале должны быть одной и той же линией, и поэтому их соответствующие точки должны объединяться вокруг одной точки. На практике эти биссектрисы будут варьироваться от сегмента к сегменту, но все еще остаются достаточно похожими, чтобы позволить использовать алгоритм кластеризации на основе плотности. Результатом выполнения этой операции кластеризации является набор кластеров, каждый из которых указывает на отдельный штрихкод. В этом примере используется dbscan (Statistics and Machine Learning Toolbox), которая не требует предварительного знания количества кластеров. В этом примере визуализируются различные кластеры (штрихкоды).
В примере проверяется наличие лицензии на Toolbox™ статистики и машинного обучения. Если лицензия найдена, в примере используется метод кластеризации. В противном случае в примере используется метод сегментации.
useClustering = license('test','statistics_toolbox'); if useClustering [boundingBox, orientation, Iclusters] = clusteringLocalization(lines, size(I)); % Display the detected clusters. imshow(Iclusters) else disp("The clustering based workflow requires a license for the Statistics and Machine Learning Toolbox") end

Метод 2: Поток операций на основе сегментации
После удаления фонового шума и изменения обнаруженные вертикальные полосы группируются в отдельные штрихкоды с использованием морфологических операций, например, imdilate. В примере используется regionprops для определения ограничивающей рамки и ориентации для каждого из штрихкодов. Результаты используются для обрезки отдельных штрихкодов из исходного изображения и для их ориентирования примерно по горизонтали.
if ~useClustering [boundingBox, orientation, Idilated] = segmentationLocalization(Ihoughlines); % Display the dilated image. imshow(Idilated) end
Шаг 4. Обрезать штрихкоды и скорректировать их вращение
Штрих-коды обрезаются из исходного изображения с помощью ограничивающих рамок, полученных в результате сегментации. Результаты ориентации используются для выравнивания штрихкодов приблизительно по горизонтали.
% Localize and rotate the barcodes in the image. correctedImages = cell(1, length(orientation)); % Store the cropped and rotation corrected images of the barcodes. 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 % Crop the barcode from the original image and rotate it using the % detected orientation. correctedImages{i} = imrotate(imcrop(Igray,boundingBox(i,:)), orientation(i)); end % Display the image with the localized barcodes. imshow(I)

Шаг 5: Определение штрихкодов на кадрированных и скорректированных по повороту изображениях
Обрезанные и скорректированные на поворот изображения штрихкодов затем используются вместе с readBarcode функция их декодирования.
% Pass each of the images to the readBarcode function. for i = 1:length(correctedImages) [msg, format, ~] = readBarcode(correctedImages{i}, '1D'); disp("Decoded format and message: " + format + ", " + msg) end
Decoded format and message: UPC-A, 012345678905 Decoded format and message: EAN-13, 4567891324562 Decoded format and message: CODE-39, ABC-123
В этом примере показано, как readBarcode функция может использоваться для обнаружения, декодирования и локализации штрихкодов в изображении. Хотя функция хорошо работает, когда выравнивание штрихкодов примерно горизонтально или вертикально, она нуждается в дополнительной предварительной обработке, когда штрихкоды появляются повернутыми. Этапы предварительной обработки, описанные выше, являются хорошей отправной точкой для работы с несколькими штрихкодами, которые не выровнены в изображении.
clusteringLocalization использует рабочий процесс на основе кластеризации для локализации отдельных штрихкодов.
function [boundingBox, orientation, Iclusters] = clusteringLocalization(lines, imSize) %------------------------------------------------------------------------ % Determine Bisectors of Barcode Line Segments %------------------------------------------------------------------------ % Table to store the properties of the bisectors of the detected lines. linesBisector = array2table(zeros(length(lines), 4), 'VariableNames', {'theta', 'rho', 'x', 'y'}); % Use the orientation values of the lines to determine the orientation. % values of the bisectors 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; % Determine the midpoints of the detected lines. midPts = zeros(length(lines),2); % Determine the 'rho' values of the bisectors. 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 % Update the [x,y] locations of the bisectors using their polar % coordinates. [linesBisector.x, linesBisector.y] = pol2cart(deg2rad(linesBisector.theta),linesBisector.rho,'ro'); %------------------------------------------------------------------------ % Perform Clustering on the Bisectors to Identity the Individual Barcodes %------------------------------------------------------------------------ % Store the [x,y] data of the bisectors to be used for clustering. X = [linesBisector.x,linesBisector.y]; % Get pairwise distance between the points D = pdist2(X,X); % Perform density-based spatial clustering to separate the different % barcodes in the image. searchRadius = max(imSize/5); minPoints = 10; idx = dbscan(D,searchRadius, minPoints); % Identify the number of clusters (barcodes). numClusters = unique(idx(idx > 0)); % Store the endpoints of the detected lines. dataXY = cell(1, length(numClusters)); % Image to show the detected clusters (barcodes). 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))'; % Insert lines corresponding to the current cluster (barcode). Iclusters = insertShape(Iclusters, 'Line', [startPts, endPts], ... 'LineWidth', 2, 'Color', rgbColor); % Update the endpoints of the lines in each cluster (barcode). dataXY{i} = [startPts; endPts]; end %------------------------------------------------------------------------ % Localization parameters for the barcode %------------------------------------------------------------------------ orientation = zeros(1,length(numClusters)); boundingBox = zeros(length(numClusters), 4); % Padding the cropped images of barcodes. padding = 40; % Determine the ROI and orientation of the individual clusters (barcodes). for i = 1:length(numClusters) % Bounding box coordinates with padding. 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 of the barcode. orientation(i) = mean(linesBisector.theta(idx == i)); end end
segingedLocalization использует рабочий процесс на основе сегментации для локализации отдельных штрихкодов.
function [boundingBox, orientation, Idilated] = segmentationLocalization(Ihoughlines) %------------------------------------------------------------------------ % Use image dilation to separate the barcodes %------------------------------------------------------------------------ % Create binary image with the detected lines. Ibw = ~Ihoughlines(:,:,1); Ibw(Ibw > 0) = true; % Dilate the image using a disk structuring element. diskRadius = 10; % Might need tuning depending on the input image. se = strel('disk', diskRadius); Idilated = imdilate(Ibw, se); %------------------------------------------------------------------------ % Localization parameters for the barcode %------------------------------------------------------------------------ % Compute region properties Orientation and BoundingBox. regionStatistics = regionprops(Idilated, 'Orientation', 'BoundingBox'); % Padding for the cropped images of barcodes. padding = 40; boundingBox = zeros(length(regionStatistics), 4); for idx = 1:length(regionStatistics) boundingBox(idx,:) = regionStatistics(idx).BoundingBox; % Bounding box coordinates with padding. 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
[1] Крезот, Мягкий, и др. «Обнаружение штрих-кода в Wild в реальном времени». Зимняя конференция IEEE по применению компьютерного зрения, 2015.