Currently, we are developing one app which bases on face detection. when face detected on live camera we place another image left side of the detected area so it will look like a selfie picture.
so currently while taking a screenshot of camera view and drawn face area on canvas is showing black so we know capture screenshot of camera surface is not possible.
Does anyone have an idea to develop this type of application?
/**
* Draws the face annotations for position on the supplied canvas.
*/
#Override
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);
// Draws a bounding box around the face.
float xOffset = scaleX(face.getWidth() / 2.3f);
float yOffset = scaleY(face.getHeight() / 2.3f);
float left = x - xOffset;
float top = y - yOffset;
float right = x + xOffset;
float bottom = y + yOffset;
canvas.drawRect(left, top, right, bottom, mBoxPaint);
// Bitmap to draw on the canvas
Bitmap bitmap = BitmapFactory.decodeResource(
resources,
R.drawable.ic_luncher);
sclledBitmp=getResizedBitmap(bitmap, (int)face.getWidth()-70, (int) face.getHeight()-70);
//Finally, Draw the source bitmap on the canvas
canvas.drawBitmap(
sclledBitmp, // Bitmap
right, // Left
top, // Top
null // Paint
);
canvas.drawText("Width: " + (int)face.getWidth() + " \nright:"+right, right, top, mIdPaint);
}
Related
I am rotating and scaling canvas using canvas.setMatrix() and then drawing text on canvas using canvas.drawText();. That's working as expected. But when I try to draw text that contains emojis (android device's default emojis), they don't get rotated. Everything else in the text gets rotated as expected. Also drawing and scaling works as expected for emojis, it's just the rotating that doesn't work,and I find it only appears in android7.0 or below 7.0.
public void draw(Canvas canvas) {
if (TextUtils.isEmpty(mText)) {
drawCursor(canvas);
return;
}
float allTextHeight = mTextLineHeight * mLines.length;
float y = (mHeight - allTextHeight) / 2;
float offset = mPaint.getFontMetrics().ascent;
canvas.save();
canvas.translate(mWidth / 2, 0);
float initY = y;
for (String line : mLines) {
drawText(canvas, line, 0f, y - offset, mPaint, initY);
y += mTextLineHeight;
}
canvas.restore();
}
I am trying to implement Image cropping in Android following the source code from AOSP gallery app (code actually taken from this library). I have set the ImageView's scale type to be MATRIX and scaled and translated the image using posttranslate and postscale method on the image matrix.
A crop rectangle of fixed 260x260 pixel is drawn on the image, centered within the ImageView. This crop rectangle is fixed in size and can't be moved. Instead the image is allowed to be moved and scaled (zoom in/ zoom out) so that user can put the desired area of the image within the crop rectangle.
while the user moves the image by dx, dy amount, posttranslate(dx, dy) is called on the image's matrix. Then the crop rectangle is mapped to the current matrix by calling matrix.map(rect). And then the new position(on original image) of the crop rectangle is calculated by converting the dx, dy to image space and shifting the crop rectangle accordingly.
here's some source excerpt for moving the image:
// This matrix is recomputed when we go from the thumbnail image to
// the full size image.
protected Matrix baseMatrix = new Matrix();
// This is the supplementary transformation which reflects what
// the user has done in terms of zooming and panning.
//
// This matrix remains the same when we go from the thumbnail image
// to the full size image.
protected Matrix suppMatrix = new Matrix();
// This is the final matrix which is computed as the concatentation
// of the base matrix and the supplementary matrix.
private final Matrix displayMatrix = new Matrix();
//move image by dx dy
protected void panBy(float dx, float dy) {
postTranslate(dx, dy);
setImageMatrix(getImageViewMatrix());
}
protected void postTranslate(float dx, float dy) {
suppMatrix.postTranslate(dx, dy);
}
// Combine the base matrix and the supp matrix to make the final matrix
protected Matrix getImageViewMatrix() {
// The final matrix is computed as the concatentation of the base matrix
// and the supplementary matrix
displayMatrix.set(baseMatrix);
displayMatrix.postConcat(suppMatrix);
return displayMatrix;
}
And this is how the image movement affects the crop rectangle view
public void handlePan(float dx, float dy)
{
RectF r = computeLayout();
float xDelta = (dx * (cropRect.width() / r.width()));
float yDelta = -(dy * (cropRect.height() / r.height()));
cropRect.offset(xDelta, yDelta);
// Put the cropping rectangle inside image rectangle
cropRect.offset(
Math.max(0, imageRect.left - cropRect.left),
Math.max(0, imageRect.top - cropRect.top));
cropRect.offset(
Math.min(0, imageRect.right - cropRect.right),
Math.min(0, imageRect.bottom - cropRect.bottom));
}
private RectF computeLayout() {
RectF r = new RectF(cropRect.left, cropRect.top,
cropRect.right, cropRect.bottom);
matrix.mapRect(r);
return r;
}
The crop view gets the image's current matrix from the following getunrotatedmatrix function
public Matrix getUnrotatedMatrix(){
Matrix unrotated = new Matrix();
getProperBaseMatrix(bitmapDisplayed, unrotated, false);
unrotated.postConcat(suppMatrix);
return unrotated;
}
// Setup the base matrix so that the image is centered and scaled properly.
private void getProperBaseMatrix(RotateBitmap bitmap, Matrix matrix, boolean includeRotation) {
float viewWidth = getWidth();
float viewHeight = getHeight();
float w = bitmap.getWidth();
float h = bitmap.getHeight();
matrix.reset();
// We limit up-scaling to 3x otherwise the result may look bad if it's a small icon
float widthScale = Math.min(viewWidth / w, 3.0f);
float heightScale = Math.min(viewHeight / h, 3.0f);
float scale = Math.min(widthScale, heightScale);
if (includeRotation) {
matrix.postConcat(bitmap.getRotateMatrix());
}
matrix.postScale(scale, scale);
matrix.postTranslate((viewWidth - w * scale) / 2F, (viewHeight - h * scale) / 2F);
}
This works perfectly. But what I am struggling with is, to handle the zooming of the image. I have tried mapping a rectangle to the matrix and then mapping this rectangle to the original image, scaling down the crop rect by the same amount the image is scaled up and vice versa. But none of them worked. Any idea how to achieve this(get the position of the crop rectangle on original image(on sdcard), after zooming the image in imageview)? The zooming is done as below:
protected void zoomTo(float scaleFactor, float centerX, float centerY) {
float oldScale = getScale();
float scale = oldScale*scaleFactor;
if (scale > maxZoom) {
scale = maxZoom;
scaleFactor=maxZoom/oldScale;
}
else if(scale<0.5)
{
scale=0.5f;
scaleFactor=0.5f/oldScale;
}
suppMatrix.postScale(scaleFactor, scaleFactor, centerX, centerY);
setImageMatrix(getImageViewMatrix());
}
I understand that the crop rectangle has to be made smaller(to point to a smaller region of original image) after zoom-in and vice versa. But how to exactly do that scaling and position the crop rectangle appropriately considering the center of zoom (which can be anywhere on the image even outside the crop rectangle).
I'm trying to draw the spectrum of an audio file on a circle. Like this:
So on the circle I just want rectangles drawn like you see on the image.
I've got this code:
public void onRender(Canvas canvas, FFTData data, Rect rect) {
canvas.drawCircle(rect.width()/2, rect.height()/2, 200, mPaint);
for (int i = 0; i < data.bytes.length / mDivisions; i++) {
byte rfk = data.bytes[mDivisions * i];
byte ifk = data.bytes[mDivisions * i + 1];
float magnitude = (rfk * rfk + ifk * ifk);
int dbValue = (int) (10 * Math.log10(magnitude));
}
}
Where FFTData is the Fast Fourier Transformation data that Android gives me. Now in my dbValue I got the strength of the signal. mDivisions is how much bars I want. Currently set on 16 because I don't know how much I can set on the circle.
I'm stuck on how I can draw the rectangle with his center on the circle line... So I want a rectangle whose height is based on the dbValue so that I get high and low rectangles. And the center must be placed on my circle line.
Can someone help me on this math formula?
Run a loop over all 360 degrees of the circle (at wanted step), and, for each point, convert Polar (this angle and the radius of the circle) coordinates into Cartesian, as described here, for instance. This way you get the location of the centre of your rectangle.
Translate the system of the coordinates, making origin to be at the wanted point on the circle line and then rotate by the circle angle at that point.
Alternatively, you can build a trapezoid by getting corners at angle +- some offset and radius +- some offset (proportional to your value to plot). It will have shorter inner edge and longer outer edge. Such trapezoids may look better if painted side by side.
i think all you have needed is a pencil and a paper and a little math and also some free time to play :-)
public class MainActivity extends Activity {
ImageView drawingImageView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
drawingImageView = (ImageView) this.findViewById(R.id.DrawingImageView);
Paint paint;
paint = new Paint();
paint.setColor(Color.GREEN);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(16);
final Bitmap bitmap = Bitmap.createBitmap((int) getWindowManager()
.getDefaultDisplay().getWidth(), (int) getWindowManager()
.getDefaultDisplay().getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
int centerX =400;
int centerY =400;
int R = 200;
canvas.drawCircle(centerX, centerY, R, paint);
int h = 100;
paint.setColor(Color.RED);
Path p = new Path();
p.moveTo(centerX + R - h/2, centerY);
p.lineTo(centerX + R + h/2, centerY);
canvas.drawPath(p, paint);
p = mySpectrumDrawer(centerX,centerY,R,h,15);
canvas.drawPath(p, paint);
h = 50;
p = mySpectrumDrawer(centerX,centerY,R,h,30);
canvas.drawPath(p, paint);
h = 60;
p = mySpectrumDrawer(centerX,centerY,R,h,60);
canvas.drawPath(p, paint);
h = 80;
p = mySpectrumDrawer(centerX,centerY,R,h,90);
canvas.drawPath(p, paint);
drawingImageView.setImageBitmap(bitmap);
}
private Path mySpectrumDrawer(int centerX, int centerY,int R,int height, int angel){
Path p = new Path();
int dX = (int) (R*(Math.cos(Math.toRadians(angel))));
int dY = (int) (R*(Math.sin(Math.toRadians(angel))));
int dhx = (int) (height/2*(Math.cos(Math.toRadians(angel))));
int dhy = (int) (height/2*(Math.sin(Math.toRadians(angel))));
p.moveTo(centerX + dX - dhx , centerY - dY + dhy);
p.lineTo(centerX + dX + dhx , centerY - dY - dhy);
return p;
}
}
I have following code:
protected void onDraw(Canvas canvas)
{
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.RED);
xRatio = getWidth()*1.0f / picWidth;
yRatio = getHeight()*1.0f / picHeight;
canvas.drawBitmap( sourceImage, null , new Rect(0,0,getWidth(),getHeight()),paint);
for (int i = 0; i < eyesMidPts.length; i++)
{
if (eyesMidPts[i] != null)
{
// where x and y are eyes mid point coordinates
float x = eyesMidPts[i].x*xRatio;
float y = eyesMidPts[i].y*yRatio;
float radius = (float) (eyesDistance[i]);
float left = x - radius;
float right = x + radius;
float top = y - radius;
// we want to increase the bottom radius by double to get other half of the face.
float bottom = (float) (y + radius * 2);
paint.setStrokeWidth(eyesDistance[i] /20);
RectF ovalBounds = new RectF();
ovalBounds.set(left, top, right, bottom);
canvas.drawOval(ovalBounds, paint);
}
}
}
Code encompass full face if face is straight. But does not get complete circle around if face is tilted. I am not sure how euler angels work but am hoping it is to get tilt on the face detection. Can someone please help me with this show me some example code so that circle encompasses whole face.
Why do you use RectF to draw a circle? Is it a 'true' circle, or is it really oval / ellipse?
If it's just a circle, why don't you use this.
canvas.drawCircle(x, y, radius, paint);
So you won't need to transform Rectf's points if it's tilted :)
update:
I believe this should work, I don't have an android workflow setup with me to really test it; sorry if it's a miss.
Matrix m = new Matrix(); //creates identity matrix
m.setRotate(tilt_angle); //rotate it by the tilt angle
m.mapRect(ovalBounds); //transform the rect
// RectF face: face position and dimentions
// Create Bitmap where to draw an oval
Bitmap ovalBmp = Bitmap.createBitmap( face.width(), face.height(), config );
canvasBmp = new Canvas(ovalBmp); // Get a canvas to draw an oval on the Bitmap
canvasBmp.drawOval( new RectF( 0, 0, face.width(), face.height ), paint );
// Create transformation matrix
transforMatrix = new Matrix();
// Rotate around center of oval
transforMatrix.postRotate( tilt_angle, face.width() / 2, face.height() / 2 );
transforMatrix.postTranslate( face.left, face.top );
canvas.drawBitmap( ovalBmp, transforMatrix, null );
ps: I assume by tilt angle you mean roll, where pitch is rotation around X axis, yaw is rotation around Y axis and roll is rotation around Z axis.
I am trying to make an application in which i can zoom in and draw some thing on the image
i have used following link to make a zoomable image view which is working fine
zoom functionality for images
now the problem is that i dont know how to scale and translate whatever i am drawing on my canvas to the image size when it is zoomed out.
following is the onDraw() function.
i have recorded the touch points added them into a list and in this onDraw() function of my view i am retrieving those points but these points are relative to screen .
i have to translate and scale it according to the image operation(in case of zoom in/out of the image) .
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(mMarkers!=null)
{
for(Marker m : mMarkers) {
// draw the marker
Log.v("IP","position"+ m.x+" "+ m.y);
Paint paint=new Paint();
paint.setARGB(255, 2, 255, 2);
canvas.drawText("O", m.x, m.y, paint);
if(x!=-1){
Log.v("IP","LINE"+x+" " + y+ " "+ m.x+" "+ m.y);
canvas.drawLine(x, y,m.x, m.y, paint);
}
x=m.x;
y=m.y;
}
x=y=-1;
}
}
Use this code
public boolean onTouchEvent(MotionEvent env) {
float x = env.getX() / mScaleFactor + rect.left;
float y = env.getY() / mScaleFactor + rect.top;
}
Please try this code
public boolean onTouchEvent(MotionEvent env) {
float x = env.getX() / mScaleFactor + rect.left;
float y = env.getY() / mScaleFactor + rect.top;
}
you can get 9 point array from the matrix which contain the relative x,y and scale factor in x and y use this to convert you current x,y (which is with respect to screen) to x,y on original image and reconvert it before drawing again on different zoom levels.