Пятница, Ноябрь 14, 2025

Python palm oil

Python скрипт для пальмового жира. Версия 1

# -*- coding: cp1251 -*-

import os
import cv2
import numpy as np
from tkinter import (
    Tk, Button, Label, Frame, filedialog, messagebox,
    Toplevel, Scale, HORIZONTAL
)
from PIL import Image, ImageTk

# —————- resample compatibility —————-
try:
    RESAMPLE = Image.Resampling.LANCZOS
except AttributeError:
    RESAMPLE = Image.LANCZOS

# —————- Global calibrated state —————-
calibrated_lower = None
calibrated_upper = None

current_image = None
current_image_path = None

# —————- Predefined HSV ranges —————-
STRICT_RANGE  = (np.array([5, 120, 120]),  np.array([25, 255, 255]))
SOFT_RANGE    = (np.array([0, 40, 40]),    np.array([35, 255, 255]))
NUCLEAR_RANGE = (np.array([8, 150, 140]),  np.array([18, 255, 255]))

# —————- Helpers —————-
def cv2_to_tk(img_bgr, max_size=(520, 520)):
    rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
    im = Image.fromarray(rgb)
    im.thumbnail(max_size, RESAMPLE)
    return ImageTk.PhotoImage(im)

def mask_to_tk(mask, max_size=(520, 520)):
    pil = Image.fromarray(mask.astype(np.uint8))
    pil = pil.convert(”RGB”)
    pil.thumbnail(max_size, RESAMPLE)
    return ImageTk.PhotoImage(pil)

def detect_by_hsv(img_bgr, lower, upper):
    hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
    mask = cv2.inRange(hsv, lower, upper)

    # morphology cleanup
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
    mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=1)
    mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=1)

    percent = (np.count_nonzero(mask) / mask.size) * 100.0
    return percent, mask

# —————- HSV Calibrator —————-
class HSVCalibrator:
    def __init__(self, parent, bgr_image):
        self.parent = parent
        self.img = bgr_image

        self.win = Toplevel(parent)
        self.win.title(”HSV Калибровка”)

        # sliders
        self.h_min = Scale(self.win, label=”H min”, from_=0, to=179, orient=HORIZONTAL, command=self.update)
        self.h_min.set(0);    self.h_min.pack(fill=”x”)
        self.h_max = Scale(self.win, label=”H max”, from_=0, to=179, orient=HORIZONTAL, command=self.update)
        self.h_max.set(179);  self.h_max.pack(fill=”x”)

        self.s_min = Scale(self.win, label=”S min”, from_=0, to=255, orient=HORIZONTAL, command=self.update)
        self.s_min.set(0);    self.s_min.pack(fill=”x”)
        self.s_max = Scale(self.win, label=”S max”, from_=0, to=255, orient=HORIZONTAL, command=self.update)
        self.s_max.set(255);  self.s_max.pack(fill=”x”)

        self.v_min = Scale(self.win, label=”V min”, from_=0, to=255, orient=HORIZONTAL, command=self.update)
        self.v_min.set(0);    self.v_min.pack(fill=”x”)
        self.v_max = Scale(self.win, label=”V max”, from_=0, to=255, orient=HORIZONTAL, command=self.update)
        self.v_max.set(255);  self.v_max.pack(fill=”x”)

        # preview
        self.preview = Label(self.win)
        self.preview.pack(pady=8)

        self.update(None)

    def update(self, event):
        global calibrated_lower, calibrated_upper

        lower = np.array([self.h_min.get(), self.s_min.get(), self.v_min.get()], dtype=np.uint8)
        upper = np.array([self.h_max.get(), self.s_max.get(), self.v_max.get()], dtype=np.uint8)

        calibrated_lower = lower
        calibrated_upper = upper

        # preview on downscaled image
        img_small = cv2.resize(self.img, (600, 600), interpolation=cv2.INTER_AREA) 
            if max(self.img.shape[:2]) > 600 else self.img

        _, mask = detect_by_hsv(img_small, lower, upper)
        tk = mask_to_tk(mask)
        self.preview.configure(image=tk)
        self.preview.image = tk

# —————- Main GUI —————-
class PalmApp:
    def __init__(self, root):
        self.root = root
        root.title(”Palm Detector — Triple + Calibrated”)
        root.geometry(”1200×760”)

        ctrl = Frame(root)
        ctrl.pack(side=”top”, pady=8)

        Button(ctrl, text=”Открыть изображение”, width=20, command=self.open_file).pack(side=”left”, padx=5)
        Button(ctrl, text=”Строгий режим”,       width=20, command=self.run_strict).pack(side=”left”, padx=5)
        Button(ctrl, text=”Мягкий режим”,        width=20, command=self.run_soft).pack(side=”left”, padx=5)
        Button(ctrl, text=”Ядрёная пальма”,      width=20, command=self.run_nuclear).pack(side=”left”, padx=5)

        # ? Новая кнопка
        Button(ctrl, text=”Калиброванный режим”, width=20, command=self.run_calibrated).pack(side=”left”, padx=5)

        Button(ctrl, text=”Калибровка HSV”,      width=20, command=self.open_calibrator).pack(side=”left”, padx=5)

        # display
        disp = Frame(root)
        disp.pack(fill=”both”, expand=True, padx=6, pady=6)

        self.left_label = Label(disp)
        self.left_label.pack(side=”left”, padx=10, pady=10)

        self.right_label = Label(disp)
        self.right_label.pack(side=”right”, padx=10, pady=10)

        self.img = None
        self.last_mask = None

    def open_file(self):
        global current_image, current_image_path
        f = filedialog.askopenfilename(
            title=”Выберите изображение”,
            filetypes=[
                (”Images”, ”*.jpg *.jpeg *.png *.bmp *.tif *.tiff *.webp”),
                (”All files”, ”*.*”)
            ]
        )
        if not f:
            return

        img = cv2.imread(f)
        if img is None:
            messagebox.showerror(”Ошибка”, ”Невозможно открыть файл”)
            return

        current_image = img
        current_image_path = f
        self.img = img

        tk = cv2_to_tk(img)
        self.left_label.configure(image=tk)
        self.left_label.image = tk

        self.right_label.configure(image=None)
        self.right_label.image = None

        self.last_mask = None

    def show_result(self, lower, upper, title):
        if self.img is None:
            messagebox.showwarning(”Нет изображения”, ”Сначала откройте картинку”)
            return

        percent, mask = detect_by_hsv(self.img, lower, upper)

        # highlight
        overlay = self.img.copy()
        overlay[mask > 0] = (0, 140, 255)
        highlighted = cv2.addWeighted(overlay, 0.6, self.img, 0.4, 0)

        tk = cv2_to_tk(highlighted)
        self.right_label.configure(image=tk)
        self.right_label.image = tk

        self.last_mask = mask
        messagebox.showinfo(title, f”Пальма: {percent:.2f}%”)

    def run_strict(self):
        self.show_result(*STRICT_RANGE, ”Строгий режим”)

    def run_soft(self):
        self.show_result(*SOFT_RANGE, ”Мягкий режим”)

    def run_nuclear(self):
        self.show_result(*NUCLEAR_RANGE, ”Ядрёная пальма”)

    def run_calibrated(self):
        global calibrated_lower, calibrated_upper
        if calibrated_lower is None or calibrated_upper is None:
            messagebox.showwarning(”Нет данных”, ”Сначала откройте калибровку и подвиньте ползунки.”)
            return
        self.show_result(calibrated_lower, calibrated_upper, ”Калиброванный режим”)

    def open_calibrator(self):
        global current_image
        if current_image is None:
            messagebox.showwarning(”Нет изображения”, ”Сначала откройте фотографию”)
            return
        HSVCalibrator(self.root, current_image)

# —————- Run —————-
def main():
    root = Tk()
    PalmApp(root)
    root.mainloop()

if __name__ == ”__main__”:
    main()
programma.jpg

Версия 2

# -*- coding: cp1251 -*-

import cv2
import numpy as np
import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image, ImageTk
import os

# ————- Параметры (строгий режим) ————-
# Эталонный цвет (центр) в RGB, вычисленный по образцам
palm_centroid_rgb = np.array([251.23151523, 96.63262181, 13.64952684], dtype=np.float32)

# Порог расстояния (в RGB-евклидовом пространстве). Меньше = строже.
threshold = 40.0

# ————- GUI ————-
root = tk.Tk()
root.title(”Palm Color Detector — strict”)
root.geometry(”1150×760”)

panel_original = tk.Label(root)
panel_original.pack(side=”left”, padx=8, pady=8)

panel_result = tk.Label(root)
panel_result.pack(side=”right”, padx=8, pady=8)

def cv2_to_tk(img, max_size=(520, 700)):
    ”"”Convert BGR OpenCV image to Tk PhotoImage, resized to max_size preserving aspect.”"”
    rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    im = Image.fromarray(rgb)
    # масштабируем аккуратно, сохраняя пропорции
    im.thumbnail(max_size, Image.ANTIALIAS)
    return ImageTk.PhotoImage(im)

def detect_palm_strict(image_path):
    img = cv2.imread(image_path)
    if img is None:
        messagebox.showerror(”Ошибка”, ”Не удалось открыть изображение.”)
        return

    # BGR -> RGB
    rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB).astype(np.float32)

    # вычисляем расстояние в RGB (евклидово) до эталона
    # reshape для векторизованного вычисления
    h, w = rgb.shape[:2]
    flat = rgb.reshape(-1, 3)
    diffs = flat - palm_centroid_rgb[np.newaxis, :]
    dists = np.linalg.norm(diffs, axis=1)

    mask_flat = (dists <= threshold).astype(np.uint8) * 255
    mask = mask_flat.reshape(h, w).astype(np.uint8)

    # морфология (убираем шум)
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
    mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=1)
    mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=1)

    # подсветка найденных пикселей
    overlay = img.copy()
    overlay[mask > 0] = (0, 140, 255)  # BGR highlight (оранжево-красный)
    highlighted = cv2.addWeighted(overlay, 0.6, img, 0.4, 0)

    # процент (по всем пикселям изображения)
    orange_pixels = int(cv2.countNonZero(mask))
    total = h * w
    percent = orange_pixels / total * 100.0

    # создаём версию на белом фоне (объект на белом)
    white_bg = np.ones_like(img, dtype=np.uint8) * 255
    object_only = np.where(mask[:,:,None] > 0, img, white_bg)

    # сохраняем результаты рядом с исходной картинкой
    out_dir = os.path.dirname(image_path) if os.path.dirname(image_path) != ”" else ”.”
    base = os.path.splitext(os.path.basename(image_path))[0]
    mask_name = os.path.join(out_dir, f”{base}_mask_strict.png”)
    highlighted_name = os.path.join(out_dir, f”{base}_palm_strict.jpg”)
    white_name = os.path.join(out_dir, f”{base}_on_white_strict.jpg”)

    cv2.imwrite(mask_name, mask)
    cv2.imwrite(highlighted_name, highlighted)
    cv2.imwrite(white_name, object_only)

    # показать в GUI
    orig_tk = cv2_to_tk(img)
    res_tk = cv2_to_tk(highlighted)

    panel_original.configure(image=orig_tk)
    panel_original.image = orig_tk

    panel_result.configure(image=res_tk)
    panel_result.image = res_tk

    messagebox.showinfo(”Готово”, f”Пальмового цвета: {percent:.2f}%nn”
                         f”Сохранено:n{mask_name}n{highlighted_name}n{white_name}”)

def open_file():
    filepath = filedialog.askopenfilename(
        title=”Выберите изображение”,
        filetypes=[(”Images”, ”*.jpg *.jpeg *.png *.bmp”)]
    )
    if filepath:
        detect_palm_strict(filepath)

# — Кнопки —
frm = tk.Frame(root)
frm.pack(side=”top”, fill=”x”, pady=6)

btn_open = tk.Button(frm, text=”Открыть изображение”, font=(”Arial”, 12), command=open_file)
btn_open.pack(side=”left”, padx=8)

lbl_info = tk.Label(frm, text=f”Строгий режим — порог = {threshold}”, font=(”Arial”, 11))
lbl_info.pack(side=”left”, padx=12)

root.mainloop()
python -m PyInstaller –onefile –windowed ^
  –hidden-import=cv2 ^
  –hidden-import=PIL ^
  –hidden-import=PIL._tkinter_finder ^
  –hidden-import=PIL.ImageTk ^
  путь до файла.py
Free Web Hosting