简体   繁体   English

如何使用opencv4android给流体效果/调整位图WRT触摸事件的大小

[英]How to give Fluid effect / resize bitmap wrt touch events using opencv4android

I'm newbie with OpenCV4Android and Android NDK 我是OpenCV4Android和Android NDK的新手

Trying to achieve 试图实现

Stretch the image with respect to Touch Points on Image.(Putting Hair on Face and stretching it accordingly using touch events Like 'Virtual Make Over Application' ) 相对于图像上的触摸点拉伸图像(将头发放在脸上并使用“虚拟化妆”应用程序之类的触摸事件进行相应拉伸)

Issues: While using Java 问题:使用Java时

Implemented warp function on Touch Events by getting Matrix from Bitmap and recomputing them onTouchEvents. 通过从位图获取矩阵并在TouchEvents上重新计算它们,在Touch Events上实现了扭曲功能。 But the Image get distorted and whole Matrix gets upside down. 但是图像会失真,整个矩阵会倒置。

How can use OpenCV4Android to achieve goal like these? 如何使用OpenCV4Android实现这些目标?

Tried to get Mat from Bitmap and Resize the Image. 试图从位图获取Mat并调整图像大小。 But didn't got any idea How I'm going to proceed further with these? 但是不知道我将如何进一步处理这些?

Any enlightenment on these would be very helpful. 这些方面的任何启示都将非常有帮助。

在此处输入图片说明

After going through lots of Image Processing Libraries, every one has warpping and morphing effects but none of them having effects on touch points. 经过大量的图像处理库后,每个库都具有扭曲和变形效果,但是没有一个对触摸点有影响。 As many of them suggested you can achieve such things using OpenCV4Android or OpenGL but none of them is my cup of tea. 正如他们中许多人所建议的那样,您可以使用OpenCV4Android或OpenGL来实现这些目标,但这些都不是我的理想之选。

So In the end implemented Warpping effect with NDK in C. 因此最终在C中使用NDK实现了扭曲效果。

Here's algorithm which applied to Bitmap Pixels on touch points. 这是应用于接触点上的位图像素的算法。

#include <stdio.h>
#include <stdlib.h>
#include <jni.h>
#include <math.h>
#include <malloc.h>
#include <android/log.h>
#define LOG_TAG "System.out"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

int *colorRed;
int *colorGreen;
int *colorBlue;
int *colorsP; //ÏñËØÖµ

int *colorAlpha;
int _width, _height;
jintArray imagecolors;

//²éÕÒ±í
static long SinXDivX_Table_8[(2 << 8) + 1];
double MySin(double x) {
    double absx;
    absx = x;
    if (x < 0)
        absx = -x;

WarpView which does the warpping effect on Touch Points: WarpView在接触点上产生扭曲效果:

public class WarpView extends View {
    static {
        System.loadLibrary("Hello");
    }

    public native int[] warpPhotoFromC(int[] image, int height, int width,
            double max_dist, double orig_x, double orig_y, double cur_x,
            double cur_y);

    private static String TAG = WarpView.class.getSimpleName();

    private Bitmap mBmp;
    private int[] image;
    private int first = 0;
    private int[] colorR;
    private int[] colorG;
    private int[] colorB;
    private Bitmap newBmp;
    private boolean fg = true;
    private Context context;

    private static final int DEFAULT_PAINT_FLAGS = Paint.FILTER_BITMAP_FLAG
            | Paint.DITHER_FLAG;
    static Paint mPaint = new Paint(DEFAULT_PAINT_FLAGS);

    public static int HWPPQ = 110;
    public static int MMQFJ = 120;

    private int MODE = MMQFJ;

    // SA VIKALP
//  public ArrayList<WarpViewUndo> mArrayListWarpViewUndo;

    static GestureDetector mGestures;
    static ScaleGestureDetector mScaleGesture;

    private Matrix mMatrix = new Matrix();
    private Matrix mInverse = new Matrix();

    private float lastFocusX;
    private float lastFocusY;

    private boolean mIsMove = false;

    // EA VIKALP
    public WarpView(Context context) {
        super(context);
    }

    public WarpView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        dest = new RectF(0, 0, 0, 0);

        // SA VIKALP
//      mArrayListWarpViewUndo = new ArrayList<WarpViewUndo>();
        mScaleGesture = new ScaleGestureDetector(getContext(),
                new ScaleListener());
        mGestures = new GestureDetector(getContext(), new GestureListener());

        mMatrix.setTranslate(5, 5);
        mMatrix.invert(mInverse);
        // EA VIKALP
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // super.onDraw(canvas);
        if (fg) {
            int viewWidht = getWidth();
            int viewHeight = getHeight();
            float scale1 = (float) width / (float) viewWidht;
            float scale2 = (float) height / (float) viewHeight;
            scale = scale1 > scale2 ? scale1 : scale2;
            int xoffset = (viewWidht - (int) (width / scale)) / 2;
            int yoffset = (viewHeight - (int) (height / scale)) / 2;
            dest.set(xoffset, yoffset, (int) (width / scale) + xoffset,
                    (int) (height / scale) + yoffset);// = new RectF(xoffset,
                                                        // yoffset, (int)
                                                        // (width/scale)+xoffset,
                                                        // (int)
                                                        // (height/scale)+yoffset);
            // SA VIKALP
            canvas.drawColor(0x000000);
            canvas.concat(mMatrix);
            // canvas.drawColor(Color.TRANSPARENT);
            // canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
            // EA VIKALP
            canvas.drawBitmap(mBmp, null, dest, mPaint);

        } else {
            // SA VIKALP
            canvas.drawColor(0x000000);
            canvas.concat(mMatrix);
            // canvas.drawColor(Color.TRANSPARENT);
            // canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
            // EA VIKALP
            canvas.drawBitmap(newBmp, null, dest, mPaint);
        }
    }

    private double orig_x, orig_y;
    private double mou_dx, mou_dy;
    private double max_dist, max_dist_sq;
    private int width;
    private int height;
    private int count = 0;
    private double mou_dx_norm;
    private double mou_dy_norm;

    private float scale;
    private RectF dest;
    private double move_x, move_y;
    private int dist = (int) getResources().getDimension(R.dimen.max_dist);
    private int line_height = (int) getResources().getDimension(
            R.dimen.warp_line);

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // SA VIKALP
        mScaleGesture.onTouchEvent(event);
        mGestures.onTouchEvent(event);
        // EA VIKALP

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            orig_x = event.getX();
            orig_y = event.getY();
            orig_x = (orig_x - dest.left) * scale;
            orig_y = (orig_y - dest.top) * scale;

            break;
        case MotionEvent.ACTION_MOVE:
            if (!mIsMove) { // SA VIKALP ADDED LINE
                max_dist = dist * scale;// Math.hypot(mou_dx, mou_dy);
                if (event.getAction() != 1) {


                    // int m = event.getHistorySize();

                    move_x = event.getX();
                    move_y = event.getY();

                    move_x = (move_x - dest.left) * scale;
                    move_y = (move_y - dest.top) * scale;

                    // if(m > 0){
                    // int i2 = m + -1;
                    // orig_x = (event.getHistoricalX(i2) - dest.left)*scale;
                    // orig_y = (event.getHistoricalY(i2) - dest.top)*scale;
                    // }

                    if (move_x >= 0 && move_y >= 0) {
                            warpPhotoFromC(image, height, width, max_dist, orig_x,
                                    orig_y, move_x, move_y);
                        first++;

                        newBmp.setPixels(image, 0, width, 0, 0, width, height);
                        fg = false;
                    }
                }
                orig_x = move_x;
                orig_y = move_y;

            } 
            break;
        case MotionEvent.ACTION_UP:
            break;
        }
        invalidate();
        return true;
    }
    // SA VIKALP
//  public void applyWarpUndo(Bitmap bmp) {
//      setWarpBitmap(bmp);
//      Log.i(TAG, "Size : "
//              + mArrayListWarpViewUndo.size()
//              + " last size :"
//              + mArrayListWarpViewUndo.get(mArrayListWarpViewUndo.size() - 1)
//                      .getSize() + 1);
//      
//      for (int i = 0; i < mArrayListWarpViewUndo.size() - (mArrayListWarpViewUndo.get(mArrayListWarpViewUndo.size() - 1).getSize()+1); i++) {
//          if (mArrayListWarpViewUndo.get(i).getMove_x() >= 0 && mArrayListWarpViewUndo.get(i).getMove_y() >= 0) {
//              warpPhotoFromC(mArrayListWarpViewUndo.get(i).getImage(),
//                      mArrayListWarpViewUndo.get(i).getHeight(),
//                      mArrayListWarpViewUndo.get(i).getWidth(),
//                      mArrayListWarpViewUndo.get(i).getMax_dist(),
//                      mArrayListWarpViewUndo.get(i).getOrig_x(),
//                      mArrayListWarpViewUndo.get(i).getOrig_y(),
//                      mArrayListWarpViewUndo.get(i).getMove_x(),
//                      mArrayListWarpViewUndo.get(i).getMove_y());
//
//              newBmp.setPixels(mArrayListWarpViewUndo.get(i).getImage(), 0,
//                      mArrayListWarpViewUndo.get(i).getWidth(), 0, 0,
//                      mArrayListWarpViewUndo.get(i).getWidth(),
//                      mArrayListWarpViewUndo.get(i).getHeight());
//              fg = false;
//          }
//      }
////        Log.i(TAG, "Step Size "+mArrayListWarpViewUndo.size()-1);
//      mArrayListWarpViewUndo.remove(mArrayListWarpViewUndo.size()-2);
//      invalidate();
//  }
    public class ScaleListener implements OnScaleGestureListener {

        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            // TODO Auto-generated method stub
            Matrix transformationMatrix = new Matrix();
            float focusX = detector.getFocusX();
            float focusY = detector.getFocusY();

            // Zoom focus is where the fingers are centered,
            transformationMatrix.postTranslate(-focusX, -focusY);

            transformationMatrix.postScale(detector.getScaleFactor(),
                    detector.getScaleFactor());

            /*
             * Adding focus shift to allow for scrolling with two pointers down.
             * Remove it to skip this functionality. This could be done in fewer
             * lines, but for clarity I do it this way here
             */
            // Edited after comment by chochim
            float focusShiftX = focusX - lastFocusX;
            float focusShiftY = focusY - lastFocusY;
            transformationMatrix.postTranslate(focusX + focusShiftX, focusY
                    + focusShiftY);
            mMatrix.postConcat(transformationMatrix);
            lastFocusX = focusX;
            lastFocusY = focusY;
            invalidate();
            return true;
        }

        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            // TODO Auto-generated method stub
            lastFocusX = detector.getFocusX();
            lastFocusY = detector.getFocusY();
            return true;
        }

        @Override
        public void onScaleEnd(ScaleGestureDetector detector) {
            // TODO Auto-generated method stub

        }
    }

    public class GestureListener implements OnGestureListener,
            OnDoubleTapListener {

        @Override
        public boolean onDoubleTap(MotionEvent arg0) {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public boolean onDoubleTapEvent(MotionEvent arg0) {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public boolean onSingleTapConfirmed(MotionEvent arg0) {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public boolean onDown(MotionEvent e) {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                float velocityY) {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public void onLongPress(MotionEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2,
                float distanceX, float distanceY) {
            // TODO Auto-generated method stub
            if (mIsMove) {
                mMatrix.postTranslate(-distanceX, -distanceY);
                invalidate();
            }
            return true;
        }

        @Override
        public void onShowPress(MotionEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            // TODO Auto-generated method stub
            return false;
        }
    }

    public void setMove(boolean isMove) {
        mIsMove = isMove;
    }

    // EA VIKALP

    public void setWarpBitmap(Bitmap bmp) {
        fg = true;// �置标志
        first = 0;
        mBmp = bmp;
        width = bmp.getWidth();
        height = bmp.getHeight();
        // 新建�?��Bitmap
        // SU VIKALP
        // newBmp = Bitmap.createBitmap(width, height,
        // Bitmap.Config.RGB_565);
        newBmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        // EU VIKALP
        image = new int[width * height];

        mBmp.getPixels(image, 0, width, 0, 0, width, height);
        newBmp.setPixels(image, 0, width, 0, 0, width, height);
        // super.setImageBitmap(mBmp);
    }

    public void setMode(int mode) {
        this.MODE = mode;
    }

    /**
     * �?回处�好的图片
     * 
     * @return
     */
    public Bitmap getWrapBitmap() {
        return newBmp;
    }

    public void changeBitmapContrastBrightness() {
        float contrast, brightness;
        Random generator = new Random();
        contrast = generator.nextFloat();
        brightness = contrast;

        // Log.i(TAG, "changeBitmapContrastBrightness " + contrast);

        ColorMatrix cm = new ColorMatrix(new float[] { 
                0.501f, 0, 0, 0,0,// red
                0, 0, 0, 0, brightness,// green
                0, 0, 0.501f, 0, brightness,// blue
                0, 0, 0, 1, 0 // alpha
                });
        mPaint.setColorFilter(new ColorMatrixColorFilter(cm));
        invalidate();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM