Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 178 additions & 3 deletions qr_code_extractor.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import cv2

import numpy as np
from skimage.measure import label, regionprops
import matplotlib.pyplot as plt

def get_qr_data(file, debug_show_image=False):
position_marker_coordinates = None
Expand All @@ -8,10 +10,183 @@ def get_qr_data(file, debug_show_image=False):
payload, bounding_box, rectified_image = cv2.QRCodeDetector().detectAndDecode(input_image)

if len(payload) > 0:
position_marker_coordinates = get_position_marker_coordinates(bounding_box)
position_marker_coordinates_linear = get_position_marker_coordinates(bounding_box)

# get the corner pixel of the qr image
x_min = int(np.floor(np.min(bounding_box[0][:, 1]))) - 10
x_max = int(np.ceil(np.max(bounding_box[0][:, 1]))) + 10
y_min = int(np.floor(np.min(bounding_box[0][:, 0]))) - 10
y_max = int(np.ceil(np.max(bounding_box[0][:, 0]))) + 10

qr_image = input_image[x_min: x_max, y_min : y_max]

# converting the image to grey image for better contrast
img_gray = cv2.cvtColor(qr_image, cv2.COLOR_BGR2GRAY)
ret, img_gray = cv2.threshold(img_gray,127,255,cv2.THRESH_BINARY)


# get all the clusters in the original black and white qr-code image
label_img = label(img_gray)
regions = regionprops(label_img)

# get all the clusters in the inverted black and white qr-code image
img_gray_invert = cv2.bitwise_not(img_gray)
label_img_invert = label(img_gray_invert)
regions_invert = regionprops(label_img_invert)



# get the diagonal from the center bobble to the other corner without bobble
diagonal_x1 = [int(bounding_box[0][0][0])-y_min, int(bounding_box[0][2][0])-y_min]
diagonal_y1 = [int(bounding_box[0][0][1])-x_min, int(bounding_box[0][2][1])-x_min]

diagonal_m1 = ((int(bounding_box[0][2][1])-x_min) - (int(bounding_box[0][0][1])-x_min)) /\
((int(bounding_box[0][2][0])-y_min) - (int(bounding_box[0][0][0])-y_min))

diagonal_b1 = (int(bounding_box[0][2][1])-x_min) - diagonal_m1 * (int(bounding_box[0][2][0])-y_min)

dia_x1 = []
dia_y1 = []
for i in range(y_max - y_min):
dia_x1.append(i)
dia_y1.append(diagonal_m1*i+diagonal_b1)


# get the diagonal from the left down bobble to the other corner with right up bobble
diagonal_x3 = [int(bounding_box[0][1][0])-y_min, int(bounding_box[0][3][0])-y_min]
diagonal_y3 = [int(bounding_box[0][1][1])-x_min, int(bounding_box[0][3][1])-x_min]

diagonal_m3 = ((int(bounding_box[0][3][1])-x_min) - (int(bounding_box[0][1][1])-x_min)) /\
((int(bounding_box[0][3][0])-y_min) - (int(bounding_box[0][1][0])-y_min))

diagonal_b3 = (int(bounding_box[0][3][1])-x_min) - diagonal_m3 * (int(bounding_box[0][3][0])-y_min)

dia_x3 = []
dia_y3 = []
for i in range(y_max - y_min):
dia_x3.append(i)
dia_y3.append(diagonal_m3*i+diagonal_b3)


# put all the cluster IDs along the first diagonal
signal1 = []
for i in range(len(dia_x1)):
if dia_y1[i] >= 0 and dia_y1[i] < x_max - x_min:
signal1.append(label_img_invert[int(dia_y1[i])][int(dia_x1[i])])

# put all the cluster IDs along the second diagonal
signal3 = []
for i in range(len(dia_x3)):
if dia_y3[i] >= 0 and dia_y3[i] < x_max - x_min:
signal3.append(label_img_invert[int(dia_y3[i])][int(dia_x3[i])])


# find the center bobble. that is the cluster after the 2nd cluster ID change
found1 = 0
index1 = 0
index1_b4 = -1
for i in range(len(signal1)):
if signal1[i] != 0 and index1_b4 != signal1[i]:
found1 += 1

if found1 == 2:
index1 = signal1[i]
break

index1_b4 = signal1[i]

x1, y1 = regions_invert[index1-1].centroid
area1 = regions_invert[index1-1].area

cv2.circle(input_image, [y_min + int(y1), x_min + int(x1)], 30, (0, 255, 255), -1)


# find the left down bobble. that is the cluster after the 2nd cluster ID change
found2 = 0
index2 = 0
index2_b4 = -1
for i in range(len(signal3)):
if signal3[i] != 0 and index2_b4 != signal3[i]:
found2 += 1

if found2 == 2:
index2 = signal3[i]
break

index2_b4 = signal3[i]

x2, y2 = regions_invert[index2-1].centroid
area2 = regions_invert[index2-1].area

cv2.circle(input_image, [y_min + int(y2), x_min + int(x2)], 30, (255, 255, 0), -1)


# find the righ up bobble. that is the cluster after the 2nd cluster ID change
found3 = 0
index3 = 0
index3_b4 = -1
for i in range(len(signal3)):
if signal3[len(signal3) - i - 1] != 0 and index3_b4 != signal3[len(signal3) - i - 1]:
found3 += 1

if found3 == 2:
index3 = signal3[len(signal3) - i - 1]
break

index3_b4 = signal3[len(signal3) - i - 1]

x3, y3 = regions_invert[index3-1].centroid
area3 = regions_invert[index3-1].area

cv2.circle(input_image, [y_min + int(y3), x_min + int(x3)], 30, (255, 0, 255), -1)

position_marker_coordinates_area = y_min + y1, x_min + x1
#maybe there needs to be a selection between the linear and the area cluster method
position_marker_coordinates = position_marker_coordinates_area


if debug_show_image:
cv2.circle(input_image, position_marker_coordinates, 10, (0, 255, 0), -1)

plt.imshow(label_img_invert)
plt.plot(diagonal_x1, diagonal_y1, "o-")
plt.plot(diagonal_x3, diagonal_y3, "o-")
plt.plot(y1, x1, "*")
plt.plot(y2, x2, "*")
plt.plot(y3, x3, "*")
plt.show()

plt.imshow(label_img)
plt.plot(diagonal_x1, diagonal_y1, "o-")
plt.plot(diagonal_x3, diagonal_y3, "o-")
plt.plot(y1, x1, "*")
plt.plot(y2, x2, "*")
plt.plot(y3, x3, "*")

# finding the smallest bobble, the 4th bobble
for i in range(len(regions_invert)):
if regions_invert[i].area > (area1 + area2 + area3) / 3 / 13 and \
regions_invert[i].area < (area1 + area2 + area3) / 3 / 6:

xm, ym = regions_invert[i].centroid

plt.plot(ym, xm, "o")


plt.title("cluster id on qr-code, diagonals and position markers")
plt.show()

plt.plot(signal1, label="diagonal 1")
plt.plot(signal3, label="diagonal 2")
plt.xlabel("x position via diagonal")
plt.ylabel("cluster id for pixel on diagonal")
plt.grid()
plt.legend()
plt.show()


circle_x = int(position_marker_coordinates[0])
circle_y = int(position_marker_coordinates[1])
cv2.circle(input_image,[circle_x, circle_y] , 10, (0, 0, 255), -1)

base = input_image.shape[0]
if base < input_image.shape[1]:
Expand Down
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ utm
opencv-python
pyproj
pyzbar
scikit-image
numpy
matplotlib