I'm using the following loop to calculate the difference between two images of the same size:
static double calculateError(BufferedImage canvas, BufferedImage ideal) {
double error = 0.0D;
for (int x = 0; x < Polygonizer.WIDTH; x++) {
for (int y = 0; y < Polygonizer.HEIGHT; y++) {
Color c1 = new Color(canvas.getRGB(x, y));
Color c2 = new Color(ideal.getRGB(x, y));
error += Math.abs(c1.getRed() - c2.getRed());
error += Math.abs(c1.getGreen() - c2.getGreen());
error += Math.abs(c1.getBlue() - c2.getBlue());
}
}
return error;
}
It works fine but rather slow, and I have no idea how to make it go faster.
I've already tried using ExecutorService to no good and I could use some advice.
Edit: Thanks, everyone. Here's the optimized version:
private static int APPROXIMATION = 1;
private static int[] idealData;
public static final void setIdeal(BufferedImage ideal) {
int[] rawData = ((DataBufferInt)ideal.getRaster().getDataBuffer()).getData();
idealData = new int[rawData.length * 3];
int counter = 0;
for (int i = 0; i < rawData.length * 3; i += 3) {
idealData[i] = (rawData[counter] & 0xFF);
idealData[i + 1] = (rawData[counter] >> 8 & 0xFF);
idealData[i + 2] = (rawData[counter] >> 16 & 0xFF);
counter++;
}
}
static double calculateError(BufferedImage canvas) {
long error = 0;
final int[] canvasData = ((DataBufferInt)canvas.getRaster().getDataBuffer()).getData();
int counter = 0;
for (int i = 0; i < canvasData.length; i += APPROXIMATION) {
error += Math.abs((canvasData[i] & 0xFF) - (idealData[counter]));
error += Math.abs((canvasData[i] >> 8 & 0xFF) - (idealData[counter + 1]));
error += Math.abs((canvasData[i] >> 16 & 0xFF) - (idealData[counter + 2]));
counter += 3 * APPROXIMATION;
}
return error;
}
If you know the format of the BufferedImages, for example because you instantiated them with the constructor, there's an even faster way.
If the BufferedImages are of type TYPE_3BYTE_BGR, do this:
byte[] canvasData = ((DataBufferByte)canvas.getRaster().getDataBuffer()).getData();
byte[] idealData = ((DataBufferByte)ideal .getRaster().getDataBuffer()).getData();
int error = 0;
for (int i = 0; i < canvasData.length; i++) {
error += Math.abs((canvasData[i] & 0xFF) - (idealData[i] & 0xFF));
}
If the BufferedImages are of type TYPE_INT_RGB, do this:
int[] canvasData = ((DataBufferInt)canvas.getRaster().getDataBuffer()).getData();
int[] idealData = ((DataBufferInt)ideal .getRaster().getDataBuffer()).getData();
int error = 0;
for (int i = 0; i < canvasData.length; i++) {
error += Math.abs((canvasData[i] & 0xFF) - (idealData[i] & 0xFF));
error += Math.abs((canvasData[i] >> 8 & 0xFF) - (idealData[i] >> 8 & 0xFF));
error += Math.abs((canvasData[i] >> 16 & 0xFF) - (idealData[i] >> 16 & 0xFF));
}
(disclaimer: Untested code, but something I've done often enough that I'm confident)
You create two instances of Color per point, that's quite a bit. There's a much faster way of extracting the RGB from an int (look at the sources of Color).
More importantly, you extract points one by one, which is usually terribly slow (as they may be organized differently in the BufferedImages). Call a method extracting more of them at once into an int[].
AFAIK there's a way to let the image compute the result, which is probably still faster.
I've already tried using ExecutorService to no good and I could really use some advice.
This should also help, but only up to the number of cores you have. However, using paralel streams is usually much simpler. But that's a different story (question).
Related
Here's what I'm working with right now:
for (int i = 0, numSamples = soundBytes.length / 2; i < numSamples; i += 2)
{
// Get the samples.
int sample1 = ((soundBytes[i] & 0xFF) << 8) | (soundBytes[i + 1] & 0xFF); // Automatically converts to unsigned int 0...65535
int sample2 = ((outputBytes[i] & 0xFF) << 8) | (outputBytes[i + 1] & 0xFF); // Automatically converts to unsigned int 0...65535
// Normalize for simplicity.
float normalizedSample1 = sample1 / 65535.0f;
float normalizedSample2 = sample2 / 65535.0f;
float normalizedMixedSample = 0.0f;
// Apply the algorithm.
if (normalizedSample1 < 0.5f && normalizedSample2 < 0.5f)
normalizedMixedSample = 2.0f * normalizedSample1 * normalizedSample2;
else
normalizedMixedSample = 2.0f * (normalizedSample1 + normalizedSample2) - (2.0f * normalizedSample1 * normalizedSample2) - 1.0f;
int mixedSample = (int)(normalizedMixedSample * 65535);
// Replace the sample in soundBytes array with this mixed sample.
soundBytes[i] = (byte)((mixedSample >> 8) & 0xFF);
soundBytes[i + 1] = (byte)(mixedSample & 0xFF);
}
From as far as I can tell, it's an accurate representation of the algorithm defined on this page: http://www.vttoth.com/CMS/index.php/technical-notes/68
However, just mixing a sound with silence (all 0's) results in a sound that very obviously doesn't sound right, maybe it's best to describe it as higher-pitched and louder.
Would appreciate help in determining if I'm implementing the algorithm correctly, or if I simply need to go about it a different way (different algorithm/method)?
In the linked article the author assumes A and B to represent entire streams of audio. More specifically X means the maximum abs value of all of the samples in stream X - where X is either A or B. So what his algorithm does is scans the entirety of both streams to compute the max abs sample of each and then scales things so that the output theoretically peaks at 1.0. You'll need to make multiple passes over the data in order to implement this algorithm and if your data is streaming in then it simply will not work.
Here is an example of how I think the algorithm to work. It assumes that the samples have already been converted to floating point to side step the issue of your conversion code being wrong. I'll explain what is wrong with it later:
double[] samplesA = ConvertToDoubles(samples1);
double[] samplesB = ConvertToDoubles(samples2);
double A = ComputeMax(samplesA);
double B = ComputeMax(samplesB);
// Z always equals 1 which is an un-useful bit of information.
double Z = A+B-A*B;
// really need to find a value x such that xA+xB=1, which I think is:
double x = 1 / (Math.sqrt(A) * Math.sqrt(B));
// Now mix and scale the samples
double[] samples = MixAndScale(samplesA, samplesB, x);
Mixing and scaling:
double[] MixAndScale(double[] samplesA, double[] samplesB, double scalingFactor)
{
double[] result = new double[samplesA.length];
for (int i = 0; i < samplesA.length; i++)
result[i] = scalingFactor * (samplesA[i] + samplesB[i]);
}
Computing the max peak:
double ComputeMaxPeak(double[] samples)
{
double max = 0;
for (int i = 0; i < samples.length; i++)
{
double x = Math.abs(samples[i]);
if (x > max)
max = x;
}
return max;
}
And conversion. Notice how I'm using short so that the sign bit is properly maintained:
double[] ConvertToDouble(byte[] bytes)
{
double[] samples = new double[bytes.length/2];
for (int i = 0; i < samples.length; i++)
{
short tmp = ((short)bytes[i*2])<<8 + ((short)(bytes[i*2+1]);
samples[i] = tmp / 32767.0;
}
return samples;
}
I have written code in java, to convert from byte array to long, code is here:
public static long bTol(byte[] b_arr) {
long res = 0;
for (int i = 0; i < b_arr.length; i++) {
res += ((b_arr[i] & 0xFFFFFFFFFFFFFFFFL) << ((b_arr.length - 1 - i) * 8));
}
return res;
}
I get different number when I run this code, but i can't understand what is problem
You must mask a single byte, otherwise the sign extension pollutes your result:
public static long bTol(byte[] b_arr) {
long res = 0;
for (int i = 0; i < b_arr.length; i++) {
res += (long)(b_arr[i] & 0xFF) << ((b_arr.length - 1 - i) * 8);
}
return res;
}
You may also use available methods (assuming that the byte array has length 8, as it should):
public static long bToL(byte[] b_arr) {
ByteBuffer buf = ByteBuffer.allocate( b_arr.length );
buf.put( b_arr );
return buf.getLong(0);
}
Try to replace
res += ((b_arr[i] & 0xFFFFFFFFFFFFFFFFL) << ((b_arr.length - 1 - i) * 8));
By this :
res += ((long) b_arr[i] & 0xFFL) << (8 * i);
What integer should be returned when we reverse all bits of integer 1? How do we do that with Java code?
No java built in functions should be used. Shouldn't use String reverse, converting to string etc. Only bitwise operations allowed.
import java.util.*;
import java.lang.*;
import java.io.*;
class BitReverseInt
{
public static void main (String[] args) throws java.lang.Exception{
System.out.println(reverser(1));
}
public static int reverser(int given){
int input = given;
int temp = 0;
int output = 0;
while(input > 0){
output = output << 1;
temp = input & 1;
input = input >> 1;
output = output | temp;
}
return output;
}
}
Bit reversal can be done by interchanging adjacent single bits, then interchanging adjacent 2-bit fields, then 4-bits, and so on as shown below. These five assignment statements can be executed in any order.
/********************************************************
* These are the bit masks used in the bit reversal process
0x55555555 = 01010101010101010101010101010101
0xAAAAAAAA = 10101010101010101010101010101010
0x33333333 = 00110011001100110011001100110011
0xCCCCCCCC = 11001100110011001100110011001100
0x0F0F0F0F = 00001111000011110000111100001111
0xF0F0F0F0 = 11110000111100001111000011110000
0x00FF00FF = 00000000111111110000000011111111
0xFF00FF00 = 11111111000000001111111100000000
0x0000FFFF = 00000000000000001111111111111111
0xFFFF0000 = 11111111111111110000000000000000
*/
uint x = 23885963; // 00000001011011000111100010001011
x = (x & 0x55555555) << 1 | (x & 0xAAAAAAAA) >> 1;
x = (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2;
x = (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4;
x = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8;
x = (x & 0x0000FFFF) << 16 | (x & 0xFFFF0000) >> 16;
// result x == 3508418176 11010001000111100011011010000000
By looking at each intermediary result you can see what is happening.
Hopefully this will give you what you need to sort it out in your head. John Doe's answer consolidates steps 4 and 5 in to a single expression. This will work on most machines.
Here is the actual implementation of Integer.reverse(int).
public static int reverse(int i) {
// HD, Figure 7-1
i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;
i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;
i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
i = (i << 24) | ((i & 0xff00) << 8) |
((i >>> 8) & 0xff00) | (i >>> 24);
return i;
}
You can use a do while loop like this:
public static int reverse(int number){
int reverse = 0;
int remainder = 0;
do{
remainder = number%10;
reverse = reverse*10 + remainder;
number = number/10;
}while(number > 0);
return reverse;
}
And for bitwise operation: here it goes:
// value=your integer, numBitsInt=how much bit you will use to reverse
public static int reverseIntBitwise(int value, int numBitsInt) {
int i = 0, rev = 0, bit;
while (i++ < numBitsInt) {
bit = value & 1;
value = value >> 1;
rev = rev ^ bit;
if (i < numBitsInt)
rev = rev << 1;
}
return rev;
}
Well there are multiple ways to reverse the bits of the given number in Java.
First, Java language has inbuild bitwise complement operator(~). So (~number) reverses the bits of number.
Second, one can use the Integer.reverse(number)
Third, if this is a part of test or you just want to play with bits, you can refer the code below.
/*
The logic uses moving bitmask from right to left:
1. Get the bit of given number, by binary and(&) with bitmask
2. XOR(^) with the bitmask, so here we reverse the bit.
3. OR(|) this reversed bit with the result(result has all Zero initially)
This logic is repeated for each 32 bits by moving the mask from right to left,
one bit at a time using (<<) left shift operator on bitmask.
*/
public class ReverseBits {
public static int reverseBits(int input) {
print("Input", input);
int bitmask = 1;
int result = 0;
do {
//print("Bitmask", bitmask);
result = result | (bitmask ^ (input & bitmask)) ;
//print("Result", result);
bitmask = bitmask << 1;
} while (bitmask != 0);
print("Reverse", result);
return result;
}
public static void print(String label, int input) {
System.out.println(label +"\t:"+Integer.toBinaryString(input));
}
public static void main(String[] args) {
reverseBits(Integer.MIN_VALUE);
reverseBits(Integer.MAX_VALUE);
reverseBits(reverseBits(170));
}
}
Output:
Input :10000000000000000000000000000000
Reverse :1111111111111111111111111111111
Input :1111111111111111111111111111111
Reverse :10000000000000000000000000000000
Input :10101010
Reverse :11111111111111111111111101010101
Input :11111111111111111111111101010101
Reverse :10101010
return Integer.reverse(given);
Integer.reverse Reference
I've got this loop that is run thousands of times (so needs to be efficient). It changes the value of the bitmap pixel.
I want to be able to run thought the loop and "switch" a certain group of pixels to alpha and then switch them back at a later point.
My question is.
How do I switch the values? So say 0xFFCC1BE0 becomes 0x00CC1BE0 and then if I want to switch back to 0xFFCC1BE0 I simply take the 00 and turn it too FF.
I can't make two bitmaps as I run out of memory :-(
Anyhow here's what I've got so far:
private void setTransparencyOnLightMap(float WidthPercentage, float LeftPosition)
{
int blankPixel = 0x00000000;
int savedPixel = 0x00000000;
int desiredAlpha = 200; //Can also be 0x00
//Find away of turning alhpa off and on.
for(int BMx = 0; BMx < mLightMap.getWidth(); BMx++)
{
for(int BMy = 0; BMy < mLightMap.getHeight(); BMy++)
{
if(mLightMap.getPixel(BMx, BMy) != blankPixel) //Make sure don't overwrite blank transparent pixels.
{
savedPixel = mLightMap.getPixel(BMx,BMy);
savedPixel = savedPixel | (desiredAlpha << 24);
mLightMap.setPixel(BMx, BMy, savedPixel);
}
}
}
}
You could switch the alpha of a pixel like so:
savedPixel = savedPixel & 0x00FFFFFF;
savedPixel = savedPixel | (desiredAlpha << 24);
The first line zeros out the 8 most significant bits of savedPixel (these are the bits where the alpha is held). The second line sets the 8 most significant bits of savedPixel to desiredAlpha. Note that desiredAlpha must be between 0 and 255 (These are the ints that can be stored in 8 bits).
Note that this uses bitwise operators, (&, |, <<) which are very efficient.
It seems to me, to reduce memory use, you can just save the original Alpha value of each pixel rather than the whole ARGB value - to do this use a byte array which will be 1/4 the size of the original bitmap. Also use a bit-mask for the new Alpha so you can use bitwise AND (&) as described by Tristan Hull...
byte[] savedAlphaArray = new byte[mLightMap.getWidth(), mLightMap.getHeight()];
int desiredAlphaMask = 0x00FFFFFF;
int pixel;
Then to save the Alpha values and apply the bit-mask do the following...
for (int i = 0; i < mLightMap.getWidth(); i++) {
for (int j = 0; j < mLightMap.getHeight(); j++) {
pixel = mLightMap.getPixel(i, j);
savedAlphaArray[i, j] = (pixel & 0xFF000000) >> 24;
mLightMap.setPixel(i, j, desiredAlphaMask & pixel);
}
}
To 'switch' back do the following...
for (int i = 0; i < mLightMap.getWidth(); i++) {
for (int j = 0; j < mLightMap.getHeight(); j++) {
pixel = mLightMap.getPixel(i, j);
mLightMap.setPixel(i, j, savedAlphaArray[i, j] << 24 & pixel);
}
}
Alright, so I am working on creating an Android audio visualization app. The problem is, what I get form the method getFft() doesn't jive with what google says it should produce. I traced the source code all the way back to C++, but I am not familiar enough with C++ or FFT to actually understand what is happening.
I will try and include everything needed here:
(Java) Visualizer.getFft(byte[] fft)
/**
* Returns a frequency capture of currently playing audio content. The capture is a 8-bit
* magnitude FFT. Note that the size of the FFT is half of the specified capture size but both
* sides of the spectrum are returned yielding in a number of bytes equal to the capture size.
* {#see #getCaptureSize()}.
* <p>This method must be called when the Visualizer is enabled.
* #param fft array of bytes where the FFT should be returned
* #return {#link #SUCCESS} in case of success,
* {#link #ERROR_NO_MEMORY}, {#link #ERROR_INVALID_OPERATION} or {#link #ERROR_DEAD_OBJECT}
* in case of failure.
* #throws IllegalStateException
*/
public int getFft(byte[] fft)
throws IllegalStateException {
synchronized (mStateLock) {
if (mState != STATE_ENABLED) {
throw(new IllegalStateException("getFft() called in wrong state: "+mState));
}
return native_getFft(fft);
}
}
(C++) Visualizer.getFft(uint8_t *fft)
status_t Visualizer::getFft(uint8_t *fft)
{
if (fft == NULL) {
return BAD_VALUE;
}
if (mCaptureSize == 0) {
return NO_INIT;
}
status_t status = NO_ERROR;
if (mEnabled) {
uint8_t buf[mCaptureSize];
status = getWaveForm(buf);
if (status == NO_ERROR) {
status = doFft(fft, buf);
}
} else {
memset(fft, 0, mCaptureSize);
}
return status;
}
(C++) Visualizer.doFft(uint8_t *fft, uint8_t *waveform)
status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
{
int32_t workspace[mCaptureSize >> 1];
int32_t nonzero = 0;
for (uint32_t i = 0; i < mCaptureSize; i += 2) {
workspace[i >> 1] = (waveform[i] ^ 0x80) << 23;
workspace[i >> 1] |= (waveform[i + 1] ^ 0x80) << 7;
nonzero |= workspace[i >> 1];
}
if (nonzero) {
fixed_fft_real(mCaptureSize >> 1, workspace);
}
for (uint32_t i = 0; i < mCaptureSize; i += 2) {
fft[i] = workspace[i >> 1] >> 23;
fft[i + 1] = workspace[i >> 1] >> 7;
}
return NO_ERROR;
}
(C++) fixedfft.fixed_fft_real(int n, int32_t *v)
void fixed_fft_real(int n, int32_t *v)
{
int scale = LOG_FFT_SIZE, m = n >> 1, i;
fixed_fft(n, v);
for (i = 1; i <= n; i <<= 1, --scale);
v[0] = mult(~v[0], 0x80008000);
v[m] = half(v[m]);
for (i = 1; i < n >> 1; ++i) {
int32_t x = half(v[i]);
int32_t z = half(v[n - i]);
int32_t y = z - (x ^ 0xFFFF);
x = half(x + (z ^ 0xFFFF));
y = mult(y, twiddle[i << scale]);
v[i] = x - y;
v[n - i] = (x + y) ^ 0xFFFF;
}
}
(C++) fixedfft.fixed_fft(int n, int32_t *v)
void fixed_fft(int n, int32_t *v)
{
int scale = LOG_FFT_SIZE, i, p, r;
for (r = 0, i = 1; i < n; ++i) {
for (p = n; !(p & r); p >>= 1, r ^= p);
if (i < r) {
int32_t t = v[i];
v[i] = v[r];
v[r] = t;
}
}
for (p = 1; p < n; p <<= 1) {
--scale;
for (i = 0; i < n; i += p << 1) {
int32_t x = half(v[i]);
int32_t y = half(v[i + p]);
v[i] = x + y;
v[i + p] = x - y;
}
for (r = 1; r < p; ++r) {
int32_t w = MAX_FFT_SIZE / 4 - (r << scale);
i = w >> 31;
w = twiddle[(w ^ i) - i] ^ (i << 16);
for (i = r; i < n; i += p << 1) {
int32_t x = half(v[i]);
int32_t y = mult(w, v[i + p]);
v[i] = x - y;
v[i + p] = x + y;
}
}
}
}
If you made it through all that, you are awesome! So my issue, is when I call the java method getFft() I end up with negative values, which shouldn't exist if the returned array is meant to represent magnitude. So my question is, what do I need to do to make the array represent magnitude?
EDIT: It appears my data may actually be the Fourier coefficients. I was poking around the web and found this. The applet "Start Function FFT" displays a graphed representation of coefficients and it is a spitting image of what happens when I graph the data from getFft(). So new question: Is this what my data is? and if so, how do I go from the coefficients to a spectral analysis of it?
An FFT doesn't just produce magnitude; it produces phase as well (the output for each sample is a complex number). If you want magnitude, then you need to explicitly calculate it for each output sample, as re*re + im*im, where re and im are the real and imaginary components of each complex number, respectively.
Unfortunately, I can't see anywhere in your code where you're working with complex numbers, so perhaps some rewrite is required.
UPDATE
If I had to guess (after glancing at the code), I'd say that real components were at even indices, and odd components were at odd indices. So to get magnitudes, you'd need to do something like:
uint32_t mag[N/2];
for (int i = 0; i < N/2; i++)
{
mag[i] = fft[2*i]*fft[2*i] + fft[2*i+1]*fft[2*i+1];
}
One possible explanation why you see negative values: byte is a signed data type in Java. All values, that are greater or equal 1000 00002 are interpreted as negative integers.
If we know that all values should are expected to be in the range [0..255], then we have map the values to a larger type and filter the upper bits:
byte signedByte = 0xff; // = -1
short unsignedByte = ((short) signedByte) & 0xff; // = 255
"The capture is a 8-bit magnitude FFT" probably means that the return values have an 8-bit magnitude, not that they are magnitudes themselves.
According to Jason
For real-valued signals, like the ones
you have in audio processing, the
negative frequency output will be a
mirror image of the positive
frequencies.
Android 2.3 Visualizer - Trouble understanding getFft()