I've written code in Arduino that cycles through 3 LED color lights but it seems (code) bug prone so I'm trying to come up with a new way to write it. Due to the complexity I'm going to stick with the phesdo code of what I'm trying to do. Here it is:
If (red LED isn't max and green LED is 0 and blue LED is 0)
{inc red LED; update dot matrix}
If (red LED is max and green LED isn't max and blue LED is 0)
{inc green LED; update dot matrix}
If ((red LED is/has-been max but not 0 ) and green LED is max and blue LED is 0)
{dec red; update dot matrix}
If (red LED is 0 and green LED is max and blue LED isn't max)
{inc blue; update dot matrix}
If (red LED is 0 and (green LED is/has-been max but not 0) and blue LED is max)
{dec green; update dot matrix}
If (red LED isn't Max and green LED is 0 and blue is Max )
{inc red; update dot matrix}
If (red LED is Max and green LED is 0 and (blue LED is/has-been Max but not 0))
{dec blue; update dot matrix}
Update LED Driver;
Note: For a visual it's a color wheel going red->orange->green->teal->blue->pink->repeat
The caveat is, all this is in a loop that is only run once before exiting to fetch other data. It then has to return to this loop and remember the color location it left off. Other wise it would be very easy to wrap all this in for loops and execute it linearly. As it is it has to inc or dec one color, understand it's color position if you will, update the led driver and then come back to inc or dec remembering where it left off. So does anyone have a better code methodologically, pseudo style, I can use besides this complex if statements style.
With a simple drawing of the situation you are able to find a formula that applies the intensity directly to the single component according to a global counter that you increment on every tick, the code is the following (I wrote it just now and haven't tested but should be enough for you to understand how it works):
int counter = 0; // counter you should increment on each tick
int phases = 6; // total phases in a cycles
int cycleLength = max_steps * phases; // total ticks in a cycle
int currentStepOfCycle = counter % cycleLength;
int currentPhase = currentStepOfCycle / max_steps;
int currentStepOfPhase = currentStepOfCycle % max_steps;
// this is how much phase shifts are performed for each primary color to have the raising line in phase 0
int phase_shifts[3] = {2, 0, 4};
// for each color component
for (int i = 0; i < 3; ++i) {
// shift the phase so that you have / at phase 0
int shiftedPhase = (currentPhase+phase_shifts[i])%phases;
if (shiftedPhase == 1 || shiftedPhase == 2)
intensity[i] = MAX;
else if (shiftedPhase == 0)
intensity[i] = currentStepOfPhase;
else if (shiftedPhase == 3)
intensity[i] = MAX - currentStepOfPhase;
else
intensity[i] = 0;
}
The idea follows from this:
The shift is needed because by adding an increment to the current phase for a different color component it is possible to consider always phase 0, 1, 2 and 3 to understand is intensity should be raising, dropping or set to max for each component.
This should be adaptable to whatever step of intensity you want to apply easily.
At least as I read your if statements, you have 7 distinct states (maybe it should be 8?), and when you reach the last, it wraps back around to the first.
That's pretty easy to implement as a counter with a small lookup table to map from a state number to which LED(s) should be lit for a state.
yeah that is not great... I would do something like..
typedef struct{ //maybe stick this in a union, depending on what the compiler does to it.
unsigned char r:2;
unsigned char g:2;
unsigned char b:2;
}color;
const int numOfColors = 3;
color colors[numOfColors] = {
{2,0,0},//r
{1,1,0},//o
{0,2,0}//g
};
for(int i = 0 ; 1 ; i++)
{
color c = colors[i%numOfColors];
//set color
//update
//wait
}
Related
I have a program in Visual Studio that is correctly rendering a 3D cube that is slowly spinning. I have a working FillTriangle() function that fills in the faces of the cube with any color whose hex code I enter as a parameter (for example, 0x00ae00ff for purple). I have set the color of each face to start at red (0xFF000000), and then I have a while loop in main() that updates the scene and draws new pixels every frame. I also have a Timer class that handles all sorts of time-related things, including the Update() method that updates things every frame. I want to make it so that the colors of the faces smoothly transitions from one color to the next, through every color of the rainbow, and I want it to loop and do it as long as the program is running. Right now, it is smoothly transitioning between a few colors before suddenly jumping to another color. For example, it might smoothly transition from yellow to orange to red, but then suddenly jump to green. Here is the code that is doing that right now:
...
main()
{
...
float d = 0.0f; //float for the timer to increment
//screenPixels is the array of all pixels on the screen, numOfPixels is the number of pixels being displayed
while(Update(screenPixels, numOfPixels))
{
...
timer.Signal(); //change in time between the last 2 signals
d += timer.Delta(); //timer.Delta() is the average current time
if(d > (1/30)) // 1 divided by number of frames
{
//Reset timer
d = 0.0f;
//Add to current pixel color being displayed
pixelColor += 0x010101FF;
}
...
}
...
}
Is there a better way to approach this? Adding to the current pixel color was the first thing that came to my mind, and it's kind of working, but it keeps skipping colors for some reason.
That constant is going to overflow with each addition. Not just as a whole number, but across each component of the color spectrum: R, G, and B.
You need to break your pixelColor into separate Red, Green, and Blue colors and do math on each byte independently. And leave Alpha fixed at 255 (fully opaque). And check for overflow/underflow along the way. When you reach an overflow or underflow moment, just change direction from incrementing to decrementing.
Also, I wouldn't increment each component by the same value (1) on each step. With the same increment on R,G, and B, you'd just be adding "more white" to the color. If you want a more natural rainbow loop, we can do something like the following:
Change this:
pixelColor += 0x010101FF;
To this:
// I'm assuming pixelColor is RGBA
int r = (pixelColor >> 24) & 0x0ff;
int g = (pixelColor >> 16) & 0x0ff;
int b = (pixelColor >> 8) & 0x0ff;
r = Increment(r, &redInc);
r = Increment(g, &greenInc);
g = Increment(g, &blueInc);
pixelColor = (r << 24) | (g << 16) | (b << 8) | 0x0ff;
Where redInc, greenInc, and blueInc are defined and initialized outside your main while loop as follows:
int redInc = -1;
int greenInc = 2;
int blueInc = 4;
And the increment function is something like this:
void Increment(int color, int* increment) {
color += *increment;
if (color < 0) {
color = 0;
*increment = (rand() % 4 + 1);
} else if (color > 255) {
color = 255;
*increment = -(rand() % 4 + 1);
}
}
That should cycle through the colors in a more natural fashion (from darker to brighter to darker again) with a bit of randomness so it's never the same pattern twice. You can play with the randomness by adjusting the initial colorInc constants at initialization time as well as how the *increment value gets updated in the Increment function.
If you see any weird color flickering, it's quite possible that you have the alpha byte in the wrong position. It might be the high byte, not the low byte. Similarly, some systems order the colors in the integer as RGBA. Others do ARGB. And quite possible RGB is flipped with BGR.
I'm trying to figure out how to make a Schindlers List (Movie) style photo filter for a .bmp file. For those who havent seen it, I want to be able to make everything grayscale except for red.
This is for a class and I am only allowed to use the following libraries : iostream, fstream, cstdlib, string, cstring.
The teacher was nice enough to give us the majority of the code, I just need to modify the pixels accordingly.
My grayscale algorithm isnt perfect. I got it by using fotor's grayscale filter and comparing the before and after RGB values. When I run this function the entire image ends up grayscale even though the picture has colors in the range I declared.
If someone could help me make this work thatd be great!
void process( int& red, int& green, int& blue ) //schindler's list filter
{
if( red < 143 && red > 80 &&
green < 64 && green > 24 &&
blue < 70 && blue >> 30 )//my red range
{
red = red;
blue = blue;
green = green;
}
else //if the pixel isnt red the program will go ahead and make it grayscale
{
red = ((red + green) / 2)*1.01;
green = red;
blue = red;
}
}
blue >> 30
Silly typo: you meant blue > 30.
blue >> 30 is basically always zero, which converts to false which leaves your "leave the colours as they are" block unreachable.
If someone could help me make this work thatd be great!
We're not really here for that. Next time please do some debugging.
Remove conditions, output the values of expressions and variables, until you find the one that isn't what you expect. Make a testcase. Abstract away your specific use case (i.e. the name of a film is not relevant to the problem).
BTW, as a matter of style, red = red etc is utterly pointless!
As a commentator said, in a classic RGB colorspace, a greyscale value is computed with the formula
grey = .2126*red + .7152*green + .0722*blue;
Also, if you just make a brutal transition between the colors you want to preserve and the grey areas, it might look like the colored zones have been painted over the picture.
I would rather apply a smoothing based on the color you want to make stand out.
// this is the center of the intervals you defined for your color
#define TARGET_R 111
#define TARGET_G 44
#define TARGET_B 50
// color distance to consider to mix grey and pure color
#define RADIUS 20 // R, G or B component
int dr = red - TARGET_R;
int dg = green - TARGET_G;
int db = blue - TARGET_B;
int dist = sqrt(dr*dr+dg*dg+db*db); // distance from target color
int grey = .2126*red+.7152*green+.0722*blue; // grey color
float color; // fraction of pure color
if (dist > RADIUS) // pure grey beyond radius
color = 0;
else if (dist > RADIUS/2) // slope from 0 # radius to 1 # radius/2
color = (RADIUS-dist)*2.0/RADIUS;
else // pure color between 0 and radius/2;
color = 1;
grey *= (1-color); // grey part
red = red * color + grey;
green = green * color + grey;
blue = blue * color + grey;
Another approach you could take is to convert the RGB color to HSV (Hue Saturation Value) color space, and than bring the saturation down only if the hue is not in a specific range. For example:
if( 30 < h && h < 330 ) s = 0
http://en.wikipedia.org/wiki/HSL_and_HSV
I've been struggling with a small problem for some time now and just can't figure out what is wrong.
So I have a black 126 x 126 image with a 1 pixel blue border ( [B,G,R] = [255, 0, 0] ).
What I want, is the pixel which is furthest away from all blue pixels (such as the border). I understand how this is done. Iterate through every pixel, if it is black then compute distance to every other pixel which is blue looking for the minimum, then select the black pixel with the largest minimum distance to any blue.
Note: I don't need to actually know the true distance, so when doing the sum of the squares for distance I don't square root, I only want to know which distance is larger (less expensive).
First thing I do is loop through every pixel and if it is blue, add the row and column to a vector. I can confirm this part works correctly. Next, I loop through all pixels again and compare every black pixel's distance to every pixel in the blue pixel vector.
Where blue is a vector of Blue objects (has row and column)
region is the image
int distance;
int localShortest = 0;
int bestDist = 0;
int posX = 0;
int posY = 0;
for(int i = 0; i < image.rows; i++)
{
for(int j = 0; j < image.cols; j++)
{
//Make sure pixel is black
if(image.at<cv::Vec3b>(i,j)[0] == 0
&& image.at<cv::Vec3b>(i,j)[1] == 0
&& image.at<cv::Vec3b>(i,j)[2] == 0)
{
for(int k = 0; k < blue.size(); k++)
{
//Distance between pixels
distance = (i - blue.at(k).row)*(i - blue.at(k).row) + (j - blue.at(k).col)*(j - blue.at(k).col);
if(k == 0)
{
localShortest = distance;
}
if(distance < localShortest)
{
localShortest = distance;
}
}
if(localShortest > bestDist)
{
posX = i;
posY = j;
bestDistance = localShortest;
}
}
}
}
This works absolutely fine for a 1 pixel border around the edge.
https://dl.dropboxusercontent.com/u/3879939/works.PNG
Similarly, if I add more blue but keep a square ish black region, then it also works.
https://dl.dropboxusercontent.com/u/3879939/alsoWorks.PNG
But as soon as I make the image not have a square black portion, but maybe rectangular. Then the 'furthest away' is off. Sometimes it even says a blue pixel is the furthest away from blue, which is just not right.
https://dl.dropboxusercontent.com/u/3879939/off.PNG
Any help much appreciated! Hurting my head a bit.
One possibility, given that you're using OpenCV anyway, is to just use the supplied distance transform function.
For your particular case, you would need to do the following:
Convert your input to a single-channel binary image (e.g. map black to white and blue to black)
Run the cv::distanceTransform function with CV_DIST_L2 (Euclidean distance)
Examine the resulting greyscale image to get the results.
Note that there may be more than one pixel at the maximum distance from the border, so you need to handle this case according to your application.
The brightest pixels in the distance transform will be the ones that you need. For example, here is a white rectangle and its distance transform:
In square due to its symmetry the furthest black point (the center) is also the furthest no matter in which direction you look from there. But now try to imagine a very long rectangle with a very short height. There will be multiple points on its horizontal axis, to which the largest minimum distance will be the short distance to both the top and bottom sides, because the left and right sides are far away. In this case the pixel your algorithm finds can be any one on this line, and the result will depend on your pixel scanning order.
It's because there is a line(more than one pixel) to meet your condition for a rectangular
EDIT
Adjusted all the algorithms posted. It's now working NEARLY flawlessly. It's just the left-most 9 tiles that it fails on (A picture is at the bottom). It selects the completely wrong tile in most cases when hovering one of those nine.
EDIT2 I'm almost certain now that the problem is due to errors when screenX or screenY are negative, so it's probably down to using math.abs on tilePixelX/Y, but it can't just be that, otherwise the results wouldn't be so far off (Although it could well be contributing)
I'm making an isometric game, and right now I'm working on the map rendering engine. In theory it should be fairly simple but I just can't get the tile coords from the mouse position.
My tiles are 64 wide and 32 tall. An image is shown below:
My map displays fairly perfectly:
The actual problem is explained at the top.
Here's the code I'm using right now:
int screenX = sf::Mouse::getPosition(window).x - 250;
int screenY = sf::Mouse::getPosition(window).y - 250;
int tilex = floor((screenY / 32) + (screenX / 64));
int tiley = floor((screenY / 32) - (screenX / 64));
int tilePixelX = abs(screenX % 64); // I believe part of the problem
int tilePixelY = abs(screenY % 32); // is absoluting these. Not all though.
sf::Color mCol = mouseMap.getPixel(tilePixelX, tilePixelY);
if (mCol.r == 20)
tilex -= 1;
else if (mCol.r == 40)
tiley -= 1;
else if (mCol.r == 60)
tilex += 1;
else if (mCol.r == 80)
tiley += 1;
I'm now using a mousemap which is working fantastic however as said above it's still failing on the left-most nine tiles in the diamond (When you hover them it selects a seemingly random around 4-5 tiles away, or no tile at all (I'm guessing out of bounds of the map):
That also shows the problem tiles highlighted in red.
This is what the map looks like, to give you an idea of how my rendering engine works. Note that transparent pixels are considered empty, and black pixels are considered walls (Which I did not render for the example picture above, so none of the tiles displayed on the picture above are 0th-column or 0-th row, nor are they the last row.
My mouse map is definitely correct due to most of the map working but here it is anyway:
Edit:
I've packaged the necessary files and DLLs into a zip file so you can run it and see for yourself what is going on:
https://dl.dropbox.com/u/37019412/Broken.zip
Drawing formula is:
(x - y) * 32 + 250, (x + y) * 16 + 250
Where before coma is X and after is Y and inside x and y are the tile coordinates.
Looking at the tutorial, it seems you need to subtract 256 (224 plus half the width) from the mouse coordinate. Tell us if that works!
And please don't dynamically allocate a new sprite each time you draw one just to delete it in the same method! Ok, I'll try to refrain from making further comments on your code. ;)
In the end it was due to a lot of rounding errors.
if (screenX < 0 || tilePixelX < 0)
tilePixelX = 64 - abs(tilePixelX);
if (screenY < 0 || tilePixelY < 0)
tilePixelY = 32 - abs(tilePixelY);
if (tilePixelX >= 64)
tilePixelX = 63;
if (tilePixelY >= 32)
tilePixelY = 31;
if (screenX < 0 || screenY < 0)
{
tilex--;
tiley++;
}
Sorted it out, even if it was a little bit of an ugly hack in places.
I need to create a colorbar like THIS
I use a scaled array of floats between 0 and 1.
Now I want to compute the RGB color from this float. How to do it? Want to write it in C/c++ so I think I need 2 functions.
The first function to build the colorbar with one parameter like STEPSIZE and the second function need the value and must just return the array index of the colorbar.
I couldn't find it on google, so please help me.
What you are referring to here is the 100% EBU Color Bars (named after the standards body, the European Broadcasting Union). This is not the same as the full SMPTE RP 219-2002 color bars, which have other features including gradients and the PLUGE (Picture Line-Up Generation Equipment), described in the Wikipedia article on Color Bars.
The EBU Color Bars consist of 8 vertical bars of equal width. They are defined in the same way for both SD and HD formats. In the RGB color space, they alternate each of the red, green and blue channels at different rates (much like counting in binary) from 0 to 100% intensity. Counting down from white, in normalised RGB form (appearing left to right):
1, 1, 1: White
1, 1, 0: Yellow
0, 1, 1: Cyan
0, 1, 0: Green
1, 0, 1: Magenta
1, 0, 0: Red
0, 0, 1: Blue
0, 0, 0: Black
So the blue channel alternates every column, the red channel after two columns, and the green after four columns. This arrangement has the useful property that the luminance (Y in YCb'Cr' colour space) results in a downward stepping plot.
To render using 8-bit RGB (most commonly found in desktop systems), simply multiply the above values by 255. The EBU bars come in 75% and 100% variants, based on the intensity of the white column. The SMPTE color bars typically use 75% levels as a reference.
Here is some simple C code to generate 100% EBU color bars and save the result as a PGM file:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
// PAL dimensions
static const unsigned kWidth = 720;
static const unsigned kHeight = 576;
typedef struct
{
uint8_t r;
uint8_t g;
uint8_t b;
} RGB;
int main(int argc, char* argv[])
{
const RGB BAR_COLOUR[8] =
{
{ 255, 255, 255 }, // 100% White
{ 255, 255, 0 }, // Yellow
{ 0, 255, 255 }, // Cyan
{ 0, 255, 0 }, // Green
{ 255, 0, 255 }, // Magenta
{ 255, 0, 0 }, // Red
{ 0, 0, 255 }, // Blue
{ 0, 0, 0 }, // Black
};
// Allocate frame buffer
size_t frameBytes = kWidth*kHeight*sizeof(RGB);
RGB* frame = malloc(frameBytes);
unsigned columnWidth = kWidth / 8;
// Generate complete frame
for (unsigned y = 0; y < kHeight; y++)
{
for (unsigned x = 0; x < kWidth; x++)
{
unsigned col_idx = x / columnWidth;
frame[y*kWidth+x] = BAR_COLOUR[col_idx];
}
}
// Save as PPM
FILE* fout = fopen("ebu_bars.ppm", "wb");
fprintf(fout, "P6\n%u %u\n255\n", kWidth, kHeight);
fwrite(frame, frameBytes, 1, fout);
fclose(fout);
free(frame);
return 0;
}
This should be readily adaptable to any other language. There's probably no need for using float unless you're implementing this on a GPU (in which case the algorithm would be quite different). There is much scope for optimization here; the code is written for clarity, not speed.
Note that while it is possible to generate a perfect digital representation of the color bars in a computer, this will not be safe for broadcast. The transitions between "perfect" color bars would require infinitely high bandwidth to accurately represent. So if the test image is to be transmitted via analog broadcast equipment, it must be bandwidth-limited by a low-pass filter (eg. ~4.3MHz for PAL). This is why you notice the "fuzzy" boundaries in between each column; these contain intermediate values between the pure colors.
Also note that it is not possible to accurately represent the SMPTE color bars in the RGB color space. This is because certain critical values are specified in the YCb'Cr' color space (notably in the PLUGE region) which are outside the gamut of RGB (either SD or HD). You can create something that approximates the values (eg. a very dark blue) but they are not correct. So unless you are representing the test frame in YCb'Cr', stick to EBU bars only (the upper 2/3).
RGB uses bytes, so assuming your array of floats is something like
float scaledColor[3]; // 0 = R, etc., all 0.0 < scaledColor[x] < 1.0
then you can do:
unsigned char r = (unsigned char)(255 * scaledColor[0]);
unsigned char g = (unsigned char)(255 * scaledColor[1]);
unsigned char b = (unsigned char)(255 * scaledColor[2]);
This will of course only work if the values in the floats are really in the range from 0.0 to 1.0.
The simplest solution:
const unsigned char* getColour(float x) /* 0 <= x < 1 */
{
static const unsigned char bar[][3] = {
{255,255,255},
{255,255,0},
// ... fill in all the colours ...
{0,0,0}
};
return bar[(int)(x*sizeof(bar))];
}
Then you can use it to generate bars of any width.
My google-fu turned up that you want the upper third of a SMPTE color bar pattern.
Wikipedia says:
In order from left to right, the colors are gray, yellow, cyan, green,
magenta, red, and blue.
So the easiest way is to simply hard code the respective RGB color codes if you only need those. The article also mentions how those colors can be generated but this seems a lot more difficult and isn't really worth the effort for seven colors.