diff --git a/README.md b/README.md index d8cbbc4..fcd5a89 100644 --- a/README.md +++ b/README.md @@ -20,29 +20,58 @@ pip3 install -r requirements.txt python3 main.py ``` -... devrait afficher ... +... devrait afficher une interface utilisateur. -```shell -_________ -_________ -_________ -___ ___ -___ ___ -___ ___ -``` +## Documentation Utilisateur : Paramètres OpenCV -... qui signifie : +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. -> 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 -## Fonctionnement +#### 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étermaxe 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. **maxRadius** +- **Description** : Rayon maximal 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_max, color1_V_max, color1_B_max, color1_R_max, color1_V_max, 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 ### Source ![](./tests/images/balls-full-small.jpg) ### Post traitement -![](./tests/images/balls-full-small-final.jpg) - - +![./tests/images/gui.png]() \ No newline at end of file diff --git a/main.py b/main.py index db43183..ffed30c 100644 --- a/main.py +++ b/main.py @@ -4,6 +4,58 @@ 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 @@ -16,12 +68,12 @@ class OpenCVInterface: "param2": (0, 400, 25), "minRadius": (0, 100, 5), "maxRadius": (0, 1000, 1000), - "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), + "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), } self.variables = { @@ -66,7 +118,7 @@ class OpenCVInterface: def on_slide(value): # Round value to nearest multiple of 5 - rounded_value = round(float(value) / 5) * 5 + rounded_value = round(float(value) / 2) * 2 variable.set(int(rounded_value)) # Update the variable with the rounded value # Slider @@ -100,7 +152,6 @@ 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 f2ef7e7..2517505 100644 --- a/process.py +++ b/process.py @@ -35,16 +35,16 @@ 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"] * 4, params["color1_V"] * 4, params["color1_B"] * 4)) + # color=(params["color1_R_min"] * 4, params["color1_V_min"] * 4, params["color1_B_min"] * 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, color1_V, color1_B, color2_R, color2_V, color2_B) = itemgetter( + color1_R_min, color1_V_min, color1_B_min, color1_R_max, color1_V_max, color1_B_max) = itemgetter( 'minDist', 'param1', 'param2', 'minRadius', 'maxRadius', - 'color1_R', 'color1_V', 'color1_B', 'color2_R', 'color2_V', 'color2_B' + 'color1_R_min', 'color1_V_min', 'color1_B_min', 'color1_R_max', 'color1_V_max', 'color1_B_max' )(params) # 1. Acquisition de l'image @@ -83,6 +83,7 @@ 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[ @@ -94,10 +95,18 @@ 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, g, r) = palette[np.argmax(counts)] / 16 + (b, v, r) = palette[np.argmax(counts)] + boules_bgr.append(f"R:{int(r)} V:{int(v)} B:{int(b)}") - # A modulariser - boules_couleurs.append(TYPE_1 if b > 4 else TYPE_2) + # 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) # 5. Calcul des distances entre chaque boule et le cochonnet selon le centre des boxs boules_distance = {} @@ -116,5 +125,7 @@ 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 \ No newline at end of file + return img_final, return_text diff --git a/tests/images/gui.png b/tests/images/gui.png new file mode 100644 index 0000000..3d07234 Binary files /dev/null and b/tests/images/gui.png differ