BoofCV polygon drawing equivalent for Android - android

https://boofcv.org/index.php?title=Example_Fit_Polygon
This link above gives does some image detection, and provides good example but it is not for android which is what I need. What I'm really stuck on right now is there any equivalent for this
VisualizeShapes.drawPolygon(vertexes,true,g2);
in Andriod. If there is can someone help me how to draw it like on the method with those paramters. For example, the drawPolygon takes vertexes as these
List<PointIndex_I32> vertexes = ShapeFittingOps.fitPolygon(c.external,true, minSide,cornerPenalty);
and the true boolean is loop, and g2 is java.awt.Graphics2D. The documentation for VisualizeShapes are provided here:
http://boofcv.org/javadoc/boofcv/gui/feature/VisualizeShapes.html
The issue is that VisualizeShapes is giving me an error because it not a supported library for android development and I need some way to find equivalent to polygonFitting detection on android.

The Android demonstration app is a good place to start when looking for stuff like that. MiscUtil.java has something similar to what you're looking for.
public static void renderPolygon(Polygon2D_F64 s, Path path , Canvas canvas , Paint paint ) {
path.reset();
for (int j = 0; j < s.size(); j++) {
Point2D_F64 p = s.get(j);
if (j == 0)
path.moveTo((float) p.x, (float) p.y);
else
path.lineTo((float) p.x, (float) p.y);
}
Point2D_F64 p = s.get(0);
path.lineTo((float) p.x, (float) p.y);
path.close();
canvas.drawPath(path, paint);
}

Related

How to properly sidescroll a screen in android, using canvas?

Ok, I am developing a sidescrolling game and my problem is on how to properly draw and update the screen. I am drawing on a SurfaceView and I use Path to make the contourns, currently the algorithm only draws this:
And I am sidescrolling by using Path.offSet() and then canvas.drawPath(), later on I update the last X position on the path by using Path.addRect() (and thats basically how I am drawing everything: using Path.addRect())
So here is the thread that updates the screen:
#Override
public void run() {
int x = LibraryLoader.getTerrainSizeX();
int y = LibraryLoader.getTerrainSizeY();
int count = 0;
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
Path path = new Path();
makePath(path, x, y, 0, LibraryLoader.getTerrainThickness());
Path path2 = new Path();
makePath(path2, x, y, LibraryLoader.getTerrainThickness(), y);
while (run) {
Canvas c = null;
try {
c = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
fps = fps();
drawMyData(c, path, path2, paint, fps);
LibraryLoader.updateOffSet();
updatePaths(path, path2, x, y);
if ((count++) == (x / 2) - 1) {
LibraryLoader.updateOffSetArray();
count = 0;
}
}
} finally {
if (c != null) {surfaceHolder.unlockCanvasAndPost(c);}
}
}
and its respective methods:
public void updatePaths(Path path, Path path2, int x, int y) {
path.offset(-1f, 0);
path.addRect(x-3, topValue, x-2, bottomValue, Path.Direction.CW);
path2.offset(-1f, 0);
path2.addRect(x-3, topValue, x-2, y, Path.Direction.CW);
}
So, in my phone it works perfectly at 60fps, the problem is I tested in a lower end device and it begins at 40fps then drops every update until it gets below 10fps...(and keeps dropping). I guess I need to clean the state of the path, or I shouldn't even be using the Path class to begin with. So my question is how should I update the screen with the best performance? Obs: The canvas is not hardware accelerated.
Well folks I figured out that I was wrong about everything I did. The answer is simple: If your android application updates the whole screen every frame, use Opengl. Canvas is for app design for what I've seen, hope I am not mistaken. For example, if you want to make a custom animation for a LOGO or a button, so you use canvas, I guess. If anyone stumbles in this post do watch the videos Morrison Chang mentioned, they are very helpful to put you on the right track. Cheers.

Crop an image using multiple points and flexible size? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I want to make a an application like a cam scanner for cropping a document.
But I need same functionality like my two images..
First Images shown image captured by camera..
Second image recognize a captured image part like this..
I research more and more but not getting any out put so, I ask here if,any one done this tell me..
Thanks
I assume your problem is to detect the object to scan.
Object detection mechanisms like pattern matching or feature detection won't bring you the results you are looking for as you don't know what exactly is the object you are scanning.
Basically you search for a rectangular object in the picture.
A basic approach to this could be as following:
Run a canny edge detector on the image. It could help to blur the image a bit before doing this. The edges of the object should be clearly visible.
Now you want to do a Hough transform to find lines in the picture.
Search for lines with an angle around 90deg to each other. The problem would be to find the right ones. Maybe it is enough to use the lines closest to the frame of the picture that are reasonably parallel to them.
Find the intersecting points to define the edges of your object.
At least this should give you a hint where to research further.
As further steps in such an app you will have to calculate the projection of the points and do a affine transform of the object.
I hope this helps.
After writing all this i found this post. It should help you lot.
As my answer targets OpenCV you have to use the OpenCV library.
In Order to do this, you need to install the Android Native Development Kit (NDK).
There are some good tutorials on how to use OpenCV on Android on the OpenCV for Android page.
One thing to keep in mind is that almost each function of the Java wrapper calls a native method. That costs lots of time. So you want to do as much as possible in your native code before returning your results to the Java part.
I know I am too late to answer but it might be helpful to someone.
Try the following code.
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
path = new Path();
path.moveTo(x1, y1); // this should set the start point right
//path.lineTo(x1, y1); <-- this line should be drawn at the end of course,sorry
path.lineTo(x2, y2);
path.lineTo(x3, y3);
path.lineTo(x4, y4);
path.lineTo(x1, y1);
canvas.drawPath(path, currentPaint);
}
Pass your image mat in this method:
void findSquares(Mat image, List<MatOfPoint> squares) {
int N = 10;
squares.clear();
Mat smallerImg = new Mat(new Size(image.width() / 2, image.height() / 2), image.type());
Mat gray = new Mat(image.size(), image.type());
Mat gray0 = new Mat(image.size(), CvType.CV_8U);
// down-scale and upscale the image to filter out the noise
Imgproc.pyrDown(image, smallerImg, smallerImg.size());
Imgproc.pyrUp(smallerImg, image, image.size());
// find squares in every color plane of the image
Outer:
for (int c = 0; c < 3; c++) {
extractChannel(image, gray, c);
// try several threshold levels
Inner:
for (int l = 1; l < N; l++) {
Imgproc.threshold(gray, gray0, (l + 1) * 255 / N, 255, Imgproc.THRESH_BINARY);
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
// find contours and store them all as a list
Imgproc.findContours(gray0, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
MatOfPoint approx = new MatOfPoint();
// test each contour
for (int i = 0; i < contours.size(); i++) {
approx = approxPolyDP(contours.get(i), Imgproc.arcLength(new MatOfPoint2f(contours.get(i).toArray()), true) * 0.02, true);
// square contours should have 4 vertices after approximation
// relatively large area (to filter out noisy contours)
// and be convex.
// Note: absolute value of an area is used because
// area may be positive or negative - in accordance with the
// contour orientation
double area = Imgproc.contourArea(approx);
if (area > 5000) {
if (approx.toArray().length == 4 &&
Math.abs(Imgproc.contourArea(approx)) > 1000 &&
Imgproc.isContourConvex(approx)) {
double maxCosine = 0;
Rect bitmap_rect = null;
for (int j = 2; j < 5; j++) {
// find the maximum cosine of the angle between joint edges
double cosine = Math.abs(angle(approx.toArray()[j % 4], approx.toArray()[j - 2], approx.toArray()[j - 1]));
maxCosine = Math.max(maxCosine, cosine);
bitmap_rect = new Rect(approx.toArray()[j % 4], approx.toArray()[j - 2]);
}
// if cosines of all angles are small
// (all angles are ~90 degree) then write quandrange
// vertices to resultant sequence
if (maxCosine < 0.3)
squares.add(approx);
}
}
}
}
}
}
In this method you get four point of document then you can cut this image using below method:
public Bitmap warpDisplayImage(Mat inputMat) {
List<Point> newClockVisePoints = new ArrayList<>();
int resultWidth = inputMat.width();
int resultHeight = inputMat.height();
Mat startM = Converters.vector_Point2f_to_Mat(orderRectCorners(Previes method four poit list(like : List<Point> points)));
Point ocvPOut4 = new Point(0, 0);
Point ocvPOut1 = new Point(0, resultHeight);
Point ocvPOut2 = new Point(resultWidth, resultHeight);
Point ocvPOut3 = new Point(resultWidth, 0);
ocvPOut3 = new Point(0, 0);
ocvPOut4 = new Point(0, resultHeight);
ocvPOut1 = new Point(resultWidth, resultHeight);
ocvPOut2 = new Point(resultWidth, 0);
}
Mat outputMat = new Mat(resultWidth, resultHeight, CvType.CV_8UC4);
List<Point> dest = new ArrayList<Point>();
dest.add(ocvPOut3);
dest.add(ocvPOut2);
dest.add(ocvPOut1);
dest.add(ocvPOut4);
Mat endM = Converters.vector_Point2f_to_Mat(dest);
Mat perspectiveTransform = Imgproc.getPerspectiveTransform(startM, endM);
Imgproc.warpPerspective(inputMat, outputMat, perspectiveTransform, new Size(resultWidth, resultHeight), Imgproc.INTER_CUBIC);
Bitmap descBitmap = Bitmap.createBitmap(outputMat.cols(), outputMat.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(outputMat, descBitmap);
return descBitmap;
}

Android MapView overlay disappearing when zooming in

I'm working on a simple Android app for plotting routes on a map. All is going well, but I have an issue when zooming in on my Samsung Galaxy S2. It works fine on a Galaxy S3, so I'm wondering whether it's related to memory management on the lower specced device. It also works fine on the emulator.
Here is equivalent code located in the overlays onDraw method, just condensed for posting here:
Point current = new Point();
Path path = new Path();
Projection projection = mapView.getProjection();
Iterator<GeoPoint> iterator = pointList.iterator();
if (iterator.hasNext()) {
projection.toPixels(iterator.next(), current);
path.moveTo((float) current.x, (float) current.y);
} else return path;
while(iterator.hasNext()) {
projection.toPixels(iterator.next(), current);
path.lineTo((float) current.x, (float) current.y);
}
Paint roadPaint = new Paint();
roadPaint.setAntiAlias(true);
roadPaint.setStrokeWidth(8.0f);
roadPaint.setColor(Color.BLACK);
roadPaint.setStyle(Paint.Style.STROKE);
canvas.drawPath(path, roadPaint);
It's not too dissimilar to most of the sample code floating around for doing this. I'm just wondering if anyone can confirm my suspicions and advise if there is anything I can do in terms of configuration or tweaks that I can do to force drawing at all zoom levels?
Thanks in advance.
Cheers,
Nathan
The problem is that you are painting the overlay yourself for a very specific state of the mapview. You should use OverlayItem instead.
The OverlayItem is added to the MapView overlays collection, and the MapView handles all the re-drawing depending on it's own state ( zoom, location, etc )
#Override
public void draw( Canvas canvas, MapView mapView, boolean shadow )
{
super.draw( canvas, mapView, shadow );
int x1 = -1;
int y1 = -1;
int x2 = -1;
int y2 = -1;
Paint paint = new Paint();
paint.setStyle( Paint.Style.STROKE );
paint.setColor( GeoLocation.ROUTE_COLOR );
paint.setStrokeWidth( STROKE_WIDTH );
for ( int i = 0; i < mRouteGeoPoints.size(); i++ )
{
Point point = new Point();
mapView.getProjection().toPixels( geoPoints.get( i ), point );
x2 = point.x;
y2 = point.y;
if ( i > 0 )
{
canvas.drawLine( x1, y1, x2, y2, paint );
}
x1 = x2;
y1 = y2;
}
}
You said that code above was an equivalent (not the real code you are running) and that's clear because you are returning a Path object in a onDraw() which you couldn't.
The "compressed form" of code you show should work as well as using the drawLine(). So the problem should come from something else (may the original code).
Anyway, I'll give you a couple of hints:
When the top and bottom of object you are drawing to a canvas are both out of screen, the object is ignored and not drawn. Check if this is not whats happening with your path. See my answer in this post Android Map Overlay Disappears on Zoom
You don't need to rebuild the path object every time. You are probably already doing it, and that's why you made the short version above. See my answer in this post with some suggestions to improve path drawing: Overlay behavior when zooming
If for some reason you really want to use the slower approach of drawLine(), you can use the follwing to make the line look better:
paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setColor(...);
paint.setAlpha(...);
paint.setStrokeWidth(...);
Finally, if the issue remains, update your question with more relevant code and let me know. Maybe I can help further.
Regards.

canvas.drawCircle does not work - while drawLine works - might be caused by using Sherlock?

I have a strange issue with the standard method canvas.drawCircle.
While I run exactly the same code on a Samsung Galaxy S3 with Android 4.0.4 and on another S2 with 2.1 it works without problems. The same code on an Acer 500 tablet with 4.0.3 does not paint anything when calling drawCircle and drawPath.
This is the code:
Paint thickLine = new Paint(scalePaint);
thickLine.setStrokeWidth(0.07f);
thickLine.setColor(Color.argb(0xff, 0xff, 0x36, 0x33));
thickLine.setFlags(Paint.ANTI_ALIAS_FLAG);
canvas.drawLine(0.5f, 0.5f, 0.1f, 0.1f, thickLine);
canvas.drawCircle(0.5f, 0.5f, 0.15f, thickLine);
But the drawLine works on all three devices!
Also just to mention - the code worked before - then I changed the standard Fragments to SherlockFragments and modified the code in the app in several places - always testing on S3. So I do not know at what stage it started to not work anymore on the Acer.
I also used the old unchanged drawing class that contains this code (before I made all changes to the app) and copied it into the new version which uses Sherlock now - even this stage of the project code does not work anymore as described.
So I guess it might have something to do with Sherlock - however, I do not have any idea how and why - and if at all....
Anyone had some similar experience where drawLine works but drawCircle and drawPath do not?
- with or without use of Sherlock
Many thanks
I had exactly the same problem - Canvas.drawCircle was not working for me.
Luckely, there is another function - Canvas.drawOval. You can use it to draw circle without changing the build target.
RectF tmpRect = new RectF();
tmpRect.top = 0;
tmpRect.bottom = diameter;
tmpRect.left = 0;
tmpRect.right = diameter;
//This call will draw nothing
canvas.drawCircle(tmpRect.centerX(), tmpRect.centerY(), tmpRect.width() / 2, selectionPaint);
//This call will draw a circle
canvas.drawOval(tmpRect, selectionPaint);
almost unbelieveble but true, just change the target setting (or remove it alltogether) and it will work - it did in my case :-)
I was just having this problem with Canvas.drawLine() and Canvas.drawRect(). My lines would be drawn but my rectangles weren't.
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
int height = canvas.getHeight();
int width = canvas.getWidth();
canvas.drawLine(width/2,0,width/2,height,paint);
canvas.drawLine(0,height/2,width,height/2,paint);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.GREEN);
canvas.drawRect(touchRect, paint);
}
However, it started to work when I put a call to View.invalidate() into my onTouchEvent() method because I wanted to draw a rectangle where I touched the screen.
#Override
public boolean onTouchEvent(MotionEvent event) {
invalidate();
if (event.getAction() == MotionEvent.ACTION_DOWN) {
float x = event.getX();
float y = event.getY();
touchRect.left = (int) (x - 20);
touchRect.top =(int) (y - 20);
touchRect.right = (int) (x + 20);
touchRect.bottom = (int) (y + 20);
}
return false;
}
I got this from reading https://developer.android.com/guide/topics/graphics/2d-graphics.html
I have had the same problem after changing min Android version from 2.3 to 3. Lines worked but not drawRect if i changed android version back all worked again.
After a lot try and error i found that switching top and buttom coordinates did the trick.
I changed the order from left-top-right-bottom to left bottom-rirht-top and it worked.

Android Google Maps drawPath toPixels error

I've been trying to include the ability to show routes in an android app, and was working this solution into my app:
J2ME/Android/BlackBerry - driving directions, route between two locations
I've got basically all of the code in place, but in the drawPath method I get the error "The method toPixels(GeoPoint, Point) in the type Projection is not applicable for the arguments (GeoPoint, Point)" on the starred code below. Here's the code:
public void drawPath(MapView mMapView, Canvas canvas)
{
int x1 = -1, y1 = -1, x2 = -1, y2 = -1;
Paint paint = new Paint();
paint.setColor(Color.GREEN);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
for (int i = 0; i < mPoints.size(); i++)
{
Point point = new Point();
mMapView.getProjection().*****toPixels*****(mPoints.get(i), point);
x2 = point.*****x*****;
y2 = point.*****y*****;
if (i > 0)
{
canvas.drawLine(x1, y1, x2, y2, paint);
}
x1 = x2;
y1 = y2;
}
}
I've not been able to test it at all yet because I've been unable to sort this error, so I don't know if there are other problems elsewhere. However in the meantime, if anybody knows why this error pops up it would be really appreciated. Thanks in advance! Oh and if anybody needs to see any of my other code or classes please let me know.
here is a good example i have posted you can try out this
I had tried this source code.
Copy the file from source code, don't change anything before that.
DON'T press Ctrl + Shift + O to load library class automatically.
Sometimes, eclipse import a wrong library. Why? That's another topic on eclipse.
Edit all these lines manually
import org.ci.geo.route.Road;
import org.ci.geo.route.RoadProvider;
Change import to your package library name.
Then edit this line that suit to your layout:
setContentView(R.layout.main);
mapView = (MapView) findViewById(R.id.mapview);
and this for sweet flavour
TextView textView = (TextView) findViewById(R.id.description);
Hope this will help you

Categories

Resources