Skip to content

Commit

Permalink
🎉 Barcode detection and recognition first approach
Browse files Browse the repository at this point in the history
  • Loading branch information
Achraf KHAZRI authored and Achraf KHAZRI committed Sep 26, 2019
1 parent 524d5b8 commit b382bd2
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 0 deletions.
130 changes: 130 additions & 0 deletions barcode_api/barcode_engine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import numpy as np
import cv2
from pyzbar import pyzbar


def grab_contours(cnts):
# if the length the contours tuple returned by cv2.findContours
# is '2' then we are using either OpenCV v2.4, v4-beta, or
# v4-official
if len(cnts) == 2:
cnts = cnts[0]

# if the length of the contours tuple is '3' then we are using
# either OpenCV v3, v4-pre, or v4-alpha
elif len(cnts) == 3:
cnts = cnts[1]

# otherwise OpenCV has changed their cv2.findContours return
# signature yet again and I have no idea WTH is going on
else:
raise Exception(("Contours tuple must have length 2 or 3, "
"otherwise OpenCV changed their cv2.findContours return "
"signature yet again. Refer to OpenCV's documentation "
"in that case"))

# return the actual contours array
return cnts

def deskew(img):

gray = cv2.bitwise_not(img)

# threshold the image, setting all foreground pixels to
# 255 and all background pixels to 0
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
# grab the (x, y) coordinates of all pixel values that
# are greater than zero, then use these coordinates to
# compute a rotated bounding box that contains all
# coordinates

coords = np.column_stack(np.where(thresh > 0))
angle = cv2.minAreaRect(coords)[-1]

# the `cv2.minAreaRect` function returns values in the
# range [-90, 0); as the rectangle rotates clockwise the
# returned angle trends to 0 -- in this special case we
# need to add 90 degrees to the angle
if angle < -45:
angle = -(90 + angle)

# otherwise, just take the inverse of the angle to make
# it positive
else:
angle = -angle

# rotate the image to deskew it
(h, w) = img.shape[:2]
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, angle, 1.0)
rotated = cv2.warpAffine(img, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)

return rotated, angle

# load the image and convert it to grayscale
image = cv2.imread("test.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# compute the Scharr gradient magnitude representation of the images
# in both the x and y direction using OpenCV 2.4
ddepth = cv2.CV_32F
gradX = cv2.Sobel(gray, ddepth=ddepth, dx=1, dy=0, ksize=-1)
gradY = cv2.Sobel(gray, ddepth=ddepth, dx=0, dy=1, ksize=-1)

# subtract the y-gradient from the x-gradient
gradient = cv2.subtract(gradX, gradY)
gradient = cv2.convertScaleAbs(gradient)

# blur and threshold the image
blurred = cv2.blur(gradient, (9, 9))
(_, thresh) = cv2.threshold(blurred, 225, 255, cv2.THRESH_BINARY)

# construct a closing kernel and apply it to the thresholded image
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 7))
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)

# perform a series of erosions and dilations
closed = cv2.erode(closed, None, iterations = 4)
closed = cv2.dilate(closed, None, iterations = 4)

# find the contours in the thresholded image, then sort the contours
# by their area, keeping only the largest one
cnts = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = grab_contours(cnts)
c = sorted(cnts, key=cv2.contourArea, reverse=True)[0]

# compute the rotated bounding box of the largest contour
rect = cv2.minAreaRect(c)
box = cv2.boxPoints(rect)
box = np.int0(box)
scale = 20
b1 = box[0]
b2 = box[1]
b3 = box[2]
b4 = box[3]
x = [b1[1], b2[1], b3[1], b4[1]]
y = [b1[0], b2[0], b3[0], b4[0]]
x_min = min(x) - scale
y_min = min(y) - scale
x_max = max(x) + scale
y_max = max(y) + scale

out = gray[x_min:x_max,y_min:y_max]
deskewed, angle = deskew(out)
# draw a bounding box arounded the detected barcode and display the
# image
thresh = cv2.threshold(deskewed, 0, 255, cv2.THRESH_OTSU)[1]

cv2.imshow("deskew", deskewed)
cv2.waitKey(0)
cv2.destroyAllWindows()

# Zbar reader
barcodes = pyzbar.decode(thresh)

# zxing reader
"""import zxing
reader = zxing.BarCodeReader()
barcodes = reader.decode(thresh)"""
print(barcodes)
Binary file added barcode_api/test.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit b382bd2

Please sign in to comment.