Skip to content

Commit 72f00ec

Browse files
committed
Pushing 2020 code from Jetson
0 parents  commit 72f00ec

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2429
-0
lines changed

.gitignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# PyCharm files
2+
.idea/
3+
4+
# Mac Temp Files
5+
.DS_Store
6+
7+
# Python temp files
8+
*.pyc
9+
10+
#Our Log Files
11+
*/logs/
12+
logs/
13+
*.log
14+
*.avi

algorithms/ArTag.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import numpy as np
2+
import cv2
3+
from ArTagEncoding import encode, HAMMINGCODE_MARKER_POSITIONS
4+
MARKER_SIZE = 9
5+
6+
class HammingMarker(object):
7+
def __init__(self, id, contours=None):
8+
self.id = id
9+
self.contours = contours
10+
11+
def __repr__(self):
12+
return '<Marker id = {} center = {} >'.format(self.id, self.center)
13+
14+
@property
15+
def center(self):
16+
if self.contours is None:
17+
return None
18+
center_array = np.mean(self.contours, axis=0).flatten()
19+
return (int(center_array[0]), int(center_array[1]))
20+
21+
def generate_image(self):
22+
img = np.zeros((MARKER_SIZE, MARKER_SIZE))
23+
#img[1, 1] = 255
24+
for count1, ar in enumerate(self.id):
25+
for count2, ar2 in enumerate(ar):
26+
img[count1+1][count2+1] = self.id[count1][count2]
27+
# return zoom(img, zoom=50, order=0)
28+
height,width = img.shape[:2]
29+
res = cv2.resize(img, (50*width, 50*height), interpolation = cv2.INTER_NEAREST)
30+
#cv2.imshow("test1", res)
31+
return res
32+
33+
def draw_contour(self, img, color=(0,255,0), linewidth=5):
34+
cv2.drawContours(img, [self.contours], -1, color, linewidth)
35+
36+
def highlite_marker(self, img, contour_color=(0,255,0), text_color=(255,0,0), linewidth=5, text_thickness=2):
37+
"""
38+
This draws a bounding box around the marker on the image. NOTE: it returns
39+
a BGR image so the highlite is in color.
40+
41+
Input:
42+
img: image with detected marker
43+
contour_color: bounding box color, default is Green (0,255,0)
44+
text_color: text color, default is Blue (255,0,0)
45+
linewidth: thickness of bonding box line
46+
text_thickness: thickness of marker number text
47+
48+
Output:
49+
A color image with the marker drawn on it
50+
"""
51+
if len(img.shape) == 2:
52+
img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
53+
self.draw_contour(img, color=contour_color, linewidth=linewidth)
54+
cv2.putText(img, str(self.id), self.center, cv2.FONT_HERSHEY_SIMPLEX, text_thickness, text_color)
55+
return img
56+
57+
@classmethod
58+
def generate(cls):
59+
#return HammingMarker(id=np.random.randint(4096))
60+
return HammingMarker(id=[[255,255,0,255,255],[255,255,0,255,255],[255,0,255,0,255],[255,255,255,255,255],[255,255,255,255,255]])
61+
@property
62+
def id_as_binary(self):
63+
return np.binary_repr(self.id, width=12)
64+
65+
@property
66+
def hamming_code(self):
67+
return encode(self.id_as_binary)

algorithms/ArTagDetection.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
2+
import cv2
3+
import numpy as np
4+
from ArTagEncoding import decode, extract_hamming_code
5+
from ArTag import MARKER_SIZE, HammingMarker
6+
7+
BORDER_COORDINATES = [
8+
[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [0, 7], [0, 8],
9+
[1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [1, 6], [1, 7], [1, 8],
10+
[7, 0], [7, 1], [7, 2], [7, 3], [7, 4], [7, 5], [7, 6], [7, 7], [7, 8],
11+
[8, 0], [8, 1], [8, 2], [8, 3], [8, 4], [8, 5], [8, 6], [8, 7], [8, 8],
12+
[2, 0], [2, 1], [2, 7], [2, 8], [3, 0], [3, 1], [3, 7], [3, 8],
13+
[4, 0], [4, 1], [4, 7], [4, 8], [5, 0], [5, 1], [5, 7], [5, 8],
14+
[6, 0], [6, 1], [6, 7], [6, 8],
15+
]
16+
17+
ORIENTATION_MARKER_COORDINATES = [[2, 2], [2, 6], [6, 2], [6, 6]]
18+
"""BORDER_COORDINATES = [
19+
[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [1, 0], [1, 6], [2, 0], [2, 6], [3, 0],
20+
[3, 6], [4, 0], [4, 6], [5, 0], [5, 6], [6, 0], [6, 1], [6, 2], [6, 3], [6, 4], [6, 5], [6, 6],
21+
]
22+
23+
ORIENTATION_MARKER_COORDINATES = [[1, 1], [1, 5], [5, 1], [5, 5]]"""
24+
25+
def validate_and_turn(marker):
26+
for crd in BORDER_COORDINATES:
27+
if marker[crd[0], crd[1]] != 0.0:
28+
raise ValueError('Border contains not entirely black parts.')
29+
#print(marker[1,1])
30+
#if marker[1,1] == 0.0 or marker[1,2] == 0.0 or marker[1,4] == 0.0 or marker[1,5] == 0.0:
31+
#raise ValueError('No orientation marker found.')
32+
print(marker)
33+
if marker[2,2] == 0.0 or marker[2,3] == 0.0 or marker [2,5] == 0.0 or marker[2,6] == 0.0:
34+
raise ValueError('No orientation marker found.')
35+
""" orientation_marker = None
36+
for crd in ORIENTATION_MARKER_COORDINATES:
37+
marker_found = False
38+
if marker[crd[0], crd[1]] == 1.0:
39+
marker_found = True
40+
if marker_found and orientation_marker:
41+
raise ValueError('More than 1 orientation_marker found.')
42+
elif marker_found:
43+
orientation_marker = crd
44+
if not orientation_marker:
45+
raise ValueError('No orientation marker found.')
46+
rotation = 0
47+
if orientation_marker == [2, 6]:
48+
rotation = 1
49+
elif orientation_marker == [6, 6]:
50+
rotation = 2
51+
elif orientation_marker == [6, 2]:
52+
rotation = 3
53+
marker = np.rot90(marker, k=rotation) """
54+
return marker
55+
56+
def detect_markers(img):
57+
"""
58+
This is the main function for detecting markers in an image.
59+
60+
Input:
61+
img: a color or grayscale image that may or may not contain a marker.
62+
63+
Output:
64+
a list of found markers. If no markers are found, then it is an empty list.
65+
"""
66+
if len(img.shape) > 2:
67+
width, height, _ = img.shape
68+
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
69+
else:
70+
width, height = img.shape
71+
gray = img
72+
#cv2.imshow("frame", gray)
73+
edges = cv2.Canny(gray, 10, 100)
74+
contours, hierarchy = cv2.findContours(edges.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[-2:]
75+
cv2.imshow("frame",edges)
76+
min_contour_length = min(width, height) / 50
77+
contours = [contour for contour in contours if len(contour) > min_contour_length]
78+
warped_size = 81
79+
canonical_marker_coords = np.array(
80+
(
81+
(0, 0),
82+
(warped_size - 1, 0),
83+
(warped_size - 1, warped_size - 1),
84+
(0, warped_size - 1)
85+
),
86+
dtype = 'float32')
87+
#print(canonical_marker_coords)
88+
markers_list = []
89+
for contour in contours:
90+
approx_curve = cv2.approxPolyDP(contour, len(contour) * 0.01, True)
91+
if not (len(approx_curve) == 4 and cv2.isContourConvex(approx_curve)):
92+
continue
93+
94+
sorted_curve = np.array(
95+
cv2.convexHull(approx_curve, clockwise=False),
96+
dtype='float32'
97+
)
98+
#print(sorted_curve)
99+
persp_trans = cv2.getPerspectiveTransform(sorted_curve, canonical_marker_coords)
100+
101+
warped_img = cv2.warpPerspective(img, persp_trans, (warped_size, warped_size))
102+
#cv2.imshow("frame", warped_img)
103+
if len(warped_img.shape) > 2:
104+
warped_gray = cv2.cvtColor(warped_img, cv2.COLOR_BGR2GRAY)
105+
else:
106+
warped_gray = warped_img
107+
108+
_, warped_bin = cv2.threshold(warped_gray, 200, 255, cv2.THRESH_BINARY)
109+
#warped_bin = cv2.adaptiveThreshold(warped_gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 3, 0) # try adaptive thresholding if needed after this actually works
110+
#cv2.imshow("frame", warped_bin)
111+
#marker = cv2.resize(warped_bin, (9,9), interpolation=cv2.INTER_AREA)
112+
marker = warped_bin.reshape([MARKER_SIZE, warped_size // MARKER_SIZE, MARKER_SIZE, warped_size // MARKER_SIZE]
113+
)
114+
marker = marker.mean(axis=3).mean(axis=1)
115+
marker[marker < 127] = 0
116+
marker[marker >= 127] = 1
117+
#cv2.imshow("frame", marker)
118+
119+
try:
120+
marker = validate_and_turn(marker)
121+
#hamming_code = extract_hamming_code(marker)
122+
#marker_id = int(decode(hamming_code), 2)
123+
markers_list.append(HammingMarker(id=1, contours=approx_curve))
124+
except ValueError:
125+
continue
126+
return markers_list

algorithms/ArTagDetectionTest.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import pyzed.sl as sl
2+
import numpy as np
3+
import cv2
4+
from ArTagDetection import detect_markers
5+
6+
7+
8+
if __name__ == '__main__':
9+
# add zed camera code
10+
fourcc = cv2.VideoWriter_fourcc(*'XVID')
11+
videoname = "./ArTest.avi"
12+
video_out = cv2.VideoWriter(videoname, fourcc, 10, (int(1920), int(1080)))
13+
grabbed = False
14+
runtime_params = sl.RuntimeParameters()
15+
camera = sl.Camera()
16+
init_params = sl.InitParameters()
17+
init_params.camera_resolution = sl.RESOLUTION.RESOLUTION_HD1080
18+
err = camera.open(init_params)
19+
if err != sl.ERROR_CODE.SUCCESS:
20+
print("FAILED TO OPEN CAMERA")
21+
22+
image_size = camera.get_resolution()
23+
left = sl.Mat(image_size.width/2, image_size.height, sl.MAT_TYPE.MAT_TYPE_8U_C4)
24+
if camera.grab(runtime_params) == sl.ERROR_CODE.SUCCESS:
25+
camera.retrieve_image(left, sl.VIEW.VIEW_LEFT, sl.MEM.MEM_CPU, int(1920), int(1080))
26+
frame = left.get_data()
27+
grabbed = True
28+
29+
while grabbed:
30+
markers = detect_markers(frame)
31+
for marker in markers:
32+
marker.highlite_marker(frame)
33+
cv2.imshow("IMAGE", frame)
34+
if cv2.waitKey(1) & 0xFF == ord('q'):
35+
break
36+
video_out.write(frame)
37+
if camera.grab(runtime_params) == sl.ERROR_CODE.SUCCESS:
38+
camera.retrieve_image(left, sl.VIEW.VIEW_LEFT, sl.MEM.MEM_CPU, int(1920), int(1080))
39+
frame = left.get_data()
40+
grabbed = True
41+
else:
42+
grabbed = False
43+
#read zed again
44+
45+
46+
47+
cv2.destroyAllWindows()
48+
camera.close()
49+
video_out.release()

algorithms/ArTagEncoding.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import numpy as np
2+
3+
GENERATOR_MATRIX = np.matrix([
4+
[1, 1, 0, 1],
5+
[1, 0, 1, 1],
6+
[1, 0, 0, 0],
7+
[0, 1, 1, 1],
8+
[0, 1, 0, 0],
9+
[0, 0, 1, 0],
10+
[0, 0, 0, 1],
11+
])
12+
13+
REGENERATOR_MATRIX = np.matrix([
14+
[0, 0, 1, 0, 0, 0, 0],
15+
[0, 0, 0, 0, 1, 0, 0],
16+
[0, 0, 0, 0, 0, 1, 0],
17+
[0, 0, 0, 0, 0, 0, 1],
18+
])
19+
20+
PARITY_CHECK_MATRIX = np.matrix([
21+
[1, 0, 1, 0, 1, 0, 1],
22+
[0, 1, 1, 0, 0, 1, 1],
23+
[0, 0, 0, 1, 1, 1, 1],
24+
])
25+
26+
HAMMINGCODE_MARKER_POSITIONS = [
27+
[2, 2], [2, 3], [2, 4],
28+
[3, 2], [3, 3], [3, 4], [3, 5], [3, 6],
29+
[4, 2], [4, 3], [4, 4], [4, 5], [4, 6],
30+
[5, 2], [5, 3], [5, 4], [5, 5], [5, 6],
31+
[6, 2], [6, 3], [6, 4],
32+
]
33+
34+
def encode(bits):
35+
encoded_code = ''
36+
if len(bits) % 4 != 0:
37+
raise ValueError('Only a multiple of 4 as bits are allowed.')
38+
while len(bits) >= 4:
39+
four_bits = bits[:4]
40+
bit_array = generate_bit_array(four_bits)
41+
hamming_code = matrix_array_multiply_and_format(GENERATOR_MATRIX, bit_array)
42+
encoded_code += ''.join(hamming_code)
43+
bits = bits[4:]
44+
return encoded_code
45+
46+
def decode(bits):
47+
decoded_code = ''
48+
if len(bits) % 7 != 0:
49+
raise ValueError('Only a multiple of 7 as bits are allowed.')
50+
for bit in bits:
51+
if int(bit) not in [0, 1]:
52+
raise ValueError('The provided bits contain other values than 0 or 1: %s' % bits)
53+
while len(bits) >= 7:
54+
seven_bits = bits[:7]
55+
uncorrected_bit_array = generate_bit_array(seven_bits)
56+
corrected_bit_array = parity_correct(uncorrected_bit_array)
57+
decoded_bits = matrix_array_multiply_and_format(REGENERATOR_MATRIX, corrected_bit_array)
58+
decoded_code += ''.join(decoded_bits)
59+
bits = bits[7:]
60+
return decoded_code
61+
62+
def parity_correct(bit_array):
63+
checked_parity = matrix_array_multiply_and_format(PARITY_CHECK_MATRIX, bit_array)
64+
parity_bits_correct = True
65+
for bit in checked_parity:
66+
if int(bit) != 0:
67+
parity_bits_correct = False
68+
if not parity_bits_correct:
69+
error_bit = int(''.join(checked_parity),2)
70+
for index, bit in enumerate(bit_array):
71+
if error_bit == index + 1:
72+
if bit == 0:
73+
bit_array[index] = 1
74+
else:
75+
bit_array[index] = 0
76+
return bit_array
77+
78+
def matrix_array_multiply_and_format(matrix, array):
79+
unformated = matrix.dot(array).tolist()[0]
80+
return [str(bit % 2) for bit in unformated]
81+
82+
def generate_bit_array(bits):
83+
return np.array([int(bit) for bit in bits])
84+
85+
def extract_hamming_code(mat):
86+
hamming_code = ''
87+
for pos in HAMMINGCODE_MARKER_POSITIONS:
88+
hamming_code += str(int(mat[pos[0], pos[1]]))
89+
return hamming_code

algorithms/ArTagTest.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import numpy as np
2+
import cv2
3+
from ArTag import HammingMarker
4+
import ArTagEncoding
5+
import time
6+
7+
print("test")
8+
#test = HammingMarker()
9+
test2 = HammingMarker.generate()
10+
im2 = test2.generate_image()
11+
#im = test.generate_image()
12+
#cv2.imshow("frame", im)
13+
cv2.imwrite("./marker2957.png", im2)
14+
cv2.waitKey(1)
15+
time.sleep(5)
16+
print("test")
17+
print("test")

0 commit comments

Comments
 (0)