Matlablib: Třída pro otestování metody autosize – Python – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Matlablib: Třída pro otestování metody autosize – Python – Fórum – Programujte.comMatlablib: Třída pro otestování metody autosize – Python – Fórum – Programujte.com

 

oxidián0
Grafoman
2. 5. 2024   #1
-
0
-

Zkoušel jsem napsat metodu ke třídě ColorPicker, která by umožnila provést autosize... Zatím to má fungovat tak, že pokud hnete oknem mimo obrazovku, zvětší se okno i s grafem. Tím se dosáhne zvětšení obrázků (testováno s 800x600), které jinak zůstávají poměrně malé. ImageHandler je třída, která umožní implementovat kód, aby to něco dělalo. Původně se mělo kliknout na ax1 a obrázek se měl zmenšit ale velikost grafu ax1 zůstala stejná. Myslím že teď to negunguje, ale to není podstatné.

Zdá se mi, že autosize_... nefunguje v ten správný okamžik, bylo by lépe, kdyby se provedl autosize až po kliknutí na obrázek, při změně velikosti.

Myslím že chyba je že dpi = self.ppi je asi 96 ať to dám na maximální rozlišení nebo na 800x600. Mám 24" monitor. Původně jsem měl pevně nastavenou velikost monitoru naměřený rozměr a z toho jsem zjišťoval dpi. A to fungovalo lépe. DPI bylo buď 38 nebo 96 podle toho jak jsem nastavil rozlišení. Zdá se, že subprocess vrací vždy 96, ale to dělá normálně:

$ xdpyinfo | grep -B 2 resolution
screen #0:
  dimensions:    800x600 pixels (212x159 millimeters)
  resolution:    96x96 dots per inch
user@Toshi:~$

No já si myslím, že je to dpi špatně, protože při malém rozlišení 800x600 budou dvě dpi a bude to ta menší hodnota těch cca 38

$ xdpyinfo | grep -B 2 resolution
screen #0:
  dimensions:    1920x1080 pixels (508x286 millimeters)
  resolution:    96x96 dots per inch

V podstatě mě zajímaj vaše krátké poznámky nebo upozornění na chybu v logice. Možná to nedělá vůbec co si myslím že to dělá, to já se obávám. Asi chápu proč to autoři matlablib neintegrovali, protože chtěli aby to nebylo závislé na externích příkazech jako subprocessy apod.

# Předchozí verze: skript hierarchie-problem-2.py
# Oproti staré verzi přibyl výpočet dpi a velikosti
# grafu. Zatím není jasné, zda velikost grafu půjde zvětšit
# a zbavit se nežádoucích mezer pod grafem nebo vpravo vedle
# grafu.
#
# Tento kód je připraven jako OOP
# Při dotazu na ChatGPT jsem v první verzi kladl důraz na:
# 1) převod kódu do třídy
# 2) hierarchii a strukturu jako při Objektově Orientovaném Programování
# 3) převod kódu z main() do metod a změnu obsluhy handlaru pro události klik na graf
#    jehož chyba byla v nesprávném handleru
#
# V nové verzi je třeba odladit a dokonfigurovat metodu
# autosize_horizontal_axes#
# Slidery nejsou na správném místě - je to bug. Chtěl bych
# aby tam nebyla ta velká mezera pod grafem a zbavit se i
# té mezery vedle.



import cv2
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.widgets import RangeSlider
import configparser
import subprocess # nutné pro zjištění dpi obrazovky
# import pyautogui

class ImageHandler:
    def __init__(self):
        self.original_image = None
        self.zoomed_image = None
        self.hsv_zoomed_image_copy = None
        self.mask = None
        self.masked_image = None

    def load_image(self):
        try:
            filename = self.load_filename()
        except KeyError:
            filename = ""
            self.save_filename(filename)
        print("Loading image:", filename)
        self.original_image = cv2.cvtColor(cv2.imread(filename), cv2.COLOR_BGR2RGB)
        self.zoomed_image = cv2.cvtColor(cv2.imread(filename), cv2.COLOR_BGR2RGB)
        self.hsv_zoomed_image_copy = cv2.cvtColor(self.zoomed_image, cv2.COLOR_RGB2HSV)
        self.mask = np.ones_like(self.zoomed_image[:, :, 0], dtype=np.uint8) * 255
        self.masked_image = np.copy(self.zoomed_image)

    def save_filename(self, filename):
        config = configparser.ConfigParser()
        config['DEFAULT'] = {'filename': filename}
        with open('config.cfg', 'w') as configfile:
            config.write(configfile)

    def load_filename(self):
        config = configparser.ConfigParser()
        config.read('config.cfg')
        return config['DEFAULT']['filename']

    def process_image(self, event, ax, color_picker_instance):
        new_height = int(color_picker_instance.fig_manager.window.geometry().split("+")[0].split("x")[1])
        if new_height > 50:
            color_picker_instance.window_height = new_height
        if event.inaxes == ax:
            try:
                if self.original_image is not None:
                    print("self.original_image obsahuje obrazová data")
                    if self.zoomed_image is not None:
                        image_to_resize = self.zoomed_image
                    else:
                        image_to_resize = self.original_image
                    self.zoomed_image = cv2.resize(image_to_resize, (0, 0), fx=0.5, fy=0.5)
                    image_to_resize = None
                    print("Nové rozměry zmenšeného obrázku:", self.zoomed_image.shape)
                    ax.imshow(self.zoomed_image)
                    plt.draw()
                else:
                    print("original_image neobsahuje obrazová data")
            except Exception as e:
                print(f"Chyba při zpracování obrázku: {e}")

class ColorPicker(ImageHandler):
    def __init__(self):
        super().__init__()
        self.fig = None
        self.ppi = 0
        self.window_height = None
        self.desktop_w_inches = 0 
        self.desktop_h_inches = 0
        self.ax_sizes = {'ax1': {'w': 0, 'h': 600}, 'ax2': {'w': 0, 'h': 0}}
        self.fig_manager = None
        self.cid = None  # ID události on_mouse_move
        self.mm = 0.0393701

    def on_mouse_move(self, event):        
        self.window_height = int(self.fig_manager.window.geometry().split("+")[0].split("x")[1])
        if self.window_height > 800:
            self.fig.canvas.mpl_disconnect(self.cid)

    def get_dpi_and_screen_size(self):
        xdpyinfo = subprocess.Popen(('xdpyinfo'), stdout=subprocess.PIPE)
        self.output = subprocess.check_output(('grep', '-B', '2', 'resolution'), stdin=xdpyinfo.stdout)
        xdpyinfo.wait()

        screen_width = None
        screen_height = None
        dpi = None
        for line in self.output.decode().split('\n'):
            if 'dimensions' in line:
                dimensions = line.split(':')[-1].strip().split('x')
                screen_width = int(dimensions[0])
                screen_height = int(dimensions[1].split(" ")[0])
            elif 'resolution' in line:
                resolution = line.split(':')[-1].strip().split('x')
                dpi = int(resolution[0])
        return dpi, screen_width, screen_height

    def create_figure(self, screen_width, screen_height):        
        self.ppi = self.dpi
        self.desktop_w_inches = screen_width / self.dpi
        self.desktop_h_inches = screen_height / self.dpi

        self.fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(self.desktop_w_inches, self.desktop_h_inches), dpi=self.dpi)
        self.load_image()
        plt.subplots_adjust(left=0.045, bottom=0.095, hspace=0, wspace=0.070)
        ax1.imshow(self.zoomed_image)
        ax2.imshow(self.masked_image)
        self.fig_manager = plt.get_current_fig_manager()

    def autosize_horizontal_axes(self, ax=None, reset_both=False):
        if self.ax_sizes == None:
            self.ax_sizes = {'ax1': {'w': 0, 'h': 600}, 'ax2': {'w': 0, 'h': 0}}        
        # ÚDAJE O VELIKOSTI CANVASU (JE MENŠÍ NEŽ PLOCHA DESKTOP)
        canvas_width_pixels, canvas_height_pixels = plt.gcf().canvas.get_width_height()
        canvas_width_inches = canvas_width_pixels * self.ppi
        canvas_height_inches = canvas_height_pixels * self.ppi
        canvas_width_inches = plt.rcParams['figure.figsize'][0]
        canvas_height_inches = plt.rcParams['figure.figsize'][1]
        # ÚDAJE O VELIKOSTI PLOCHY DESKTOP
        # screen_width, screen_height = pyautogui.size()
        print(self.desktop_w_inches)
        print(self.desktop_h_inches)

        # get dimention values
        if not ax: ax=plt.gca()
        xmin, ymin, xmax, ymax = ax.bbox.bounds
        bb = ax.get_window_extent().bounds
        inch_per_px = 1 / self.ppi
        w=ax.bbox.width/self.ppi
        h=ax.bbox.height/self.ppi
        if self.window_height != None:
            client_height = self.window_height
            client_height_inches = self.window_height / self.ppi
        else:
            client_height = self.desktop_h_inches*self.ppi
        # první volání
        if self.ax_sizes['ax1']['w'] == 0:
            self.ax_sizes['ax1']['w']=w
            self.ax_sizes['ax1']['h']=h
        else: # druhé volání
            if self.ax_sizes['ax2']['w'] == 0:
                self.ax_sizes['ax2']['w']=w
                self.ax_sizes['ax2']['h']=h
                space_horizontal = abs(self.desktop_w_inches-self.ax_sizes['ax1']['w']-self.ax_sizes['ax2']['w'])
                # This is calculated from one line of axis of two columns
                max_vs=max(self.ax_sizes['ax1']['h'],self.ax_sizes['ax2']['h'])
                space_vertical = abs(self.desktop_h_inches-max_vs)
                # Estimation of the space for enlargement
                pdl2=space_horizontal/2
                pdb2=space_vertical/2
                h_ratio = self.ax_sizes['ax1']['w']/pdl2
                v_ratio = self.ax_sizes['ax1']['h']/pdb2
                enlarge_w1 = (self.ax_sizes['ax1']['w']+v_ratio)
                enlarge_h1 = self.ax_sizes['ax1']['h']+h_ratio
                enlarge_w2 = (self.ax_sizes['ax2']['w']+v_ratio)
                enlarge_h2 = self.ax_sizes['ax2']['h']+h_ratio
                # ww=round(w*self.ppi)
                # hh=round(h*self.ppi)
                # figw = float(w)/(r-l)
                # figh = float(h)/(t-b)
                ax.figure.get_axes()[0].figure.set_size_inches(enlarge_w1, enlarge_h1)
                ax.figure.set_size_inches(enlarge_w2, enlarge_h2)
                self.ax_sizes['ax1']['w']=0
                self.ax_sizes['ax1']['h']=0
                if reset_both == True:
                    self.ax_sizes['ax2']['w']=0
                    self.ax_sizes['ax2']['h']=0

    def main(self):
        self.dpi, screen_width, screen_height = self.get_dpi_and_screen_size()
        self.create_figure(screen_width, screen_height)
        # Nastavení velikosti os podle slidů
        self.autosize_horizontal_axes(self.fig.axes[0])
        self.autosize_horizontal_axes(self.fig.axes[1])

        rslider_ax = self.fig.add_axes([0.20, 0.05, 0.60, 0.03])
        rslider = RangeSlider(rslider_ax, "H", 0, 255, valinit=(0, 255))
        gslider_ax = self.fig.add_axes([0.20, 0.01, 0.60, 0.03])
        gslider = RangeSlider(gslider_ax, "S", 0, 255, valinit=(0, 255))
        bslider_ax = self.fig.add_axes([0.20, -0.03, 0.60, 0.03])
        bslider = RangeSlider(bslider_ax, "V", 0, 255, valinit=(0, 255))

        self.fig.canvas.mpl_connect('button_press_event', lambda event: self.process_image(event, ax1, self))
        self.cid = self.fig.canvas.mpl_connect('motion_notify_event', self.on_mouse_move)

        plt.show(block=False)
        runme = True
        while plt.fignum_exists(self.fig.number):
            w = plt.get_current_fig_manager().window
            subprocess.run(["xdotool", "windowactivate", "--name", "'Figure 1'", "windowmove", "75", "1"])
            subprocess.run(["xdotool", "windowactivate", "--name", "'Figure 1'", "windowmove", "1", "1"])
            # Získání výšky titulní lišty okna
            runme = False
            plt.pause(4000000)

if __name__ == "__main__":
    picker = ColorPicker()
    picker.main()
Nahlásit jako SPAM
IP: 78.45.192.–
oxidián0
Grafoman
3. 5. 2024   #2
-
0
-

Tak už vím co dělám špatně. Já musím především změnit velikost ve figsize, a potom v
set_size_inches
protože to je uvedené v tom výpisu:

$ xdpyinfo | grep -B 2 resolution
screen #0:
  dimensions:    1920x1080 pixels (508x286 millimeters)
  resolution:    96x96 dots per inch
user@Toshi:~$ xdpyinfo | grep -B 2 resolution
screen #0:
  dimensions:    800x600 pixels (212x159 millimeters)
  resolution:    96x96 dots per inch

je důležité rozlišovat mezi různými typy dpi. Zde je přesnější vysvětlení:

DPI obsahu souboru s fotografií: Toto je měřítko, které určuje, kolik bodů (neboli pixelů) je obsaženo na každý palec v digitálním obrazovém souboru. Tato hodnota je pevná a nezmění se, pokud nedojde k úpravě samotného souboru.

DPI monitoru: Toto je fyzická specifikace monitoru, která určuje, kolik pixelů se vejde na každý palec obrazovky. Tato hodnota je stálá a nezávisí na rozlišení, které je nastaveno v operačním systému.

DPI nastavení monitoru v systému: Toto je nastavení v operačním systému, které ovlivňuje, jak jsou obsah a aplikace zobrazeny na obrazovce. Změna tohoto nastavení může způsobit, že obsah bude vypadat větší nebo menší, ale nezmění fyzické DPI monitoru.

Parametr dpi v matplotlibu určuje hustotu pixelů grafu, který generujete. Tato hodnota dpi ovlivňuje kvalitu obrazu grafu při jeho exportu do souboru, jako je PNG nebo PDF. Vyšší dpi znamená vyšší rozlišení a ostřejší obraz při tisku nebo zobrazení na zařízeních s vysokým rozlišením.

Pokud jde o zobrazení grafu na monitoru při interaktivní práci s matplotlibem, dpi nemá přímý vliv na velikost okna grafu, jak jsem se mylně domníval. Velikost okna je určena parametrem figsize, který udává velikost grafu v palcích. Matplotlib pak používá hodnotu dpi k výpočtu počtu pixelů, které mají být použity pro vykreslení grafu v dané velikosti okna.

Zde je příklad, jak dpi a figsize spolupracují:

Pokud máte figsize=(6, 4) a dpi=100, matplotlib vykreslí okno o velikosti 600x400 pixelů.
Pokud změníte dpi na 200, ale ponecháte figsize stejné, okno zůstane 600x400 pixelů, ale graf bude vykreslen s dvojnásobným počtem pixelů, což znamená, že bude vypadat ostřejší, pokud ho zvětšíte nebo vytisknete.

Takže pokud máte monitor s rozlišením 96 dpi a zvýšíte dpi grafu nad tuto hodnotu, nezvětší se tím velikost okna grafu na monitoru. Změní se pouze kvalita obrazu, která se projeví, pokud graf uložíte a vyexportujete jako soubor s vyšším rozlišením.

Ohledně renderování a DPI:

Snížení hodnoty DPI (dots per inch) může vést k rychlejšímu vykreslování grafů v matplotlib, protože se generuje méně pixelů. Standardní hodnota DPI pro zobrazení na obrazovce je obvykle 96 DPI. Pokud nastavíte nižší DPI, jako je například 38, může to způsobit, že obrázek bude mít nižší kvalitu a bude méně detailní, ale skutečně se vykreslí rychleji.

Pro vykreslování fotografií je však důležité najít rovnováhu mezi kvalitou a rychlostí vykreslování. Pokud je pro vás prioritou rychlost, můžete experimentovat s nižšími hodnotami DPI, ale mějte na paměti, že to může negativně ovlivnit kvalitu výsledného obrázku.

V případě, že potřebujete zachovat určitou kvalitu obrázku, může být lepší optimalizovat jiné aspekty kódu nebo využít efektivnější metody vykreslování, místo snižování DPI. Například můžete zvážit použití vektorových formátů pro grafy, které mohou být škálovány bez ztráty kvality, nebo optimalizovat velikost datových bodů, které vykreslujete.

Přikládám ilustrační obrázek:

Připojen obrázek.

Nahlásit jako SPAM
IP: 62.245.117.–
Zjistit počet nových příspěvků

Přidej příspěvek

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 2 hosté

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý