Převod 15-bit RGB na 24-bit RGB – C / C++ – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Převod 15-bit RGB na 24-bit RGB – C / C++ – Fórum – Programujte.comPřevod 15-bit RGB na 24-bit RGB – C / C++ – Fórum – Programujte.com

 

Toto vlákno bylo označeno za vyřešené — příspěvek s řešením.
PiranhaGreg0
Stálý člen
21. 3. 2015   #1
-
0
-

Zdravím,

mám obrázek s 15-bit barevnou hloubkou a potřebuji ho dostat do 24-bit barevné hloubky. Tedy původní obrázek může mít pro např. červenou složku rozsah 0 - 31, kdyžto výsledný 0 - 255.

Jenže mě teď nějak nenapadá vzoreček, jak to udělat, aby se mi to rovnoměrně namapovalo  .

Násobit to osmi je supr pro tmavý barvy, ale u světlejších to bude čím dál horší a nejbělejší bude 31 * 8 = 248, což má do bílé (255) docela daleko.

Když tak tady je kód, se kterým to lze testovat... 

#include <iostream>
#include <cstdint>

using namespace std;

const uint16_t R_mask = 0x7c00;
const uint16_t G_mask = 0x03e0;
const uint16_t B_mask = 0x001f;

struct RGB {
	uint8_t R, G, B;

	RGB(uint16_t color) : 
		R((color & R_mask) >> 10),
		G((color & G_mask) >> 5),
		B(color & B_mask)
		{ }

	friend ostream & operator<<(ostream & out, const RGB & color) {
		return out << (uint)color.R 
			<< ' ' << (uint)color.G 
			<< ' ' << (uint)color.B;
	}
};

int main(void) {
	cout << "Black: " << RGB(0x0000) << endl;
	cout << "White: " << RGB(0x7fff) << endl;
	cout << "Red: " << RGB(R_mask) << endl;
	cout << "Green: " << RGB(G_mask) << endl;
	cout << "Blue: " << RGB(B_mask) << endl;
}
Nahlásit jako SPAM
IP: 109.81.210.–
lukas.balaz0
Super člen
21. 3. 2015   #2
-
0
-

#1 PiranhaGreg
Ja myslím, že by k tomu ešte trebalo pripočítať x/4 (teda samozrejme celočíselné delenie, to asi pôjde pomocou shiftovania jednoducho urobiť), teda by to bolo x*8+x/4, takto pre čísla 0-3 by to bolo +0, pre čísla 4-7 by to bolo +1, a pre čísla 28-31 by to bolo +7.

Nahlásit jako SPAM
IP: 80.242.41.–
oxidián0
Grafoman
21. 3. 2015   #3
-
0
-

A co to zkusit matematicky? Něco ve smyslu 31/255 * barva.

Nahlásit jako SPAM
IP: 78.45.199.–
lukas.balaz0
Super člen
21. 3. 2015   #4
-
0
-

#3 oxidián
skôr 255/31*farba, ale to je jedno. Myslím si, že PiranhaGreg nechcel používať desatinné čísla. To, čo som napísal ja, je skoro (nie vo všetkých, ale vo väčšine prídadov) to isté, ako dolná celá hranica 255/31*farba. A stačí k tomu len zobrať číslo, nakopírovať ho do dvoch intov, pri prvom to shiftnut o 3 pozície tak, aby sa zväčšilo (nwm či je to doprava alebo doľava teraz :) ), pri druhom ho shiftnut o 2 pozície do druhej strany a potom tie čísla sčítať (dúfam že som sa nepomýlil, ale nemyslím).

Nahlásit jako SPAM
IP: 80.242.41.–
Řešení
PiranhaGreg0
Stálý člen
21. 3. 2015   #5
-
0
-
Vyřešeno Nejlepší odpověď

#2 lukas.balaz
Díky za radu. Našel jsem mezitím něco na StackOverflow, kde je celá plejáda řešení. Ty rychlejší jsou méně přesný a naopak. Já šel po kvalitě, takže jsem skončil nakonec u 

floor((value * 255.0) / 31.0 + 0.5)

Už jsem s tím nějaké obrázky převedl a vypadají na pixel stejně jak originál  .

Nahlásit jako SPAM
IP: 109.81.210.–
oxidián0
Grafoman
21. 3. 2015   #6
-
0
-

Ještě tomu tak moc nerozumím, ale teoreticky by to jít mělo i pomocí shiftů. Já teď provádím dělení a násobení pomocí shiftů, ale jen s číslicí 256 (posun o osum míst). Jestliže by to bylo 31 tak by to byl posun o 5 míst a odečíst nebo přičíst jedna podle situace. Teoreticky: floor((((value << 8)-value) >> 5)+value(?) + 0.5) vychází mí ale nula, takže něco mám špatně. Plus nahradit funkci floor inline algoritmem. Edit: tak násobení by šlo: ((value << 8)-value) ale dělení už ne, když v reálu vychází desetinná místa tak shiftem ty desetinný místa zaniknou.

 

Nahlásit jako SPAM
IP: 78.45.199.–
nergal+1
Návštěvník
21. 3. 2015   #7
-
0
-

   

inline int convert(int value) {
        return (value*510+31)/62;}

je podla mojich merani 5 krat rychlejsie s rovnakymi vysledkami lebo sa nepracuje s desatinnymi cislami :)

inline int convert(int value) {
	static int table[] = {    0,   8,  16,  25,  33,  41,  49,  58,
				 66,  74,  82,  90,  99, 107, 115, 123, 
				132, 140, 148, 156, 165, 173, 181, 189,
				197, 206, 214, 222, 230, 239, 247, 255 };
	return table[value];
}

a toto je 5 krat rychlejsie ako prve :) lebo je to len jeden skok v pamati :)

Nahlásit jako SPAM
IP: 85.135.200.–
viem že neviem čo viem
PiranhaGreg0
Stálý člen
21. 3. 2015   #8
-
0
-

#7 nergal
Ta tabulka není špatnej nápad. Přece jen jde akorát o 32 hodnot, že  .

Nahlásit jako SPAM
IP: 109.81.210.–
oxidián0
Grafoman
21. 3. 2015   #9
-
0
-

Už jsem na to přišel

funkci
floor(((value+1 << 8) >> 5) + 0.5) - 8

lze přepsat
 

result = (((value+1) << 8) >> 5)  - 8;

předstírám, že rozsah je 1..32, protože přičtu jedna a na konci musím odečíst 256/32 (tj.8) problém je v tom, že nevyjde celek 255. Mohl bys odečíst jen 4 ale stejně nevýjde celek, protože to je důsledek toho že rozsah 0..31  je sám o sobě nepřesný. Musel bys to rozdělit do svou kroků a v tom druhém se rozhodnout jestli v případě 254 přičíst jedna. Osobně ale tyhle věci řeším přes tabulku, v případě že je tabulka větší si ji u obrazových operací přeem vypočítám a uložím. Tady je nejlepší řešení tabulky od nergala.

Nahlásit jako SPAM
IP: 78.45.199.–
remmidemmi0
Věrný člen
23. 3. 2015   #10
-
0
-

#1 PiranhaGreg
jenže kvalita obrázku se nijak nezlepší. Když máš jednou 15-bitu barevnou hloubku, tak tam prostě je 15 bitů. S tím nic nenaděláš.... To by jsi pak také mohl chtít udělat z obrázku s 16 barvami obrázek true color ...

Nahlásit jako SPAM
IP: 109.81.210.–
PiranhaGreg0
Stálý člen
23. 3. 2015   #11
-
0
-

#10 remmidemmi
Ano, to samozřejmě vím. Ty obrázky převádím do dvou různých formátů. Jeden 15-bit hloubku zvládá (ppm), tak to nechávám být a druhý (png) podporuje akorát 24-bit a 48-bit, tak to musím takhle převádět...

Nahlásit jako SPAM
IP: 195.113.241.–
peter
~ Anonymní uživatel
3981 příspěvků
23. 3. 2015   #12
-
0
-

oxidián: Myslis nebo vis? Mas to overene v excelu nebo vygenerovane do pole?
0-31 je 32 hodnot, to je 2 na 5-tou, cili shift 3 doleva (*8) mas z toho 0-255
value << 3
Fakt je nutne to tak slozite shiftovat vpravo, vlevo, pricitat a odcitat? Samozrejme nejlepsi je ta tabulka.

Nahlásit jako SPAM
IP: 2001:718:2601:1f7:a070:c2...–
oxidián0
Grafoman
23. 3. 2015   #13
-
0
-

Peter:

nechápu tě. Když máš 2^5 tak snad shift 5x, ne? Já to testoval tak je divné, že by mi vycházely jiné výsledky než tobě. Mě to právě vůbec složité nepříjde, když si uvědomíš co se tam děje. Jediný problém je v tom, že když nenásobíš/nedělíš číslem které je mocninou se základem 2 * tak musíš provést menší úpravu (přičtení rozdílu toho čísla (*) a odečtení násobku rozdílu toho čísla (*)  ).

Můj testovací kód:

// POKUS S PŘEVODEM BARVY
int value, result;
value = 31;
result = floor((value * 255.0) / 31.0 + 0.5);
printf("\n%d\n", result);

result = (((value+1) << 8) >> 5)  - 8;
printf("\n%d\n", result);

rychlé, ale nepřesné. Zopakovat to několikrát, tak obrázek viditelně zesvětlí.

Nahlásit jako SPAM
IP: 78.45.199.–
PiranhaGreg0
Stálý člen
23. 3. 2015   #14
-
+1
-
Zajímavé

#1 oxidián
Potřebuješ dostat číslo z 2^5 do 2^8, čili stačí 3 shifty. Tvoje řešení není o nic přesnější než value << 3  .

Nahlásit jako SPAM
IP: 109.81.210.–
peter
~ Anonymní uživatel
3981 příspěvků
24. 3. 2015   #15
-
0
-

0-255 je 2 na 8
0-31 je 2 na 5, abys z toho dostal 2 na 8, musis to 3x posunout nebo vynasobit 8 (2 na 3).
binarne:
00000 = 0
11111 = 31 (matematicky je to 32)
11111xxx = 255 (31 = 32<<3 - 1 matematicky, coz ale programove stejne napises jako value<<3)

Nahlásit jako SPAM
IP: 2001:718:2601:1f7:e9d3:95...–
peter
~ Anonymní uživatel
3981 příspěvků
24. 3. 2015   #16
-
0
-

Na druhou stranu, neco na tom je, ze z toho nedostanes rozsah 256 jen shiftovanim, protoze ty posledni 3 cisla nejsou jednicky.
00000 000 = 0
00001 000 = 8 (+8)
00010 000 = 16 (+8)
00011 000 = 24 (+8)
00100 000 = 32 (+8)
00101 000 = 40 (+8)
00110 000 = 48
...
11100 000 = 224
11101 000 = 232
11110 000 = 240
11111 000 = 248

Nahlásit jako SPAM
IP: 2001:718:2601:1f7:e9d3:95...–
oxidián0
Grafoman
24. 3. 2015   #17
-
0
-

#14 PiranhaGreg
Tak už chápu

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

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×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, 4 hosté

Podobná vlákna

Převod z RGB do CMYK — založil Iffka

HSB -&gt; RGB — založil mylan4

Načtení RGB — založil raptor181

S bit — založil Koudis

Ovládání RGB led — založil misisnik

Moderátoři diskuze

 

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