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:


Odkaz na YouTube

 


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)

 


úvodní strana webu AstroMiK.org

poslední úprava stránky 12.8.2013