« 1 2 3 4 »
Autor Zpráva
1Pupik1989
Profil
Ještě jsem to stáhnul na 0.435 sekundy, ale víc to nejde. Nejdůležitější je nejdřív načíst barvy z pixelů a uložit si je do pole. Další důležitá věc je používat jen 1D pole. Pak už mám jen takové blbosti jako abs a min v binární soustavě.
Oxidián
Profil *
Mě by zajímalo jestli to druhé pravidlo bude platit i u C/C++. Nad tím jsem už uvažoval jestli by bylo efektivní dělat to v 2D poli. Myslím, že pole má jen jeden ukazatel ať je jednorozměrné nebo dvourozměrné. Takže teoreticky program si pamatuje jen ten první index, ten druhý už bude odpočítávat znova. A u větších obrázků jako 1024 nebo 2048 by ten rozdíl byl znát.
1Pupik1989
Profil
Tak můžeš si to načtené pole uložit do proměnné. V PHP to ale ztrácí, protože vznikne další proměnná navíc. Je to v řádu milisekund, ale při větších obrazech to bude znát. Jenže tam už je znát všechno. Ještě se vyplatí spočítat kolik je v matici nul. Pokud víc jak polovina, tak se vyplatí je přeskakovat. Třeba typický příklad je ta matice 9x9 na motion blur. 3x3 matice se zase vyplatí násobit natvrdo a nepoužívat cyklus. 9 hodnot si uložíš do proměnné až je nemusíš dokola načítat.

Přemýšlím jak to celé nacpat do jedné funkce, abych tam to samé neměl 3x a rychlost se nezměnila.
Oxidián
Profil *
1Pupik1989:
Tak já si hlavně myslím že pro php to nemá moc smysl řešit ty detaily, je to zkrátka moc pomalé a je výhodnější to napsat v C/C++. 5x5 i 6x6 stále není moc napsat to natvrdo. Ale to násobení je třeba psát pro každou funkci nebo jen pro jednu funkci? Já se k tomu tento týden nedostanu, snad příští.
1Pupik1989
Profil
Pokud to násobení chceš natvrdo, tak by násobení muselo být pro každou matici zvlášť. Vyplatí se ale jen na 3x3 matici, která je nejčastější pro kernel. Zbytek je nejjednošší řešit cykly, jinak se v tom nedá vyznat. Přemýšlím jestli by javascript a canvas nebyly rychlejší. Nejspíš určitě a server by si odfrknul.

Momentálně jsem to ještě stáhnul. Takže při obrázku 320 x 240 pixelů se filter sharpen aplikuje za 0.3587338924408.
Při rozlišení 640 x 360 se aplikuje za 1.0789358615875.

Větší už pak dělím na segmenty, abych nepřekročil limit paměti.

Ukázka sharpen filtru.
$filter = new Filter(Array(
  -1, -1, -1,
  -1,  9, -1,
  -1, -1, -1
),3,3); 
Oxidián
Profil *
Dělíš na segmenty. Myslíš dělit třeba na 4 obrázky místo jednoho? Tam je problém při zpracování okrajů. Třeba co se týče C/C++ chtěl bych to udělat tak, že uživatel zdá regulární výraz, které soubory chce zpracovat. Takže může ty soubory už mít nakouskované a pak jen zdá regex, abych věděl, na které soubory to mám aplikovat a pak je spojit. Přitom bych teda měl počítat s možností načíst nějaké pixely z jiného souboru, než který momentálně zpracovávám, protože se to na okrajích překrývá. Ale vidím to jako projekt na delší dobu, protože v C/C++ to nejde tak snadno jako v PHP.
1Pupik1989
Profil
Ono to jde rozdělit, ale nedají ukládat všechny barvy pixelů. Nechci měnit nastavení php. Takže bloky nakouskuju podle poměru na největší bloky, co se vejdou do 76800 hodnot a pak postupně filtruji jeden blok po druhém. K velikosti bloku přidávám na každou stranu půlku velikosti matice právě kvůli okrajům. Tím pádem ale načítám některé pixely více jak jednou a to chci nějak eliminovat.
Oxidián
Profil *
Nevím jak konkrétně to dělíš ba bloky, ale ještě mě napadlo, že to nemusí být nutně čtverce, i když já bych to tak chtěl udělat. Napadlo mě, že když místo čtverců budou použity pouze bloky o velikosti výšky původního obrazu, tak tím eliminujeme ten překryv u vodorovných hran. Tedy například obrázek o velikosti 1000x1000 je možné rozdělit na bloky o rozměrech 10x1000 o počtu 100 obrazů.
1Pupik1989
Profil
No vymyšlené to mám jednoduše. Mějme obrázek 1000 x 1000 pixelů pro lepší počítání. Rozdělím ho na bloky 100 x 100 pixelů. Matice kernelu bude mít 5 x 5. Načtu první blok a aplikuji matici. Teď mám ale okraje nekompletní, protože nemají ještě výslednou barvu. To nevadí. Normálně je vykreslím do obrázku. Přejdu na další blok. Opět na něj aplikuji matici. Jenže tentokrát použiji ještě jeden cyklus a budu násobit ještě pravou stranu předchozího bloku. Čili teď prvnímu bloku chybí jen horní, dolní a levá strana. Postupně budu bloky projíždět dál, až narazím na konec řádku (X: 900, Y:0). Opět znásobím maticí. Tentokrát ale vezmu pravou stranu, znásobím s maticí a přičtu je k levé straně prvního bloku. Takže chybí už jen horní a dolní strana u prvního bloku. A tak pojedu dál, až nakonec bude vynásobeno všechno.

Je to ale zbytečně náročné. Napadlo mě, že k velikosti bloků bych ještě přičetl velikost matice, abych měl nějakou paměťovou rezervu a každému bloku bych nekompletní pixely ukládal do pole zvlášť. Pak při dalším průchodu bych je znásobil, zapsal do obrázku a pole smazal. Zkusím jak to bude vypadat v praxi. Třeba mě nakonec napadne úplně něco jiného.

Zatím jen zrychluji co se dá.
Oxidián
Profil *
Takže projíždíš zbytečně 4 strany místo dvou. Když bys obrázek rozdělil na svislé pruhy, tak nebudeš znova projíždět horní a dolní okraj. Ale ono to možná vyjde nastejno, protože vlastně těch pruhů budeš mít více než když to dělíš na čtverce. Protože chceš-li zachovat stejně velkou plochu, musíš pruh zužit, takže je to skoro to samý jen jinak udělaný.
1Pupik1989
Profil
Zatím to mám takto, to jsou ty okraje jak jsem psal. Rozlišení 640 x 360 pixelů. Bloky mám 304 x 171 pixelů



Nicméně tohle už mám pojištěné. Když mám blok o velikosti 100 x 100 pixelů a matici 3x3, tak vykreslím jen 98 x 98 s odsazením 1 x 1 od levého horního rohu.
Ve finále zjistím na jakou stranu je obrázek větší a pak to proložím těmi pruhy, jak píšeš.

//edit:
Tak koukám, že vynalézám kolo. www.php.net/manual/en/function.imageconvolution.php

//edit2:

Tak už jsem to upravil. Použil jsem akorát jiný filtr na druhém obrázku.

Oxidián
Profil *
A je ten filtr rychlejší než ten tvůj skript? Mám pocit, že na ten filtr v php jsem už taky narazil a zapomněl na to. Ale já to stejně budu dělat v C++.
http://rosettacode.org/wiki/Image_convolution
1Pupik1989
Profil
Otestuji jestli je rychlejší. Každopádně já to nemám limitované na 3x3 matici.

Já si to v klidu napíšu v PHP. Převod do C++ mi už tolik práce nedá. Jsou to jen 2 objekty. Možná, že bych na to použil OpenGL a aplikaci filtru řešil v shaderu.

K tomu odkazu. Já to našel přímo na Wikipedii. Pseudo kód stačí.

//edit: Tak imageconvolution je mnohonásobně rychlejší.
Oxidián
Profil *
1Pupik1989:
A ty umíš používat OpenGL, to jako že by to místo CPU vypočítala grafická jednotka?
1Pupik1989
Profil
Ano, umím používat OpenGL v Javě, C++ a v javascriptu WebGL. Právě ve WebGL jsem to zkoušel a je to řádově několikrát rychlejší, než pouze softwarový výpočet.
Oxidián
Profil *
No to by mě zajímalo jak se taková věc dělá, to by bylo dobré znát - ne že bych teď měl čas to studovat, ale kdybys mi třeba ukázal jak na to tak bych to ocenil (nespěchá).
1Pupik1989
Profil
Tak příklady shaderů: www.ozone3d.net/tutorials/image_filtering.php

OpenGL už se budeš muset naučit z tutoriálů. Pokud ale C++ znáš, tak to není problém. Pokud neznáš, tak si přečti nějaký návod. Zase nic extra složitého to není. Pokud umíš jakýkoliv jazyk na nějaké úrovni včetně OOP, tak nebudeš mít problém.
Oxidián
Profil *
1Pupik1989:
Dík za link, určitě se podívám až na to bude čas
1Pupik1989
Profil
Klidně bych se nebál ani Javy, pokud to bude hardwarově akcelerované. Pro co to ve finále bude?
Oxidián
Profil *
Úprava textur. Potřebuju aplikovat některé filtry, hlavně se bude hodit rozmazávání, zaostřování, hledání okrajů, rozšíření nebo zúžení plochy.
1Pupik1989
Profil
Textury jako herní textury? V reálném čase? U hry bych to asi řešil v shaderu, kde bych si napsal nějakou funkci na násobení.

Pokud se to bude provádět jen jednou a textury se poté uloží do souboru, tak bych použil nějaký hotový program.

Filtry které píšeš mají 3x3 matici, pokud nechceš ze zdroje brát více pixelů.
Oxidián
Profil *
Textury do hry, ale ne v reálném čase. Vždycky je lepší si napsat program na míru.
1Pupik1989
Profil
Tak jsem našel ještě příklad bluru. Je tam krásně vidět, jak se to ve fragment shaderu řeší.

www.gamerendering.com/2008/10/11/gaussian-blur-filter-shader/

Já jsem zjistil, že to přepíši jako filtr pro PNG parser. Takže k tomu nepotřebuji PHP GD ani Canvas v JS.
Oxidián
Profil *
Určitě se to bude hodit až bude správný čas. Ještě jsem uvažoval o tom že by uživatel mohl mít nějaké kritéria pro vykreslování např. toho filtru. Dejme tomu, že obrázek má 6 barev a uživatel chce rozblurovat jednu konkrétní barvu, nikoliv celý obrázek. Tak by mohl zadat pro jaké barvy to má či nemá platit. To o co jde je vlastně porovnávat gradient dvou barev. Nejjednodušším příkladem je B/W maska. Ale stejné pravidlo může platit mezi jakoukoliv barvou. Nejdříve by bylo třeba zjistit jak velké množství konkrétní barvy tam je obsaženo (dá se zjistit z odstínu). Tzn. máš třeba nějaký odstín cyanu, chceš ale porovnávat cyan s oranžovou. Detekuješ tedy kolik dotyčný pixel má dané barvy v procentech. Když si to představíš, zjednodušeně jako přechod mezi černou a bílou, tak tato hodnota ti jasně řekne jak moc by daný efekt měl být ovlivněn. Nastavím tedy, že ovlivnit chci jen přechod mezi černou a bílou (nebo cyanem a oranžovou), tedy to co je šedé nebo-li to co je v určitém intrvalu hodnot dvou odstínů. Ten gradient vlastně zachycuje vzdálenost dvou barev. Mezi černou a bílou máš, šedé odstíny. A díky tomu se dají například zjistit okraje. Např. okraj černé je to co má hodnotu světla menší než 100% ale větší než 90%. A tak teda můžeš filtr aplikovat bez toho aniž bys použil filtr okrajů. Samozřejmě, že pokud tě zajímá jiná barva na nejde jen o dvě barvy, tak by těch podmínek muselo být více. Ale určitě by se s tím dalo dělat hodně věcí.
1Pupik1989
Profil
Tak pokud by si chtěl filtrovat jen rozsah barev, tak bych nejdřív vybral jen správné pixely a pak je v cyklu projel. Nebo druhá možnost je aplikovat filtr rovnou. U druhé možnosti by jako parametr funkce mohla být funkce, kterou by si uživatel mohl sám definovat. V C++ ten rozdíl funkce nebude tak extrémní oproti PHP. Vzdálenost barvy od jiné barvy už není tak složitý.
Oxidián
Profil *
No v podstatě, to je jedno a to samé. Ale ještě je tu druhá možnost a to zadat podmínky pro výstup. Pokud by např. výstupem měla být bílá, ale ty chceš ve výstupu ovlivnit jen světlé odstíny v rozsahu 5-10%.

A jinak jsem si povzdechl, škoda, že neexistuje v obrazových souborech header, který by bylo možno přečíst a vyhodnotit hned na začátku. Určité statistické informace o barvách by tam mohli být, které by urychlily vyhledávání konkrétních barev. Program, který obraz vytváří by mohl vyhodnotit, které barvy se nejčastěji v obraze vyskytují a do headeru by zapsal, kde v obraze se vyskytují nebo kde se nevyskytují. Dejme tomu že zápis +FF00CC 1/4 by říkal, že v první čtvrtině obrazu (když ho rozdělíš na rovnoměrnou mřížku o čtyřech čtvercích obsahuje danou barvu. Naopak -FF00CC 2/4 , druhá čtvrtina barvu neobsahuje. Nebo -FF00CC,FFFFFF 1-2/4 by zase řekl, že ty dvě barvy se tam nenachází, ale ve zbytku prostoru ano. Jednalo by se ale jen o ty nejvýznamnější barvy v obraze, tj. těch co jich tam je nejvíce. Samozřejmě, že by bylo možné napsat i detailnější zápis jako 000000 10/25
1Pupik1989
Profil
Takové PNG s filtrem 3 obsahuje paletu. Tam by se dalo zjistit, jestli barva z palety je v rozmezí. JPEG mám pocit má paletu také. Takže v C++ bych to napsal v parseru
Přečteš header a víš na co se máš připravit. Mrkni na PNG a chunk IHDR.
Oxidián
Profil *
Dneska jsem zjistil, že existuje nějaká knihovna Magick++ (Mám ji jako součást zdrojů ImageMagicku.
http://www.imagemagick.org/Magick++/Image.html
a tam jsou zahrnuty příklady, které pracují s maticema. Což o to, ImageMagick jsem už používal (ne jako součást C/C++, ale kompilovaný IM), ale chtěl jsem psát vlastní program pro to abych dosáhl vyšší rychlosti pracování úkonů. Jestli si někdy zkoušel nějaké filtry z ImageMagicku tak víš jak dlouho tam všechno trvá ve srovnání např. s Photoshopem. A to je právě ten důvod proč jsem chtěl zkusit udělat nějaký vlastní program, který by jel rychleji. U toho IM bude asi problém v tom, že většina cyklů na zpracování obrázku se bude opakovat za sebou, místo aby se v jednom cyklu provedlo více akcí, což by snad bylo efektivnější. Chci zkusit tu knihovnu ImageMagick jestli se mi to povede rozjet.
1Pupik1989
Profil
Já to teď testoval s PNG na binární úrovni v Javascriptu. Výsledek byl o dost rychlejší než v PHP a GD. Vlastně převedu IDAT chunk podle filtrů pro scanline na finální podobu a už mám rovnou pole. Takový Canvas by to zvládl ještě rychleji. Zkusím někdy to WebGL.

ImageMagick znám, ale nikdy jsem neměl potřebu ho využít.
Oxidián
Profil *
Hledám jak otevřít jpg nebo png soubory v C++. Chtěl jsem to udělat v CImg, ale ten používá ImageMagick.
Rosetta code nabízí toto:
http://rosettacode.org/wiki/Read_image_file_through_a_pipe
ale používaj nějakou knihovnu imglib.h a není tam odkaz kde ji stáhnout.
« 1 2 3 4 »

Vaše odpověď

Mohlo by se hodit

Odkud se sem odkazuje


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0