I want to divide the image into sub images and when I click on a part of the image will give me the name of the region, for example, this is my question how to recognize a region from the image, or how to divide the image into sub-images and use it in imageViews
And thank you in advance
In my opinion #fractalwrench's idea is quite good for your case. Basic steps are listed below.
Subclass Android ImageView. For example, MultiRegionImageView.
Override its onTouchEvent method. (This method gets called whenever user touches the view)
User touches the image and thereby onTouchEvent is called and provides the exact touch point (x, y).
Declare another method or interface which determines at which region a given point is. For example, getRegionByPoint(int x, int y)
If you would like to highlight that region boundaries, you could use paths. First off, you should define paths and save them into a raw file (XML, for example), then using region ID, fetch its path and finally draw that path over the main image.
For drawing a path over the main image, you should also override onDraw method of ImageView class and use canvas.drawPath();
public class MultiRegionImageView extends ImageView {
RegionProvider mRegionProvider;
int mId = -1;
private Paint mPaint;
public MultiRegionImageView(Context context) {
super(context);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
mId = mRegionProvider.getRegionIdByPoint(event.getX(), event.getY());
return super.onTouchEvent(event);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(mId != -1) {
canvas.drawPath(mRegionProvider.getRegionBoundaryPath(mId), mPaint);
}
}
public interface RegionProvider{
int getRegionIdByPoint(float x, float y);
Path getRegionBoundaryPath(int id);
}
}
You should only need one ImageView to display the map. If you override onTouchEvent(MotionEvent e), you can get the position which is being touched in the View. If you store the position and shape of each region in some sort of List, you can check whether a touch event is within a region (and display whatever text you need to).
Related
I'm working in an app that uses the ml kit text recognition library; The app reads text from images and puts a Rect around every word.
Now I want these Rects to change color when the user tap on one of them or swipe above some words.
So, I was able to handle touch events correctly, but what I can't do is changing the color of the touched Rect!
Should I draw new colored Rects above the touched Rect? Or can I color the existing rects (which I don't think I can)?
Classes:
TextGraphic, GraphicOverlay.
//This is where the Rects get drawn
I also tried this solution, so I typed this methods in the TextGraphic class:
public void changeColor(boolean isHighlighted) {
if(isHighlighted) {
rectPaint.setColor(COLOR_HIGHLIGHTED);
rectPaint.setAlpha(400);//set opacity of rect
}else{
rectPaint.setColor(COLOR_DEFAULT);
rectPaint.setAlpha(400);//set opacity of rect
}
postInvalidate();
}
and called it when the user touches the text, but the problem is that all Rects colors get changed, and they do not change at runtime!
A snippet from my ActivityClass, where I used some callback methods to pass things out.
ArrayList<Rect> rects = new ArrayList<>();
#Override
public void onAdd(FirebaseVisionText.Element element, Rect elementRect, String wordText) {
GraphicOverlay.Graphic textGraphic = new TextGraphic(mGraphicOverlay, element);
mTextGraphic = new TextGraphic(mGraphicOverlay, element);
mGraphicOverlay.add(textGraphic);
rects.add(elementRect);
}
A snippet from my ActivityClass where I handle touch events:
#Override
public boolean onDown(MotionEvent event) {
helper.dismissKeyboard();
touchX = Math.round(event.getX());
touchY = Math.round(event.getY());
for(int x=0; x< rects.size();x++) {
if (rects.get(x).contains(touchX, touchY)) {
// line has been clicked
mTextGraphic.changeColor(true);
return true;
}
}
return true;
}
You are changing the color using the mTextGraphic variable. If you look closely in your onAdd() method you will see that you are assigning a new object to mTextGraphic that has nothing to do with the objects drawn to screen because only the objects that you add to GraphicOverlay list using the mGraphicOverlay.add() will get drawn to screen.
So what you need is to call changeColor() not on mTextGraphic but on the respective object that is already in the list inside GraphicOverlay
Since the list inside GraphicOverlay is private you can't manipulate it in the onDown() method. You will need to write a public method that will do the job for you.
Write the following method in GraphicOverlay class
public TextGraphic getGraphicElementAtIndex(int index) {
return (TextGraphic)graphics.get(index)
}
Now use this method inside the if condition of onDown() method like this
if (rects.get(x).contains(touchX, touchY)) {
// line has been clicked
Log.d("PreviewActivity", "changeColor() is called");
mGraphicOverlay.getGraphicElementAtIndex(x).changeColor();
touchedText = texts.get(x);
return true;
}
Hope this helps.
SIDE NOTE: Now even after this if for some reason the ordering of objects inside rects list and graphics list (which is inside GraphicOverlay) change then you will see that when you click a rectangle some other rectangle changes color.
Maybe you should not do it by coding but by ColorStateList
Android Developer: colorstatelist
I have an ImageView which has a transparent drawable with a circle at the center like (http://wallpaperswide.com/circle_outline-wallpapers.html). Just that the circle is red, and the surrounding are not coloured but are transparent, it is a .png image. So now I will implement Canvas.ondraw(), and when while tracing the user goes outside the circle, the drawing should restart.
The doubt is:
1. How do I detect the boundaries of this image without hardcoding.
2. How do I detect that the user has clicked outside this, as this is not a regular rectangle.
I am doing this to help students trace alphabets, so I want the answer to be generic on the basis of any image in the shape of a letter.
Can it be done this way? If not, what better way can you suggest?
i'd go the easy route: just draw the image and check the colour of the point the user touched. if the alpha channel transparent, the user moved out.
the following code is untested (and very rough). i have no idea if the getDrawingCache trick works.
public class FooBar extends ImageView {
Bitmap b = null;
public FooBar(Context context) {
super(context);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
b = getDrawingCache(true);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_MOVE)
check((int) event.getX(), (int) event.getY());
return super.onTouchEvent(event);
}
private void check(int x, int y) {
if (b != null && Color.alpha(b.getPixel(x, y)) >= 0)
onMovedOutOfShape();
}
private void onMovedOutOfShape() {
Toast.makeText(getContext(), "You're out", Toast.LENGTH_SHORT).show();
}
}
What you're after is almost the same thing as "collision detection for irregular shapes". Googling on that will result in a zillion hits.
But if I had the problem to do, I'd probably bring in one of the game engines/frameworks such as Box2D, AndEngine, libGDX, or BatteryTech. I'd combine a few simple rectangles and curves to build up reactive places over each of my letter images and then use of of the library's pre-optimized collision detection algorithms to do the heavy lifting. I'd also at least look through their open source code to learn how they do their detection.
I have a class which extends SurfaceView and implements SurfaceHolder.Callback. Using onDraw() method i'm drawing some bitmaps on my canvas. The, after pressing a button I'm adding new image to the canvas calling invalidate(). Is any possibility to save all the changes which I made on every invalidate() which were earlier, so as to after new invalidate() add new image, but not delete the earlier?
From what I have understood you will want to save the image that was drawn and also it's position? By using the code I provided you will have a list that is filled with the image and position. The list is unordered; if you would like an ordered list you can use a LinkedList instead.
Create a new class, you may name it anything.
public class ImageHolder {
private int mX;
private int mY;
private int mDrawableResource;
private String mBitmapFilePath;
public ImageHolder(int x, int y, int drawableResource, String bitmapFilePath) {
mX = x;
mY = y;
mDrawableResource = drawableResource;
mBitmapFilePath = bitmapFilePath;
}
public int getX() {
return mX;
}
public int getY() {
return mY;
}
public int getDrawableResource() {
return mDrawableResource;
}
public String getBitmapFilePath() {
return mBitmapFilePath;
}
}
Then in your SurfaceView you add it a holder each time you draw to a list. Notice that this is bare minimum code so no synchronization has been added.
private void customDrawMethod() {
mImageHolders.add(new ImageHolder(x, y, drawableResource, bitmapFilePath));
Canvas canvas = getHolder().lockCanvas();
canvas.drawBitmap(bitmap, matrix, paint);
getHolder().unlockCanvasAndPost(canvas);
}
I added both a Bitmap and a Drawable because I am unsure what you use. I could not post more code because I have no idea what you want to do with the saved images. More info could help you further.
This is pretty straightforward case of using Bitmaps to store your previous canvas. Simply attach a bitmap to your canvas. Before drawing, save the old bitmap to something like "prevBitmap" and then draw over it. You can redraw the previous Bitmap by calling canvas.drawBitmap(prevBitmap);
You can save your old drawings on canvas and dont draw them again when adding new picture. Just call invalidate(x, y, x+sizeX, y+sizeY) when you need to add new image with left-top point's coordinates (x, y) and size (sizeX, sizeY) to the View's canvas. About to save all images in array you already got answer.
P.S. sorry for my english, hope it was helpfull
I have drawn a bitmap image over a canvas.
Bitmap image = BitmapFactory.decodeResource(getResources(), R.drawable.sq);
canvas.drawColor(color.black);
Rect dstRectForRender = new Rect(0,0,320,450);
canvas.drawBitmap(image, null,dstRectForRender,null);
The image gets displayed based on my screnn on a cnavs.
On my touch input, I need to pass the x and y co-ordinate position of the image and fill that pixel with a color to show that the image is painted on a drag event.
How can I pass the x and y coo-ordinate parameters? Which functions should I use to plot the pixels on the image?
I appreciate your help and sweet time.
I'm not sure if this is the best way to do this, but it would be much easier to do this if you defined your own subclass of ImageView and name it something like DrawableImageView. You'd have to make sure you implement all the basic constructors from ImageView, then override the onTouchEvent method. From that event you can get the touch coordinates and store them in an ArrayList<Point> and use that ArrayList by overriding the onDraw method and "painting" the image.
public class DrawableImageView extends ImageView {
ArrayList<Point> list = new ArrayList<Point>();
//constructors..
#Override
public boolean onTouchEvent (MotionEvent event) {
float x = event.getX();
float y = event.getY();
list.add(new Point(x,y));
invalidate();
}
This is just a very brief overview of how to start your class, and may not be the most accurate way of doing things (depending on your specific code). Now, instead of using <ImageView> tags in your xml (or, loading an ImageView programatically), you refer to your subclass like so:
<your.package.name.DrawableImageView
/>
Edit
In response to your comment, there is no predetermined way to draw over an image. You must implement this yourself, which is why I recommended storing Points in an ArrayList. I'm not really sure what you're trying to achieve here, but to draw (for example) black dots over an image you have to override onDraw:
public void onDraw(Canvas c) {
super.onDraw(c);
for(Point p : list) {
//Draw black point at x and y.. I'm posting from my cell so I can't go into much detail
}
}
Also, to force a View to redraw itself you need to use the invalidate() method in your onTouchEvent() (which I've added above).
I've an ImageView, but how can I see where the user has clicked/touched on the image.
I know I have to use MotionEvent.getX() and MotionEvent.getY(), but how can I see where the user has clicked on the image?
Thanks !
You have to subclass your image view and explicitly draw an indicator at the position where the user is touching.
public class TouchableImageView extends ImageView {
// Constructors should come here
// Override onTouch to remember the touch position in our variable touchLocation
// Set touchLocation to null when getting the ACTION_UP event
// Override onDraw to draw something at touchLocation. You should create a proper Paint object
// in your constructors and use it here
public void onDraw(Canvas c) {
if (touchLocation!=null) {
canvas.drawCircle(touchLocation.x, touchLocation.y, 10, indicatorPaint);
}
}
private Point touchLocation;
private Paint indicatorPaint;
}