Přidat otázku mezi oblíbenéZasílat nové odpovědi e-mailem Algoritmus spočítání všech unikátních barev v bitmapě

Tato funkce je v bitmapovém editoru PaintShopPro a ať přemýšlím jak přemýšlím, nenapadá mě jak to elegantně a rychle udělat. Když má obrázek barevnou hloubku 24b (16,7 milionu barev) jak spočítat kolik kombinací RGB bylo opravdu použitých? Napadá někoho nějaký chytrý algoritmus? Mně napadlo jenom vynulované bitové pole s 16,7 miliony položek (cca 2MB paměti)což by se ale zřejmě muselo udělat jako pole s 2097152 položkami typu BYTE a pro každý bod bitmapy zapsat bit 1 na vypočítaném indexu a bitu podle té barvy a pak spočítat kolik je tam jedniček.
Pokud si dobře vzpomínám, bylo to už ve verzi 3.0, která běhala na Win3.11 s 4MB paměti a nebylo to nijak extra pomalé nebo žeby to nějak mohutně swapovalo, aby měl kam nacpat ty 2MB dat.

Předmět Autor Datum
Alikuj to pole dynamicky dle potreby. Nepotrebujes naalokovat vsehcny kombinace, protoze takovy JPG…
Jan Fiala 07.02.2012 07:32
Jan Fiala
To je sice hezké, ale tím se podle mně hodně časově zesložití to vyhodnocování, pokud nebude to dyna…
JoDiK 07.02.2012 10:43
JoDiK
na truecolor ti bude stačit 3-rozměrné pole 256 bit x 256 bit x 256 bit ;-) alias 32kB paměti... ed…
touchwood 07.02.2012 08:46
touchwood
256*256*256 bitov je 2MB.
x22 07.02.2012 09:24
x22
no jo! Jak jsem došel k těm 32kB? :-p edit: no jo, já to počítal jako 32B^3 edit2: řekl bych, že t…
touchwood 07.02.2012 10:04
touchwood
Teď jsem se do toho zamotal taky. Teoreticky je třeba uložit 2^24 bitů, což jsou ty cca 2MB dat což…
JoDiK 07.02.2012 10:57
JoDiK
problém/vtip je právě v těch vyšších rozměrech..
touchwood 07.02.2012 11:15
touchwood
A nemohl bys mi to prosím zkusit nějak vysvětlit? To trojrozměrné pole zabere v paměti 32768 Bajtů,…
JoDiK 07.02.2012 11:25
JoDiK
máš tam taky chybu. Je to 3D- takže 32768B = 8^3 * 32768B = 16,7Mb To je celé kouzlo. Vzpomeň si,…
touchwood 07.02.2012 12:25
touchwood
O kubickom bajte (8 x 8 x 8 bitov) som este nepocul. Bajt nema 8 x 8 x 8, ale len 8 bitov. Takze je…
x22 07.02.2012 12:37
x22
Jo, taky to tak vidím...
JoDiK 07.02.2012 12:48
JoDiK
ok. 32B x 32B 2D zabírá přesně 1KiB. pokud jich vytvořím 32, pak budou zabírat přesně 32KiB.
touchwood 07.02.2012 15:07
touchwood
Maj pravdu oni, ze (proc 32B?), kaslete na nasobeni - je to 16mil barev a do dokaze reprezetovat 16m…
AZOR 07.02.2012 18:52
AZOR
Edit: zádrhel bude tady: Ale když si vemu každou složku jako index, přičemž každý ještě rozdělím po…
JoDiK 07.02.2012 12:45
JoDiK
špatně. - máš pole bitů o délce 256bit tj. 32byte, klidně reprezentované nějakým polem booleanů (po…
touchwood 07.02.2012 15:04
touchwood
Bohužel nemám jazyk, který by uměl pole bitů nebo booleanů (Ty ano? To snad umí jen nějaké jednočipy…
JoDiK 07.02.2012 18:25
JoDiK
Já zase neznám žádný jazyk, který by nemuměl pole booleanu :D, i kdyby neuměl tak alokuješ 8xmenší p…
AZOR 07.02.2012 18:30
AZOR
Aha, špatně jsem se vyjádřil, pole booleanů ano, ale ty zabírají v paměti minimálně 1 bajt.
JoDiK 07.02.2012 18:54
JoDiK
8-) možná tvoje pole, ja kdyz chci bajt v paměti tak ho dostanu - v C++ určitě, v Delphi ktere ma in…
AZOR 07.02.2012 19:01
AZOR
1. vše záleží na "iteligenci" kompilátoru, jak se s tím popasuje. Logika věci říká, že "chytrý" komp…
touchwood 07.02.2012 19:41
touchwood
No tak nic... Jsem tě chtěl vyzvat, ať to napíšeš :-) poslední
JoDiK 07.02.2012 22:13
JoDiK
A aký máš jazyk? Tu máš niečo v jave: www.programmersheaven.com
pme 07.02.2012 18:40
pme
Efektivnejsie sa ta 16 megabitova bitmapa (nemysim obrzaok, ale to 2MB pole) da ulozit do stromu. N…
x22 07.02.2012 11:02
x22
Jeden z odkazů od strejdy: http://blogs.mathworks.com/steve/2008/01/31/counti ng-occurrences-of-imag…
host 07.02.2012 15:20
host
:-D kde jsou ti tipnci, co porád tvrdí, ze 4GB stačí každému? Asi staci, ale kdo se má srát s algori…
AZOR 07.02.2012 18:42
AZOR
A vubec neni to nahodou prace pro streamy na grafiku? Tohle by melo byt threadovato a pocitano na gr…
AZOR 07.02.2012 18:48
AZOR
Problem totiz je - co vlastne chces Chci si procvičit hlavu... přijít na co nejméně náročný algorit…
JoDiK 07.02.2012 19:09
JoDiK

na truecolor ti bude stačit 3-rozměrné pole 256 bit x 256 bit x 256 bit ;-) alias 32kB paměti...

edit: je to blbost, zpětná rekonstrukce není možná.

edit2: nesmysl, rekonstrukce není třeba, funguje to, za předpokladu, že se použije ještě počitadlo. Pak stačí přičítat, když bude "v kostce" na daných souřadnicích nula (následně změněná na jedničku), jinak byla barva již zaznamenána.

edit3: jsem se trochu zamotal, ono není třeba ani to počitadlo, ale je to optimální řešení než to potom znova zbytečně procházet. Zároveň se tím ale vygenerují indexované barvy obrázku (takže JE to rekonstruovatelné - zapomněl jsem, že jednotlivé osy jsou jasně definovány jako R-G-B).

edit4: a připadne mi to i celkem efektivní, defacto se to bude dát řešit velmi jednoduše xorováním a orováním, tj. velmi nenáročné operace z hlediska výpočetního výkonu - jediné náklady na výpočty budou v okamžiku převodu bajtové hodnoty jednotlivých barvových kanálů na indexový bit.

Teď jsem se do toho zamotal taky.
Teoreticky je třeba uložit 2^24 bitů, což jsou ty cca 2MB dat což odpovídá adresaci jednorozměrného pole v této velikosti.
U trojrozměrného pole by se tedy mělo uložit stejné množství bitů, jediný rozdíl je v adresaci ne?
Ale když si vemu každou složku jako index, přičemž každý ještě rozdělím po 8-mi, tzn 256/8=32B, pak ve třech rozměrech se opravdu zdá že 32B^3 je 32KB paměti, to je přece ale jen 262144 bitů???
Tak jak to teda je?
Abstraktní myšlení mi dnes nějak nejede už ani ve třech rozměrech :-(
Na n-rozměrné prostory, ze kterých se mi točila hlava, když jsem si měl představit třeba kolmici, už raději ani nevzpomínám...

Edit: zádrhel bude tady:

Ale když si vemu každou složku jako index, přičemž každý ještě rozdělím po 8-mi,

Takhle to nefunguje...
Mám RGB 3 bajtové hodnoty, k nimž potřebuju někam uložit 1 bit. Kdybych měl to tebou navržené pole
rgb : array[0..31,0..31,0..31] of byte;
tak ten index musí vycházet z bytových hodnot RGB přičemž z každé z nich mi zbyde ještě hodnota 0-7, podle které musím zapsat do toho adresovaného byte 1 bit. Já tam mám ale jen 8 bitů, a potřebuju jich 8x8x8=512? A jsem zpátky na 16777216b neboli cca 2MB.

špatně.

- máš pole bitů o délce 256bit tj. 32byte, klidně reprezentované nějakým polem booleanů (podle toho co tvůj jazyk umí a podporuje - technicky to lze realizovat i jako 4xbyte nebo 2xinteger - jen budeš muset provést binární konverzi pořadí barvy a dohledání správného bitu ve správné pozici ve vyšším ordinálním typu napříč třemi dimenzemi).
- složky jakékoli barvy mají v RGB 3x256hodnot, od 0 do 256, tomu odpovídá "průsečík" pořadí bitů v každé "ose" R-G-B, tj. např. pro 100-120-255 bude zapsána logická jednička do pole 100,120,255)
- před zápisem jen zkontroluješ, zda už tam jednička je či není, pokud už jednička je, nic neřešíš a jdeš na další pixel (barvu). Pokud tam jednička není, zapíšeš jedničku a zvýšíš počitadlo o jednotku, protože jsi našel novou barvu.

Tvůj omyl je v tom, že pole stavíš na bajtech, přitom ti stačí nikoli číselná hodnota, ale prosté ano/ne na zjištění toho, zda se už objevila daná variace s opakováním pro tři čísla od 0 do 255.

edit: abych předešel hádkám: samozřejmě záleží na implementaci toho, jak je typ boolean, případně jeho pole v daném jazyku implementován(o) - zda je v paměti alokován opravdu jako bit, nebo jako byte (pak by samozřejmě toto snažení z hlediska přeloženého kódu bylo zbytečné, a proto výše zmiňuju "okliku" přes integer)

Bohužel nemám jazyk, který by uměl pole bitů nebo booleanů (Ty ano? To snad umí jen nějaké jednočipy, klasické procesory pokud vím adresují jenom bajty), tak jsem to chtěl obejít polem bajtů, jenže se mi nějak v představách pomíchaly adresy a hodnoty. Stále mi to nedochází, budu ještě zkoumat...

8-) možná tvoje pole, ja kdyz chci bajt v paměti tak ho dostanu - v C++ určitě, v Delphi ktere ma integorovany ASM taky, ale urcite jak jsem psal vejš je 8x větší a tak se mi tam vejde 8x více informací. Například mam 24 bitovou barvuto je 111111111111111100000010 tak si alokuju pole o velikosti ten tvuj bajt krát x 2na16 tzn ty dvě mega: a uložim to takto:

POLE(1111111111111111):=POLE(1111111111111111) OR 000000010;

Print: POLE(1111111111111111):
2=00000010

1. vše záleží na "iteligenci" kompilátoru, jak se s tím popasuje. Logika věci říká, že "chytrý" kompilátor pole boolů zkompiluje do integeru a bude s ním interně pracovat efektivně

2. pokud je kompilátor blbý, je to na pogromátorovi, aby pogrom uspořádal podle svého

3. nenuťte mě, abych si po 20 letech nainstaloval zase nějaký "těžký" programovací jazyk, když už jsem se jednou zařekl, že pogromovat nebudu.. :-D

Efektivnejsie sa ta 16 megabitova bitmapa (nemysim obrzaok, ale to 2MB pole) da ulozit do stromu.

Napr. 256 ukazovatelov, kazdy ukazuje na pole 256 ukazovatelov a tie uz budu ukazovat na pole 256 bitov. Na zaciatku bude vsetkych 256 poloziek nastavenych na null a alokovat sa budu podla potreby.

:-D kde jsou ti tipnci, co porád tvrdí, ze 4GB stačí každému? Asi staci, ale kdo se má srát s algoritmem kvuli trapným 2MB ram?

Problem totiz je - co vlastne chces, otazka je jestli to chces rychle nebo s ohledem na pamet, je mezitim jasnej trade-off.

Honza ma jednoznacne pravdu, ze muzes alokovat jen pole, které je nutné pro daný obrázek a pak ho zvětšovat dynamicky - a NE ROZHODNE to neovlivni slozitost (ne n krát, maximálně n logkrát a doví jestli).

Dalsi vec je, jak velky ten obrázek bude - kazdá barva jiná - 4000x4000+px, aby se alokovaly cele 2MB.
--
Dolni mez algoritmu (jak nejrychleji to asyptoticky teoreticky lze, omezeni daneho problemu) je dána výstupem a to je NxN a to jak pro paměti tak pro výpočetní složitost s tim nic neuděláš. A ty máš asyptoticky stejnou.
--

Pro specialni obtázky by se asi dal najít rychlejší algortmus, ale ne o moc.

Zpět do poradny Odpovědět na původní otázku Nahoru