-
Notifications
You must be signed in to change notification settings - Fork 0
6. Rozpoznanie osoby podľa oblečenia
Táto ukážka znázorňuje rozpoznanie osoby pomocou počítačového videnia, klasifikáciu obrázku a spätnú väzbu vo forme audia.
Na spustenie ukážky musíme cez terminál najskôr spustiť demo.launch súbor, ktorý sme si pripravili.
roslaunch matus_showcase demo.launch
Zároveň musíme na našom Raspberry, ktoré sme si správne nakonfigurovali spustiť python skript receive_image.py.
./receive_image.py
Potom môžeme spustiť na Jupiterovi:
rosrun matus_showcase person_recognizer.py
rosrun matus_showcase take_picture.py
rosrun matus_showcase send_image.py
Pri spustení uzla take_picture paramater nemusíme uviesť nakoľko vrchná kamera je nastavená ako predvolená.
Pri tomto spustení si robot vypýta meno osoby ak ju ešte nepozná.
Pri každom ďalšom spustení uzla rosrun matus_showcase send_image.py
už robot povie meno osoby alebo si vypýta meno.
Neurónová sieť v obraze rozpoznala okuliare ako je vidno v spodnom termináli. Vpravo dolu je vypísané glasses.
Pohľad cez vrchnú kameru.
Raspberry Pi 4 s Google Coral USB akcelerátorom zapojeným cez USB3.0.
Video s rozpoznávaním nájdete TU
Architektúra tohto programu sa skladá z piatich komponentov a to uzlu na odfotenie obrazu, komponentu na odoslanie obrázka, komponentu na prijatie obrázka, komponentu na klasifikáciu obrázka a komponentu na rozpoznanie osoby.
Tento uzol máme podrobne popísaný TU. Uzol v tomto programe voláme bez parametrov, pretože chcem použiť vrchnú kameru robota, ktorá je predvolená automaticky.
Tento kód vytvára spojenie s Raspberry Pi pomocou TCP/IP a odosiela obrazové dáta na danú IP adresu a port. Popíšme si jednotlivé časti kódu:
# Specify the IP address and port number of the receiver
# Specify the path of the image you want to send
self.IP_ADDRESS = '192.168.8.5'
self.PORT = 7123
self.path = '/home/mustar/jupiter/matus/matus_showcase/images/photo.png'
self.image_data = None
S inicializáciou triedy SendImage nastavíme IP adresu Raspberry Pi z konfiguračného súboru, PORT a cestu k obrázku.
def load_image(self, path):
with open(path, 'rb') as f:
self.image_data = f.read()
Metóda slúži na načítanie dát obrázka.
def send_image(self):
self.load_image(self.path)
# Create a TCP/IP socket
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect to the receiver
self.sock.connect((self.IP_ADDRESS, self.PORT))
# Send the size of the image data as a 4-byte integer
image_size = struct.pack("!L", len(self.image_data))
self.sock.sendall(image_size)
# Send the image data
self.sock.sendall(self.image_data)
# Wait for the answer
answer = self.sock.recv(4096)
print(answer)
# Publish a message to /clothes topic
ClothingPublisher(answer)
# Say the answer out loud
talker = Talker(answer)
talker.talk()
# Close the socket
self.sock.close()
Hlavná metóda, ktorá odosiela obrázok.
- Najprv načítame obrazové dáta.
- Vytvoríme TCP/IP socket, ktorý naviaže spojenie s Raspberry cez IP aresu a port.
- Najprv odošleme veľkosť obrázka ako štvorbajtové číslo a následne odošleme samotné obrazové dáta.
- Čakáme na odpoveď od príjemcu, ktorú publikujeme na topic "clothes" pomocou "ClothingPublisher".
- Socket uzavrie spojenie.
Tento komponent sa nachádza na Raspberry Pi a slúži na prijímanie obrazových dát z robota Jupiter a ich následné spracovanie.
def __init__(self):
# Specify the IP address and port number of the sender
# Specify the path of the image save destination
self.IP_ADDRESS = '0.0.0.0'
self.PORT = 7123
self.save_path = '/home/pi/jupiter/clothes/received.png'
Pri inicializácii triedy ImageReceiver nastavíme IP adresu robota Jupiter, PORT a cestu na uloženie obrázka.
def receive_image(self):
# Create a TCP/IP socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
# Bind socket to IP address and port number
sock.bind((self.IP_ADDRESS, self.PORT))
sock.listen(1)
while True:
# Wait for a connection
print("Waiting for connection>>")
conn, addr = sock.accept()
print('Connected by', addr)
# Receive the size of the image data as a 4-byte integer
size_bytes = conn.recv(4)
size = int.from_bytes(size_bytes, byteorder='big')
# Receive the image data
data = b''
while len(data) < size:
packet = conn.recv(size - len(data))
if not packet:
break
data += packet
# Save the image data to a file
with open(self.save_path, 'wb') as f:
f.write(data)
result = classification()
# Send the classification result as answer
conn.send(result.encode("utf-8"))
print(result)
# Close the connection
conn.close()
Hlavná funkcionalita programu sa vykonáva v tejto metóde.
- Vytvorí sa TCP/IP socket, ktorý vytvorí spojenie na IP adresu a PORT robota Jupiter.
- Socket čaká na pripojenie odosielateľa a príjme veľkosť obrazových dát ako štvorbajtové číslo.
- Potom príjme samotné obrazové dáta a uloží ich do určeného priečinka.
- Obrázok sa spracuje pomocou funkcie "calsification()".
- Výsledok klasifikácie sa odošle naspäť odosielateľovi ako odpoveď a spojenie sa zatvorí.
Tento komponent sa nachádza na Raspberry Pi a má na starosti klasifikáciu obrázku a rozpoznanie typu oblečenia, ktoré sa nachádza na obrázku.
model = 'clothes/clothes_model_edgetpu.tflite'
labels_path = 'clothes/clothing_labels.txt'
input = 'clothes/clothing_labels.txt'
Ako prvé si nastavíme cesty k nášmu modelu, súboru s popismi tried a vstupnému obrázku.
labels = read_label_file(labels_path) if labels_path else {}
interpreter = make_interpreter(*model.split('@'))
interpreter.allocate_tensors()
Načítame si model a vytvoríme inštanciu interpretera.
size = common.input_size(interpreter)
image = Image.open(input).convert('RGB').resize(size, Image.ANTIALIAS)
params = common.input_details(interpreter, 'quantization_parameters')
scale = params['scales']
zero_point = params['zero_points']
mean = 128.0
std = 128.0
if abs(scale * std - 1) < 1e-5 and abs(mean - zero_point) < 1e-5:
# Input data does not require preprocessing.
common.set_input(interpreter, image)
else:
# Input data requires preprocessing
normalized_input = (np.asarray(image) - mean) / (std * scale) + zero_point
np.clip(normalized_input, 0, 255, out=normalized_input)
common.set_input(interpreter, normalized_input.astype(np.uint8))
Prekonvertujeme obrázok do RGB formátu, zmenšíme na veľkosť požadovanú modelom a ak je to potrebné predspracujeme ho, aby bol v správnom formáte a škálovanej hodnote pre model.
# Run inference
for _ in range(5):
interpreter.invoke()
classes = classify.get_classes(interpreter, 1, 0.0)
print('-------RESULT--------')
for c in classes:
print('%s: %.5f' % (labels.get(c.id, c.id), c.score))
return (labels.get(c.id, c.id))
Spustíme inferenciu pomocou interpretera modelu a získame triedy a skóre klasifikácie. Na konci vrátime názov triedy rozpoznaného oblečenia.
Tento komponent slúži na to, aby podľa kusu oblečenia vedel povedať o akú konkrétnu osobu ide. Ak osobu ešte nepozná, vypýta si jej meno, inak ju pozdraví a osloví jej menom.
self.people = {}
self.recognized_clothing = ""
rospy.init_node('people_recognizer')
rospy.Subscriber('clothes', ClothesMessage, self.clothes_callback)
while not rospy.is_shutdown():
rospy.sleep(1)
Inicializujeme si slovník ľudí a ich oblečenia do ktorého budeme pridávať osoby, ktoré poznáme.
- Vytvoríme uzol s názvom "people_recognizer".
- Vytvoríme subscribera napojeného na topic "clothes" so správou typu ClothesMessage, ktorú sme si vytvorili a funkciou "self.clothes_callback()"
def recognize_person(self):
if not self.known_person():
self.add_person()
self.say_hello()
Táto metóda slúži na rozpoznanie osoby. Ak osoba nie je známa (metóda known_person vráti False), volá sa metóda "add_person()" na pridanie novej osoby. Potom sa zavolá metóda "say_hello()" na privítanie osoby.
def clothes_callback(self, data):
if data.glasses:
self.recognized_clothing = "glasses"
if data.cap:
self.recognized_clothing = "cap"
else:
self.recognized_clothing = "red_t_shirt"
self.recognize_person()
Metóda "clothes_callback()" je volaná pri príchode správy typu ClothesMessage na topic "clothes". Na základe informácií v správe sa nastaví hodnota recognized_clothing na základe oblečenia. Potom sa volá metóda "recognize_person()" na rozpoznanie osoby.
def say_hello(self):
person = self.people[self.recognized_clothing]
talker = Talker(self.recognized_clothing)
talker.talk()
talker = Talker("Hello ", person)
talker.talk()
Na základe typu oblečenia v správe sa zo slovníka vyberie meno osoby, ktorú má robot pozdraviť.
def known_person(self):
return self.recognized_clothing in self.people
def add_person(self):
talker = Talker("Please enter your name below:")
talker.talk()
name = input("YOUR NAME HERE:")
self.people[self.recognized_clothing] = name
- Metóda "known_person()", slúži na zistenie, či osobu už poznáme alebo ešte nie.
- Ak osobu nepoznáme tak metóda "add_person()" osobu do slovníka pridá po vypýtaní mena z konzole s názvom daného oblečenia ako kľúčom.
Tieto diagramy znázorňujú priebeh komunikácie medzi jednotlivými komponentami programu, ako aj medzi Jupiterom a Raspberry Pi.
Význam jednotlivých častí diagramu je bližšie popísaný TU.