Arduino Ambilight: black bar detection

Hallo,

Onlangs heb ik mezelf ambilight gemaakt voor mijn 41" tv. Maar op sommige films heb je vanboven en vanonder zo'n zwarte balk. Waardoor alle LEDs vanboven en vanonder zwart blijven.
Is hier een oplossing voor om dit probleem op te lossen. Ik heb al op google zitten rond zoeken maar daar vind ik niks van code.

De code die ik op mijn Arduino micro gebruik is:

// Slightly modified Adalight protocol implementation that uses FastLED
// library (http://fastled.io) for driving WS2811/WS2812 led stripe
// Was tested only with Prismatik software from Lightpack project

#include "FastLED.h"

#define NUM_LEDS 166 // Max LED count
#define LED_PIN 6 // arduino output pin
#define GROUND_PIN 10
#define BRIGHTNESS 255 // maximum brightness
#define SPEED 115200 // virtual serial port speed, must be the same in boblight_config 

CRGB leds[NUM_LEDS];
uint8_t * ledsRaw = (uint8_t *)leds;

// A 'magic word' (along with LED count & checksum) precedes each block
// of LED data; this assists the microcontroller in syncing up with the
// host-side software and properly issuing the latch (host I/O is
// likely buffered, making usleep() unreliable for latch).  You may see
// an initial glitchy frame or two until the two come into alignment.
// The magic word can be whatever sequence you like, but each character
// should be unique, and frequent pixel values like 0 and 255 are
// avoided -- fewer false positives.  The host software will need to
// generate a compatible header: immediately following the magic word
// are three bytes: a 16-bit count of the number of LEDs (high byte
// first) followed by a simple checksum value (high byte XOR low byte
// XOR 0x55).  LED data follows, 3 bytes per LED, in order R, G, B,
// where 0 = off and 255 = max brightness.

static const uint8_t magic[] = {
  'A','d','a'};
#define MAGICSIZE  sizeof(magic)
#define HEADERSIZE (MAGICSIZE + 3)

#define MODE_HEADER 0
#define MODE_DATA   2

// If no serial data is received for a while, the LEDs are shut off
// automatically.  This avoids the annoying "stuck pixel" look when
// quitting LED display programs on the host computer.
static const unsigned long serialTimeout = 150000; // 150 seconds

void setup()
{
  pinMode(GROUND_PIN, OUTPUT); 
  digitalWrite(GROUND_PIN, LOW);
  FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);

  // Dirty trick: the circular buffer for serial data is 256 bytes,
  // and the "in" and "out" indices are unsigned 8-bit types -- this
  // much simplifies the cases where in/out need to "wrap around" the
  // beginning/end of the buffer.  Otherwise there'd be a ton of bit-
  // masking and/or conditional code every time one of these indices
  // needs to change, slowing things down tremendously.
  uint8_t
    buffer[256],
  indexIn       = 0,
  indexOut      = 0,
  mode          = MODE_HEADER,
  hi, lo, chk, i, spiFlag;
  int16_t
    bytesBuffered = 0,
  hold          = 0,
  c;
  int32_t
    bytesRemaining;
  unsigned long
    startTime,
  lastByteTime,
  lastAckTime,
  t;
  int32_t outPos = 0;

  Serial.begin(SPEED); // Teensy/32u4 disregards baud rate; is OK!

  Serial.print("Ada\n"); // Send ACK string to host

    startTime    = micros();
  lastByteTime = lastAckTime = millis();

  // loop() is avoided as even that small bit of function overhead
  // has a measurable impact on this code's overall throughput.

  for(;;) {

    // Implementation is a simple finite-state machine.
    // Regardless of mode, check for serial input each time:
    t = millis();
    if((bytesBuffered < 256) && ((c = Serial.read()) >= 0)) {
      buffer[indexIn++] = c;
      bytesBuffered++;
      lastByteTime = lastAckTime = t; // Reset timeout counters
    } 
    else {
      // No data received.  If this persists, send an ACK packet
      // to host once every second to alert it to our presence.
      if((t - lastAckTime) > 1000) {
        Serial.print("Ada\n"); // Send ACK string to host
        lastAckTime = t; // Reset counter
      }
      // If no data received for an extended time, turn off all LEDs.
      if((t - lastByteTime) > serialTimeout) {
        memset(leds, 0,  NUM_LEDS * sizeof(struct CRGB)); //filling Led array by zeroes
        FastLED.show();
        lastByteTime = t; // Reset counter
      }
    }

    switch(mode) {

    case MODE_HEADER:

      // In header-seeking mode.  Is there enough data to check?
      if(bytesBuffered >= HEADERSIZE) {
        // Indeed.  Check for a 'magic word' match.
        for(i=0; (i<MAGICSIZE) && (buffer[indexOut++] == magic[i++]););
        if(i == MAGICSIZE) {
          // Magic word matches.  Now how about the checksum?
          hi  = buffer[indexOut++];
          lo  = buffer[indexOut++];
          chk = buffer[indexOut++];
          if(chk == (hi ^ lo ^ 0x55)) {
            // Checksum looks valid.  Get 16-bit LED count, add 1
            // (# LEDs is always > 0) and multiply by 3 for R,G,B.
            bytesRemaining = 3L * (256L * (long)hi + (long)lo + 1L);
            bytesBuffered -= 3;
            outPos = 0;
            memset(leds, 0,  NUM_LEDS * sizeof(struct CRGB));
            mode           = MODE_DATA; // Proceed to latch wait mode
          } 
          else {
            // Checksum didn't match; search resumes after magic word.
            indexOut  -= 3; // Rewind
          }
        } // else no header match.  Resume at first mismatched byte.
        bytesBuffered -= i;
      }
      break;

    case MODE_DATA:

      if(bytesRemaining > 0) {
        if(bytesBuffered > 0) {
          if (outPos < sizeof(leds))
            ledsRaw[outPos++] = buffer[indexOut++];   // Issue next byte
          bytesBuffered--;
          bytesRemaining--;
        }
        // If serial buffer is threatening to underrun, start
        // introducing progressively longer pauses to allow more
        // data to arrive (up to a point).
      } 
      else {
        // End of data -- issue latch:
        startTime  = micros();
        mode       = MODE_HEADER; // Begin next header search
        FastLED.show();
      }
    } // end switch
  } // end for(;;)
}

void loop()
{
  // Not used.  See note in setup() function.
}

De code die ik in processing gebruik, is de adalight.pde van het adalight project: Download & Install | Adalight Project Pack | Adafruit Learning System

Iemand die kan helpen ?

Alvast bedankt,
Svenq

idea:

void loop()
{
set_all_leds();
foreach led == black:
led = color of neighbour (opt. 90% vd intensity is leuker?)
}

verwachting: de zwarte leds zijn binnen een seconde gekleurd, beetje na-ijlend wellicht

Hoi Svenq, en welkom.

De oplossing van Rob is aardig, en het is best interessant om te zien of dat ook een mooi eigen leven gaat leiden als je een tijdje een zwart beeld hebt (kans is een stuk kleiner als je 'm inderdaad zou laten faden want dan bloedt het snel dood).

Maar de oorzaak zit niet in de Arduino sketch.
Je moet hier in de sketch voor Processing gaan kijken.
Ik heb me daar nog nooit mee bezig gehouden, dus ik kan je niet precies vertellen wat en hoe.
Het beeld bestaat uit lijnen die opgebouwd worden.
Boven eerst en dan steeds verder naar beneden.
Als de zwarte balken er zijn, dan heb je dus een behoorlijk groot gebied waar de informatie nul is (en in dit geval is nul dus niet niets).
Dan moet je dus gaan kijken of je vaak "niets" tegenkomt, waarna je kunt concluderen dat er balken zijn.
Je kunt ook kijken waar di balken dan zijn, links en rechts, of boven en onder.
Als je geconcludeerd hebt dat de balken er zijn, moet je dus ergens anders gaan kijken.
Ik heb me er eens aan gewaagd, maar ik kan niet goed volgen wat er daar gebeurt (desondanks het commentaar).
Ik heb het vermoeden dat je eens zou moeten spelen met de plaats van de LEDs die je op moet geven waar er over Rectangle gaat.
Die sketch is mij te ingewikkeld om zomaar even te doorgronden wat er daar gebeurt, maar het is zeker dat je in de processing sketch moet kijken en niet in de Arduino sketch.

Als je geen alternatieven hebt of er net zoveel van snapt als ik, dan kun je Rob's idee ook uitwerken.
Of gewoon om wat leuks te spelen te hebben natuurlijk.

robtillaart:
idea:

void loop()
{
set_all_leds();
foreach led == black:
led = color of neighbour (opt. 90% vd intensity is leuker?)
}

verwachting: de zwarte leds zijn binnen een seconde gekleurd, beetje na-ijlend wellicht

Dit snap ik niet meteen, want als je de LED gewoon de kleur geeft van zijn buur dan blijft deze toch nog steeds zwart ? Aangezien je met een volledige zwarte balk zit over de lengte van je scherm.
Dit komt doordat ik een bvb een widescreen film afspeel of een verkeerde conversie van film: 4:3 --> 16:4

MAS3:
Hoi Svenq, en welkom.

De oplossing van Rob is aardig, en het is best interessant om te zien of dat ook een mooi eigen leven gaat leiden als je een tijdje een zwart beeld hebt (kans is een stuk kleiner als je 'm inderdaad zou laten faden want dan bloedt het snel dood).

Maar de oorzaak zit niet in de Arduino sketch.
Je moet hier in de sketch voor Processing gaan kijken.
Ik heb me daar nog nooit mee bezig gehouden, dus ik kan je niet precies vertellen wat en hoe.
Het beeld bestaat uit lijnen die opgebouwd worden.
Boven eerst en dan steeds verder naar beneden.
Als de zwarte balken er zijn, dan heb je dus een behoorlijk groot gebied waar de informatie nul is (en in dit geval is nul dus niet niets).
Dan moet je dus gaan kijken of je vaak "niets" tegenkomt, waarna je kunt concluderen dat er balken zijn.
Je kunt ook kijken waar di balken dan zijn, links en rechts, of boven en onder.
Als je geconcludeerd hebt dat de balken er zijn, moet je dus ergens anders gaan kijken.
Ik heb me er eens aan gewaagd, maar ik kan niet goed volgen wat er daar gebeurt (desondanks het commentaar).
Ik heb het vermoeden dat je eens zou moeten spelen met de plaats van de LEDs die je op moet geven waar er over Rectangle gaat.
Die sketch is mij te ingewikkeld om zomaar even te doorgronden wat er daar gebeurt, maar het is zeker dat je in de processing sketch moet kijken en niet in de Arduino sketch.

Als je geen alternatieven hebt of er net zoveel van snapt als ik, dan kun je Rob's idee ook uitwerken.
Of gewoon om wat leuks te spelen te hebben natuurlijk.

Heb nog nooit geprogrammeerd met processing code dus dit klinkt mij inderdaad een beetje onbekend. Ik snap wat je bedoelt maar zou er niet aan kunnen beginnen.

Svenq:
Dit snap ik niet meteen, want als je de LED gewoon de kleur geeft van zijn buur dan blijft deze toch nog steeds zwart ? Aangezien je met een volledige zwarte balk zit over de lengte van je scherm.
Dit komt doordat ik een bvb een widescreen film afspeel of een verkeerde conversie van film: 4:3 --> 16:4

Maar er zijn LED-buren die niet zwart zijn, en dan worden zij ook niet-zwart (rood/geel/whatever) en zo krijgt bij iedere iteratie een LED extra een niet zwarte kleur.

IK neem aan dat de LEDs rondom het hele scherm zitten?

robtillaart:
Maar er zijn LED-buren die niet zwart zijn, en dan worden zij ook niet-zwart (rood/geel/whatever) en zo krijgt bij iedere iteratie een LED extra een niet zwarte kleur.

IK neem aan dat de LEDs rondom het hele scherm zitten?

De LEDs zitten inderdaad rondom het hele TV scherm.

Snap je ook dat een iteratie een rondje van je programma is ?
En dat dus bij ieder rondje een LED de kleur van de buurman erft, en er dus kleuren gaan rondlopen ?

Dus als er zwart word weergegeven, kijk je naar links om te zien wat daar te zien is, en neem je daar wat van over.
De volgende keer is er 1 extra LED die oplicht in die kleur, en dus word die kleur geërfd door de volgende LED.
En je kunt ook naar links en naar rechts kijken om te zien wat er daar is.
Kun je ook mooie mix kleuren van krijgen, ligt er maar net aan hoe ingewikkeld je het wil maken.

ergens krijg je mogelijk het probleem dat een zwarte LED 2 gekleurde buren heeft, en dan zou je de tussenkleur kunnen kiezen

R = (Rlinks + Rrechts)/2;
G en B ook zoiets.

Volgens mij snappen jullie niet wat de bedoeling is, momenteel wanneer ik een film kijk met zwarte randen dan nemen alle bijbehorende LEDs de zwarte kleur aan, eigenlijk zouden deze de eerste volledig gekleurde lijn moeten aannemen en dus alle zwarte lijnen overslaan.

MAS3:
Snap je ook dat een iteratie een rondje van je programma is ?
En dat dus bij ieder rondje een LED de kleur van de buurman erft, en er dus kleuren gaan rondlopen ?

Dus als er zwart word weergegeven, kijk je naar links om te zien wat daar te zien is, en neem je daar wat van over.
De volgende keer is er 1 extra LED die oplicht in die kleur, en dus word die kleur geërfd door de volgende LED.
En je kunt ook naar links en naar rechts kijken om te zien wat er daar is.
Kun je ook mooie mix kleuren van krijgen, ligt er maar net aan hoe ingewikkeld je het wil maken.

Ik programmeer in C#, java, .net dus ik weet wat een iteratie is ja.

Maar wat jullie nu hier zeggen is dat ik moet kijken naar de LEDs achter de TV wat hun kleur is. Uiteindelijk heeft dit geen effect op wat ik wil bereiken. Zoals hierboven gezegd moet hij alle zwarte lijnen overslaan, niet slechts 1 zwarte pixel.

Wij zeggen niet wat je MOET doen.
Ik snap precies wat je wil.

We (nou, Rob Tillaart en ik da daar in mee) stellen een alternatief voor dat je wel door je Arduino kan laten uitvoeren.
Zoals eerder gesteld, de zwarte balken kun je alleen detecteren en een andere beeldlijn selecteren in de Processing sketch.
Dit is echt onmogelijk in de Arduino sketch.
Daarom dit voorstel om ook leuk met licht te spelen.

Aan jou of je daar wat mee wil doen.
Zo niet dan is daar niets mis mee.
Maar zo ja dan is dat weer een leuke kans om ervan te leren c.q. de programming skills te oefenen.
Want van een beetje spelen kun je heel veel opsteken.