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
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ The vision system has main packages, helpers and 3rd helpers.
- [libfreenect2](https://github.com/butia-bots/libfreenect2);
- [yolov5](https://github.com/butia-bots/yolov5).

## Workspace directory ( If there's none )
Create a workspace
```
mkdir -p ~/butia_ws/src
cd ~/butia_ws/src
```

## Clone

Clone this repository using the follow command:
Expand Down Expand Up @@ -74,5 +81,17 @@ source ~/.zshrc
Run catkin_make

```
cd ~/butia_ws/
catkin_make
```

Source setup

For bash users:
```
source ~/butia_ws/devel/setup.bash
```
For zsh users:
```
source ~/butia_ws/devel/setup.zsh
```
3 changes: 2 additions & 1 deletion butia_recognition/launch/face_rec.launch
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
<node pkg="butia_recognition" type="face_recog.py" output="$(arg output)" name="face_recognition_node" machine="$(arg machine)">
<rosparam command="load" file="$(find butia_recognition)/config/face_rec.yaml"/>
</node>

<include file="$(find butia_world)/launch/redis_cache_reader.launch" />
<include file="$(find butia_world)/launch/redis_cache_writer.launch" />
</launch>
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@

from std_msgs.msg import Header
from sensor_msgs.msg import Image
from butia_vision_msgs.msg import Description2D, Recognitions2D
from butia_vision_msgs.msg import Description2D, Recognitions2D, FaceEncoding, FaceDescription
from butia_vision_msgs.srv import PeopleIntroducing, PeopleIntroducingResponse
from geometry_msgs.msg import Vector3

from butia_world_msgs.srv import RedisCacheReaderSrv, RedisCacheWriterSrv
from std_msgs.msg import Empty

PACK_DIR = rospkg.RosPack().get_path('butia_recognition')
class FaceRecognition(BaseRecognition):
def __init__(self, state=True):
Expand All @@ -33,8 +36,10 @@ def __init__(self, state=True):

self.initRosComm()

self.cache = self.getCache()
known_faces_dict = self.loadVar('features')
self.know_faces = self.flatten(known_faces_dict)
#self.encode_faces()

def initRosComm(self):
self.debug_publisher = rospy.Publisher(self.debug_topic, Image, queue_size=self.debug_qs)
Expand Down Expand Up @@ -76,14 +81,14 @@ def encode_faces(self):
except:
encoded_face = {}
train_dir = os.listdir(self.dataset_dir)

for person in train_dir:
if person not in self.know_faces[0]:
if person not in self.know_faces[0] or person not in self.cache[0]:
pix = os.listdir(self.dataset_dir + person)

for person_img in pix:
face = face_recognition.load_image_file(self.dataset_dir + person + "/" + person_img)
face_bounding_boxes = face_recognition.face_locations(face, model = 'yolov8')
shape = face.shape
face_bounding_boxes = face_recognition.face_locations(face, model='yolov8')

M_face = None
M_area = -float('inf')
Expand All @@ -96,6 +101,14 @@ def encode_faces(self):
if M_face is not None:
face_enc = face_recognition.face_encodings(face, known_face_locations=[M_face])[0]
encodings.append(face_enc)

# Database saving service
data = [person, list(face_enc)]
try:
if person not in self.cache[0]:
self.saveToDB(data)
except rospy.ServiceException as e:
rospy.logerr('Service call failed: %s' % e)

if person not in names:
names.append(person)
Expand All @@ -109,11 +122,79 @@ def encode_faces(self):
pass
self.saveVar(encoded_face, 'features')

def _encapsulateDataRequest(self, data):
h = Header()
h.stamp = rospy.Time.now()
h.seq = self.seq

description = FaceDescription()
description.header = h

description.label = data[0]
description.encoding = data[1]

request = FaceEncoding()
request.header = h
request.descriptions.append(description)

return request

def saveToDB(self, data):
rospy.wait_for_service(self.cache_writer_servername)
try:
self.cache_writer_service = rospy.ServiceProxy(self.cache_writer_servername, RedisCacheWriterSrv)
request = self._encapsulateDataRequest(data)
response = self.cache_writer_service(request)
if response.response:
rospy.loginfo('New face was saved in database.')
self.getCache()

else:
rospy.logerr('New face was not saved in database.')
except rospy.ServiceException as e:
rospy.logerr("Service call failed: %s" % e)

def getCache(self):
rospy.wait_for_service(self.cache_reader_servername)
try:
self.cache_reader = rospy.ServiceProxy(self.cache_reader_servername, RedisCacheReaderSrv)
cache = self._saveCache(self.cache_reader(Empty()))
except rospy.ServiceException as e:
cache = {}
rospy.logerr("Service call failed: %s" % e)

return cache

def _saveCache(self, response):
cache = {}
cache_global_id = []

data = response.response
data_header = data.header
descriptions = data.descriptions

for item in descriptions:
h = item.header
if item.label not in cache.keys():
cache[item.label] = []
cache[item.label].append(list(item.encoding))
cache_global_id.append(item.global_id)
if cache != {}:
rospy.loginfo('Cache was saved and is not empty.')
#print(cache.keys())
formated_cache = self.flatten(cache)
formated_cache_final = formated_cache + tuple(cache_global_id)
return formated_cache_final

def PeopleIntroducing(self, ros_srv):

name = ros_srv.name
num_images = ros_srv.num_images
NAME_DIR = os.path.join(self.dataset_dir, name)

if os.path.exists(NAME_DIR):
NAME_DIR = os.path.join(self.dataset_dir, name + '_1')

os.makedirs(NAME_DIR, exist_ok=True)
os.makedirs(self.features_dir, exist_ok=True)
image_type = '.jpg'
Expand Down Expand Up @@ -160,9 +241,9 @@ def PeopleIntroducing(self, ros_srv):
face_locations = face_recognition.face_locations(ros_image, model='yolov8')

if len(face_locations) > 0:
ros_image = cv2.cvtColor(ros_image, cv2.COLOR_BGR2RGB)
cv2.imwrite(os.path.join(NAME_DIR, add_image_labels[i]), ros_image)
rospy.logwarn('Picture ' + add_image_labels[i] + ' was saved.')
cv2.imwrite(os.path.join(NAME_DIR, add_image_labels[i]), ros_image)
ros_image = cv2.cvtColor(ros_image, cv2.COLOR_BGR2RGB)
i+= 1
else:
rospy.logerr("The face was not detected.")
Expand All @@ -172,7 +253,6 @@ def PeopleIntroducing(self, ros_srv):
response.response = True

self.encode_faces()

known_faces_dict = self.loadVar('features')
self.know_faces = self.flatten(known_faces_dict)
return response
Expand Down Expand Up @@ -211,7 +291,18 @@ def callback(self, *args):
top, right, bottom, left = current_faces[idx]
description = Description2D()
name = 'unknown'
if(len(self.know_faces[0]) > 0):
global_id = ""
if(len(self.cache[0]) > 0):
#rospy.loginfo('Using cache')
face_distances = np.linalg.norm(self.cache[1] - current_encoding, axis = 1)
#print(self.cache[0])
min_distance_idx = np.argmin(face_distances)
min_distance = face_distances[min_distance_idx]
if min_distance < thold:
name = (self.cache[0][min_distance_idx])
global_id = self.cache[2][min_distance_idx]
elif(len(self.know_faces[0]) > 0):
#rospy.loginfo('Using pkl file')
face_distances = np.linalg.norm(self.know_faces[1] - current_encoding, axis = 1)
min_distance_idx = np.argmin(face_distances)
min_distance = face_distances[min_distance_idx]
Expand All @@ -224,6 +315,7 @@ def callback(self, *args):
description_header = img.header
description_header.seq = 0
description.header = copy(description_header)
description.global_id = global_id
description.type = Description2D.DETECTION
description.id = description.header.seq
description.score = 1
Expand Down Expand Up @@ -255,6 +347,10 @@ def readParameters(self):
self.face_recognition_qs = rospy.get_param("~publishers/face_recognition/queue_size", 1)

self.introduct_person_servername = rospy.get_param("~servers/introduct_person/servername", "/butia_vision/br/introduct_person")

self.cache_writer_servername = "redis_cache_writer_srv"

self.cache_reader_servername = "redis_cache_reader_srv"

super().readParameters()
rospy.loginfo('foi 1')
Expand Down
2 changes: 1 addition & 1 deletion butia_vision_msgs
11 changes: 8 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
base
numpy==1.21.6
tensorflow==2.8.0
protobuf==3.19.4
tensorboard==2.10.0
Expand All @@ -13,6 +12,12 @@ idna==3.3
pyparsing==3.0.9
props
librosa==0.9.2
multipledispatch==0.6.0
yolov5==7.0.9
open3d==0.15.2
open3d
face_recognition
ultralytics
torch
torchvision
multipledispatch
numpy==1.22.2
rosnumpy