drawing in canvas using canvas width and height - android

I'm trying to draw 3 rows of barrels with 4 barrels each row. In order for it to fit all screens I'm using canvas' height and width. this is my code:
int width = canvas.getWidth();
int height=canvas.getHeight();
int x = 20, y = 20, count = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
canvas.drawBitmap(BarrelSprite, width*(x/100), height*(y/100), null);
rect[count] = new Rect( width*(x/100), height*(y/100), width*(x/100) + BarrelSprite.getWidth(), height*(y/100) + BarrelSprite.getHeight());
count++;
x += 20;
}
y += 20;
x = 20;
when I run it all the barrels seems to stack at the top left corner for some reason. I wanted to draw every barrel's X in the first 20% of the screen, 40%,60% etc. same for Y value.

found the mistake, height was int variable and dividing it by 100 making it 0 so I multiply by 0 all the the time hence making all the barrels fit the 0,0 coordinates

Related

How to get X and Y of detected circles?

I want to extract circles in and Image, So I extract them with below code:
Mat circles = new Mat();
Imgproc.HoughCircles(adaptiveThresh, circles, Imgproc.HOUGH_GRADIENT, 1.0, (double) adaptiveThresh.rows() / 40, 100.0, 30.0, 20, 30);
And then I iterate through them with below code:
for (int x = 0; x < circles.cols(); x++) {
double[] c = circles.get(0, x);
Point center = new Point(Math.round(c[0]), Math.round(c[1]));
int radius = (int) Math.round(c[2]);
Imgproc.circle(source, center, radius, new Scalar(0, 0, 255), 3);
}
But I want to sort them from topleft to bottom right, And the problem is I can not access the x and y of the circles!
How may I sort them based on row from top left to bottom right?
Your question is can be confusing. As it can be (1) sort distance to the circle to the top left of the image. (2)sort the distance from top left of each circle to top left of the image corner?
I assume you want to find the circle which is most close to top left case (1).
Here is my response.
From the C++ sample( i guess you are using android, not very familiar). You can convert using my sample code below.
for( size_t i = 0; i < circles.size(); i++ )
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
// circle center
circle( src, center, 3, Scalar(0,255,0), -1, 8, 0 );
// circle outline
circle( src, center, radius, Scalar(0,0,255), 3, 8, 0 );
}
the center should be the point you want.
To sort them from top left to bottom right using city block distance you just have to
void sort_points (std::vector<Vec3f> &array)
{
std::cout<<"Elements in the array: "<<array.size()<<std::endl;
//comparisons will be done n times
for (int i = 0; i < array.size(); i++)
{
//compare elemet to the next element, and swap if condition is true
for(int j = 0; j < array.size() - 1; j++)
{
if ((array[j][0]+array[j][1]) > (array[j+1][0]+ array[j+1][1])
Swap(&array[j], &array[j+1]);
}
}
}
int main(argc,argv)
// ...................//do your stuff
vector<Vec3f> circles; //detected circle
// ... //do the detection
sort_points(circles);
//circles here is fully sorted from city block distance
std::cout<<circles<<std::endl; // print out all sorted circile
// ...................//do your stuff
}
if it is 2nd case just change if by
if ((array[j][0]+array[j][1]-2*array[j][2]) > (array[j+1][0]+ array[j+1][1]-2*array[j+1][2])
Here is what you need to do:
First, declare a Circle class (for encapsulation the circle properties for sorting purpose)
class Circle {
int cX;
int cY;
int radius;
double distance;
}
Now iterate over the HoughCircles result, and create a Circle instance and then add it to the List
List<Circle> circleList = new ArrayList<>();
//start point, it is used to calculate the distance
Point p1 = new Point(0, 0);
for (int x = 0; x < circles.cols(); x++) {
double[] c = circles.get(0, x);
Point center = new Point(Math.round(c[0]), Math.round(c[1]));
int radius = (int) Math.round(c[2]);
Imgproc.circle(source, center, radius, new Scalar(0, 0, 255), 3);
// here create the Circle instance
Circle circle = new Circle();
cricle.cX = center.x;
circle.cY = center.y;
circle.radius= radius;
double D = Math.sqrt(Math.pow(abs(p1.x - circles.x), 2) + Math.pow(abs(p1.y - circles.y), 2));
circle.distance = D;
// add the circle instance to the list
circleList.add(circle);
}
Now sort the circles in the list, use distance from small to bigger
circleList.sort(new Comparator<File>() {
#Override
public int compare(Circle c1, Circle c2) {
return Double.compare(c1.distance, c2.distance);
}
});
Now you can do what you want with circles list.
Hope it helps!!

How to efficiently get and set bitmap pixels

I am currently making an app that involves altering the RGB values of pixels in a bitmap and creating a new bitmap after.
My problem is I need help increasing speed of this process. (It can take minutes to process a bitmap with inSampleSize = 2 and forever to process an inSampleSize = 1) Right now, I am using the getPixel and setPixel methods to alter the pixels and believe these two methods are the root of the problem as they are very inefficient. The getPixels method isn't suitable as I am not altering each pixel in order (ex. getting a pixel and changing a radius of 5 pixels around it to the same colour) unless anyone knows of a way to use getPixels (perhaps be able to put the pixels in a 2D array).
This is part of my code:
public static final alteredBitmp(Bitmap bp)
{
//initialize variables
// ..................
Bitmap bitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
for (int x = 0; x < width; x++) {
int left = Math.max(0, x - RADIUS);
int right = Math.min(x + RADIUS, width - 1);
for (int y = 0; y < height; ++y) {
int top = Math.max(0, y - RADIUS);
int bottom = Math.min(y + RADIUS, height - 1);
int maxIndex = -1;
for (int j = top; j <= bottom; j++) {
for (int i = left; i <= right; i++) {
pixelColor = bitmap.getPixel(i, j);
//get rgb values
//make changes to those values
}
}
}
}
//set new rgb values
bitmap.setPixel(x, y, Color.rgb(r, g, b));
//return new bitmap
Much thanks in advance!
Consider looking at RenderScript, which is Android's high performance compute framework. As you are iterating over width x height number of pixels and altering each one which in a modern device could be around a million pixels or higher, doing it in a single thread can take minutes. RenderScript can parallelize operations over CPU or the GPU where possible.
http://android-developers.blogspot.com/2012/01/levels-in-renderscript.html
http://developer.android.com/guide/topics/renderscript/index.html
Google IO 2013 session:
https://youtu.be/uzBw6AWCBpU
RenderScript compatibility library: http://android-developers.blogspot.com/2013/09/renderscript-in-android-support-library.html

Drawing a Moving Grid on Android Canvas?

Is it possible to create and draw a Moving Grid on a canvas that recycles its points? I want to create a Grid on an android canvas that moves downwards and recycles its points when a point reaches the bottom of the screen.
The First part of the question is: How do I draw a grid with lines on an Android Canvas?
The Second part: How do I make it scroll and repeat?
The grid should look something like this:
I have tried doing this with a Bitmap , but I am not sure if that is as efficient as doing it By using the Draw Line feature. Plus, I cannot access the girds points when using a bitmap, so it is not very useful when trying to draw a graph for example.
I am developing a drawing app, and I encountered the same problem. I searched everywhere, but I could not found a direct solution. That is why I developed a library that do exactly that. It creates a infinite grid that can be transformed, include transformations are: Translate, Rotate and Scale. The library generates only the visible lines, that are shown on the View and are generated in real time using simple math. Here is a direct link to the library
The explanation is pretty simple, if you want to learn more about how it works your can check the Wiki page.
Here is a link to the library source code, if you are interested.
To tag onto Balha's answer:
the android/java equivalent looks something like this:
int canvasWidth = 0;
int canvasHeight = 0;
float gridSize = 20f;
float ecart = Math.max(mCanvasHeight, mCanvasWidth) / gridSize;
//last j index value
int lj= 0;
//last i index value
int li = 0;
canvasWidth = canvas.getWidth();
canvasHeight = canvas.getHeight();
for (int j = 0; j <= Math.min(canvasWidth, canvasHeight); j += (int)ecart)
{
for (int i = 0; i <= Math.max(canvasWidth, canvasHeight); i += (int)ecart)
{
li = i;
}
lj = j;
}
canvas.clipRect(0, 0, lj, canvas.getHeight());
for (int j = 0; j <= Math.min(canvasWidth, canvasHeight); j += (int)ecart)
{
for (int i = 0; i <= Math.max(canvasWidth, canvasHeight); i += (int)ecart)
{
//horizontal lines
canvas.drawLine(j, i, i, i, paint);
//vertical lines
canvas.drawLine(j, i, j, j, paint);
}
}
I know its too late but It can help someone else;
This Draws a perfect grid mesh
Note: This is a c# code
float gridSize = 20f;
var ecart = Math.Max(MaxHeight, MaxWidth) / gridSize;
//last j index value
int lj= 0;
//last i index value
int li = 0;
for (int j = 0; j <= Math.Min(canvas.Width, canvas.Height); j += (int)ecart)
{
for (int i = 0; i <= Math.Max(canvas.Width, canvas.Height); i += (int)ecart)
{
li = i;
}
lj = j;
}
canvas.ClipRect(0, 0, lj, canvas.Height);
for (int j = 0; j <= Math.Min(canvas.Width, canvas.Height); j += (int)ecart)
{
for (int i = 0; i <= Math.Max(canvas.Width, canvas.Height); i += (int)ecart)
{
//horizontal lines
canvas.DrawLine(j, i, i, i, paint);
//vertical lines
canvas.DrawLine(j, i, j, j, paint);
}
}

Trying to draw grid ends up in drawing long rectangle

I'd like to draw a grid. Therefore I've got
private int GRID_WIDTH = 6; <----Amount of columns
private int GRID_HEIGHT = 6; <----Amount of rows
private int GRID_SIZE; = 50 <----Width and height of a cell
Now I am trying to draw them:
for(int i = 0; i < GRID_WIDTH; i++) {
for(int j = 0; j < GRID_HEIGHT; j++) {
canvas.drawRect(new Rect(i*GRID_SIZE + 5, j*GRID_SIZE + 5, GRID_SIZE, GRID_SIZE), paint);
}
}
The "5" after each coordinate should make a gap between two rectangles.
This should end up in some nice grid, but as result I see multiple rectangles pushed together, without these 5px padding between them. No matter what I choose as padding, It resuls in following image: (Here the padding is set to 20 instead of 5...)
What am i doing wrong?
Thanks in advance!
Consider that the Rect constructor signature is:
Rect(int left, int top, int right, int bottom)
and you're doing like:
Rect(int left, int top, int width, int height)
Notice the difference in the last two arguments. You must do like this:
int left = i * (GRID_SIZE + 5);
int top = j * (GRID_SIZE + 5);
int right = left + GRID_SIZE;
int bottom = top + GRID_SIZE;
canvas.drawRect(new Rect(left, top, right, bottom), paint);

onDraw() triggered but results don't show

I have the following routine in a subclass of view:
It calculates an array of points that make up a line, then erases the previous lines, then draws the new lines (impact refers to the width in pixels drawn with multiple lines). The line is your basic bell curve, squeezed or stretched by variance and x-factor.
Unfortunately, nothing shows on the screen. A previous version with drawPoint() and no array worked, and I've verified the array contents are being loaded correctly, and I can see that my onDraw() is being triggered.
Any ideas why it might not be drawn? Thanks in advance!
protected void drawNewLine( int maxx, int maxy, Canvas canvas, int impact, double variance, double xFactor, int color) {
// impact = 2 to 8; xFactor between 4 and 20; variance between 0.2 and 5
double x = 0;
double y = 0;
int cx = maxx / 2;
int cy = maxy / 2;
int mu = cx;
int index = 0;
points[maxx<<1][1] = points[maxx<<1][0];
for (x = 0; x < maxx; x++) {
points[index][1] = points[index][0];
points[index][0] = (float) x;
Log.i(DEBUG_TAG, "x: " + x);
index++;
double root = 1.0 / (Math.sqrt(2 * Math.PI * variance));
double exponent = -1.0 * (Math.pow(((x - mu)/maxx*xFactor), 2) / (2 * variance));
double ePow = Math.exp(exponent);
y = Math.round(cy * root * ePow);
points[index][1] = points[index][0];
points[index][0] = (float) (maxy - y - OFFSET);
index++;
}
points[maxx<<1][0] = (float) impact;
for (int line = 0; line < points[maxx<<1][1]; line++) {
for (int pt = 0; pt < (maxx<<1); pt++) {
pointsToPaint[pt] = points[pt][1];
}
for (int skip = 1; skip < (maxx<<1); skip = skip + 2)
pointsToPaint[skip] = pointsToPaint[skip] + line;
myLinePaint.setColor(Color.BLACK);
canvas.drawLines(pointsToPaint, bLinePaint); // draw over old lines w/blk
}
for (int line = 0; line < points[maxx<<1][0]; line++) {
for (int pt = 0; pt < maxx<<1; pt++) {
pointsToPaint[pt] = points[pt][0];
}
for (int skip = 1; skip < maxx<<1; skip = skip + 2)
pointsToPaint[skip] = pointsToPaint[skip] + line;
myLinePaint.setColor(color);
canvas.drawLines(pointsToPaint, myLinePaint); / new color
}
}
update: Replaced the drawLines() with drawPoint() in loop, still no joy
for (int p = 0; p<pointsToPaint.length; p = p + 2) {
Log.i(DEBUG_TAG, "x " + pointsToPaint[p] + " y " + pointsToPaint[p+1]);
canvas.drawPoint(pointsToPaint[p], pointsToPaint[p+1], myLinePaint);
}
/// canvas.drawLines(pointsToPaint, myLinePaint);
I was attempting to write from within onCreate() and onStart(). The View and its Canvas are never actually rendered for the first time until the end of onStart().
aren't you suppose to call invalidate (like a mapview) to force the view to reload?
YourView.invalidate() (or maybe postInvalidate(), depending where you are : main sthread or not)
here is the detail

Categories

Resources