Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 1 of 1

Thread: Getting distorted image from movie2Serail and Teensy 3.2

  1. #1
    Junior Member
    Join Date
    Jan 2017
    Posts
    9

    Getting distorted image from movie2Serail and Teensy 3.2

    Hi All,

    First of all I would like to Thank you Paul for making such a wonderful library which requires almost negligible code changes to run it.
    Great stuff.

    I am using Teensy 3.2 to display videos/images on WS2811 driven display. I have tried some prototyping with the RGB modules and things went well.
    I got an idea to display the Black and white image which clicked me that what not use the every output of WS2811 chip to drive an individual pixel i.e. OUTR is running 1 pixel, OUTG is running another pixel and OUTB is running another one. In this way I will be able to drive three pixels through a single WS2811 chip.

    I design a PCB which has 24 columns and 24 rows and a WS2811 chip on every three pixels. In this way there are 8 chips in every row.
    I made some changes in movie2Serial program (as mentioned below) and test it on my newly made PCB.
    Now the problem which I am facing is that when I try to display any image (.png) on this small display then that Image is not being properly shown on the display.

    Please see the attached file which has both the LED display image as well as the real .png file which I was trying to show on the display.
    Also, I tried the same with the video (.mp4) and I got the same results.
    I was trying to display letter 'N' image which has white background and letter is written in Black.

    I tried many changes in movie2Serial program but with no results.
    Can someone please point me that what I am doing wrong over here, as, in my opinion things should work in this way as well as it works with the RGB LEDs.

    The main changes which I have done in movie2Serail program is in image2data and colorWiring function.
    In image2data function where its converting 8 pixels to 24 bytes, I have changed it to convert 8 pixels to 8 bytes only.
    In colorWiring function I have changed the code so that it returns a single color after fetching the value from gamma table.

    I am stuck up with this and have been struggling a lot since quite sometime and I would highly appreciate any help from anyone in this regard.


    Please note that I am using processing 3.1.2 and OctoWS2811 library.

    Code:
    import processing.video.*;
    import processing.serial.*;
    import java.awt.Rectangle;
    
    Movie myMovie = new Movie(this, "C://Users//nshrivas//Documents//Croma//Led Wall//N.png");
    
    float gamma = 1.7;
    
    int numPorts=0;  // the number of serial ports in use
    int maxPorts=24; // maximum number of serial ports
    
    Serial[] ledSerial = new Serial[maxPorts];     // each port's actual Serial port
    Rectangle[] ledArea = new Rectangle[maxPorts]; // the area of the movie each port gets, in % (0-100)
    boolean[] ledLayout = new boolean[maxPorts];   // layout of rows, true = even is left->right
    PImage[] ledImage = new PImage[maxPorts];      // image sent to each port
    int[] gammatable = new int[256];
    int errorCount=0;
    float framerate=0;
    
    void setup() {
      String[] list = Serial.list();
      delay(20);
      println("Serial Ports List:");
      println(list);
      //serialConfigure("COM3");  // change these to your port names
     serialConfigure("COM4");
      if (errorCount > 0){ 
        exit();
      }
       for (int i=0; i < 256; i++) {
         gammatable[i] = (int)(pow((float)i / 255.0, gamma) * 255.0 + 0.5);
      }
      size(1000, 1000);  // create the window
      myMovie.loop();  // start the movie :-)
    }
    
     
    // movieEvent runs for each new frame of movie data
    void movieEvent(Movie m) {
      // read the movie's next frame
      m.read();
      
      //if (framerate == 0) framerate = m.getSourceFrameRate();
      framerate = 30.0; // TODO, how to read the frame rate???
      
      for (int i=0; i < numPorts; i++) {    
        // copy a portion of the movie's image to the LED image
        int xoffset = percentage(m.width, ledArea[i].x);
        int yoffset = percentage(m.height, ledArea[i].y);
        int xwidth =  percentage(m.width, ledArea[i].width);
        int yheight = percentage(m.height, ledArea[i].height);
        
         //println("m.width =" +m.width);
         //println("ledArea[i].x =" +ledArea[i].x);
         //println("m.height =" +m.height);
         //println("ledArea[i].y =" +ledArea[i].y);
         //println("ledArea[i].width =" +ledArea[i].width);
         //println("ledArea[i].height =" +ledArea[i].height);
         
         
        //println("xoffset =" +xoffset);
        //println("yoffset =" +yoffset);
        //println("xwidth =" +xwidth);
        //println("yheight =" +yheight);
        
        ledImage[i].copy(m, xoffset, yoffset, xwidth, yheight,0, 0, ledImage[i].width, ledImage[i].height);
        //ledImage[i].copy(m, 0, 0, 576, 576,0, 0, 24, 24);
        
        // convert the LED image to raw data
        byte[] ledData =  new byte[(ledImage[i].width * ledImage[i].height*3) + 3];
         println("xoffset = "+xoffset);
         println("yoffset = "+yoffset);
         println("Source Image Width = "+xwidth);
         println("Source Image Height = "+yheight);
        
        image2data(ledImage[i], ledData, ledLayout[i]);
        
        if (i == 0) {
          ledData[0] = '*';  // first Teensy is the frame sync master
          int usec = (int)((1000000.0 / framerate) * 0.75);
          ledData[1] = (byte)(usec);   // request the frame sync pulse
          ledData[2] = (byte)(usec >> 8); // at 75% of the frame time
        } else {
          ledData[0] = '%';  // others sync to the master board
          ledData[1] = 0;
          ledData[2] = 0;
        }
        // send the raw data to the LEDs  :-)
        //for(int ii =0;ii<ledData.length;ii++){
        //  println("LEDDATA=  " +ii+" "+ ledData[ii]+"  ");
         
        //}
        ledSerial[i].write(ledData); 
      }
    }
    
    // image2data converts an image to OctoWS2811's raw data format.
    // The number of vertical pixels in the image must be a multiple
    // of 8.  The data array must be the proper size for the image.
    void image2data(PImage image, byte[] data, boolean layout) {
      int offset = 3;
      int x, y, xbegin, xend, xinc, mask, modulo;
      int linesPerPin = image.height / 8;
      int pixel[] = new int[8];
      
      for (y = 0; y < linesPerPin; y++) {
        if ((y & 1) == (layout ? 0 : 1)) {
          // even numbered rows are left to right
          xbegin = 0;
          xend = image.width;
          xinc = 1;
        } else {
          // odd numbered rows are right to left
          xbegin = image.width - 1;
          xend = -1;
          xinc = -1;
        }
        int j =0;
        for (x = xbegin; x != xend; x += xinc) {
          for (int i=0; i < 8; i++) {
            // fetch 8 pixels from the image, 1 for each pin
            pixel[i] = image.pixels[x + (y + linesPerPin * i) * image.width];
            modulo = (x + (y + linesPerPin * i) * image.width)%3;
            //println("i m here pixel " + i +"=  " + pixel[i]);
           //println("Pixel Number ="+ (x + (y + linesPerPin * i) * image.width));
           pixel[i] = colorWiring(pixel[i], modulo);
           
             // println("ColorWiring Pixel j= " +j +"  "+ pixel[i]);
              j++;
          }
          // convert 8 pixels to 24 bytes
          for (mask = 0x80; mask != 0; mask >>= 1) {
            byte b = 0;
            for (int i=0; i < 8; i++) {
              if ((pixel[i] & mask) != 0){ 
                  
                //b = b | (1 << i); 
                b |= (1 << i);
              }
               // b |= (1 << i);
            }
            int temp = 0;
            int tempOffset = offset-3;;
            if(b <0){          
              temp = (b+255);
              println("data[" + tempOffset + "]=" +temp);  
            }else{
              temp = b;
             println("data[" + tempOffset + "]=" +temp); 
            }
            
            data[offset++] = b;
          }
        }
      } 
    }
    
    // translate the 24 bit color from RGB to the actual
    // order used by the LED wiring.  GRB is the most common.
    int colorWiring(int c, int modulo) {
      int red = 0;
      int green = 0;
      int blue = 0;
      int colorToShow =0;
      if(modulo == 0){         // Red Case
        red = (c & 0xFF0000) >> 16;
        red = gammatable[red];
        colorToShow = red ;//<< 16;
      }
      if(modulo == 1){   // Green Case
        green = (c & 0x00FF00) >> 8;
        green = gammatable[green]; 
        colorToShow = green; //<<8;
      }
      if(modulo == 2){    //Blue Case
        blue = (c & 0x0000FF);
        blue =gammatable[blue];
        colorToShow = blue;
      }
      //int red = (c & 0xFF0000) >> 16;
      //int green = (c & 0x00FF00) >> 8;
      //int blue = (c & 0x0000FF);
      //red = gammatable[red];
      //green = gammatable[green];
      //blue = gammatable[blue];
     // return (green << 16) | (red << 8) | (blue); // GRB - most common wiring
     return colorToShow;
    
     
    }
    
    // ask a Teensy board for its LED configuration, and set up the info for it.
    void serialConfigure(String portName) {
      if (numPorts >= maxPorts) {
        println("too many serial ports, please increase maxPorts");
        errorCount++;
        return;
      }
      try {
        ledSerial[numPorts] = new Serial(this, portName);
        if (ledSerial[numPorts] == null) throw new NullPointerException();
        ledSerial[numPorts].write('?');
      } catch (Throwable e) {
        println("Serial port " + portName + " does not exist or is non-functional");
        errorCount++;
        return;
      }
      delay(50);
      String line = ledSerial[numPorts].readStringUntil(10);
      if (line == null) {
        println("Serial port " + portName + " is not responding.");
        println("Is it really a Teensy 3.0 running VideoDisplay?");
        errorCount++;
        return;
      }
      String param[] = line.split(",");
      if (param.length != 12) {
        println("Error: port " + portName + " did not respond to LED config query");
        errorCount++;
        return;
      }
      // only store the info and increase numPorts if Teensy responds properly
      ledImage[numPorts] = new PImage(Integer.parseInt(param[0]), Integer.parseInt(param[1]));
      ledArea[numPorts] = new Rectangle(Integer.parseInt(param[5]), Integer.parseInt(param[6]),
                         Integer.parseInt(param[7]), Integer.parseInt(param[8]));
      ledLayout[numPorts] = (Integer.parseInt(param[5]) == 0);
      numPorts++;
    }
    
    // draw runs every time the screen is redrawn - show the movie...
    void draw() {
      // show the original video
      image(myMovie, 0, 80);
      
      // then try to show what was most recently sent to the LEDs
      // by displaying all the images for each port.
      for (int i=0; i < numPorts; i++) {
        // compute the intended size of the entire LED array
        int xsize = percentageInverse(ledImage[i].width, ledArea[i].width);
        int ysize = percentageInverse(ledImage[i].height, ledArea[i].height);
        // computer this image's position within it
        int xloc =  percentage(xsize, ledArea[i].x);
        int yloc =  percentage(ysize, ledArea[i].y);
        // show what should appear on the LEDs
        image(ledImage[i], 240 - xsize / 2 + xloc, 10 + yloc);
      } 
    }
    
    // respond to mouse clicks as pause/play
    boolean isPlaying = true;
    void mousePressed() {
      if (isPlaying) {
        myMovie.pause();
        isPlaying = false;
      } else {
        myMovie.play();
        isPlaying = true;
      }
    }
    
    // scale a number by a percentage, from 0 to 100
    // num is movie and percent is ledArea size
    int percentage(int num, int percent) {
      double mult = percentageFloat(percent);
      double output = num * mult;
      return (int)output;
    }
    
    // scale a number by the inverse of a percentage, from 0 to 100
    int percentageInverse(int num, int percent) {
      double div = percentageFloat(percent);
      double output = num / div;
      return (int)output;
    }
    
    // convert an integer from 0 to 100 to a float percentage
    // from 0.0 to 1.0.  Special cases for 1/3, 1/6, 1/7, etc
    // are handled automatically to fix integer rounding.
    double percentageFloat(int percent) {
      if (percent == 33) return 1.0 / 3.0;
      if (percent == 17) return 1.0 / 6.0;
      if (percent == 14) return 1.0 / 7.0;
      if (percent == 13) return 1.0 / 8.0;
      if (percent == 11) return 1.0 / 9.0;
      if (percent ==  9) return 1.0 / 11.0;
      if (percent ==  8) return 1.0 / 12.0;
      return (double)percent / 100.0;
    }
    Attached Thumbnails Attached Thumbnails Click image for larger version. 

Name:	20170109_171158.jpg 
Views:	27 
Size:	51.5 KB 
ID:	9378   Click image for larger version. 

Name:	N.jpeg 
Views:	56 
Size:	24.9 KB 
ID:	9379  


Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •