diff --git a/README.md b/README.md index c251ba5..d8cbbc4 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## Todo -- [x] Utiliser une webcam en entrée +- [ ] Utiliser une webcam en entrée - [x] Créer une interface avec tkinter - [x] Variabliser les tailles et couleurs via l'interface @@ -20,58 +20,29 @@ pip3 install -r requirements.txt python3 main.py ``` -... devrait afficher une interface utilisateur. +... devrait afficher ... -## Documentation Utilisateur : Paramètres OpenCV +```shell +_________ +_________ +_________ +___ ___ +___ ___ +___ ___ +``` -L'interface graphique **Yiking** permet de contrôler divers paramètres pour un traitement d'image réalisé avec OpenCV. Voici une explication de chaque paramètre et son rôle dans l'algorithme de détection. +... qui signifie : ---- +> 11. LA PAIX (TAI 泰) +> La rencontre entre le Ciel et la Terre – une combinaison rare de grâce et de force -annonce la paix, l’harmonie, la stabilité et la prospérité. Un moment de consensus promettant des résultats constructifs et prometteurs. Ces circonstances augurent une coexistence pacifique entre tout le monde. -### Paramètres OpenCV -#### 1. **maxDist** -- **Description** : Distance maximale entre les centres de deux cercles détectés. -- **Rôle** : Permet de contrôler la densité des cercles détectés. Une valeur élevée empêche la détection de cercles trop proches. -- **Conseil** : Augmentez cette valeur si trop de cercles se chevauchent. - -#### 2. **param1** -- **Description** : Seuil supérieur pour le détecteur de bords (fonction Canny). -- **Rôle** : Définit la sensibilité de la détection des bords dans l'image. Une valeur élevée capture uniquement les bords bien définis. -- **Conseil** : Utilisez une valeur basse pour détecter plus de détails, mais avec plus de bruit. - -#### 3. **param2** -- **Description** : Seuil pour le processus d'accumulation circulaire (HoughCircles). -- **Rôle** : Détermine la robustesse de la détection des cercles. Une valeur élevée garantit que seuls les cercles bien définis seront détectés. -- **Conseil** : Augmentez cette valeur pour réduire les faux positifs. - -#### 4. **minRadius** -- **Description** : Rayon minimal des cercles détectés. -- **Rôle** : Filtre les cercles dont le rayon est inférieur à cette valeur. -- **Conseil** : Utilisez une valeur basse si vous souhaitez détecter de petits cercles. - -#### 5. **maxRadius** -- **Description** : Rayon maximal des cercles détectés. -- **Rôle** : Filtre les cercles dont le rayon dépasse cette valeur. -- **Conseil** : Réglez cette valeur en fonction de la taille des cercles que vous recherchez. - -#### 6. **color1_R_min, color1_R_max, color1_V_min, color1_V_max, color1_B_min, color1_B_max** -- **Description** : Couleur en (Rouge, Vert, Bleu) avec des valeurs minimales et maximales pour le filtrage par couleur. -- **Rôle** : Définit un seuil bas et un seuil haut pour détecter uniquement les pixels correspondants à une certaine teinte. -- **Conseil** : Ajustez ces valeurs pour isoler une couleur d'intérêt. Toute teinte en dehors de cette plage sera affectée à l'autre couleur. - ---- - -### Utilisation - -- Appuyer sur le bouton `Run` pour afficher une capture. -- Utiliser les sliders de détection de forme jusqu'à obtention du résultat voulu. -- Utiliser les valeurs (R, V, B) affichées pour les boules détectées pour définir la plage de couleur d'une couleur voulue. - -## Exemple +## Fonctionnement ### Source ![](./tests/images/balls-full-small.jpg) ### Post traitement -![./tests/images/gui.png]() \ No newline at end of file +![](./tests/images/balls-full-small-final.jpg) + + diff --git a/main.py b/main.py index ffed30c..db43183 100644 --- a/main.py +++ b/main.py @@ -4,58 +4,6 @@ from process import process_frame from PIL import Image, ImageTk # Required for displaying images import cv2 # OpenCV for numpy array to image conversion -""" -Here’s a detailed prompt you can use to generate the same GUI code anew using a language model: - ---- - -**Prompt:** - -"I need a Python program to create a Tkinter-based GUI named 'Yiking'. The GUI will control parameters for an OpenCV image processing program. The program must be split into two files: - -1. **`process.py`**: Contains a `process_frame` function that takes parameters as input, performs OpenCV operations (not implemented in this request), and returns an image as a NumPy array and a result string. - -2. **`gui.py`**: Implements the GUI and integrates with `process.py`. Here are the detailed requirements: - -### GUI Details: -- **Window Title**: 'Yiking' -- **Layout**: - - **Row 1**: Two columns - - Left column: Group of sliders for controlling parameters. - - Right column: A canvas for displaying a processed image (1024x768 pixels). - - **Row 2**: Two columns - - Left column: A "Run" button. - - Right column: A text box for displaying results or error messages. -- **Widgets**: - - Sliders with corresponding min, max, and default values: - - `minDist` = (0, 500, 100) - - `param1` = (0, 500, 30) - - `param2` = (0, 400, 25) - - `minRadius` = (0, 100, 5) - - `maxRadius` = (0, 1000, 1000) - - `color1_R_min` = (0, 64, 5) - - `color1_V_min` = (0, 64, 5) - - `color1_B_min` = (0, 64, 5) - - `color1_R_min` = (0, 64, 5) - - `color1_V_min` = (0, 64, 5) - - `color1_B_min` = (0, 64, 5) - - Sliders must snap to increments of 5 and synchronize with a text entry box. - - The image canvas must resize input images to fit within 1024x768 while maintaining aspect ratio. - - A "Run" button executes the `process_frame` function with the current slider values. - - If an exception occurs in `process_frame`, it should display the error in the result text box and clear the canvas. - -### Key Features: -- Use the `Pillow` library (`PIL`) to handle image conversion and resizing. -- Catch exceptions in `run_process` to display error messages. -- Keep the GUI responsive and visually clean. - -### Output: -Please provide a fully functional `gui.py` implementation meeting these requirements. Include imports, class structure, and the `__main__` block. Do not implement the OpenCV functionality within `process.py`—assume it exists for integration purposes." - ---- - -This prompt is designed to give the LLM everything it needs to generate the desired `gui.py` code. Let me know if you'd like to adjust it further! -""" class OpenCVInterface: def __init__(self, root): self.root = root @@ -68,12 +16,12 @@ class OpenCVInterface: "param2": (0, 400, 25), "minRadius": (0, 100, 5), "maxRadius": (0, 1000, 1000), - "color1_R_min": (0, 255, 0), - "color1_R_max": (0, 255, 0), - "color1_V_min": (0, 255, 0), - "color1_V_max": (0, 255, 0), - "color1_B_min": (0, 255, 0), - "color1_B_max": (0, 255, 0), + "color1_R": (0, 64, 5), + "color1_V": (0, 64, 5), + "color1_B": (0, 64, 5), + "color2_R": (0, 64, 5), + "color2_V": (0, 64, 5), + "color2_B": (0, 64, 5), } self.variables = { @@ -118,7 +66,7 @@ class OpenCVInterface: def on_slide(value): # Round value to nearest multiple of 5 - rounded_value = round(float(value) / 2) * 2 + rounded_value = round(float(value) / 5) * 5 variable.set(int(rounded_value)) # Update the variable with the rounded value # Slider @@ -152,6 +100,7 @@ class OpenCVInterface: new_width = int(original_width * aspect_ratio) new_height = int(original_height * aspect_ratio) pil_image = pil_image.resize((new_width, new_height), Image.Resampling.LANCZOS) + tk_image = ImageTk.PhotoImage(pil_image) # Convert PIL Image to Tkinter Image # Clear canvas and display the image diff --git a/process.py b/process.py index deef6a8..f2ef7e7 100644 --- a/process.py +++ b/process.py @@ -13,35 +13,6 @@ dir_path = Path(".").absolute() TYPE_1 = "_________" TYPE_2 = "___ ___" -import cv2 - - -def capture_frame_from_webcam(): - """ - Captures a single frame from the webcam. - - Returns: - frame (numpy.ndarray): The captured frame as a NumPy array. - """ - # Open a connection to the default webcam (index 0) - cap = cv2.VideoCapture(0) - - if not cap.isOpened(): - raise Exception("Could not open webcam. Please check your webcam connection.") - - try: - # Capture a single frame - ret, frame = cap.read() - - if not ret: - raise Exception("Failed to capture frame from webcam.") - - return frame - finally: - # Release the webcam resource - cap.release() - - @dataclass class Object: @@ -64,23 +35,21 @@ def process_frame(params): # Simulate processing: for now, return a dummy image and text. # width, height = 400, 300 # image = Image.new("RGB", (width, height), - # color=(params["color1_R_min"] * 4, params["color1_V_min"] * 4, params["color1_B_min"] * 4)) + # color=(params["color1_R"] * 4, params["color1_V"] * 4, params["color1_B"] * 4)) # image_tk = ImageTk.PhotoImage(image) # # result_text = f"Processed image with params: {params}" # return image_tk, result_text (minDist, param1, param2, minRadius, maxRadius, - color1_R_min, color1_V_min, color1_B_min, color1_R_max, color1_V_max, color1_B_max) = itemgetter( + color1_R, color1_V, color1_B, color2_R, color2_V, color2_B) = itemgetter( 'minDist', 'param1', 'param2', 'minRadius', 'maxRadius', - 'color1_R_min', 'color1_V_min', 'color1_B_min', 'color1_R_max', 'color1_V_max', 'color1_B_max' + 'color1_R', 'color1_V', 'color1_B', 'color2_R', 'color2_V', 'color2_B' )(params) # 1. Acquisition de l'image - # src = dir_path.joinpath('tests/images/balls-full-small.jpg') - # raw_image = cv2.imread(str(src)) - - raw_image = capture_frame_from_webcam() + src = dir_path.joinpath('tests/images/balls-full-small.jpg') + raw_image = cv2.imread(str(src)) # 2. Boxing des objets via opencv gray = cv2.cvtColor(raw_image, cv2.COLOR_BGR2GRAY) @@ -114,7 +83,6 @@ def process_frame(params): s = np.clip(s, 0, 255) imghsv = cv2.merge([h, s, v]) boules_couleurs = [] - boules_bgr = [] for boule in boules: half_diametre = int(boule.rayon / 2) crop = imghsv[ @@ -126,18 +94,10 @@ def process_frame(params): criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 200, .1) _, labels, palette = cv2.kmeans(pixels, n_colors, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS) _, counts = np.unique(labels, return_counts=True) - (b, v, r) = palette[np.argmax(counts)] - boules_bgr.append(f"R:{int(r)} V:{int(v)} B:{int(b)}") + (b, g, r) = palette[np.argmax(counts)] / 16 - # On récupère les valeurs de R G et B qui sont à analyser - if int( - color1_R_min <= math.floor(r) <= color1_R_max - and color1_V_min <= math.floor(v) <= color1_V_max - and color1_B_min <= math.floor(b) <= color1_B_max - ): - boules_couleurs.append(TYPE_1) - else : - boules_couleurs.append(TYPE_2) + # A modulariser + boules_couleurs.append(TYPE_1 if b > 4 else TYPE_2) # 5. Calcul des distances entre chaque boule et le cochonnet selon le centre des boxs boules_distance = {} @@ -156,7 +116,5 @@ def process_frame(params): boule = boules[i] return_text += f"{boules_couleurs[i]}\n" cv2.circle(img_final, (boule.x, boule.y), boule.rayon, (0, 255, 0), 2) - cv2.putText(img_final, boules_bgr[i], (boule.x, boule.y), cv2.FONT_HERSHEY_SIMPLEX, - fontScale=0.75, color=(255, 255, 255), thickness=1, lineType=cv2.LINE_AA) - return img_final, return_text + return img_final, return_text \ No newline at end of file diff --git a/tests/images/gui.png b/tests/images/gui.png deleted file mode 100644 index 3d07234..0000000 Binary files a/tests/images/gui.png and /dev/null differ