I found some bitshift code in the Java implementation of Hough Transform on Rosetta code, I understand in general what the code does, except this part:
rgbValue = (int)(((rgbValue & 0xFF0000) >>> 16) * 0.30 + ((rgbValue & 0xFF00) >>> 8) * 0.59 + (rgbValue & 0xFF) * 0.11);
I think it takes the average of all 3 pixels, that is at least what it looks like when I output the result. But how does this work? What are these magic numbers?
Method in which this function is used, pasted for convenience:
public static ArrayData getArrayDataFromImage(String filename) throws IOException
{
BufferedImage inputImage = ImageIO.read(new File(filename));
int width = inputImage.getWidth();
int height = inputImage.getHeight();
int[] rgbData = inputImage.getRGB(0, 0, width, height, null, 0, width);
ArrayData arrayData = new ArrayData(width, height);
// Flip y axis when reading image
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int rgbValue = rgbData[y * width + x];
// What does this do?
rgbValue = (int)(((rgbValue & 0xFF0000) >>> 16) * 0.30 + ((rgbValue & 0xFF00) >>> 8) * 0.59 + (rgbValue & 0xFF) * 0.11);
arrayData.set(x, height - 1 - y, rgbValue);
}
}
return arrayData;
}
This is the trick that converts a 24-bit RGB value to a grayscale value using coefficients 0.3, 0.59, and 0.11 (note that these values add up to 1).
This operation (rgbValue & 0xFF0000) >>> 16 cuts out bits 17..24, and shifts them right to position 0..7, producing a value between 0 and 255, inclusive. Similarly, (rgbValue & 0xFF00) >>> 8 cuts out bits 8..16, and shifts them to position 0..7.
This Q&A talks about the coefficients, and discusses other alternatives.
I have a simple quantization function
public static int quantize(int oldpixel) {
int r = (oldpixel >> 16) & 0xff;
int g = (oldpixel >> 8) & 0xff;
int b = (oldpixel >> 0) & 0xff;
int color = 0xff << 24 | (((int) ((r) / 32) * 32) & 0xff) << 16 |
(((int) ((g) / 32) * 32) & 0xff) << 8 |
(((int) ((b) / 32) * 32)& 0xff) << 0;
return color;
}
What it does is reduce a color to a lower detail color, then expands it, this artificially limits the pallet and I'll use it for a dither filter, an image through the function produces this
In:
Unquantized hue wheel
Out:
Quantized hue wheel
This is almost perfect as the result, except the whites are reduced to a gray, I understand the cause is my flooring of divided colors in the algorithm, but I do not know how to fix this, any suggestions would be appreciated
After dividing each component by 32, you have an integer between 0 and 7. You are trying to map this back to the range 0 to 255, so that 0 is 0 and 7 is 255.
You can do this by multiplying it by 255/7, which happens to be about 36.428.
You could use something like (int)((r / 32) * (255.0 / 7.0)), but the cast is ugly in Java. To improve that you could wrap it in a function, and have quantizeChannel(r), quantizeChannel(g) and quantizeChannel(b). Or you could swap the order and use integer arithmetic: r / 32 * 255 / 7.
I'm making a program that plays a sine wave varying in pitch and I'm dealing with something that i've never seen before: the program should play a sine wave from 220 hz to 0 hz, and I can see the frequency going from 220 to 0, but what I hear is a sine wave that goes from 220 to 0 and then back to 220.
I have no idea how this piece of code can do that
http://pastebin.com/HS36k7XJ (had to post it here because of screwed up layout)
(where t is the time in seconds and f the current frequency (which is calculated by a simple linear interpolation, which behaves properly))
You scale f linearly down to zero. This means that the expression t * Math.PI * 2 will be scaled back to zero as well. The value you pass to sin() goes from 0 initially (because t=0) to some positive value (because t>0 and f>0), back to 0 (because f=0).
Let's look at the values of t * Math.PI * 2 * f over time and the frequencies:
At t=0, the value is 0 and will increase with speed 220
At t=0.5, the value is 345 and will stop increasing
At t=1, the value is 0 again and will decrease with speed -220
It's reversing it's direction because t * Math.PI * 2 is multiplied by f, and f is getting smaller. This means the whole expression will become smaller as t approaches 1.
Try this code instead:
double ct = 0;
for (;;) {
if(t>=1) break;
//System.out.println(t+" "+e.getValueAt(t));
for (int i = 0; i < buff.length; i++) {
double f=lerp(fa,fb,t);
buff[i] = (short) (Short.MAX_VALUE * 0.5 * Math.sin(Math.PI * 2 * ct));
toSoundCard[2 * i] = (byte) buff[i];
toSoundCard[2 * i + 1] = (byte) (buff[i] >> 8); //(i know i could avoid doing this)
t += 1.0 / 44100.0;
ct += f / 44100.0;
}
speaker.write(toSoundCard, 0, toSoundCard.length);
}
I sort of understand what it's doing, but what is the logic behind the steps in the code provided below? It's a way of loading a texture in LWJGL. But what is happening in the for loop? Wouldn't you just multiply x and y to get the location of a pixel? Any explanation of whats going on from the for loop to the end of the code would be helpful, as the comments are vary vague when it gets to the for loop. I don't understand the weird symbols when putting pixel info into the buffers.
public class TextureLoader {
private static final int BYTES_PER_PIXEL = 4;//3 for RGB, 4 for RGBA
public static int loadTexture(BufferedImage image){
int[] pixels = new int[image.getWidth() * image.getHeight()];
image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());
ByteBuffer buffer = BufferUtils.createByteBuffer(image.getWidth() * image.getHeight() * BYTES_PER_PIXEL); //4 for RGBA, 3 for RGB
for(int y = 0; y < image.getHeight(); y++){
for(int x = 0; x < image.getWidth(); x++){
int pixel = pixels[y * image.getWidth() + x];
buffer.put((byte) ((pixel >> 16) & 0xFF)); // Red component
buffer.put((byte) ((pixel >> 8) & 0xFF)); // Green component
buffer.put((byte) (pixel & 0xFF)); // Blue component
buffer.put((byte) ((pixel >> 24) & 0xFF)); // Alpha component. Only for RGBA
}
}
buffer.flip(); //FOR THE LOVE OF GOD DO NOT FORGET THIS
// You now have a ByteBuffer filled with the color data of each pixel.
// Now just create a texture ID and bind it. Then you can load it using
// whatever OpenGL method you want, for example:
int textureID = glGenTextures(); //Generate texture ID
glBindTexture(GL_TEXTURE_2D, textureID); //Bind texture ID
//Setup wrap mode
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
//Setup texture scaling filtering
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
//Send texel data to OpenGL
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image.getWidth(), image.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
//Return the texture ID so we can bind it later again
return textureID;
}
public static BufferedImage loadImage(String loc)
{
try {
return ImageIO.read(DefenseStep.class.getResource(loc));
} catch (IOException e) {
//Error Handling Here
}
return null;
}
}
All it's doing is loading the colors from the image into a buffer pixel-by-pixel.
This code is doing it using the bitwise operators from Java. See this Java trail.
When you see >>, this means "shift the binary of this number to the right," and when you see num >> n, this means "shift the binary of num's value n bits to the right. For example:
System.out.println(4 >> 2); // Prints "1"
This prints 1 because 4 in binary is 0100, and when shifted right by 2 bits, you get 0001, which is 1 in decimal.
Now, that being said, colors in an image are represented using ARGB. This means that every 32 bits from the image has 8 bits dedicated to each of A, R, G, and B (alpha, red, green, and blue), so its hexadecimal form looks like this:
0xAARRGGBB
Where each letter is a hexadecimal digit.
The code you've posted is using binary logic to retrieve each group of AA, RR, etc. Each group is exactly one byte, or 8 bits, so that's where the 8, 16, and 24 come from. & does a bitwise logical AND on the two numbers, where only bit positions that are 1 in both numbers remain 1, and every other position becomes 0.
For a concrete example, let's retrieve the RR byte from purple in ARGB.
In ARGB, yellow is A=255, R=127, G=0, and B=127, so our hexadecimal version of this is:
0xAARRGGBB
0xFF7F007F
Looking at the hexadecimal value, we see that RR is the third byte from the end. To get RR when the ARGB value is in a variable, let's start by putting this into int pixel:
int pixel = 0xFF7F007F;
Note the similarity to your code. Each int in the pixel matrix is an ARGB color.
Next, we'll shift the number right by 2 bytes so RR is the lowest byte, which gives us:
0x0000AARR
0x0000FF7F
This is done with this code:
int intermediate = pixel >> 16;
The 16 here comes from the fact that we want to shift right by 2 bytes, and each byte contains 8 bits. The >> operator expects bits, so we have to give it 16 instead of 2.
Next, we want to get rid of AA, but keep RR. To do this, we use what's called a bitmask along with the & operator. Bitmasks are used to single out the particular bits of a binary number. Here, we want 0xFF. This is exactly eight 1's in binary. (Each F in hexadecimal is 1111 in binary.)
Bear with me, cause this will look ugly. When we do int red = intermediate & 0xFF, what it's doing (in binary) is:
0000 0000 0000 0000 1111 1111 0111 1111 (0x00007F7F)
& 0000 0000 0000 0000 0000 0000 1111 1111 (0x000000FF)
= 0000 0000 0000 0000 0000 0000 0111 1111 (0x0000007F)
Remember that & means that the resulting bit is only 1 if both input bits are 1.
So we get that red = 0x7F or red = 127, which is exactly what we had above.
Edit:
Why is he looping through the image's pixels starting from y, then x, instead of x then y? And when he creates the variable pixel, why would he multiply y by width and add x? Shouldn't it just be x * y to get the pixel?
Let's use a simple 3x3 image to demonstrate. In a 3x3 image, you have 9 pixels, which means the pixels array has 9 elements. These elements are created by getRGB in a row-by-row order with respect to the image, so the pixel/index relationship looks like this:
0 1 2
3 4 5
6 7 8
The positions correspond to the index used to get that pixel. So to get the top-left pixel of the image, (0, 0), I use pixel[0]. To get the center pixel, (1, 1), I use pixel[4]. To get the pixel under the center pixel, (1, 2), I use pixel[7].
Notice that this produces a 1:1 mapping for image coordinate to index, like so:
Coord. -> Index
---------------
(0, 0) -> 0
(1, 0) -> 1
(2, 0) -> 2
(0, 1) -> 3
(1, 1) -> 4
(2, 1) -> 5
(0, 2) -> 6
(1, 2) -> 7
(2, 2) -> 8
The coordinates are (x, y) pairs, so we need to figure out a mathematical way to turn x and y pairs into an index.
I could get into some fun math, but I won't do that for sake of simplicity. Let's just start with your proposal, using x * y to get the index. If we do that, we get:
Coord. -> Index
-------------------
(0, 0) -> 0 * 0 = 0
(1, 0) -> 1 * 0 = 0
(2, 0) -> 2 * 0 = 0
(0, 1) -> 0 * 1 = 0
(1, 1) -> 1 * 1 = 1
(2, 1) -> 2 * 1 = 2
(0, 2) -> 0 * 2 = 0
(1, 2) -> 1 * 2 = 2
(2, 2) -> 2 * 2 = 4
This isn't the mapping we have above, so using x * y won't work. Since we can't change how getRGB orders the pixels, we need it to match the mapping above.
Let's try his solution. His equation is x = y * w, where w is the width, in this case, 3:
Coord. -> Index
-----------------------
(0, 0) -> 0 + 0 * 3 = 0
(1, 0) -> 1 + 0 * 3 = 1
(2, 0) -> 2 + 0 * 3 = 2
(0, 1) -> 0 + 1 * 3 = 3
(1, 1) -> 1 + 1 * 3 = 4
(2, 1) -> 2 + 1 * 3 = 5
(0, 2) -> 0 + 2 * 3 = 6
(1, 2) -> 1 + 2 * 3 = 7
(2, 2) -> 2 + 2 * 3 = 8
See how the mappings line up to those above? This is what we wanted. Basically what y * w is doing here is skipping the first y * w pixels in the array, which is exactly the same as skipping y rows of pixels. Then by iterating through x, we're iterating through each pixel of the current row.
In case it's not clear from the explanation above, we iterate over y then x because the pixels are added row-by-row to the array in horizontal (x) order, so the inner loop should iterate over the x value so that we aren't jumping around. If we used the same y * w + x, then iterating over x then y would cause the iteration to go 0, 3, 6, 1, 4, 7, 2, 5, 8, which is undesirable since we need to add the colors to the byte buffer in the same order as the pixel array.
Each pixel is represented by a 32-bit integer. The leftmost eight bits of that integer are its alpha component, followed by red, followed by green, followed by blue.
(pixel >> 16) & 0xFF shifts the integer sixteen bits to the right, so the rightmost eight bits in it are now the red component. It then uses a bit mask to set all other bits to zero, so you're left with just the red component. The same logic applies for the other components.
Further reading.
Weird symbols you are referring to are shift operators, and bitwise AND operators I think.
>> n shifts right with n bits
&& 0xFF means that you take the lowest 8 bits of a given binary value
So in short: The for loop decomposes the pixel variable into 4 different 8bit parts: the highest 8 bit will be the alpha, the second the red, the third the green, and the last the blue
So this is the map of the 32bits:
AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB
Where:
A: alpha
R: red
G: green
B: blue
well each component of RGBA (red, green, blue, alpha) has 256 = 2^8 (= 1 byte) different values. Concatenating each component yields a 32 bit binary string which the for loop is loading into buffer byte-wise.