diff --git a/assets/background.png b/assets/background.png new file mode 100644 index 0000000..af41669 Binary files /dev/null and b/assets/background.png differ diff --git a/assets/flower.png b/assets/flower.png new file mode 100644 index 0000000..b383735 Binary files /dev/null and b/assets/flower.png differ diff --git a/blurme/pages/about.py b/blurme/pages/about.py index 056e64d..518c622 100644 --- a/blurme/pages/about.py +++ b/blurme/pages/about.py @@ -42,8 +42,26 @@ Dziękujemy za korzystanie z **BlurMe**! @template(route="/about", title="O autorach", image = "/about-icon.png") def about() -> rx.Component: - return rx.vstack( - #rx.heading("O autorach", font_size="3em"), - rx.markdown(about_authors_text), - ) + return rx.vstack(rx.heading("O autorach", font_size="3em", margin_bottom="10px", background_image="linear-gradient( 64.5deg, rgba(245,116,185,1) 14.7%, rgba(89,97,223,1) 88.7% )", background_clip="text", padding = "10px"), + + rx.box( + rx.text("Jesteśmy grupą studentek kierunku Przetwarzania i Analizy Danych, które postanowiły połączyć swoje różnorodne umiejętności w ramach wspólnego projektu. Zależy nam nie tylko na zdobywaniu wiedzy na uczelni, ale także na praktycznym wykorzystaniu naszych umiejętności w realnych projektach.", margin_right="5%", margin_left="5%", margin_bottom = "10px"), + rx.list( + rx.list_item( rx.icon(tag="arrow_forward")," W naszym zespole każda z nas wnosi unikalne perspektywy i pomysły, co sprawia, że nasza współpraca jest inspirująca.",), + rx.list_item(rx.icon(tag="arrow_forward"), " Nasza pasja do analizy danych oraz zrozumienie dziedziny przetwarzania danych stanowią fundamenty naszego projektu."), + rx.list_item( rx.icon(tag="arrow_forward")," Naszym głównym celem jest stworzenie innowacyjnego rozwiązania, które nie tylko będzie spełniać potrzeby dzisiejszych czasów, ale również przyczyni się do ochrony prywatności w kontekście współdzielenia zdjęć online.",), + margin_left = "18%", margin_right = "18%"), + rx.text("Dzięki zaufaniu naszych użytkowników oraz naszemu zangażowaniu, wierzymy, że nasz projekt przyczyni się do tworzenia bezpieczniejszej przestrzeni dla współdzielenia zdjęć w sieci. Cieszymy się, że możemy być częścią tej fascynującej podróży.", margin_right="5%", margin_left="5%", margin_top="10px"), text_align = "center",), + rx.list( + rx.list_item(rx.text("Nasza Misja",padding = "10px", text_align="center",background_image="linear-gradient( 64.5deg, rgba(245,116,185,1) 14.7%, rgba(89,97,223,1) 88.7% )", background_clip="text", font_size="2em", font_weight="bold", margin_top="30px", margin_bottom="5px"), + rx.text("Nasza grupa powstała z fascynacji technologią oraz z troską o prywatność w dzisiejszym świecie online. Świadomi wyzwań związanych z udostępnianiem fotografii publicznie, postanowiliśmy stworzyć aplikację, która umożliwi użytkownikom ochronę swojej prywatności, jednocześnie pozwalając na swobodne udostępnianie chwil z życia."),margin_right = "40%"), + rx.list_item(rx.text("Jak Powstała Nasza Grupa",padding = "10px", text_align="center",background_image="linear-gradient( 64.5deg, rgba(245,116,185,1) 14.7%, rgba(89,97,223,1) 88.7% )", background_clip="text", font_size="2em", font_weight="bold", margin_top="30px", margin_bottom="5px"), + rx.text("Nasza grupa skupia się na różnorodnych dziedzinach, takich jak sztuczna inteligencja, przetwarzanie obrazów i programowanie. Nasza wspólna pasja do technologii oraz zaangażowanie w projekt zrodziły kreatywną współpracę. Spotkaliśmy się na naszych studiach, gdzie zauważyliśmy potrzebę stworzenia narzędzia, które połączy technologię z ochroną prywatności."),margin_left = "40%"), + rx.list_item(rx.text("Dlaczego BlurMe?",padding = "10px", text_align="center",background_image="linear-gradient( 64.5deg, rgba(245,116,185,1) 14.7%, rgba(89,97,223,1) 88.7% )", background_clip="text", font_size="2em", font_weight="bold", margin_top="30px", margin_bottom="5px"), + rx.text("BlurMe to wynik naszej wspólnej wizji, aby uczynić proces ochrony prywatności prostym i dostępnym dla każdego. Chcemy, aby ludzie czuli się pewnie dzieląc się zdjęciami, nie martwiąc się o potencjalne naruszenia prywatności.",), margin_right = "40%"), + rx.list_item(rx.text("O Naszych Umiejętnościach",padding = "10px", text_align="center",background_image="linear-gradient( 64.5deg, rgba(245,116,185,1) 14.7%, rgba(89,97,223,1) 88.7% )", background_clip="text", font_size="2em", font_weight="bold", margin_top="30px", margin_bottom="5px"), + rx.text("Nasza grupa składa się z pasjonatów programowania, inżynierii oprogramowania i sztucznej inteligencji. Dzięki naszym umiejętnościom oraz współpracy zdobyliśmy doświadczenie w tworzeniu zaawansowanych algorytmów przetwarzania obrazów, które pozwalają na automatyczne wykrywanie twarzy i rejestracji samochodowych na zdjęciach." ),margin_left = "40%"), + rx.list_item(rx.text("Kontakt",padding = "10px", text_align="center",background_image="linear-gradient( 64.5deg, rgba(245,116,185,1) 14.7%, rgba(89,97,223,1) 88.7% )", background_clip="text", font_size="2em", font_weight="bold", margin_top="30px", margin_bottom="5px"), + rx.text("Jeśli masz pytania, sugestie lub chciałbyś dowiedzieć się więcej o naszej grupie, skontaktuj się z nami poprzez naszą stronę kontaktową. Jesteśmy otwarci na współpracę i ciekawe pomysły!"),margin_right = "40%"), + text_align = "center"), margin_right= "65px", margin_left = "65px") diff --git a/blurme/pages/dashboard.py b/blurme/pages/dashboard.py index 97949e3..97a16ce 100644 --- a/blurme/pages/dashboard.py +++ b/blurme/pages/dashboard.py @@ -40,31 +40,24 @@ def dashboard() -> rx.Component: The UI for the dashboard page. """ container_style = {"background-color": "#f5f5f5", "padding": "10px", "margin-bottom": "20px", "display": "flex", "align-items": "center"} - icon_style = {"width": "20px", "height": "20px", "margin-right": "10px"} + icon_style = {"width": "20px", "height": "30px", "margin-right": "10px"} heading_style = {"font-weight": "bold", "font-family": "Arial, sans-serif"} return rx.fragment( - rx.heading("Kontakt", font_size="3em"), - rx.text("Witaj na stronie Kontaktowej w aplikacji BlurMe!"), + rx.heading("Kontakt", font_size="3em", margin_bottom="10px", background_image="linear-gradient( 64.5deg, rgba(245,116,185,1) 14.7%, rgba(89,97,223,1) 88.7% )", background_clip="text", padding = "10px", text_align = "center"), + rx.text("Witaj na stronie Kontaktowej w aplikacji BlurMe!", text_align = "center", margin_right = "15%", margin_left="15%"), rx.text( "Jesteśmy dostępni dla Ciebie na różnych platformach. " "Skontaktuj się z nami, gdy tylko masz pytania, sugestie lub " - "po prostu chcesz porozmawiać o naszej aplikacji." + "po prostu chcesz porozmawiać o naszej aplikacji.", text_align = "center", margin_right = "15%", margin_left="15%" ), - rx.fragment( - rx.fragment( - rx.image(src=ICON_EMAIL, alt="Email icon", style=icon_style), - rx.heading("E-mail", level=3, style=heading_style), + rx.wrap(rx.hstack(rx.vstack(rx.fragment( + rx.hstack(rx.icon(tag="email",style=icon_style), + rx.heading("E-mail", level=3, style=heading_style), margin_top="20px"), rx.text("Zapraszamy do napisania do nas na adres: contact@blurme.com"), - style=container_style - ) - ), - rx.fragment( - rx.fragment( - rx.image(src=ICON_PHONE, alt="Phone icon", style=icon_style), - rx.heading("Telefon", level=3, style=heading_style), + style=container_style,text_align = "center")), + rx.vstack(rx.fragment( + rx.hstack(rx.icon(tag="phone", style=icon_style),rx.heading("Telefon", level=3, style=heading_style), margin_top="20px"), rx.text("Możesz także zadzwonić pod numer: +48 123 456 789"), - style=container_style - ) - ) - ) + style=container_style, text_align = "center"),), + ),style={"align-self": "flex-center"}),) diff --git a/blurme/pages/settings.py b/blurme/pages/settings.py index 7703e77..ee5ba95 100644 --- a/blurme/pages/settings.py +++ b/blurme/pages/settings.py @@ -10,20 +10,66 @@ color = "rgb(107,99,246)" @template(route="/settings", title="Zdjęcie", image = "/image-icon.png") def settings() -> rx.Component: - return rx.vstack( + return rx.vstack( rx.heading("BlurMe", font_size="3em", margin_bottom="25px", background_image="linear-gradient(271.68deg, #7566fe 0.75%, #f96caf 88.52%)", background_clip="text", padding = "10px"), rx.text("Dodaj zdjęcie, które chcesz zanonimizować", font_size="1.2em"), rx.upload( - rx.vstack(rx.text("Drag and drop files here or click to select files"),), + rx.vstack(rx.text("Przeciągnij albo kliknij, aby wybrać pliki"),), border=f"1px dotted {color}", - padding="5em",), + padding="5em", + multiple=True, + accept={ + "image/png": [".png"], + "image/jpeg": [".jpg", ".jpeg"], + "image/webp": [".webp"], + "image/tiff": [".tif", ".tiff"], }, + max_files=5, + ), rx.hstack(rx.foreach(rx.selected_files, rx.text)), - rx.button( "Upload", + rx.button( "Załaduj zdjęcie", on_click=lambda: State.handle_upload( - rx.upload_files()),), - rx.button("Clear", - on_click=rx.clear_selected_files), - rx.foreach( - State.img, lambda img: rx.image(src=f'/{img}')), - padding="5em", - ) + rx.upload_files()),color = "rgba(47, 187, 74,255)"), + + rx.responsive_grid( + rx.foreach( + State.img, + lambda img: rx.vstack( + rx.image(src=f'/{img}', height = "200px"), + rx.text(img), + + + rx.hstack(rx.button("Usuń", + on_click=lambda img_name=img: State.delete_image(img_name), color="rgba(255, 75, 42,255)", + width = "125px"), + rx.button("Anonimizuj", + width = "125px"), + rx.button("Pobierz", + on_click=lambda img_name=img: State.download_image(img_name), + width = "125px"), + padding="1em" + ), + ), + + ),columns=[2], + spacing="5px", + + + + #rx.foreach( + # State.img, + # lambda img: rx.vstack( + # rx.image(src=f'/{img}', max_width = "800px"), + # rx.hstack(rx.button("Usuń", + # on_click=lambda img_name=img: State.delete_image(img_name), + # width = "125px"), + # rx.button("Anonimizuj", + # width = "125px"), + # rx.button("Pobierz", + # on_click=lambda img_name=img: State.download_image(img_name), + # width = "125px"), + # padding="1em" + # ), + # padding="3em", + + ),) + \ No newline at end of file diff --git a/blurme/state.py b/blurme/state.py index 359220d..cfb47b6 100644 --- a/blurme/state.py +++ b/blurme/state.py @@ -4,7 +4,53 @@ import reflex as rx from blurme import styles import asyncio +class State(rx.State): + """The app state.""" + # The images to show. + img: list[str] = [] + # Dark mode status + #dark_mode: bool = False + show: bool = False + + def change(self): + self.show = not (self.show) + + + async def handle_upload(self, files: list[rx.UploadFile]): + """Handle the upload of file(s). + Args: + files: The uploaded files. + """ + for file in files: + #if len(self.img) >= 5: + + upload_data = await file.read() + outfile = rx.get_asset_path(file.filename) + + # Save the file. + with open(outfile, "wb") as file_object: + file_object.write(upload_data) + + # Update the img var. + self.img.append(file.filename) + self.img = self.img + def delete_image(self, img_name: str): + if img_name in self.img: + self.img.remove(img_name) + self.img=self.img + def download_image(self, img_name): + print(self.img) + return rx.download(url=f'/{img_name}', filename=img_name) + + + + + + #async def toggle_dark_mode(self): + # self.dark_mode = not self.dark_mode + # print(f"Dark Mode State: {self.dark_mode}") + #class State(rx.State): # def __init__(self): # super().__init__() @@ -17,30 +63,4 @@ import asyncio # styles.text_color = text_color # print(f"Dark Mode State: {self.dark_mode_state}") # print(f"Current Text Color: {text_color}") -# pass - -class State(rx.State): - """The app state.""" - - # The images to show. - img: list[str] = [] - async def handle_upload(self, files: list[rx.UploadFile]): - """Handle the upload of file(s). - Args: - files: The uploaded files. - """ - for file in files: - upload_data = await file.read() - outfile = rx.get_asset_path(file.filename) - - # Save the file. - with open(outfile, "wb") as file_object: - file_object.write(upload_data) - - # Update the img var. - self.img.append(file.filename) - self.img = self.img - print(f"Current Text Color: {self.img[0]}") - - - +# pass \ No newline at end of file diff --git a/blurme/styles.py b/blurme/styles.py index c0bd4f4..8ea89b2 100644 --- a/blurme/styles.py +++ b/blurme/styles.py @@ -13,9 +13,6 @@ text_color_light = "black" text_color_dark = "white" accent_text_color = "black" accent_color = "linear-gradient(linear-gradient(43deg, rgba(201,238,248,1) 18%, rgba(253,210,227,0.7792366946778712) 86%)" -#linear-gradient(120deg, #d299c2 0%, #fef9d7 100%);" -#linear-gradient(to top, #d9afd9 0%, #97d9e1 100%);" - hover_accent_color = {"_hover": {"color": accent_color}} hover_accent_bg = {"_hover": {"bg": accent_color}} content_width_vw = "90vw" @@ -43,16 +40,6 @@ overlapping_button_style = { "border_radius": border_radius, } -#base_style = { -# rx.MenuButton: { -# "width": "3em", -# "height": "3em", -# **overlapping_button_style, -# }, -# rx.MenuItem: hover_accent_bg, -#} - - markdown_style = { "code": lambda text: rx.code(text, color="#1F1944", bg="#EAE4FD", margin="10px 0"), "a": lambda text, **props: rx.link( diff --git a/graphics/image_modification.py b/graphics/image_modification.py new file mode 100644 index 0000000..8edde89 --- /dev/null +++ b/graphics/image_modification.py @@ -0,0 +1,48 @@ +import os +from typing import List + +from PIL import Image, ImageDraw, ImageFont, ImageFilter +from PIL.Image import composite + +from BlurMe.ml.element_detection import BoundBox + +DIR_PATH = os.path.dirname(os.path.realpath(__file__)) + + +def show_image_with_boxes( + in_image_path: str, bounding_boxes: List[BoundBox], out_image_path: str = None +): + img = Image.open(in_image_path) + draw = ImageDraw.Draw(img) + font_path = DIR_PATH + "/assets/fonts/arial.ttf" + font = ImageFont.truetype(font_path, 25) + for i, box in enumerate(bounding_boxes): + draw.rectangle(box.get_params(), outline="red", width=2, fill=None) + draw.text((box.x1 + 5, box.y1 + 5), str(i + 1), fill="red", font=font) + if not out_image_path: + out_image_path = ( + in_image_path.split(".")[0] + "_out." + in_image_path.split(".")[1] + ) + img.save(out_image_path) + + +def blur_boxes_on_image( + in_image_path: str, bounding_boxes: List[BoundBox], out_image_path: str = None +): + img = Image.open(in_image_path) + blur_img = img.filter(ImageFilter.GaussianBlur(radius=7)) + mask = Image.new("L", img.size, 255) + draw_mask = ImageDraw.Draw(mask) + for box in bounding_boxes: + if box.selected: + if box.object == "plate": + draw_mask.rectangle(box.get_params(), fill=0) + elif box.object == "face": + draw_mask.ellipse(box.get_params(), fill=0) + mask = mask.filter(ImageFilter.GaussianBlur(radius=3)) + img = composite(img, blur_img, mask) + if not out_image_path: + out_image_path = ( + in_image_path.split(".")[0] + "_blurred." + in_image_path.split(".")[1] + ) + img.save(out_image_path) diff --git a/ml/element_detection.py b/ml/element_detection.py index 071cb77..6cfd74d 100644 --- a/ml/element_detection.py +++ b/ml/element_detection.py @@ -2,7 +2,6 @@ import os from typing import List, Tuple import torch -from PIL import Image, ImageDraw, ImageFont from ultralytics import YOLO @@ -16,9 +15,12 @@ IOU_THRESH = 0.5 class BoundBox: - def __init__(self, x1, y1, x2, y2): + def __init__(self, x1, y1, x2, y2, object=None): self.x1, self.y1, self.x2, self.y2 = x1, y1, x2, y2 self.selected = True + if object not in ["face", "plate"]: + raise ValueError("object must be either 'face' or 'plate'") + self.object = object def select(self): self.selected = True @@ -41,29 +43,14 @@ def detect(image_path: str) -> List[BoundBox]: ) plates = plates[0].cpu().numpy().boxes bounding_boxes = [] - for boxes in [faces, plates]: + for boxes, tag in zip([faces, plates], ["face", "plate"]): for box in boxes: xyxyn = box.xyxy[0] x1 = int(xyxyn[0]) y1 = int(xyxyn[1]) x2 = int(xyxyn[2]) y2 = int(xyxyn[3]) - bounding_boxes.append(BoundBox(x1, y1, x2, y2)) + bounding_boxes.append(BoundBox(x1, y1, x2, y2, tag)) return bounding_boxes -def show_image_with_boxes( - in_image_path: str, bounding_boxes: List[BoundBox], out_image_path: str = None -): - img = Image.open(in_image_path) - draw = ImageDraw.Draw(img) - font_path = DIR_PATH + "/assets/fonts/arial.ttf" - font = ImageFont.truetype(font_path, 25) - for i, box in enumerate(bounding_boxes): - draw.rectangle(box.get_params(), outline="red", width=2, fill=None) - draw.text((box.x1 + 5, box.y1 + 5), str(i+1), fill="red", font=font) - if not out_image_path: - out_image_path = ( - in_image_path.split(".")[0] + "_out." + in_image_path.split(".")[1] - ) - img.save(out_image_path) diff --git a/ml/test.py b/ml/test.py index e41296a..ad99d45 100644 --- a/ml/test.py +++ b/ml/test.py @@ -1,6 +1,8 @@ import unittest from unittest.mock import Mock, patch -from element_detection import detect, show_image_with_boxes, BoundBox +from element_detection import detect, BoundBox +from BlurMe.graphics.image_modification import show_image_with_boxes + class TestYourModule(unittest.TestCase):