Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ProjInf#71 #2

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
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
33 changes: 12 additions & 21 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,11 @@
"""
TODO:
! Implementar "warm-up" do modelo (5 ciclos de inferencia)- to do
!! O que deve e tem de ir nos metadados do frame, e como pode ser codificado no base64?
1.2) Criar variável de entrada e saída para o sistema de obfuscação - to do
1.3) Testar output dos modelos Yolov9, Gelan e RTMDet e implementar class para adaptar a saída - 30% done
2) Implementar frame obfuscatiom striding - implementar logica que está no Unity

Usage:
python main.py \
--model_number 0 \
--class_id_list 0 1 \
--obfuscation_type_list "pixelation" "masking" \
--image_base64_file "test_samples/images/img_640x640_base64.txt" \
--square 10 \
--sigma 5
"""

import sys
import os
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), 'src')))

import argparse
import importlib
import os
import logging

import src.seg_yolov8
from src.safear_service import SafeARService
Expand All @@ -31,6 +14,8 @@
importlib.reload(src.seg_yolov8)
importlib.reload(src.safear_service)

logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def main(args):
safeARservice = SafeARService()
Expand All @@ -40,11 +25,14 @@ def main(args):
obfuscation_policies=args.obfuscate_policies,
)

# Log the policies
logger.debug(f"Configured with model_number: {args.model_number}")
logger.debug(f"Obfuscation policies: {args.obfuscate_policies}")

frame_bytes = safeARservice.process_frame(args.image_base64)

return frame_bytes


def parse_args():
arg_parser = argparse.ArgumentParser(description="Obfuscation script")
arg_parser.add_argument(
Expand Down Expand Up @@ -100,8 +88,11 @@ def parse_args():
arg_parser.print_help()
exit()

# Create the obfuscate_policies dictionary directly in the parser
args.obfuscate_policies = dict(zip(args.class_id_list, args.obfuscation_type_list))
# Check if class_id_list and obfuscation_type_list are provided
if args.class_id_list and args.obfuscation_type_list:
args.obfuscate_policies = dict(zip(args.class_id_list, args.obfuscation_type_list))
else:
args.obfuscate_policies = {}

# Print the absolute path of the file
abs_path = os.path.abspath(args.image_base64_file)
Expand Down
44 changes: 27 additions & 17 deletions src/flask_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@

import base64
import logging

from flask import Flask, request, render_template, send_from_directory, jsonify

from src.safear_service import SafeARService

# Initialize the Flask app
Expand All @@ -52,35 +50,45 @@
app.config["STATIC_FOLDER"] = "templates"


# Set up logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

@app.route("/obfuscate", methods=["POST"])
def safeAR_service():
try:
# Extract the base64 image data from the JSON payload
data = request.get_json()
model_number = data.get('model_number', 0)
class_id_list = data.get('class_id_list')
obfuscation_type_list = data.get('obfuscation_type_list')

# Log the incoming request data
logging.debug(f"Received request data: {data}")

if data is None or "img" not in data:
logger.error("No valid request body or 'img' missing in JSON")
return jsonify({"error": "No valid request body, json missing!"}), 400
# TODO: no canal tem de vir a classe a ser obfuscada e o tipo de obfuscation!

img_data = data["img"]
# Ensure the base64 string is correctly padded
#logger.info(f"Received base64 image data of length: {len(img_data)}")

img_data += "=" * ((4 - len(img_data) % 4) % 4)
# Decode the base64 image data
# img_bytes = base64.b64decode(img_data)

# Initialize the SafeARService
safe_ar_service = SafeARService()
obfuscation_policies = dict(zip(class_id_list, obfuscation_type_list))
logging.info(f"Obfuscation policies: {obfuscation_policies}")

# Configure the SafeARService with the desired model number and obfuscation policies
safe_ar_service.configure(model_number=0, obfuscation_policies={0: "blurring"})
safe_ar_service.configure(model_number=model_number, obfuscation_policies=obfuscation_policies)

# Image Obfuscation using the SafeARService
processed_frame_bytes = safe_ar_service.process_frame(img_data)
detected_objects = safe_ar_service.process_frame(img_data)

# Encode the processed frame as base64
safeAR_image_base64 = base64.b64encode(processed_frame_bytes).decode("utf-8")
if detected_objects is None:
logger.error("Error processing frame")
return jsonify({"error": "Error processing frame"}), 500

return jsonify({"img": safeAR_image_base64})
return jsonify({"detected_objects": detected_objects})
except Exception as e:
app.logger.error(f"Error processing image: {e}")
logger.exception(f"Error processing image: {e}")
return jsonify({"error": "Failed to process image"}), 500


Expand Down Expand Up @@ -120,4 +128,6 @@ def shutdown():


if __name__ == "__main__":
app.run(host="0.0.0.0", port=8080, debug=True)
app.run(host="0.0.0.0", port=8080, debug=True, ssl_context=('/mnt/c/users/ivo/desktop/ServerSafeAR/SafeAR/src/fullchain.pem', '/mnt/c/users/ivo/desktop/ServerSafeAR/SafeAR/src/privkey.pem'))


22 changes: 22 additions & 0 deletions src/fullchain.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDoTCCAomgAwIBAgIUDWhCwIo0EvpnPYvTdUjYfTUmmnkwDQYJKoZIhvcNAQEL
BQAwYDELMAkGA1UEBhMCUFQxDzANBgNVBAgMBkxlaXJpYTEPMA0GA1UEBwwGTGVp
cmlhMQwwCgYDVQQKDANJUEwxDTALBgNVBAsMBEVTVEcxEjAQBgNVBAMMCWxvY2Fs
aG9zdDAeFw0yNDA5MDExNTM0NTFaFw0yNTA5MDExNTM0NTFaMGAxCzAJBgNVBAYT
AlBUMQ8wDQYDVQQIDAZMZWlyaWExDzANBgNVBAcMBkxlaXJpYTEMMAoGA1UECgwD
SVBMMQ0wCwYDVQQLDARFU1RHMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDgk1BCtxolUonL7eCg3QwfE1uO+WMl/E8+
2vkcoNuMEkF/FveNQJ9Tca7qhtPKXpcNZdCio1tOMoEIziRlmf0P3B1P/n5PdKAL
pUkrDHSTf0h7CsvsgPigYzG8xLKlLrCpzsEQJcksPQSyDHfIBluk8eRzihVS5Dxl
uJRainIZSnhFDmhsfl2e96xpG0jnP4sX7dNGffnxchk0FBMf36zoHLz67Y0v1Fz7
QV/f3egWhwRSu0oEZLys4nkkFAolKO+c0RCy0P7r9sWyFT768aUpZVhrOLv1/Puh
O/vazMCacYfQOQ0sWUmkGvhrDCE6SIjmNMfYWXARvx+DzS1e7nSJAgMBAAGjUzBR
MB0GA1UdDgQWBBRnu5dvfQAVbqGah7Zj0pq+oSP8BDAfBgNVHSMEGDAWgBRnu5dv
fQAVbqGah7Zj0pq+oSP8BDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA
A4IBAQB9aKdNW+y/cVaEVKssY1PiL126FSAxqBpeqsJIU5+gUEaU85jkJlpMRaKd
oQ1S/KTLquhx2T6VqUKuVjZKRColU4GbU8ytg58Wue0ZxJKnsxNQzxKrHexrGGZS
Yr5lgFMPEeOnr2nyJqa3gZee5YA1Ai3SV6AZVQDTzQlekYhQZUuXP7kIoSeqLa9n
+aLY/W+V9tmA7e9JAKMQQtce2UUxwS6KaaQIO72gLXF7zMj4572fmwZxPBXGklmC
a0CA1SqcA5YuOx48KUNkGj0iz20PSmjzBjAuavHk2N0DXrz+Lr2tMSCdHyyyXoxK
dDeLXAPy3ErtmsPpZYIAMMZpRDFR
-----END CERTIFICATE-----
28 changes: 28 additions & 0 deletions src/privkey.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDgk1BCtxolUonL
7eCg3QwfE1uO+WMl/E8+2vkcoNuMEkF/FveNQJ9Tca7qhtPKXpcNZdCio1tOMoEI
ziRlmf0P3B1P/n5PdKALpUkrDHSTf0h7CsvsgPigYzG8xLKlLrCpzsEQJcksPQSy
DHfIBluk8eRzihVS5DxluJRainIZSnhFDmhsfl2e96xpG0jnP4sX7dNGffnxchk0
FBMf36zoHLz67Y0v1Fz7QV/f3egWhwRSu0oEZLys4nkkFAolKO+c0RCy0P7r9sWy
FT768aUpZVhrOLv1/PuhO/vazMCacYfQOQ0sWUmkGvhrDCE6SIjmNMfYWXARvx+D
zS1e7nSJAgMBAAECgf8OGAsSBZmhrXxZqJWHwy5cso6cDGhGsRDTlj7rB4dHlUVn
0Vw3bIsetLrRdHFWtSVkcha+OcchR0pdSRFILvbyk8ofXmnqrxXZCxqtAu+EJi0f
NXXv2KFc8q7cIFD00jDUMZ492xj3A5MAwQmfnxrxkTvVMWtRN+2BAD8tTJy0KTkp
Te6kw+0SOZSUMKZDOGOJvc41WKHt4S4HwI5rkUSDtYQrrg3mSda9YXFnu630oXO7
nPrTTbcI/TbJKlWnhf/eV57on357z0UgpbhSxEurm6p77VZjNdSvyCqQDiSC1Xx0
D8C2T4QpUklzMU3MQ+YFlc5aIvKcZ7CIV7CD8t8CgYEA89vuhH/MwzPm4JQwWFOt
KqeFaGAKGVAjpLtBdrWWmbuNA34yiJA07PL41F5P6TU0SIfznb3cOd2B2S+Og6Og
j9xoXp3LuF3wCyRJQMsGp3s05GVO3gCmMoJ3Nbb7M9LFxWTl1Xcwot2KC0SlmSAo
qmht9Y8TuSY4UnyeeuwZSocCgYEA68Ga2Dd5YYNqljCVdiSf9JS2CjYh1LPfuLL1
3h3Ihg+MorQ6lu6hAe4OaBU8Z5z1fHXQrXtxet86ngB3cUbxdlGQrFAhRHSgdLy+
vsazlV6gdS6FiiG5iP/RT+IYYSz1rUd/yrgszsVTcRBPnH/LU9IpKvN22bK0wVfh
6cvkvG8CgYBR8FN72Alwic8JJSH9e9hS3ck44hRinwfrATSk860v6NIgG1ZVhscR
2y57BVmqjcMMoAnetf36v5Ay7wTe/Ksly7SSHklmoMHYrI+kotOQkRibqeLPO76c
eDQgK2TK7AaiJh4IFS2VfAU3dhCCnEitwbs46KOC8fG43cDOouh4nwKBgQDnDfoa
SlQV89w0ki0Jet+hr1WyMFd7xUZQGGTLadkrOnYUyBpb7keyQoOwEo/+5F/buQPp
4n/Xcoxaag6l4GeqFEp79pSEKOFRR+KRyuAaVoFgF1YdiOvzjvSvG+HU62FkkBx4
q4SOqeobd2bu9HhsEB70z2P9/B0XGHB62K+21QKBgQDKQ4GpZKnl40Mba4d5ICXM
bol5RBPfiyp2UV7GnSpSolx61DH5qxaGoMKCbcwXSYFoLlR97pKTAUOkYDp7Rykq
78SUqFcGaB0DlAOoe3CfmS0iS7mW+rE0yCRbp9auq+iIKMq9OebgLWWqgZ3Umj82
jsZnt8hU/KdX9gNWMoJaHQ==
-----END PRIVATE KEY-----
78 changes: 36 additions & 42 deletions src/safear_service.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,22 @@
import base64
import os
from io import BytesIO
from typing import Any

import cupy as cp
import imageio
import yaml
import logging

from src.obfuscator import ImageObfuscator
from src.seg_yolov8 import Yolov8seg

# # Reload the modules
# importlib.reload(seg_yolov8)
# importlib.reload(obfuscator)
# Import the classes from the reloaded modules

logger = logging.getLogger(__name__)

class SafeARService:

def __init__(self):
self.obfuscator = None
self.model = None
self.obfuscation_policies: dict[str, Any] = {}
self.obfuscation_policies = {}

def configure(self, model_number: int, obfuscation_policies: dict):
config_yml = self.load_config()
Expand All @@ -32,37 +27,39 @@ def configure(self, model_number: int, obfuscation_policies: dict):
self.obfuscation_policies = obfuscation_policies
self.obfuscator = ImageObfuscator(policies=self.obfuscation_policies)

def process_frame(self, image_base64: str) -> bytes:
"""
Process a frame by detecting objects and applying obfuscation.
Args:
image_base64: str representation of an image, encoded in Base64 format

Returns:
safe_frame_bytes: the processed frame, encoded in bytes
"""
# Decode the Base64 image string to bytes
image_bytes = base64.b64decode(image_base64)
print(f"Image bytes: {len(image_bytes)}")
# Create a buffer (`BytesIO` object) from the image bytes
buffer = BytesIO(image_bytes)

# Read the image from the buffer using imageio
img_array = imageio.v2.imread(buffer)
# Convert the Numpy array to a cuPY array
frame = cp.asarray(img_array)

# DEBUG: save the input frame
imageio.imwrite("outputs/img_in_flask_2.png", frame.get())

boxes, masks = self.model(frame)
safe_frame = self.obfuscator.obfuscate(
image=frame, masks=masks, class_ids=[int(box[5]) for box in boxes]
)

safe_frame = safe_frame.astype(cp.uint8)
safe_frame_bytes = safe_frame.tobytes()
return safe_frame_bytes
def process_frame(self, image_base64: str):
try:
# Decode the base64 image data
image_bytes = base64.b64decode(image_base64.encode("utf-8"))
logger.info(f"Decoded image bytes length: {len(image_bytes)}")

# Read the image data into an array
buffer = BytesIO(image_bytes)
img_array = imageio.v2.imread(buffer)
logger.info(f"Read image array shape: {img_array.shape}")

frame = cp.asarray(img_array)

# Process the image using the model
boxes, masks = self.model(frame)
logger.info(f"Model output: {len(boxes)} boxes, {len(masks)} masks")

if len(boxes) == 0 or len(masks) == 0:
logger.warning("No objects detected.")
return []

detected_objects = []
for i, box in enumerate(boxes):
detected_objects.append({
'class_id': int(box[5]),
'bbox': [int(box[0]), int(box[1]), int(box[2]), int(box[3])],
'mask': cp.asnumpy(masks[i]).tolist() # Convert mask to a list of lists for JSON serialization
})

return detected_objects
except Exception as e:
logger.exception(f"Error processing image: {e}")
return None

@staticmethod
def read_base64_image(file_path):
Expand All @@ -83,11 +80,8 @@ def save_processed_frame(frame_bytes, output_path):

@staticmethod
def load_config() -> dict:
# Get the current directory
current_directory = os.path.dirname(os.path.abspath(__file__))
# Get the parent directory
parent_directory = os.path.dirname(current_directory)
# Construct the path to the config.yml file
config_file_path = os.path.join(parent_directory, "config.yml")

with open(file=config_file_path, mode="r", encoding="utf-8") as file:
Expand Down
1 change: 1 addition & 0 deletions test_samples/images/baber.txt

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions test_samples/images/teste.txt

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions test_samples/images/woman.txt

Large diffs are not rendered by default.