How to capture detected face image using MLKit firebase FaceDetection - android

I want to only capture detected face image not whole image on camerasource.
I am drowing box like this
public void draw(Canvas canvas) {
Face face = mFace;
if (face == null) {
return;
}
// Draws a circle at the position of the detected face, with the face's track id below.
float x = translateX(face.getPosition().x + face.getWidth() / 2);
float y = translateY(face.getPosition().y + face.getHeight() / 2);
canvas.drawCircle(x, y, FACE_POSITION_RADIUS, mFacePositionPaint);
canvas.drawText("id: " + mFaceId, x + ID_X_OFFSET, y + ID_Y_OFFSET, mIdPaint);
canvas.drawText("happiness: " + String.format("%.2f", face.getIsSmilingProbability()), x - ID_X_OFFSET, y - ID_Y_OFFSET, mIdPaint);
canvas.drawText("right eye: " + String.format("%.2f", face.getIsRightEyeOpenProbability()), x + ID_X_OFFSET * 2, y + ID_Y_OFFSET * 2, mIdPaint);
canvas.drawText("left eye: " + String.format("%.2f", face.getIsLeftEyeOpenProbability()), x - ID_X_OFFSET*2, y - ID_Y_OFFSET*2, mIdPaint);
// Draws a bounding box around the face.
float xOffset = scaleX(face.getWidth() / 2.0f);
float yOffset = scaleY(face.getHeight() / 2.0f);
float left = x - xOffset;
float top = y - yOffset;
float right = x + xOffset;
float bottom = y + yOffset;
this.faceTrackingCords.y = top;
this.faceTrackingCords.width = right;
this.faceTrackingCords.x = left-right;
this.faceTrackingCords.height = bottom;
canvas.drawRect(left, top, right, bottom, mBoxPaint);
}
and trying to capture image like this but cropped image is not as expected.
mCameraSource.takePicture(null, new CameraSource.PictureCallback() {
#Override
public void onPictureTaken(byte[] bytes) {
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
Bitmap bitmapCropped = Bitmap.createBitmap(bitmap,(int)faceTrackingCords.x, (int)faceTrackingCords.y,
(int)faceTrackingCords.width, (int)faceTrackingCords.height);
screenImage.setImageBitmap(bitmapCropped);
}
});
Kindly please help

Related

android canvas draw text on circle radius based

I need to make lucky wheel like view, and there texts are drawn regarding the radius, as you can see image below. ( there you can see red line, I want to draw texts along that red line )
This is the result I want to achieve but, right now with my method, it just draws text based on circle like below
private void drawText(Canvas canvas, float tempAngle, float sweepAngle, String text) {
Path path = new Path();
Log.d("mytag", "tempAngle = " + tempAngle + ", sweepAngle = " + sweepAngle);
path.addArc(range, tempAngle, sweepAngle);
float textWidth = textPaint.measureText(text);
int hOffset = (int) (radius * Math.PI / mWheelItems.size() / 2 - textWidth / 2);
int vOffset = (radius / 2 / 3) - 15; // here 15 is distance from image
canvas.drawTextOnPath(text, path, hOffset, vOffset, textPaint);
}
Instead of creating an arc to draw the text on, you need a path from the outside of the circle to the center. I think you need something like this
int radius = 180;
float centerX = width/2f;
float centerY = height/2f
double radians = radius * Math.PI / 180;
float x = (float)Math.sin(radians);
float y = (float)-Math.cos(radians);
Path path = new Path();
path.moveTo(x,y);
path.lineTo(centerX, centerY);
canvas.drawTextOnPath(text, path, hOffset, vOffset, textPaint);
First, find the slice centre points.
Kotlin sample snippet
val arcCenter = startAngle + (arcProgress / 2)
//middle point radius is half of the radius of the circle
val pointRadius = size.width / 4
/*Calculate the x & y coordinates
* find points using angle and radius
*https://en.wikipedia.org/wiki/Polar_coordinate_system#Converting_between_polar_and_Cartesian_coordinates
* */
val x =
(pointRadius * cos(Math.toRadians(arcCenter.toDouble()))) +
size.center.x
val y =
(pointRadius * sin(Math.toRadians(arcCenter.toDouble()))) +
size.center.y
Then Rotate your canvas to the arch centre angle, Draw your text and restore the canvas to a normal position
it.nativeCanvas.rotate( arcCenter, x, y)
it.nativeCanvas.drawText(...)
it.nativeCanvas.rotate( -arcCenter, x, y)

How to map Frame coordinates to Overlay in vision

I'm feeling that this Question is already solved many times, but I cannot figure it out. I was basically following this little Tutorial about mobile vision and completed it. After that I tried to detect Objects myself starting with a ColorBlob and drawing its borders.
The idea is to start in the middle of the frame (holding the object in the middle of the camera on purpose) and detecting the edges of that object by its color. It works as long as I hold the phone in landscape mode (Frame.ROTATION_0). As soon as I'm in Portrait mode (Frame.Rotation_90) the bounding Rect gets drawn rotated, so an object with more height gets drawn with more width, and also a bit off.
The docs say that a detector always delivers coords to an unrotated upright frame, so how am I supposed to calculate the bounding rectangle coords relative to its rotation?
I don't think it matters much, but here is how I find the color Rect
public Rect getBounds(Frame frame){
int w = frame.getMetadata().getWidth();
int h = frame.getMetadata().getHeight();
int scale = 50;
int scaleX = w / scale;
int scaleY = h / scale;
int midX = w / 2;
int midY = h / 2;
float ratio = 10.0
Rect mBoundary = new Rect();
float[] hsv = new float[3];
Bitmap bmp = frame.getBitmap();
int px = bmp.getPixel(midX, midY);
Color.colorToHSV(px, hsv);
Log.d(TAG, "detect: mid hsv: " + hsv[0] + ", " + hsv[1] + ", " + hsv[2]);
float hue = hsv[0];
float nhue;
int x, y;
for (x = midX + scaleX; x < w; x+=scaleX){
px = bmp.getPixel(x, midY);
Color.colorToHSV(px, hsv);
nhue = hsv[0];
if (nhue <= (hue + ratio) && nhue >= (hue - ratio)){
mBoundary.right = x
} else {
break;
}
}
for (x = midX - scaleX; x >= 0; x-= scaleX){
px = bmp.getPixel(x, midY);
Color.colorToHSV(px, hsv);
nhue = hsv[0];
if (nhue <= (hue + ratio) && nhue >= (hue - ratio)){
mBoundary.left = x
} else {
break;
}
}
for (y = midY + scaleY; y < h; y+=scaleY){
px = bmp.getPixel(midX, y);
Color.colorToHSV(px, hsv);
nhue = hsv[0];
if (nhue <= (hue + ratio) && nhue >= (hue - ratio)){
mBoundary.bottom = y;
} else {
break;
}
}
for (y = midY - scaleY; y >= 0; y-=scaleY){
px = bmp.getPixel(midX, y);
Color.colorToHSV(px, hsv);
nhue = hsv[0];
if (nhue <= (hue + ratio) && nhue >= (hue - ratio)){
mBoundary.top = y
} else {
break;
}
}
return mBoundary;
}
Then I simply draw it in the GraphicOverlay.Graphics draw method on the canvas. I already use the transformX/Y methods on the Graphic and thought, that it will also account for the rotation.
I also use the CameraSource and CameraSourcePreview class provided from the samples.

Zoom Imageview using matrix

Hi I am trying to zoom in on a specific point on the image in my imageview with this code:
private void calculateAndZoom() {
matrix.set(getImageMatrix());
printMatrixValues(getImageMatrix());
float startpointY = (start_y_rel/ template_y_rel) * getHeight() * scale;
float startpointX = (start_x_rel / template_x_rel)* getWidth() * scale;
PrintDevMessage.print("Width: " + getWidth() + " Height: " + getHeight());
matrix.setScale(1,1,0,0);
matrix.postScale(scale, scale, startpointX, startpointY);
this.setScaleType(ImageView.ScaleType.MATRIX);
this.setImageMatrix(matrix);
printMatrixValues(getImageMatrix());
}
start_y_rel and start_x_rel is points relative to the template_y_rel and template_x_rel
I am using matrix.setScale(1,1,0,0) to remove any previous zooming and move to the first position.
This code works with scale 3 but when I try another scale it zooms in on the wrong position.
Ok so after 3 days of head-scratching i found the solution:
private void calculateAndZoom() {
float cScale=getMatrixValue(getImageMatrix(),Matrix.MSCALE_X);
float newScale = ((float)1.0/cScale)*scale;
matrix.set(getImageMatrix());
printMatrixValues(matrix);
float startpointY = ((start_y_rel / template_y_rel) * getHeight());
float startpointX = ((start_x_rel / template_x_rel) * getWidth());
PrintDevMessage.print("Width: " + getWidth() + " Height: " + getHeight());
matrix.postScale(newScale, newScale, startpointX, startpointY);
this.setScaleType(ImageView.ScaleType.MATRIX);
this.setImageMatrix(matrix);
printMatrixValues(getImageMatrix());
}
I did not account for the image being larger than the screen and when placed in the imageview the scale is changed. So i had to recalculate the scale i wanted with the old scale like this:
float newScale = ((float)1.0/cScale)*scale;

libgdx - find the coordinates different from the point of origin?

I 'd like someone to advise me a way to find the coordinates of a point on a sprite in libgdx .
As you can see from the image I have set the sprite with the point of origin on the red dot , and I can not change it.
I would leave the red dot as the source and find the coordinates of the green on the same sprite .
Thanks for your help.
EDIT
#Override
public void create () {
img = new Texture("rocket.png");
font = new BitmapFont();
font.setColor(Color.BLUE);
MyInputProcessor inputProcessor = new MyInputProcessor();
Gdx.input.setInputProcessor(inputProcessor);
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
sprite = new Sprite(img);
spacesprite = new Sprite(new Texture(Gdx.files.internal("space.jpg")));
spacesprite.setPosition(0,0);
spacesprite.setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
point = new Sprite(new Texture(Gdx.files.internal("point.png")));
batch = new SpriteBatch();
}
#Override
public void render () {
sprite.setPosition(Gdx.graphics.getWidth() / 2 - sprite.getWidth()/2, Gdx.graphics.getHeight() / 2 - sprite.getHeight()/2);
sprite.setOrigin(sprite.getWidth()/2, sprite.getHeight()/2);
point.setPosition(sprite.getX() + sprite.getWidth()/2 - point.getWidth()/2, sprite.getY() + sprite.getHeight()/2);
point.setOrigin(point.getWidth()/2, 0);
if(Gdx.input.isButtonPressed(Input.Buttons.LEFT)){
//sprite.setPosition(Gdx.input.getX() - sprite.getWidth()/2, Gdx.graphics.getHeight() - Gdx.input.getY() - sprite.getHeight()/2);
if(Gdx.input.getX() < Gdx.graphics.getWidth() / 2)
{
//System.out.println("x: " + Gdx.input.getX() + " - y: " + Gdx.input.getY());
sprite.setRotation(rotation++);
point.setRotation(rotation++);
System.out.println("Sprite: X" + sprite.getX() + " - Y:" + sprite.getY());
}
else
{
//System.out.println("x: " + Gdx.input.getX() + " - y: " + Gdx.input.getY());
sprite.setRotation(rotation--);
point.setRotation(rotation--);
System.out.println("Sprite: X" + sprite.getX() + " - Y:" + sprite.getY());
}
}
batch.begin();
spacesprite.draw(batch);
sprite.draw(batch);
point.draw(batch);
batch.end();
}
someone can adapt the code , when I rotate I'd get the position , but they are insecure about my implementation .
if you're looking for a middle point on the rectangular sprite, try something like this:
float x = obj.getOriginX() + obj.getHeight();
float y = obj.getOriginY() + obj.getWidth() / 2;
Either use Gonio, matrix or quaternions to calculate the rotated coordinates.
For a few simple calculations I'd use gonio, something like:
float angle_rad = sprite.getRotation() / 180.0f * PI;
float rotated_x = Math.sin(angle_rad) * y + Math.cos(angle_rad) * x;
float rotated_y = Math.sin(angle_rad) * x + Math.cos(angle_rad) * y;
If you have to do this more often look into matrices or quaternions, matrices are a little easier though: http://en.wikipedia.org/wiki/Rotation_matrix

Android canvas draw multiple rectangles of equal distance

I have 4 Strings. I'd like to draw a rectangle around each, and have them be equal distance to each other. I have code that "works" but I need 3 spaces for my last rectangle to make the distance equal, and I don't understand why. I am using an LG G Watch R, in case it is relevant.
private void drawDate(Canvas canvas, float centerX, float centerY)
{
float x = centerX + 75f;
float y = centerY + 50f;
String dayOfWeek = daysOfWeek[mTime.weekDay] + ",";
String month = months[mTime.month];
String monthDay = mTime.monthDay + ",";
String year = Integer.toString(mTime.year);
float height = outLinePaint.getTextSize();
float totalWidth = outLinePaint.measureText(String.format("%s %s %s %s", dayOfWeek, month, monthDay, year));
final float spaceWidth = outLinePaint.measureText(" ");
x -= totalWidth/2f;
outLinePaint.setStyle(Paint.Style.FILL);
float halfWidth = outLinePaint.measureText(dayOfWeek)/2f;
canvas.drawRect(x - halfWidth, y - height, x + halfWidth, y + height /2f , whitePaint);
canvas.drawText(dayOfWeek, x, y, outLinePaint);
x += (halfWidth*2f)+spaceWidth;
halfWidth = outLinePaint.measureText(month)/2f;
canvas.drawRect(x - halfWidth, y - height, x + halfWidth, y + height /2f , whitePaint);
canvas.drawText(month, x, y, outLinePaint);
x += (halfWidth*2f)+spaceWidth;
halfWidth = outLinePaint.measureText(monthDay)/2f;
canvas.drawRect(x - halfWidth, y - height, x + halfWidth, y + height /2f , whitePaint);
canvas.drawText(monthDay, x, y, outLinePaint);
//THIS LINE
x += (halfWidth*2f)+spaceWidth+spaceWidth+spaceWidth;
//it looks right on the canvas, but why can I not simply
//x += (halfWidth*2f)+spaceWidth; like above?
halfWidth = outLinePaint.measureText(year)/2f;
canvas.drawRect(x - halfWidth, y - height, x + halfWidth, y + height /2f , whitePaint);
canvas.drawText(year, x, y, outLinePaint);
outLinePaint.setStyle(Paint.Style.STROKE);
}
NOTE: THIS "BUG" ONLY EFFECTS THE LAST STRING
This is what I expect (AND what I get if I use x += (halfWidth*2f)+spaceWidth+spaceWidth+spaceWidth;):
However if I use x += (halfWidth*2f)+spaceWidth; like I do with my other 3, I get:
I have solved it. I could not get #pskink's example to work for the life of me (it didn't draw on my canvas). The problem was my center alignment.
x was in the middle of my Rect not the left. Whereas I was expecting x to be the leftmost point in my Rect when I added its width to x.
I have fixed it by setting the text align to left (so that x IS my leftmost point), and changing my drawDate() method to:
float spaceWidth;
private void drawDate(float centerX, float centerY)
{
float x = centerX + centerX*DATE_AND_COMPASS_X_OFFSET;
float y = centerY + centerY*DATE_AND_COMPASS_Y_OFFSET;
String dayOfWeek = daysOfWeek[mTime.weekDay] + ",";
String month = months[mTime.month];
String monthDay = mTime.monthDay + ",";
String year = Integer.toString(mTime.year);
float height = outLinePaint.getTextSize();
float totalWidth = outLinePaint.measureText(String.format("%s %s %s %s", dayOfWeek, monthnthDay, year));
spaceWidth = outLinePaint.measureText(" ");
outLinePaint.setStyle(Paint.Style.FILL);
x-=totalWidth/2;
x+=drawDateInline(dayOfWeek, x, y, height);
x+=drawDateInline(month, x, y, height);
x+=drawDateInline(monthDay, x, y, height);
drawDateInline(year, x, y, height);
outLinePaint.setStyle(Paint.Style.STROKE);
}
private float drawDateInline(String word, float x, float y, float height) {
float width = outLinePaint.measureText(word);
canvas.drawRect(x, y - height, x + width, y + height /2f, whitePaint);
canvas.drawText(word, x, y, outLinePaint);
return width+spaceWidth;
}
I'm also not sure how this is a "bad approach".

Categories

Resources