| Parametr | Wybór | Uwagi |
|---|---|---|
| Metoda Krawędzi | Dowolna (np. Canny) | Zastosujemy standardową procedurę OpenCV. |
| Źródło Zdjęć | Ścieżka do pliku | Aplikacja jako skrypt przyjmujący argument. |
| Kolory | Biały, Czarny, Szary | Krawędzie będą czarne, a cieniowanie użyje białego i szarego. |
| Wykrywanie Cienia | Bazujące na analizie głębi/kontrastu | Największe wyzwanie techniczne. |
| Grubość Krawędzi | Stała (1px) | Dla prostoty i czytelności. |
| Mechanizm Cieniowania | Na podstawie kontrastu/jasności | Symulacja cieniowania (shading) na podstawie danych źródłowych. |
| Maska głównych obiektów | Adaptacyjne progowanie + połączone komponenty | Wycinamy tło (liście, trawę), pozostawiamy największe bryły. |
| Biblioteki | Tylko OpenCV i NumPy | Minimalizacja zależności. |
| Przygotowanie Obrazu | Tak (Skala Szarości, Rozmycie) | Standardowa procedura. |
| Format Zapisu | PNG/JPEG | Opcja zapisu. |
| Priorytet | Prostota i Czytelność Kodu |
W odpowiedzi na punkt 4, gdzie zależy Ci na cieniowaniu w obszarach, gdzie naturalnie występowałby cień (pod szyją, na zgięciach rąk), należy zastosować bardziej zaawansowane podejście niż proste wypełnianie obszarów zamkniętych konturów.
Biblioteki OpenCV i NumPy nie posiadają wbudowanych, prostych funkcji do rozumienia głębi sceny (jak to robią zaawansowane modele Deep Learning). Musimy więc zasymulować efekt cieniowania, wykorzystując informację o jasności (luminancji) oryginalnego obrazu.
| Etap | Opis Funkcjonalny | Użycie Kolorów |
|---|---|---|
| Wykrycie Krawędzi | Użycie Canny'ego na przetworzonym obrazie. | Krawędzie będą koloru Czarnego. |
| Symulacja Cieniowania | Konwersja oryginalnego obrazu (skala szarości) na dwa poziomy jasności (dla uproszczenia) za pomocą progowania (cv2.threshold). |
Jasne obszary otrzymają kolor Biały, a ciemne obszary otrzymają kolor Szary. |
| Maskowanie Tła | Adaptacyjne progowanie + analiza komponentów (connectedComponentsWithStats). |
Zostawiamy tylko największe bryły (np. sylwetki ludzi). |
- Wczytanie i Konwersja: Wczytaj obraz, przekształć go na skalę szarości (
L). - Maska głównych obiektów:
- Wygładź obraz filtrem bilateralnym (zostaw krawędzie, usuń szum liści).
- Zastosuj progowanie adaptacyjne (
cv2.adaptiveThreshold) i domknięcie morfologiczne. - Użyj
connectedComponentsWithStats, aby wybrać tylko największe komponenty (domyślnie dwie sylwetki). - Powstaje maska
M, którą później nałożymy na cieniowanie i krawędzie.
- Symulacja Cienia (Dwa Kolory Wnętrza):
- Zastosuj globalne progowanie na obrazie w skali szarości (
L). Prog ustali, które piksele są "jasne" (cieńsze, oświetlone) i które są "ciemne" (zacienione). - Piksele jaśniejsze od progu wypełnij kolorem Białym.
- Piksele ciemniejsze od progu wypełnij kolorem Szarym.
- Wynikiem będzie wstępnie pokolorowany obraz (tylko biały i szary), nazwijmy go
T. - Na tym etapie ustaw piksele poza maską
Mna biało, aby tło nie generowało "bałaganu".
- Zastosuj globalne progowanie na obrazie w skali szarości (
- Wykrycie Krawędzi:
- Zastosuj rozmycie Gaussa na obrazie
L. - Zastosuj algorytm Canny'ego na rozmyciu, uzyskując mapę krawędzi binarnych
K. - Wyzeruj krawędzie poza maską
M, dzięki czemu liście/tło nie będą rysowane.
- Zastosuj rozmycie Gaussa na obrazie
- Kompozycja:
- Nałóż mapę krawędzi
Kna obrazT. Wszędzie tam, gdzie na mapieKjest krawędź (piksel ma wartość 1), ustaw ten piksel na obrazieTna kolor Czarny.
- Nałóż mapę krawędzi
To podejście w naturalny sposób przeniesie cieniowanie (w postaci jasnych i ciemnych obszarów) z oryginalnego zdjęcia, bez potrzeby skomplikowanej analizy głębi obiektów.
Poniżej przedstawiam funkcjonalną strukturę kodu w Pythonie. Możemy przejść do generowania poszczególnych fragmentów przez LLM.
import cv2
import numpy as np
import sys
import os
# --- 1. Funkcja Główna ---
def process_image(input_path, output_path, shadow_color, light_color, edge_color, threshold_value):
# Wczytywanie obrazu
# Konwersja do skali szarości (L)
# --- 2. Symulacja Cieniowania (T) ---
# Zastosowanie progowania (cv2.threshold) na L
# Zastąpienie pikseli jasnych (powyżej progu) kolorem light_color
# Zastąpienie pikseli ciemnych (poniżej progu) kolorem shadow_color
# --- 3. Wykrywanie Krawędzi (K) ---
# Rozmycie Gaussa i Canny (cv2.Canny)
# --- 4. Kompozycja ---
# Nałożenie krawędzi K na obraz cieniowany T
# --- 5. Zapis i Wyświetlanie ---
# Zapis wyniku (cv2.imwrite) i opcjonalne wyświetlenie (cv2.imshow)
pass
# --- 6. Uruchomienie Skryptu ---
if __name__ == "__main__":
# Obsługa argumentów wejściowych (ścieżka do pliku)
# Definicja stałych kolorów (RGB/BGR dla OpenCV)
# Wywołanie process_image
passcd /Users/aleksandrakaminska/Documents/Projekty-moje/edgeFindersource venv/bin/activatepython edge_finder.py /absolutna/sciezka/do_obrazu.jpg
Domyślnie wynik zapisuje się w output/<nazwa_pliku_wejściowego>_processed.png. Jeśli chcesz podać własną ścieżkę docelową, użyj parametru -o /sciezka/docelowa.png. Pozostałe flagi (-t, --canny-low, --canny-high, --blur, --show) działają bez zmian.
Nowa część pipeline'u pozwala zachować tylko największe obiekty (domyślnie dwie największe sylwetki). Sterujemy tym dwoma parametrami:
--main-area-ratio 0.02— minimalny udział pojedynczego obiektu w powierzchni zdjęcia (np. 0.02 = 2%). Zwiększ, jeśli wciąż łapią się liście; zmniejsz, gdy obiekt jest mały.--max-components 2— ile największych obiektów zachować. Dla jednej osoby ustaw1, dla pary2, dla całej grupy3+.
Przykład uruchomienia dla zdjęcia z drzewami:
python edge_finder.py ./fotos/mama_i_syn.jpg \
--main-area-ratio 0.025 \
--max-components 2 \
--canny-low 40 --canny-high 120 \
--threshold 135
Jeśli maska obetnie fragmenty postaci, zmniejsz --main-area-ratio lub zwiększ --max-components. Gdy liście wrócą, zrób odwrotnie. Dzięki temu końcowy obraz zawiera tylko główne sylwetki, a nie każdy listek w tle.