Rehmat Alam
Rehmat Alam

Reputation: 81

Calculate width of each bar of Barcode in Matlab

I have a barcode and I would like process it in matlab and calculate the width of each bar in a 1-D barcode in pixels.

I have tried converting the image to gray scale through graythresh level and converted it to binary as well.

%read the image code3
barz=imread('barcode1.jpg');
grayBarz=rgb2gray(barz);

binImage = imbinarize(barz,graythresh(barz));

s = regionprops(binImage == 0,'Area','PixelIdxList');
imshow(barz);

I want the width in pixels of each bar in the barcode.

Barcode Image

Upvotes: 3

Views: 783

Answers (3)

nathancy
nathancy

Reputation: 46630

enter image description here

For fun, here's an implementation using Python OpenCV

  • Convert image to grayscale and Otsu's threshold
  • Detect all vertical lines and draw onto mask
  • Find contours on mask and sort from left-to-right
  • Iterate through contours and find pixel width of each line

Results

Barcode Width: [13, 7, 20, 27, 7, 19, 12, 13, 13, 7, 6, 13, 20, 7, 14, 7, 6, 12, 20, 7, 13, 27, 19, 7, 6, 6, 13, 7, 27, 7, 14, 19, 6, 19, 6, 13, 13, 7, 5, 6, 26, 6, 6, 13, 6, 12, 20, 7, 13]

Barcode Bars: 49

Total Pixels: 599

Code

import cv2
from imutils import contours
import numpy as np

# Load in image, grayscale, and Otsu's threshold
image = cv2.imread('1.jpg')
mask = np.zeros(image.shape, dtype=np.uint8)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray,0,255,cv2.THRESH_OTSU + cv2.THRESH_BINARY_INV)[1]

# Detect vertical lines
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,80))        
remove_vertical = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel)
cnts = cv2.findContours(remove_vertical, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cv2.fillPoly(mask, cnts, (255,255,255))

# Find contours on mask and sort from left to right
mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
cnts = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts, _ = contours.sort_contours(cnts, method="left-to-right")

# Iterate through contours and find width of each line
barcode_width = []
for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    current = image.copy()
    cv2.rectangle(current, (x, y), (x + w, y + h), (36,255,12), -1)
    cv2.putText(current, 'Width: {}'.format(w), (15,50), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (36,255,12), 3)
    barcode_width.append(w)
    cv2.imshow('current', current)
    cv2.waitKey(175)

print("Barcode Width:", barcode_width)
print('Barcode Bars: ', len(barcode_width))
print('Total Pixels: ', sum(barcode_width))
cv2.waitKey()

Upvotes: 1

Hoki
Hoki

Reputation: 11812

Sometime it is fun to be able to do things without needing the full image processing toolbox.

The solution below allows you to count the pixel width of every black bar, without needing any additional toolbox:

%% Read the image
barz=imread('barcode.jpg');
grayBarz=rgb2gray(barz);

%% Extract an horizontal line in the middle
sz = size(grayBarz) ;
idxMidLine = round(sz(1)/2) ; % index of a line roughly in the middle
eline = grayBarz(idxMidLine,:) ;    % extract a line
eline(eline<128) = 0 ;              % sharpen transitions
eline = ~logical(eline) ;           % convert to logical (0=white / 1=black)

%% Now count the pixels
npts = numel(eline) ;   % number of points in the line

% Find every transition:
    % high to low   => -1
    % no change     =>  0
    % low to high   => +1
idd = find( diff(eline) ) ;

% this contain the start and end indices of every interval
ddd = [ 1 , idd ; ...
        idd , npts ] ;

% This contains the width of every bar (white and black),
% in order from left to right
barWidth = diff(ddd) ;

if ~eline(1)
    % The first interval is 0 (is white)
    pixBarWhite = barWidth( 1:2:end ) ;
    pixBarBlack = barWidth( 2:2:end ) ;
else
    % The first interval is 1 (is black)
    pixBarBlack = barWidth( 1:2:end ) ;
    pixBarWhite = barWidth( 2:2:end ) ;
end

nBarWhite = numel(pixBarWhite) ;
nBarBlack = numel(pixBarBlack) ;

%% Display results
fprintf('Found a total of %d black pixels along the horizontal,\n',sum(pixBarBlack))
fprintf('spread over %d black bars,\n',nBarBlack)
fprintf('Individual bar pixel thickness:\n')
for k=1:nBarBlack
    fprintf('Bar %02d : Thickness: %02d pixels\n',k,pixBarBlack(k))
end

For your image it will return:

Found a total of 599 black pixels along the horizontal,
spread over 49 black bars,
Individual bar pixel thinchness:,
Bar 01 : Thickness: 13 pixels
Bar 02 : Thickness: 07 pixels
Bar 03 : Thickness: 20 pixels
% [edited to keep it short]
Bar 47 : Thickness: 20 pixels
Bar 48 : Thickness: 07 pixels
Bar 49 : Thickness: 13 pixels

Note that the variable pixBarWhite also contain the pixel thickness of all the white intervals between the black bars. It might come handy for later ...

Upvotes: 2

Piglet
Piglet

Reputation: 28954

Assuming that you alread have the regionprops of the bars the width can be easily obtained through

'MinFeretProperties'

or

'MinorAxisLength'

If your bars are paralell to the image raster you can also use the smaller dimension of the 'BoundingBox'

https://de.mathworks.com/help/images/ref/regionprops.html

Upvotes: 1

Related Questions