aboutsummaryrefslogtreecommitdiff
path: root/src/argaze/RegionOfInterest/ROI3DScene.py
blob: cf55e63339ef3ae1b8855ac8a1e55b7d768cc725 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#!/usr/bin/env python

import math
import re

from argaze.RegionOfInterest import ROI2DScene

import numpy
import cv2 as cv
import matplotlib.path as mpath

class ROI3DScene(list):
	"""List of ROI3D dictionary.
	```
	{
		'NAME': str,
		'VERTICES': array of (x, y, z) tuples
	}
	```
	"""

	def __new__(cls):
		return super(ROI3DScene, cls).__new__(cls)

	def __init__(self):

		# define rotation and translation matrix
		self.__rotation = [0, 0, 0]
		self.__translation = [0, 0, 0]

	def __del__(self):
		pass

	def load(self, obj_filepath: str):
		"""Load ROI3D scene from .obj file."""

		# regex rules for .obj file parsing
		OBJ_RX_DICT = {
			'comment': re.compile(r'#(.*)\n'),
			'name': re.compile(r'o (\w+)(.*)\n'),
			'vertice': re.compile(r'v ([+-]?[0-9]*[.]?[0-9]+) ([+-]?[0-9]*[.]?[0-9]+) ([+-]?[0-9]*[.]?[0-9]+)\n'),
			'face': re.compile(r'f (.*)\n')
		}

        # regex .obj line parser
		def __parse_obj_line(line):

			for key, rx in OBJ_RX_DICT.items():
				match = rx.search(line)
				if match:
					return key, match

			# if there are no matches
			return None, None
        
        # start parsing
		try:

			roi3D = {}
			vertices = []
			faces = []

			# open the file and read through it line by line
			with open(obj_filepath, 'r') as file:

				line = file.readline()

				while line:

					# at each line check for a match with a regex
					key, match = __parse_obj_line(line)

					# extract comment
					if key == 'comment':
						pass

					# extract roi3D name
					elif key == 'name':

						roi3D['NAME'] = str(match.group(1))

					# fill vertices array
					elif key == 'vertice':

						vertices.append(tuple([float(match.group(1)), float(match.group(2)), float(match.group(3))]))

					# extract roi3D vertice id
					elif key == 'face':

						roi3D['FACE'] = [int(i) for i in match.group(1).split()]

						# store roi3D dict into scene array
						self.append(roi3D)

						# clear roi3D dict
						roi3D = {}

					# go to next line
					line = file.readline()

				file.close()

				# retreive all roi3D vertices
				for roi3D in self:
					roi3D['VERTICES'] = [ vertices[i-1] for i in roi3D['FACE'] ]
					roi3D.pop('FACE', None)

		except IOError:
			raise IOError(f'File not found: {obj_filepath}')

	def set_rotation(self, rvec: list):
		"""Set scene rotation vector."""
		self.__rotation = rvec

	def set_translation(self, tvec: list):
		"""Set scene translation vector."""
		self.__translation = tvec

	def project(self, K, D):
		"""Project 3D scene onto 2D scene according optical parameters.
		**Returns:** AOI2DScene"""

		roi2D_scene = ROI2DScene.ROI2DScene()

		for roi3D in self:

			vertices_3D = numpy.array(roi3D['VERTICES']).astype('float32')

			vertices_2D, J = cv.projectPoints(vertices_3D, self.__rotation, self.__translation, K, D)
			vertices_2D = vertices_2D.astype('int').reshape((len(vertices_2D), 2))

			roi2D = {
				'NAME': roi3D['NAME'],
				'VERTICES': vertices_2D,
				'POINTER_INSIDE': False
			}

			roi2D_scene.append(roi2D)

		return roi2D_scene