Ce qui m'a surpris, c'est que je pouvais obtenir les résultats que je voulais avec un code court. La figure ci-dessous montre l'écran (vidéo en temps réel) qui a généré 68 données de repère du visage de dlib avec l'application iPad, les a relayées sur le serveur via Internet et les a affichées sur mac. Le code Python pour cet affichage est [Code] 1] Comme indiqué, il n'y a qu'environ 30 lignes. C'est évident pour les pythonistes, mais c'est incroyable pour les débutants. J'ai senti que c'était le plus fort pour les idées de prototypage.
Le côté qui crée les données de repères du visage à partir de l'image du visage de la caméra et l'envoie avec udp, J'ai utilisé le projet git Xcode suivant. (Pour git du même auteur, version Android, Il existe également une version Javascript. )
https://github.com/Tastenkunst/brfv4_ios_examples
Modifiez track_single_face.hpp comme suit.
addr.sin_port = htons(5000); addr.sin_addr.s_addr = inet_addr("XXX.XX.XXX.XXX");
Numéro de port 5000 et L'adresse IP de «XXX.XX.XXX.XXX» correspond à vos paramètres. Lorsque vous créez et lancez un projet Xcode et que vous prenez une photo de votre visage, il enverra les données de position de 68 points de repère de visage au serveur sous forme de 68x2 octets de données.
track_single_face.hpp
#ifndef __brf__cpp__BRFCppExample_hpp
#define __brf__cpp__BRFCppExample_hpp
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
namespace brf {
class BRFCppExample: public BRFBasicCppExample {
int sock;
struct sockaddr_in addr;
uint16_t shorts;
uint8_t bytes[sizeof(uint8_t)*136*2];
public: BRFCppExample() : BRFBasicCppExample()
{
addr.sin_family = AF_INET;
addr.sin_port = htons(5000);
addr.sin_addr.s_addr = inet_addr("XXX.XX.XXX.XXX");
//sock = socket(AF_INET, SOCK_DGRAM, 0);
}
public: void initCurrentExample(brf::BRFManager& brfManager, brf::Rectangle& resolution) {
brf::trace("BRFv4 - basic - face tracking - track single face" + brf::to_string("\n")+
"Detect and track one face and draw the 68 facial landmarks.");
}
public: void updateCurrentExample(brf::BRFManager& brfManager, brf::DrawingUtils& draw) {
// In a webcam example imageData is the mirrored webcam video feed.
// In an image example imageData is the (not mirrored) image content.
brfManager.update();
// Drawing the results:
draw.clear();
// Face detection results: a rough rectangle used to start the face tracking.
//draw.drawRects(brfManager.getAllDetectedFaces(), false, 1.0, 0x00a1ff, 0.5);
//draw.drawRects(brfManager.getMergedDetectedFaces(), false, 2.0, 0xffd200, 1.0);
// Get all faces. The default setup only tracks one face.
std::vector< std::shared_ptr<brf::BRFFace> >& faces = brfManager.getFaces();
for(size_t i = 0; i < faces.size(); i++) {
brf::BRFFace& face = *faces[i];
if( face.state == brf::BRFState::FACE_TRACKING_START ||
face.state == brf::BRFState::FACE_TRACKING) {
sock = socket(AF_INET, SOCK_DGRAM, 0);
for(int i = 0; i < 136; i++){
shorts = (int)face.vertices[i];
bytes[i * 2] = (uint8_t) (shorts & 0xFF);
bytes[(i * 2) + 1] = (uint8_t) (shorts >> 8);
}
sendto(sock, bytes, sizeof(bytes), 0, (struct sockaddr *)&addr, sizeof(addr));
close(sock);
//draw.drawTriangles( face.vertices, face.triangles, false, 1.0, 0x00a0ff, 0.4);
draw.drawVertices( face.vertices, 2.0, false, 0x00a0ff, 0.4);
}
}
}
};
}
#endif // __brf__cpp__BRFCppExample_hpp
Vient ensuite le côté serveur. C'est un code qui envoie uniquement les données de repère du côté LAN. Le numéro de port et l'adresse IP sont adaptés à votre environnement. L'écriture en Python facilite l'écriture côté serveur.
sendBak.py
import socket
import time
print (time.ctime(),flush=True)
host = '192.168.10.101'
port = 5001
bufsize = 512
portFace = 5000
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#sock.settimeout(0.01)
sock.bind((host,port))
#
sock2 = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
sock2.settimeout(30.0)
sock2.bind((host,portFace))
while True:
global data, addr
string,addr = sock.recvfrom(bufsize)
print("from:",addr,time.ctime())
while True:
try:
data, (host, port) = sock2.recvfrom(bufsize)
result = sock.sendto(data,addr)
#if result != 272:
# print(result)
except socket.error as e:
#print ('Error: %s' % e)
break
Enfin, le côté réception. Peu importe si Python fonctionne sur Mac, Windows ou Linux. Vous pouvez également utiliser Pythoinista sur iOS.
FaceLineOpenCV.py
import cv2
import socket
import numpy as np
from struct import unpack
from datetime import datetime
host = 'XXXX.com'
port = 5001
message = b'hello'
if __name__ == "__main__" :
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#server.bind(('192.168.2.100', 5000))
width = 600
height = 800
img = np.zeros((height, width, 3), np.uint8)
server.sendto(message, (host, port))
while True:
data, addr = server.recvfrom(1024)
cv2.rectangle(img, (0, 0), (600, 700), color=(255, 0, 0), thickness=-1)
val = unpack('<'+'H'*(len(data)//2), data)
j = 0
for i in range(64):
cv2.circle(img, (int(val[j]), int(val[j+1])), 4, (255, 255, 256), -1)
j = j + 2
cv2.imshow('camera capture', img)
k = cv2.waitKey(1) #
if k == 27:
break
cv2.destroyAllWindows()
FaceLineQt.py
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QTimer
import socket
import numpy as np
from struct import unpack
host = 'XXXX.com'
port = 5001
bufsize = 512
message = b'hello'
class Widget(QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.timer = QTimer(self)
self.timer.timeout.connect(self.update)
self.timer.start(20)#mise à jour
#
self.server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#self.server.settimeout(0.5)
#self.server.setblocking(False)
#self.img = np.zeros((height, width, 3), np.uint8)
self.server.sendto(message, (host, port))
def paintEvent(self, event):
data, addr = self.server.recvfrom(bufsize)
val = unpack('<'+'H'*(len(data)//2), data)
painter = QPainter(self)
painter.setPen(Qt.red)
painter.setBrush(Qt.red)
j = 0
for i in range(68):
painter.drawRect(int(val[j]), int(val[j+1]), 5, 5)
j = j + 2
def main():
app = QApplication(sys.argv)
w = Widget()
w.show()
w.raise_()
app.exec_()
if __name__ == '__main__':
main()
J'ajouterai une description de code plus tard.
Ajout de la version Pythonista. Pour Pythonista, utilisez une scène rapide.
FalceLinePythonista.py
from scene import *
import socket
import numpy as np
from struct import unpack
host = 'XXXX.com'
port = 5001
bufsize = 512
class FaceLine (Scene):
def setup(self):
self.landmarks = []
for i in range(68):
shape = ShapeNode(ui.Path.oval(0,0,5,5), 'white')
self.landmarks.append(shape)
self.add_child(shape)
self.server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#
message = b'hello'
self.server.sendto(message, (host, port))
def update(self):
#
data, addr = self.server.recvfrom(bufsize)
val = unpack('<'+'H'*(len(data)//2), data)
dtx = np.array(val[::2])
dty = np.array(val[1::2])
for i in range(68):
self.landmarks[i].position = (dtx[i]+200,800-dty[i])
run(FaceLine())
Recommended Posts