Ok Daniel Garcia ,

Ok @Daniel_Garcia , trying to figure this puppy out. I can iterate over an image and get the rgb values for every pixel in ascii values of $r, $g, and $b (and $alpha for that matter). So how do I store this in a format that I can read back in and pass to CRGB()? As is?

By the way, the process creates an INT depending on what I do with it:
$rgb = imagecolorat($img, $column, $row);
=> int(422851125)
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $RGB & 0xFF;

Now I have $r = 52, $g = 50, $b = 53.

I could do it all in one step:
$rgb = imagecolorat($img, $column, $row);
$colors = imagecolorsforindex($img, $rgb);

This creates an array:
$colors = {red -> 52, green -> 50, blue -> 53, alpha -> 25}

Eventually I will have to write this in C/C++ using the API calls for ImageMagick, but for now this is the quickest I can get something going.

My two cents: I’d write the data out to a made-up trivial (binary, not ascii) image storage format such as:

  • a format-version-number, for which you just write 0x01 for now, followed by
  • a 16-bit unsigned number for “number of rows in this file”,
  • a 16-bit unsigned number for “number of columns in each row”, and then
  • the image data: for each pixel, an 8-bit number for red, an 8-big number for green, and an 8-bit number for blue. (And if you wish, an 8-bit number for alpha.)

This makes it relatively easy for your arduino code to read the file in in straight ‘binary’ mode.

What’s the purpose of the image format number? If it’s not being used anywhere (that I can think of.)

As for the actual storage and subsequent read back into Arduino, that’s the part I’m foggy on …

The format number is so that if you make fifty files in this format, and then change your mind about the format, you can bump the format number to 2 on new files that you make, and the file-reader on the Arduino will know what’s going on.

As for reading the data, do I recall correctly that you’re using the SdFat library? If so, once you open the file, you can call
inStream.read( yourBuffer, rowCount * columnCount * 3 );
to load in an entire image of pixels at once once you’ve read the rowCount and columnCount from the start of the file, with something like:
uint16_t rowCount, columnCount;
inStream.read( &rowCount, 2);
inStream.read( &columnCount, 2);

I haven’t played with SdFat myself, so I’m just going from their docs.

The other day, Dan was suggesting that you could interleave reading data and piping it to the LED strip, but I’d first get it working without that, just in a read-all-at-once mode, and then once that’s working you can play with trying to interleave the reading and displaying.

Is this helping? Do you have existing code to read from the SD card (or wherever you’re putting the images)?

I’m doing this in steps. At the moment, the code I have stores images in the Arduino’s PROGMEM as 0b0rrggbb0 (in HEX form). This works for a few images and 64 levels of each color.

My plan is to offload the data, and in that process also allow for a higher color range. So my idea is to put all of the image data into separate files onto an SD card, and then have the POV code read the images in without interrupting the currently displayed on. However, for the time being, I’m ignoring that last step, the interrupting part. I want to get it reading the data in and displaying it first.

Where I’m stuck is actually multiple places:

  • how to create the necessary file format
  • how to read that format back in

I’m not sure I can read that much data in at once, and rather than fighting it later down the road, I thought I’d try to do a constant read and display of data. However, I don’t know if
a) I can do that with the time it takes to read an open file and the time it takes to update the string
b) whether it’s worth doing continuously as the image repeats several times.

Storage is storage, except external storage is cheaper than the internal one. There just isn’t enough. One thought was to read everything, the entire sd card, at startup and shove it all into a dataflash module, then use that to read from. But that just adds yet another layer …

Keep in mind also that I’m not a C/C++ programmer, everything I do is done in either PHP (command line) or within the Arduino confine. Though that’s my own personal issue to deal with …

Oy vey, learning how to extract the color values in c++ … the class returns the color values as a ratio from 0 to 1. Oh this is fun … (note to self: multiply by 255!)

#include <Magick++.h>
#include

using namespace Magick;
using namespace std;

int main(int argc, char **argv) {
try {
InitializeMagick(*argv);
Image img(“noname-th.jpg”);
ColorRGB rgb(img.pixelColor(0, 0)); // ie. pixel at pos x=0, y=0
cout << "red: " << rgb.red();
cout << ", green: " << rgb.green();
cout << ", blue: " << rgb.blue() << endl;
}
catch ( Magick::Exception & error) {
cerr << "Caught Magick++ exception: " << error.what() << endl;
}
return 0;
}

=> red: 0.203922, green: 0.196078, blue: 0.207843

Ok, some more trial and error and I’ve gotten to this:

#include <Magick++.h>
#include
#include

using namespace Magick;
using namespace std;

unsigned short int version = 1;
unsigned short int cols, rows;
short int myCol, myRow;

int main(int argc, char *argv) {
ofstream myFile;
myFile.open(“img001.bin”, ios::out | ios::trunc | ios::binary);
myFile.write(reinterpret_cast<const char
> (&version), sizeof(version));

try {
InitializeMagick(argv);
Image img(“noname-th.jpg”);
cols = img.columns();
rows = img.rows();
myFile.write(reinterpret_cast <const char
> (&cols), sizeof(cols));
myFile.write(reinterpret_cast <const char*> (&rows), sizeof(rows));

for (myCol = cols - 1; myCol >= 0; myCol--) {
  for (myRow = rows - 1; myRow >= 0; myRow--) {
    ColorRGB rgb(img.pixelColor(myCol, myRow));
    cout << "red: " << (rgb.red() * 255);
    cout << ", green: " << (rgb.green() * 255);
    cout << ", blue: " << (rgb.blue() * 255) << endl;
  }
}

}
catch ( Magick::Exception & error) {
cerr << "Caught Magick++ exception: " << error.what() << endl;
}
return 0;
}

Now I have a (binary) file that has
line 1: version
line 2: rows
line 3: columns

How should I store the rgb values now? NOTE: in the above code I’m piping the results to stdout so I can see what it’s doing and actually spitting out the proper values.

Never mind, I’m being an idiot. I can just write all those values as I read them, one after the other. On the Arduino side I should be able to read things in chunks and get what I need … I think. Won’t know till I try it I suppose.

Also: if you wind up holding the LED strip vertically, you might want to write out columns of pixels instead of rows, to avoid having to load the whole image at once on the Arduino. Maybe? Timing is going to be the whole story here I think. Well, that, and RAM.

It’s reading column by column, starting with the last one to the first, and rows from bottom to top. That works.

Yeehaw, got the necessary file I needed, based on what you suggested above @Mark_Kriegsman :

unsigned short int version
unsigned short int columns
unsigned short int rows
byte r
byte g
byte b
byte r
byre g
byte b
ad infinitum (or till the end of the file, whichever comes first.)

However, the issue I have now is reading it back within Arduino. The first three, because they’re INTs, I get:

1 // version
0
160 // columns
0
100 // rows
0
125 // r
91 // g
124 // b
153 // r
87 // g
121 // b

I can probably convert the version to a char instead so it only stores it as a single byte (after all, I don’t expect to reach 127 versions, really now.) Probably also the rows since they will always be 48. But colums can be big, so I have to stick with an INT. But that means it’s storing two bytes … Kinda annoying.

Never mind, figured it out. Operator’s lack of understanding. Onward we go …