Raspberry Pi
43) Čidlo barev TCS3200
Po delší době tu mám další čidlo, které se mi povedlo
rozchodit na RasPi.
Tentokrát se jedná o čidlo, které dokáže rozpoznat barvy.
Vlastní obvod má označení TCS3200 a jeho katalogový list je zde: www.ams.com/.....
Přes eBay jsem sehnal tento obvod přidělaný na malém
plošňáku společně se 4 bílými LEDkami: www.ebay.com/......
Je tam spousta prodejců těchto čidel a obvyklá cena je kolem 100Kč.
Princip měření je následující:
Čidlo obsahuje 64 fotodiod, které podle velikosti osvětlení
mění proud, který jimi protéká.
Tento proud se pak převádí na frekvenci. Pomocí logických stavů na vývodech
S0 a S1 je možné frekvenci dělit 5, 50, nebo ponechat bez dělení.
64 fotodiod je rozděleno na 4 bloky po 16 diodách.
Před prvním blokem diod je červený filtr, před druhým blokem je
zelený filtr a před třetím blokem je modrý filtr. Posledních 16 diod
je bez filtru.
Rozložení jednotlivých bloků fotodiod je hezky vidět
pod mikroskopem:
Každý čtvereček je jedna fotodioda.
Na 48 diodách jsou nanesené barevné filtry (rudý, zelený a modrý),
16 diod je bez filtru (bílých).
Pomocí signálů S2 a S3 se vybírá blok, který bude převádět
světlo na frekvenci. Takže je možné zjišťovat intenzitu dopadajícího
světla pro každý filtr zvlášť.
Poslední signál (OE) slouží k odpojování výstupu.
Když je OE v logické "0", je na výstupu obdélníkový signál,
jehož frekvence je závislá na intenzitě světla dopadajícího na fotodiody
přes vybrané filtry.
Pokud je vývod OE v logické "1" není na výstupu žádný
signál.
Na internetu se dá sehnat spousta materiálů o tomto čidle,
včetně ovládacích programů v různých programovacích jazycích.
Jako příklady uvedu třeba tyto stránky:
http://www.elecfreaks.com/wiki/index.php?title=Color_Sensor_Module
http://reibot.org/2011/07/06/tcs3200/
Já jsem nechtěl jen hloupě opisovat, tak jsem si vymyslel vlastní způsob
měření s použitím mého oblíbeného čítače PCF8583.
Schéma zapojení:
Princip mého způsobu měření je následující:
1) Signál OE se nastaví do "1" - tím přestane
čidlo vysílat impulzy.
2) Pomocí komunikace I2C se vynuluje počítadlo v obvodu PCF8583.
3) Pomocí signálů S2 a S3, se vybere filtr.
4) Signál OE se na půl sekundy nastaví do "0" - tím se na půl
sekundy spustí generování impulzů.
Tyto impulzy jsou počítány obvodem PCF8583.
5) Pak se OE nastaví zpátky na "1" - to způsobí vypnutí
generátoru.
6) Přes I2C se zjistí počet nasčítaných impulzů v obvodu PCF8583 -
čím víc impulzů, tím větší intenzita světla.
Celý cyklus se pak opakuje od bodu 2) s nastavením dalšího
filtru.
Výsledkem jsou pak 4 čísla, která udávají intenzitu
světla ve 4 kanálech: rudý, zelený, modrý a bílý (nefiltrovaný).
Většina programů tímto výsledkem končí. Některé
programy se sice snaží pomocí těchto čísel určit barvu, ale v
programech, které jsem viděl jsou to jen obyčejná porovnání velikostí
čísel.
Když je například v "rudém" kanálu nejvyšší číslo,
určí tyto programy, že snímaná barva je rudá.
Trochu lepší programy kromě tří základních barev (R-G-B),
určí i dalších 5 jejich vzájemných kombinací (C-M-Y-K-W).
Například když jsou v zeleném a zároveň modrém kanálu výrazně větší
hodnoty, než v rudém, určí tyto programy, že snímaná barva je azurová.
Převod na 24bitové RGB
Já jsem však chtěl jít dál - chtěl jsem tyto 4
barevné kanály převést přes grafický doplněk pygame zpátky na
24bitovou RGB
barvu na monitoru.
To se ale ukázalo jako docela velký problém.
Jako zdroj barvy jsem použil LCD monitor. V
"MS-Malování" jsem si vytvořil obrázek
s různobarevnými čtverci, jejichž barvu jsem pak snímal čidlem.
V katalogovém listu se píše, že poměr frekvencí v
jednotlivých kanálech (R, G, B) odpovídá poměru jednotlivých složek
snímaného světla a v nefiltrovaném kanálu (W) je pak celková intenzita.
Jenže když jsem zkoušel jednoduchý přepočet výsledek
byl velice špatný - vypočtené barvy vůbec neodpovídaly snímaným barvám
z monitoru.
Zjistil jsem totiž, že i když je na monitoru černá
barva, tak se v jednotlivých kanálech naměří nějaké hodnoty osvětlení
(a v každém kanále jsou ty hodnoty různě velké).
Stejný problém
byl i při bílé barvě. Předpokládal jsem, že když bude snímaná
barva bílá, budou všechny kanály měřit nějakou vysokou, stejně
velkou hodnotu. Ve skutečnosti ale červený kanál měřil podstatně vyšší
hodnotu osvětlení, než zbývající kanály (zelený a modrý). Tím pádem
se všechny ostatní snímané barvy přepočítávaly špatně a výsledná
vypočtená barva byla o hodně červenější, než by měla být.
Používal jsem tento jednoduchý přepočet:
.
.
.
.
maximalni_w = 17119 # hodnota nefiltrovaneho kanalu pri snimani bile barvy
# sig_r, sig_g, sig_b a sig_w obsahuji pocet nascitanych impulzu v jednotlivych kanalech
soucet_rgb = sig_r + sig_g + sig_b
jas = float(sig_w) / maximalni_w
slozka_r = int(jas * 255.0 * sig_r / soucet_rgb)
slozka_g = int(jas * 255.0 * sig_g / soucet_rgb)
slozka_b = int(jas * 255.0 * sig_b / soucet_rgb)
# tohle je zobrazeni RGB barvy pres doplnek pygame
background.fill((slozka_r , slozka_g , slozka_b))
screen.blit(background, (0,0))
pygame.display.flip()
.
.
.
.
|
Nakonec jsem problém vyřešil kalibrací na černé a bílé
barvě.
Kalibrační hodnoty se pak použijí pro normalizaci.
Nový přepočet pak vypadá takto:
.
.
.
.
# kor_lx jsou namerene hodnoty jednotlivych kanalu pri snimani cerne kalibracni barvy
# kor_hx jsou namerene hodnoty jednotlivych kanalu pri snimani bile kalibracni barvy
# sig_x obsahuji pocet nascitanych impulzu v jednotlivych kanalech
# sirka pasma pro kazdou barvu mezi minimem a maximem
pasmo_r = kor_hr - kor_lr
pasmo_g = kor_hg - kor_lg
pasmo_b = kor_hb - kor_lb
# prepocet jednotlivych barev na rozsah 0 az 255 s vyuzitim koncovych kalibracnich bodu
slozka_r = int((sig_r - kor_lr) * (255.0 / pasmo_r))
slozka_g = int((sig_g - kor_lg) * (255.0 / pasmo_g))
slozka_b = int((sig_b - kor_lb) * (255.0 / pasmo_b))
# pokud je po prepoctu nejaky kanal prebuzeny, vsem kanalum se snizi jas
# toto snizovani se provadi tak dlouho, nez se ten prebuzeny kanal vejde do 255
jas = 1
while (slozka_r > 255 or slozka_g > 255 or slozka_b > 255):
jas = jas - 0.01
slozka_r = int((sig_r - kor_lr) * (255.0 / pasmo_r) * jas)
slozka_g = int((sig_g - kor_lg) * (255.0 / pasmo_g) * jas)
slozka_b = int((sig_b - kor_lb) * (255.0 / pasmo_b) * jas)
# pokud by pri korekci nejjasnejsiho kanalu doslo k podteceni jineho kanalu
# pod nulu, zustane ten nejslabsi kanal na nule
if(slozka_r < 0) : slozka_r = 0
if(slozka_g < 0) : slozka_g = 0
if(slozka_b < 0) : slozka_b = 0
print "R - G - B = " , slozka_r , slozka_g , slozka_b
.
.
.
|
Ani toto není úplně přesné. Velký vliv na rozpoznání
barev má i parazitní světlo, které se do čidla dostává z okolí.
Za tmy
byly výsledky trochu lepší, než přes den. I tak je to ale o hodně lepší, než ten původní přepočet.
Celý program je ke stažení tady: color-kal.py
Ukázkové video:
Doplnění 12.8.2013:
Porovnání originálních a vypočtených barev:
Obrázek je kvůli zachování barev ve formátu TIF.
Pokud se nezobrazí v internetovém prohlížeči, stáhněte si ho tady: porovnanibarev.tif
Pak ho můžete zobrazit nějakým prohlížečem grafiky (např. I-View)
|