Autor Zpráva
Oxidián
Profil *
Hledal jsem funkci pro převod z CMYK na HSV a naopak (a nenašel). Ale aspoň jsem našel jednu knihovnu, kde je toto:

r = RGB.r / 255;
g = RGB.g / 255;
b = RGB.b / 255;

k = Math.min( 1 - r, 1 - g, 1 - b );
c = ( 1 - r - k ) / ( 1 - k );
m = ( 1 - g - k ) / ( 1 - k );
y = ( 1 - b - k ) / ( 1 - k );

Jelikož bych to chtěl použít Céčku a tento kód není optimální, chci se vás, zdatných matematiků zeptat, jak by se to dalo převést, aby na začátku a na konci číslo vycházelo v možných hodnotách 0 až 255? Narážím na to, že mi přijde zbytečné dělit (v Céčku bych použil typ float) 255 a pak to musel znova převádět. Jelikož jsou tam všude samé jedničky tak to musí jít nějak převést. Nejlépe aby se pracovalo s integerem. Matematika mi moc nešla ale koho baví logika, určitě by to šlo nějak zefektivnit. Já to chci použít na převod barev velkého obrazu, takže to potřebuji co nejjednodušší z hlediska matematického výpočtu pro procesor. No a jestli znáte nějaký vzorec jak to převést rovnou z HSB/HSV tak to by bylo supt.
Keeehi
Profil
Oxidián:
A hledal jsi to anglicky? Protože když do googlu zadám RGB to HSV tak mi to najde spoustu věcí. A hned dokonce na druhém výsledku jsem našel implementaci použitelnou v Cčku. www.cs.rit.edu/~ncs/color/t_convert.html. Pracuje to sice s floaty, ale chceš aby to používalo integery, nebo aby to bylo co nejpřesnější?
Oxidián
Profil *
Keeehi:
Co že si to našel? RGB2HSV? Já hledám HSV<->CMYK. Hledal jsem HSV2CMYK algorhitm nebo tak nějak. Jde o to najít něco mezi. Bez floatů to asi nepůjde, ale skvělé by bylo kdybych mohl alespoň část těch výpočtů vypočítat předem mimo cyklus. U výše uvedeného vzorce se dá ta první část vypočítat předem a výsledky uložit do pole tak aby byly snadno přístupné z cyklu.

r = RGB.r / 255;
g = RGB.g / 255;
b = RGB.b / 255;

1 - r, 1 - g, 1 - b
tyto se dají snadno vypočítat a uložit, dál to už nejde protože tam je funkce min. Ale nejlepší by bylo kdybych se mohl zbavit těch převodů na relativní čísla.

Bohužel nevím jak ten převod funguje.


Nejlepší by bylo kdyby fungovalo něco jako místo 1 dát 255 a místo x/255 dát * 1:


r = RGB.r;
g = RGB.g;
b = RGB.b;

k = Math.min( 255 - r, 255 - g, 255 - b );
c = ( 255 - 255*r - 255*k ) / ( 255 - 255*k );
m = ( 255 - 255*g - 255*k ) / ( 255 - 255*k );
y = ( 255 - 255*b - 255*k ) / ( 255 - 255*k );

Snažím se tu číslici 1 představit jako celek (255), ale nevím jestli to funguje asi by z toho vylezlo záporné číslo
Keeehi
Profil
Oxidián:
Aha nějak jsem to špatně pochopil. myslel jsem, že jde o převod rgb to cmyk. Co jsem se tak díval, tak převod HSV <> CMYK se asi řeší přes mezistupeň RGB. Toto není můj obor, ale z toho co jsem zahlédl, se mi zdá, že převod z HSV není tak jednoduchý. Protože kromě těch hodnot se tam pracuje ještě s nějakým barvným profilem. Což tedy asi nějak definuje, jak se to má převádět. Při tom hleání jsem narazil na celkem zajímyvý projekt colormine.org/convert/cmyk-to-hsv

tyto se dají snadno vypočítat a uložit, dál to už nejde protože tam je funkce min
Minimum ze 3 stejných čísel je pořád stejné. Celá ta funkce je stabilní. Pro stejný vstup vždy vrátí sejný výsledek, takže se kešovat dá. Teď záleží co je rychlejší. Jestli provedení pár matematických operací nebo vyhledávání v nakešovaných výstupech. Jelikož za funkce má konstantní složitost, může být řešení lepší jen o nějakou konsttantu. Naopak se to dá keší i dost zkazit (pokud nebude vyhledávání dost rychlé, pokud počet schodných vstupů bude malý)
Oxidián
Profil *
Minimum není vždy stejné. Minumum je v podstatě nejnižší hodnota , jedna z těch tří R,G,B. Převod nemusí zahrnovat barvový profil. Drtivá většina obrázků ho stejně nemá uložený, to používají jen profíci co profesionálně fotí a editují fotky.

To by chtělo zjistit jak jsou definovány jednotlivé barevné složky CMYK jako z čeho se skládaj.


Že by možná jen stačilo v HSV posunout odstín podle principu Y=R+G, M=B+R, C=B+G, K=R+B+G . Když známe odstín tak by to snad mělo jít nějak posunout nebo "namíchat" a K by mělo jít vypočítat ze vztahu mezi Saturací (S) a Světlostí (V).
Keeehi
Profil
Oxidián:
Minimum není vždy stejné.
Ale je.
1. řekněme že máme tři čísla 5, 2 a 6
2. jejich minimum min(5, 2, 6) je 2
3. když znovu někdy v budoucnu budu chtít zjisti minimum z čísel 5, 2 a 6 tak to bude zase 2

Je ale samozřejmě hloupost kešovat mezivýsledky když můžeš kešovat celou funkci. Řekněme, že máme funkci convert(R, G, B). Pseudokód pro kešování by mohl vypadat takto:
function cachedConvert(R, G, B) {
    $foundItem = storage->searchFor(RGB)
    if (search was successfull) {
        return $foundItem;
    }
    
    $result = convert(R, G, B);
    storage->save(RGB, $result);
    
    return $result;
}
1Pupik1989
Profil
Tak po ořezání mě vypadlo:

r = RGB.r / 255;
g = RGB.g / 255;
b = RGB.b / 255;

var k = Math.max(r, g, b);

var c = (k - r) / k; 
var m = (k - g) / k; 
var y = (k - b) / k;

k = 1-k;

console.log(c,m,y,k);

Samozřejmě by šlo ještě místo dělení násobit.
Nicméně bez převodu HSV -> RGB to nejspíš nepůjde.
Oxidián
Profil *
1Pupik1989:
Díky za kód. Mě jde právě o to aby tam nebylo to dělení. Hlavně proč dělit 255 když pak to musím znova násobit na 255?
Jako tohle by bylo nejjednodušší řešení a asi by to nebylo stoprocentně přesné, ale kdo to pozná? Pokud budu spokojený s výsledkem tak mě to trápit nemusí. Nadruhou stranu jsem našel:

Našel jsem:
http://stackoverflow.com/questions/4858131/rgb-to-cmyk-and-back-algorithm
Takže mohu použít knihovnu:
http://www.argyllcms.com/icclibsrc.html


1Pupik1989:
Ale nechci být vybíravý, tak jak si to napsal to stačí. Já si ty hodnoty načtu předem, takže si je pak najdu v poli abych to nemusel dělit.
Keeehi
Profil
Oxidián:
Jestli můžeš použít nějakou knihovnu, tak je to v 99% to nejlepší a nejjednodušší řešení.
Oxidián
Profil *
Keeehi:
To se uvidí až podle toho jaká bude rychlost a jaký bude zisk. Jinak k tomu nápadu cachovat všechny výsledky to se mi nezdá jako dobrý nápad protože bych buď musel mít 3D pole což by už nebylo tak výhodné z hlediska paměti a rychlosti přístupu k datům. U té knihovny icclib je ale problém v tom, že ten převod zřejmě nemohu provést v rámci jednoho cyklu který mi tam už běží. Myslím tím to že provádím nejdříve načtení obrázku do paměti, příp. dekódování, pak převod rgb2hsv a v rámci tohoto převodu bych mohl provést najednou i jiné úkony jako vytvoření histogramu a vytvoření bufferu v cmyk. Předopkládám, že knihovna ale pravděpodobně bude převádět celý obraz spíš než že by to šlo po jedné barvě (a jestli jo tak po jedné barvě by to nemohlo být efektivní protože by to zase znamenalo zevnitř vnořeného cyklu volat min. jednu funkci což opět zpomalí chod). Čili nakonec zbudou dvě možnosti: 1) převést to pomocí icclib samostatně a za cenu ztráty času 2) převést to v rámci vnořeného cyklu za cenu menší nepřesnosti, ale stále ušetřím značné kvantum času.
juriad
Profil
Máš změřené to „značné kvantum času“?
O jakém programovacím jazyku se zde vlastně bavíme? (Jsme v kategorii JavaScript)
Oxidián
Profil *
Změřené to budu mít až to rozjedu. Algoritmus je snad stejný pro JS i pro C


Chceš skutečně abych to rozváděl když nejde o JS? Značné kvantum času změřené mám, protože v mém případě se jedná o obraz 4096x4096 a měřím setiny sekundy. Značné kvantum času pro mě je tedy vše co je dvě setiny a výše
Keeehi
Profil
Oxidián:
Trojrozměrné pole to být nemusí. Dá se to nacpat do jednorozměrného nebo použít úplně jinou strukturu.
Samozřejmě nejrychlejší varianta je předpočítat si celou konverzní mapu a podle toho jen převádět. Počítal jsem, kolik by to tak v paměti zabralo. U HSV > CMYK jsem se při naivní implementaci polem dopočítal k nějakým 64MB což není nic strašného. Pro CMYK > HSV je to 12GB což už je tedy horší. Samozřejmě toto předpočítání se hodí jen v prípadě, že se postupně převádí větší množství obrazů. Vytvoření mapy něco zabere a to se musí rozprostřít mezi větší počet obrazů. Konkrétně inicializace mapy pro HSV > CMYK zabere stejně jako převod 4 obrazů a inicializace CMYK > HSV zabere 768 konverzí.

Ta mapa se dá samozřjmě vytvářet postupně, stejně jako v [#6]. Rychlost zase bude záviset od toho, jak moc rozdílné budou vstupy a jaký overhead přidá kontrola existence vypočteného výsledku.

Všechno toto ale nezávisí na tom, jak ta funkce pro samotnou konverzi bude implementovaná.


Zkoušel jsem se podívat, jak to implementované v knihovně z [#8]. Algoritmus jsem sice nenašel, ale co jsem se tak díval, tak se mi zdá, že dost dbá na efektivitu. Takže s případnou vlastní implementací pravděpodobně nebudete o moc lepší.
Oxidián
Profil *
Mě teda přijde dost i těch 64 MB. Vzhledem k tomu že jedu na x86 s max. pamětí 3 GB ale 1GB mi konzumují další programy. Nevím kolik paměti bude konzumovat program samotný. Ale určitě budu zpracovávat minimálně 4 obrazy najednou. Takže počítej to že ten obraz bude v paměti min. 2x (HSV+CMYK+případné další vrstvy a masky načtené v paměti). Proto nechci pamětí plýtvat, takže mě příjde v pohodě když se jedná např. o 256*256 ale 256*256*256 je už trochu moc. Momentálně program zabírá 1.5MB paměti a po načtení toho souboru to je 24Mb. Když tedy odmyslím těch 64MB tak bych tu paměť mohl využít k tomu abych současně otevřel 4 soubory a vytvořil pro každý z nich 20 kopií. tj celkem 1.875Gb. Prostě proč zbytečně plýtvat, když to mohu jednoduše spočítat případně najít nějaký kompromis mezi rychlostí a místem v paměti. Třeba dvou rozměrné pole 256*256*4b=256kb to mi přijde úplně v pohodě a ne aby to zabíralo jako nějaký větší obraz.
1Pupik1989
Profil
Oxidián:
Hlavně proč dělit 255 když pak to musím znova násobit na 255?

Dělit 255 to nemusíš.
r = RGB.r;
g = RGB.g;
b = RGB.b;

var k = Math.max(r, g, b);

var c = (k - r) / k; 
var m = (k - g) / k; 
var y = (k - b) / k;

k = 255-k;

Nicméně násobit 255 to budeš muset. Já používám rozsah 0-1, takže spoustu násobení a dělení můžu ve finále vynechat. Ty by si mohl používat úplně stejný rozsah. Případně až při poslední operaci násobit 255 u rgb.

Vaše odpověď

Mohlo by se hodit

Neumíte-li správně určit příčinu chyby, vkládejte odkazy na živé ukázky.
Užíváte-li nějakou cizí knihovnu, ukažte odpovídajícím, kde jste ji vzali.

Užitečné odkazy:

Prosím používejte diakritiku a interpunkci.

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