Android int/double calculation randomly overflow - android

int n1 = 65535;
int n2 = 1659;
int fs1 = 144000;
int fs2 = 7056000;
int dfrq = 44100;
int delay = (int) ((double) n1 / 2 / ((double) fs1 / dfrq) + (double) n2 / 2 / ((double) fs2 / dfrq));
The above calculation result give me randomly values, sometimes it's correct delay= 10040, but sometimes the delay= 2147483647, which is 0b1111111111111111111111111111111 in binary, it's overflow.
The problem is why on android, this calculation gives two different results, and randomly.
My temp solution is:
double s1 = 1f * n1 / 2;
double s2 = 1f * fs1 / dfrq;
double s3 = 1f * n2 / 2;
double s4 = 1f * fs2 / dfrq;
L.d(TAG, "s1:" + s1 + " s2:" + s2 + " s3:" + s3 + " s4:" + s4);
int delay = (int) (s1 / s2 + s3 / s4);

Related

Crop YUV byte[] based on a rectangle without any convertion

I have tried to use the logic and pictorial representation from this SO. I am though confused with the images since one of them follow 4:1:1 whereas the later one does 4:2:2 nomenclature for YUV image (NV21).
Right now the issue is that i get an image (converted to Bitmap/PNG) with YUV component all over, essentially an unusable image.
Any recommendation to fix this?
private byte[] cropImage(byte[] data, Rect cropRect) {
int dataHeight = 480;
int dataWidth = 640;
int totalWH = dataWidth * dataHeight;
// make rect points even, currently the width & height is even number
// adjust x coordinates to make them
if (cropRect.left % 2 != 0 || cropRect.right % 2 != 0) {
cropRect.left -= 1;
cropRect.right -= 1;
}
// adjust y coordinates to make them even
if (cropRect.top % 2 != 0 || cropRect.bottom % 2 != 0) {
cropRect.top -= 1;
cropRect.bottom -= 1;
}
int area = cropRect.width() * cropRect.height() * 3/2;
Logger.getLogger().d("Size of byte array " + data.length + " Size of alloc area " + area);
byte[] pixels = new byte[area];//the size of the array is the dimensions of the sub-photo
// size.total = size.width * size.height;
// y = yuv[position.y * size.width + position.x];
// u = yuv[(position.y / 2) * (size.width / 2) + (position.x / 2) + size.total];
// v = yuv[(position.y / 2) * (size.width / 2) + (position.x / 2) + size.total + (size.total / 4)];
try {
// copy Y plane first
int srcOffset = cropRect.top * dataWidth;
int destOffset = 0;
int lengthToCopy = cropRect.width();
int y = 0;
for (; y < cropRect.height(); y++, srcOffset += dataWidth, destOffset += cropRect.width()) {
// Logger.getLogger().d("IO " + srcOffset + cropRect.left + " oO " + destOffset + " LTC " + lengthToCopy);
System.arraycopy(data, srcOffset + cropRect.left, pixels, destOffset, lengthToCopy);
}
Logger.getLogger().d("Completed Y copy");
// U and V components are not-interleaved, hence their size is just 1/4th the original size
// copy U plane
int nonYPlanerHeight = dataHeight / 4;
int nonYPlanerWidth = dataWidth / 4;
srcOffset = totalWH + (cropRect.top / 4 * nonYPlanerWidth);
for (y = 0; y < cropRect.height();
y++, srcOffset += nonYPlanerWidth, destOffset += cropRect.width() / 4) {
System.arraycopy(data, srcOffset + cropRect.left / 4, pixels, destOffset, cropRect.width() / 4);
}
Logger.getLogger().d("Completed U copy " + y + " destOffset=" + destOffset);
// copy V plane
srcOffset = totalWH + totalWH / 4 + (cropRect.top / 4 * nonYPlanerWidth);
for (y = 0; y < cropRect.height();
y++, srcOffset += nonYPlanerWidth, destOffset += cropRect.width() / 4) {
System.arraycopy(data, srcOffset + cropRect.left / 4, pixels, destOffset, cropRect.width() / 4);
}
Logger.getLogger().d("Completed V copy " + y + " destOffset=" + destOffset);
} catch (ArrayIndexOutOfBoundsException ae) {
// do nothing
Logger.getLogger().e("Exception " + ae.getLocalizedMessage());
}
return pixels;
}

How to fix a memory leak in Android regarding array of arrays?

I've created an application that takes an image captured by the Android device, displays this image in the ImageView. The user can then press a button to either blur or deblur the image. When I run the application on my Android device I can take an image with the camera and display this without any problems. A problem occurs when I press the blur button, which runs some code to blur the image. The application becomes frozen and I get an OutOfMemoryException for a line of my code that creates a new array and stores this in another array in a nested for loop.
This is the code for the nested for loop:
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int xTranslated = (x + width / 2) % width;
int yTranslated = (y + height / 2) % height;
double real = temp[2 * (xTranslated + yTranslated * width)];
double imaginary = temp[2 * (xTranslated + yTranslated * width) + 1];
degradation[2 * (x + y * width)] = real;
degradation[2 * (x + y * width) + 1] = imaginary;
Complex c = new Complex(real, imaginary);
complex[y * width + x] = c;
}
}
This nested for loop deals with data extracted from the input image, which is stored as a Bitmap.
Here is the full method that applies the motion blur:
public Complex[] motionBlur(double[] degradation, int width, int height, double alpha, double gamma, double sigma) {
Complex[] complex = new Complex[width * height];
double[] temp = new double[2 * width * height];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
double teta = Math.PI * ( (((x - width/2) % width) * gamma) + ((((y - height/2) % height) * sigma) ));
Sinc sinc = new Sinc();
double real = (Math.cos(teta) * sinc.value(teta)) * alpha;
double imaginary = (Math.sin(teta) * sinc.value(teta)) * alpha;
Complex cConj = new Complex(real, imaginary).conjugate();
temp[2 * (x + y * width)] = cConj.getReal();
temp[2 * (x + y * width) + 1] = cConj.getImaginary();
}
}
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int xTranslated = (x + width / 2) % width;
int yTranslated = (y + height / 2) % height;
double real = temp[2 * (xTranslated + yTranslated * width)];
double imaginary = temp[2 * (xTranslated + yTranslated * width) + 1];
degradation[2 * (x + y * width)] = real;
degradation[2 * (x + y * width) + 1] = imaginary;
Complex c = new Complex(real, imaginary);
complex[y * width + x] = c;
}
}
return complex;
}
Here is a link to what is being output by the logcat when I try to run the application: http://pastebin.com/ysbN9A3s
MainActivity.java:373 corresponds to the line,
Complex c = new Complex(real, imaginary);
Here is nice talk about android crashes.
Pierre-Yves talks about OOM (OutOfMemory error) at the time 11:39. So the problem in OOM is not place where OOM happens. You should profile your app to find the place where most memory is consumed. I should admit that OOM is one of the hardest error to resolve.
Good luck!

Algorithm to draw arrowhead at the end of arbitrary line in an Android custom View

I've been trying to come up with an algorithm to draw an arrow in a custom View, using Path, but I haven't figured out how to get the coordinates of the arrowhead tips. The line startpoint and endpoint coordinates are arbitrary, the angle of the arrowhead relative to the line and the length of the arrowhead are fixed.
I think I have to use trigonometry somehow, but I'm not sure how.
My friend came up with a math equation, which I have translated into java code here:
public static void calculateArrowHead(Point start, Point end, double angleInDeg, double tipLength){
double x1 = end.getX();
double x2 = start.getX();
double y1 = end.getY();
double y2 = start.getY();
double alpha = Math.toRadians(angleInDeg);
double l1 = Math.sqrt(Math.pow(x2-x1, 2) + Math.pow(y2-y1, 2)); // length of the arrow line
double l2 = tipLength;
double a = Math.pow(y2-y1, 2) + Math.pow(x2-x1, 2);
double b = -2 * l1 * l2 * Math.cos(alpha) * (y2 - y1);
double c = Math.pow(l1, 2) * Math.pow(l2, 2) * Math.pow(Math.cos(alpha), 2) - Math.pow(l2, 2) * Math.pow(x2-x1, 2);
double s2a = (-b + Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
double s2b = (-b - Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
double s1a = (l1 * l2 * Math.cos(alpha) - s2a * (y2 - y1)) / (x2-x1);
double s1b = (l1 * l2 * Math.cos(alpha) - s2b * (y2 - y1)) / (x2-x1);
double x3a = s1a + x1;
double y3a = s2a + y1;
double x3b = s1b + x1;
double y3b = s2b + y1;
System.out.println("(A) x:" + (int)x3a + "; y:" + (int)y3a);
System.out.println("(B) x:" + (int)x3b + "; y:" + (int)y3b);
}
I haven't tested it thoroughly, but for the first few tests, it appears to be correct.

Google Map API making lines smoother when bending

I am using Google Map API to get lines on the map in my application. I am loading the nodes of the lines from a database using following code:
// Add polyline "walks voda"
List<WalkLine> dbwalknodes = dbclass.queryWalksFromDatabase(this); // list of latlng
for (int i = 0; i < dbwalknodes.size() - 1 ; i++) {
WalkLine source = dbwalknodes.get(i);
WalkLine destination = dbwalknodes.get(i+1);
Polyline line = mMap.addPolyline(new PolylineOptions()
.add(new LatLng(source.getLat(), source.getLon()),
new LatLng(destination.getLat(), destination.getLon()))
.width(16)
.color(Color.parseColor("#1b9e77"))
.geodesic(true));
line.setZIndex(1000);
}
Do you have any idea how to create the lines smoother while it bends than on the picture bellow? Is it possible?
https://www.dropbox.com/s/6waic988mj90kdk/2014-10-22%2012.48.04.png?dl=0
You should not create a polyline for each two points, it should be a connected polyline with mulitple points, something like this:
public void drawRoute(List<LatLng> location) {
polylineOptions = new PolylineOptions().width(MAPS_PATH_WIDTH).color(routeColor).addAll(location);
polyLine = map.addPolyline(destinationRoutePolyLineOptions);
polyLine.setPoints(location);
}
This will make it much smoother.
Use the following code based on bSpline algorithm, it worked for me on Android.
public List<LatLng> bspline(List<LatLng> poly) {
if (poly.get(0).latitude != poly.get(poly.size()-1).latitude || poly.get(0).longitude != poly.get(poly.size()-1).longitude){
poly.add(new LatLng(poly.get(0).latitude,poly.get(0).longitude));
}
else{
poly.remove(poly.size()-1);
}
poly.add(0,new LatLng(poly.get(poly.size()-1).latitude,poly.get(poly.size()-1).longitude));
poly.add(new LatLng(poly.get(1).latitude,poly.get(1).longitude));
Double[] lats = new Double[poly.size()];
Double[] lons = new Double[poly.size()];
for (int i=0;i<poly.size();i++){
lats[i] = poly.get(i).latitude;
lons[i] = poly.get(i).longitude;
}
double ax, ay, bx, by, cx, cy, dx, dy, lat, lon;
float t;
int i;
List<LatLng> points = new ArrayList<>();
// For every point
for (i = 2; i < lats.length - 2; i++) {
for (t = 0; t < 1; t += 0.2) {
ax = (-lats[i - 2] + 3 * lats[i - 1] - 3 * lats[i] + lats[i + 1]) / 6;
ay = (-lons[i - 2] + 3 * lons[i - 1] - 3 * lons[i] + lons[i + 1]) / 6;
bx = (lats[i - 2] - 2 * lats[i - 1] + lats[i]) / 2;
by = (lons[i - 2] - 2 * lons[i - 1] + lons[i]) / 2;
cx = (-lats[i - 2] + lats[i]) / 2;
cy = (-lons[i - 2] + lons[i]) / 2;
dx = (lats[i - 2] + 4 * lats[i - 1] + lats[i]) / 6;
dy = (lons[i - 2] + 4 * lons[i - 1] + lons[i]) / 6;
lat = ax * Math.pow(t + 0.1, 3) + bx * Math.pow(t + 0.1, 2) + cx * (t + 0.1) + dx;
lon = ay * Math.pow(t + 0.1, 3) + by * Math.pow(t + 0.1, 2) + cy * (t + 0.1) + dy;
points.add(new LatLng(lat, lon));
}
}
return points;
}

How to compute the zoom level against returned markers?

I'd like to know if there is already a way to know from a given set of markers, the zoom I should apply to the map or do I have to do it my self? (This depends on the resolution so i expected to find it in MapView because it knows its boundaries.)
int minLat = Integer.MAX_VALUE;
int minLong = Integer.MAX_VALUE;
int maxLat = Integer.MIN_VALUE;
int maxLong = Integer.MIN_VALUE;
for( GeoPoint l : points ) {
minLat = Math.min( l.getLatitudeE6(), minLat );
minLong = Math.min( l.getLongitudeE6(), minLong);
maxLat = Math.max( l.getLatitudeE6(), maxLat );
maxLong = Math.max( l.getLongitudeE6(), maxLong );
}
mapView.getController().zoomToSpan(Math.abs( minLat - maxLat ), Math.abs( minLong - maxLong ));
I've attempted to do a method my self, it doesn't work perfectly but it seems sufficient (maybe I should round the quotient up to have the real value):
private void adjustZoomToMarkers(ArrayList<GeoLocationFlag> flags) {
GeoPoint mapCenter = mapView.getMapCenter();
int lat = mapCenter.getLatitudeE6(), lng = mapCenter.getLongitudeE6();
int farestLat = 0, farestLng = 0;
for (GeoLocationFlag geoLocationFlag : flags) {
Log.d(LOG_TAG, "lat: " + geoLocationFlag.getLat());
int flagLatDistance = Math.abs(geoLocationFlag.getLat() - lat);
if (farestLat < flagLatDistance)
farestLat = flagLatDistance;
Log.d(LOG_TAG, "lng: " + geoLocationFlag.getLng());
int flagLngDistance = Math.abs(geoLocationFlag.getLng() - lng);
if (farestLng < flagLngDistance)
farestLng = flagLngDistance;
}
Log.d(LOG_TAG, "farest: " + farestLat + "," + farestLng);
Log.d(LOG_TAG, "spans: " + mapView.getLatitudeSpan() + "," + mapView.getLongitudeSpan());
// compute how many times this screen we are far on lat
float latQuotient = (float) farestLat / ((float) mapView.getLatitudeSpan() / 2);
// compute how many times this screen we are far on lng
float lngQuotient = (float) farestLng / ((float) mapView.getLongitudeSpan() / 2);
int zoom = 0;
if (latQuotient > 1 || lngQuotient > 1) {
// must zoom out
float qutient = Math.max((int) latQuotient, (int) lngQuotient);
while ((qutient / 2) > 1) {
qutient = qutient / 2;
zoom--;
}
} else {
float qutient = Math.max((int) (1 / (float) latQuotient), (int) (1 / (float) lngQuotient));
while ((qutient / 2) > 1) {
qutient = qutient / 2;
zoom++;
}
}
Log.d(LOG_TAG, "Zoom found " + zoom);
int zoomLevel = mapView.getZoomLevel();
mapController.setZoom(zoomLevel + zoom);
}
Best regards,
Zied Hamdi
I like your code that is a lot shorter ;-), maybe I should only avoid creating new instances in the for loop to have the min and max points...
Best Regards,
Zied Hamdi
As guessed when I was writing the answer above: when the quotient is eg. 9, it means you need more than 4 iterations to see it:
so just correst both lines:
while ((qutient / 2) > 0.5) {
Best Regards,
Zied Hamdi

Categories

Resources