2012-12-18 9 views
6

Herhangi biriniz herhangi bir dörtgede nasıl bir görüntüyü bozacağınızı biliyor musunuz? Görüntüyü çarpıtarak herhangi bir köşeyi herhangi bir yöne çekebileceğiniz bir görüntü uygulamak istiyorum. Bunun nasıl yapılacağı hakkında bir fikri olan var mı? Bir süredir android'de bir şeyler kullanıyorum ve yazdım ama android bunun için bir işlevi var gibi görünmüyor. Gerçekten yeni bir matematik kütüphanesi yazmak gibi hissetmiyorum :). Eğer Canvas.drawBitmapMesh ihtiyaç gibiGörüntüyü herhangi bir dörtgene doğru nasıl bozulur?

Selamlar, Can

cevap

8

görünüyor. Android SDK'da nasıl kullanılacağını gösteren bir örnek var.

Canvas adresinden bitmap'inizi çizmek için Matrix kullanmanız gerekir. Bitmap görüntüsünüzü Matrix.polyToPoly yöntemiyle herhangi bir dörtgene sığacak şekilde bu dönüşümü kolayca oluşturabilirsiniz. Bu gibi görünecektir:

matrix.setPolyToPoly(
     new float[] { 
      0, 0, 
      bitmap.getWidth(), 0 
      0, bitmap.getHeight(), 
      bitmap.getWidth(), bitmap.getHeight() 
     }, 0, 
     new float[] { 
      x0, y0, 
      x1, y1, 
      x2, y2, 
      x3, y3 
     }, 0, 
     4); 

canvas.drawBitmap(bitmap, matrix, paint); 

Nerede x0-x3, y0-y3 sizin dörtgen köşe koordinatlarını vardır.

+0

teşekkürler hızlı cevap için çok. Matrix sınıfında setPolytoPoly yöntemini görmemek için aptal hissediyorum, ancak bu işe yaramalı. Bunu yarın işte test edeceğim :-)! – Geki

+0

Bu yöntemle ilgili problem, sayısal olarak çok yoğun olduğu ve bu nedenle düşük uçlu cihazlarda çok yavaş olmasıdır. – user2498079

+0

Evet, ancak bizden başka bir seçenek yok. – Geki

3

Kodunuzda bir sorun var.

matrix.setPolyToPoly(
     new float[] { 
      x0, y0, 
      x1, y1, 
      x2, y2, 
      x3, y3}, 
    0, 
new float[] { 
     0, 0, 
     bitmap.getWidth(), 0 
     0, bitmap.getHeight(), 
     bitmap.getWidth(), bitmap.getHeight() 
    }, 0, 
    4); 

:

public boolean setPolyToPoly (float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount) 
WHERE 
src: The array of src [x,y] pairs (points) 
... 
dst: The array of dst [x,y] pairs (points) 

Yani, kodla göre, matris olarak oluşturulmalıdır: Doğru yöntem olmasına rağmen Android belgelerinde göründüğü gibi, sen şamandıra [] parametreleri ters gelmiş resimde görüldüğü gibi bu şekilde, uygulama, gayet iyi çalışıyor:

enter image description here

Öte yandan By user2498079 söylediklerinin ilişkin, onun Düşük uç cihazlarda hesaplama problemi hakkında yorum yaparsanız, matris dönüşüm hesaplamasından önce kaynak görüntü boyutunu (ve örneğin renk derinliğini) azaltmak için bazı kolay yapılır tekniklerini kullanabilirsiniz. Düşük son telefonun bu görevi gerçekleştirmesini kolaylaştırır.

1

Umarım bu yardımcı olur. Sol üstte ve sağ üst köşede, sol altta ve sağ altta değil. Birisi ekleyebilir. Alt kısımların nasıl yapılacağını anlayamıyorum. :)

public class PerspectiveDistortView extends View implements OnTouchListener { 

private Paint paintRect, paintCircle; 
public int LEFT; 
public int TOP; 
public int RIGHT; 
public int BOTTOM; 
Point CIRCLE_TOP_LEFT; 
Point CIRCLE_TOP_RIGHT; 
Point CIRCLE_BOTTOM_LEFT; 
Point CIRCLE_BOTTOM_RIGHT; 
private int lastX, lastY; 
Bitmap image; 
Rect src, dst; 
Matrix matrix2; 
boolean isTouchCirclePoints = true; 
float deform2 = 5f; 

public PerspectiveDistortView(Context context) { 
    super(context); 
    // TODO Auto-generated constructor stub 
    init(); 
} 

public PerspectiveDistortView(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    // TODO Auto-generated constructor stub 
    init(); 
} 

public PerspectiveDistortView(Context context, AttributeSet attrs, 
     int defStyle) { 
    super(context, attrs, defStyle); 
    // TODO Auto-generated constructor stub 
    init(); 
} 

private void init(){ 
    this.setOnTouchListener(this); 
    paintRect = new Paint(); 
    paintRect.setColor(0xffff0000); 
    paintRect.setAntiAlias(true); 
    paintRect.setDither(true); 
    paintRect.setStyle(Paint.Style.STROKE); 
    paintRect.setStrokeJoin(Paint.Join.BEVEL); 
    paintRect.setStrokeCap(Paint.Cap.BUTT); 
    paintRect.setStrokeWidth(3); 
    paintCircle = new Paint(); 
    paintCircle.setColor(0xff000000); 
    paintCircle.setAntiAlias(true); 
    paintCircle.setDither(true); 
    paintCircle.setStyle(Paint.Style.FILL_AND_STROKE); 
    paintCircle.setStrokeJoin(Paint.Join.BEVEL); 
    paintCircle.setStrokeCap(Paint.Cap.BUTT); 

    LEFT = 90; 
    TOP = 40; 
    RIGHT = 500; 
    BOTTOM = 700; 
    CIRCLE_TOP_LEFT = new Point(LEFT, TOP); 
    CIRCLE_TOP_RIGHT = new Point(RIGHT, TOP); 
    CIRCLE_BOTTOM_LEFT = new Point(LEFT, BOTTOM); 
    CIRCLE_BOTTOM_RIGHT = new Point(RIGHT, BOTTOM); 

    image = BitmapFactory.decodeResource(getResources(), R.drawable.ai); 

    src = new Rect(); 
    dst = new Rect(); 

    matrix2 = new Matrix(); 
} 

@Override 
protected void onDraw(Canvas canvas) { 
    // draw image 
    src.left = LEFT; 
    src.top = TOP; 
    src.right = RIGHT; 
    src.bottom = BOTTOM + image.getHeight(); 

    dst.left = CIRCLE_TOP_LEFT.x; 
    dst.top = CIRCLE_TOP_LEFT.y; 
    dst.right = CIRCLE_TOP_RIGHT.x; 
    dst.bottom = CIRCLE_BOTTOM_RIGHT.y; 

    // Free Transform bitmap 
     int bw = image.getWidth(); 
     int bh = image.getHeight(); 
     RectF src = new RectF(LEFT, TOP, bw, bh); 
     RectF dst = new RectF(CIRCLE_TOP_LEFT.x + 35, CIRCLE_TOP_LEFT.y + 30, CIRCLE_TOP_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y); 
     matrix2.setRectToRect(src, dst, ScaleToFit.FILL); 

     float[] pts = { 
         // source 
         0, 0, 
         0, bh, 
         bw, bh, 
         bw, 0, 
         // destination 
         0, 0, 
         0, 0, 
         0, 0, 
         0, 0}; 
     matrix2.mapPoints(pts, 8, pts, 0, 4); 
     int DX = 100; 
     pts[10] -= CIRCLE_TOP_LEFT.x - LEFT; 
     pts[12] -= CIRCLE_TOP_RIGHT.x - RIGHT; 
     pts[13] += 0; 
     pts[14] += 0; 
     pts[15] += CIRCLE_TOP_RIGHT.y - CIRCLE_TOP_LEFT.y; 

     matrix2.setPolyToPoly(pts, 0, pts, 8, 4); 
     canvas.drawBitmap(image, matrix2, null); 
     isTouchCirclePoints = false; 

    // line left 
    canvas.drawLine(CIRCLE_TOP_LEFT.x, CIRCLE_TOP_LEFT.y, CIRCLE_BOTTOM_LEFT.x, CIRCLE_BOTTOM_LEFT.y, paintRect); 
    // line top 
    canvas.drawLine(CIRCLE_TOP_LEFT.x, CIRCLE_TOP_LEFT.y, CIRCLE_TOP_RIGHT.x, CIRCLE_TOP_RIGHT.y, paintRect); 
    // line right 
    canvas.drawLine(CIRCLE_TOP_RIGHT.x, CIRCLE_TOP_RIGHT.y, CIRCLE_BOTTOM_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y, paintRect); 
    // line bottom 
    canvas.drawLine(CIRCLE_BOTTOM_LEFT.x, CIRCLE_BOTTOM_LEFT.y, CIRCLE_BOTTOM_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y, paintRect); 
    // circle top left 
    canvas.drawCircle(CIRCLE_TOP_LEFT.x, CIRCLE_TOP_LEFT.y, 10, paintCircle); 
    // circle top right 
    canvas.drawCircle(CIRCLE_TOP_RIGHT.x, CIRCLE_TOP_RIGHT.y, 10, paintCircle); 
    // circle bottom left 
    canvas.drawCircle(CIRCLE_BOTTOM_LEFT.x, CIRCLE_BOTTOM_LEFT.y, 10, paintCircle); 
    // circle bottom right 
    canvas.drawCircle(CIRCLE_BOTTOM_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y, 10, paintCircle); 
} 

@Override 
public boolean onTouch(View view, MotionEvent event) { 
    lastX = (int) event.getX(); 
    lastY = (int)event.getY(); 
    if (inCircle(lastX, lastY, CIRCLE_TOP_LEFT.x, CIRCLE_TOP_LEFT.y, 40)) 
    { 
     isTouchCirclePoints = true; 
     CIRCLE_TOP_LEFT.set(lastX, lastY); 
    } else if (inCircle(lastX, lastY, CIRCLE_TOP_RIGHT.x, CIRCLE_TOP_RIGHT.y, 40)) 
    { 
     isTouchCirclePoints = true; 
     CIRCLE_TOP_RIGHT.set(lastX, lastY); 
    } else if (inCircle(lastX, lastY, CIRCLE_BOTTOM_LEFT.x, CIRCLE_BOTTOM_LEFT.y, 40)) 
    { 
     isTouchCirclePoints = true; 
     CIRCLE_BOTTOM_LEFT.set(lastX, lastY); 
    } else if (inCircle(lastX, lastY, CIRCLE_BOTTOM_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y, 40)) 
    { 
     isTouchCirclePoints = true; 
     CIRCLE_BOTTOM_RIGHT.set(lastX, lastY); 
    } 
    invalidate(); 
    return true; 
} 

private boolean inCircle(float x, float y, float circleCenterX, float circleCenterY, float circleRadius) { 
    double dx = Math.pow(x - circleCenterX, 2); 
    double dy = Math.pow(y - circleCenterY, 2); 

    if ((dx + dy) < Math.pow(circleRadius, 2)) { 
     return true; 
    } else { 
     return false; 
    } 
} 

}

4

@donmj. Kodunu tamir ettim.

public class PerspectiveDistortView extends View implements View.OnTouchListener { 

private Paint paintRect, paintCircle; 
public int LEFT; 
public int TOP; 
public int RIGHT; 
public int BOTTOM; 
Point CIRCLE_TOP_LEFT; 
Point CIRCLE_TOP_RIGHT; 
Point CIRCLE_BOTTOM_LEFT; 
Point CIRCLE_BOTTOM_RIGHT; 
private int lastX, lastY; 
Bitmap image; 
Matrix matrix2; 
boolean isTouchCirclePoints = true; 

public PerspectiveDistortView(Context context) { 
    super(context); 
    // TODO Auto-generated constructor stub 
    init(); 
} 

public PerspectiveDistortView(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    // TODO Auto-generated constructor stub 
    init(); 
} 

public PerspectiveDistortView(Context context, AttributeSet attrs, 
           int defStyle) { 
    super(context, attrs, defStyle); 
    // TODO Auto-generated constructor stub 
    init(); 
} 

private void init() { 
    this.setOnTouchListener(this); 
    paintRect = new Paint(); 
    paintRect.setColor(0xffff0000); 
    paintRect.setAntiAlias(true); 
    paintRect.setDither(true); 
    paintRect.setStyle(Paint.Style.STROKE); 
    paintRect.setStrokeJoin(Paint.Join.BEVEL); 
    paintRect.setStrokeCap(Paint.Cap.BUTT); 
    paintRect.setStrokeWidth(3); 
    paintCircle = new Paint(); 
    paintCircle.setColor(0xff000000); 
    paintCircle.setAntiAlias(true); 
    paintCircle.setDither(true); 
    paintCircle.setStyle(Paint.Style.FILL_AND_STROKE); 
    paintCircle.setStrokeJoin(Paint.Join.BEVEL); 
    paintCircle.setStrokeCap(Paint.Cap.BUTT); 

    LEFT = 90; 
    TOP = 40; 
    RIGHT = 500; 
    BOTTOM = 700; 
    CIRCLE_TOP_LEFT = new Point(LEFT, TOP); 
    CIRCLE_TOP_RIGHT = new Point(RIGHT, TOP); 
    CIRCLE_BOTTOM_LEFT = new Point(LEFT, BOTTOM); 
    CIRCLE_BOTTOM_RIGHT = new Point(RIGHT, BOTTOM); 

    image = BitmapFactory.decodeResource(getResources(), R.drawable.penguins); 

    matrix2 = new Matrix(); 
} 

@Override 
protected void onDraw(Canvas canvas) { 
    // Free Transform bitmap 
    int bw = image.getWidth(); 
    int bh = image.getHeight(); 

    float[] pts = { 
      // source 
      0, 0, 
      0, bh, 
      bw, bh, 
      bw, 0, 
      // destination 
      0, 0, 
      0, 0, 
      0, 0, 
      0, 0}; 
    pts[8] = CIRCLE_TOP_LEFT.x; 
    pts[9] = CIRCLE_TOP_LEFT.y; 
    pts[10] = CIRCLE_BOTTOM_LEFT.x; 
    pts[11] = CIRCLE_BOTTOM_LEFT.y; 
    pts[12] = CIRCLE_BOTTOM_RIGHT.x; 
    pts[13] = CIRCLE_BOTTOM_RIGHT.y; 
    pts[14] = CIRCLE_TOP_RIGHT.x; 
    pts[15] = CIRCLE_TOP_RIGHT.y; 

    matrix2.setPolyToPoly(pts, 0, pts, 8, 4); 
    canvas.drawBitmap(image, matrix2, null); 
    isTouchCirclePoints = false; 

    // line left 
    canvas.drawLine(CIRCLE_TOP_LEFT.x, CIRCLE_TOP_LEFT.y, CIRCLE_BOTTOM_LEFT.x, CIRCLE_BOTTOM_LEFT.y, paintRect); 
    // line top 
    canvas.drawLine(CIRCLE_TOP_LEFT.x, CIRCLE_TOP_LEFT.y, CIRCLE_TOP_RIGHT.x, CIRCLE_TOP_RIGHT.y, paintRect); 
    // line right 
    canvas.drawLine(CIRCLE_TOP_RIGHT.x, CIRCLE_TOP_RIGHT.y, CIRCLE_BOTTOM_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y, paintRect); 
    // line bottom 
    canvas.drawLine(CIRCLE_BOTTOM_LEFT.x, CIRCLE_BOTTOM_LEFT.y, CIRCLE_BOTTOM_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y, paintRect); 
    // circle top left 
    canvas.drawCircle(CIRCLE_TOP_LEFT.x, CIRCLE_TOP_LEFT.y, 10, paintCircle); 
    // circle top right 
    canvas.drawCircle(CIRCLE_TOP_RIGHT.x, CIRCLE_TOP_RIGHT.y, 10, paintCircle); 
    // circle bottom left 
    canvas.drawCircle(CIRCLE_BOTTOM_LEFT.x, CIRCLE_BOTTOM_LEFT.y, 10, paintCircle); 
    // circle bottom right 
    canvas.drawCircle(CIRCLE_BOTTOM_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y, 10, paintCircle); 
} 

@Override 
public boolean onTouch(View view, MotionEvent event) { 
    lastX = (int) event.getX(); 
    lastY = (int) event.getY(); 

    if (inCircle(lastX, lastY, CIRCLE_TOP_LEFT.x, CIRCLE_TOP_LEFT.y, 40)) { 
     isTouchCirclePoints = true; 
     CIRCLE_TOP_LEFT.set(lastX, lastY); 
    } else if (inCircle(lastX, lastY, CIRCLE_TOP_RIGHT.x, CIRCLE_TOP_RIGHT.y, 40)) { 
     isTouchCirclePoints = true; 
     CIRCLE_TOP_RIGHT.set(lastX, lastY); 
    } else if (inCircle(lastX, lastY, CIRCLE_BOTTOM_LEFT.x, CIRCLE_BOTTOM_LEFT.y, 40)) { 
     isTouchCirclePoints = true; 
     CIRCLE_BOTTOM_LEFT.set(lastX, lastY); 
    } else if (inCircle(lastX, lastY, CIRCLE_BOTTOM_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y, 40)) { 
     isTouchCirclePoints = true; 
     CIRCLE_BOTTOM_RIGHT.set(lastX, lastY); 
    } 
    invalidate(); 
    return true; 
} 

private boolean inCircle(float x, float y, float circleCenterX, float circleCenterY, float circleRadius) { 
    double dx = Math.pow(x - circleCenterX, 2); 
    double dy = Math.pow(y - circleCenterY, 2); 

    if ((dx + dy) < Math.pow(circleRadius, 2)) { 
     return true; 
    } else { 
     return false; 
    } 
} 
} 
+0

Sadece iOS/Swift'de bunu yapamayan herkes için burada. [İşte iOS için çözümde bir düşüş ile bir QA!] (Http: // stackoverflow.com/a/39981054/294884) – Fattie

+0

bu harika cevap için teşekkür etmek için bir ödül gönderdi! – Fattie

+0

@JoeBlow Ödülün için teşekkürler! Yardım ettiğine sevindim. – h2nghia

İlgili konular