如何实现旋转图像算法和缩放图像算法?

时间:2017-03-14 06:03:24

标签: java image-processing

如何实现旋转图像算法并放大或缩小图像? 我尝试实现旋转算法,但图像不显示,我不知道算法是否正常,请检查旋转算法是否正常,请帮我在旋转后显示图像并在缩放后显示图像。我想在没有预定义功能的情况下旋转和缩放图像。

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Rotation extends JPanel{

public static void main(String []args){
    JFrame f = new JFrame();
    f.add(new Rotation());
    f.setSize(750, 600);
    f.setVisible(true);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    BufferedImage img = null;
    try {
        img = ImageIO.read(new File("img.jpg"));
    } catch (IOException e) {
        e.printStackTrace();
    }
    Rotation r = new Rotation();
    r.rotateCw(img, null);
}

public static void rotateCw( BufferedImage img, Graphics g )
{
    int         width  = img.getWidth();
    int         height = img.getHeight();
    BufferedImage   newImage = new BufferedImage( height, width, img.getType() );

    for( int i=0 ; i < width ; i++ ){
        for( int j=0 ; j < height ; j++ ){
            newImage.setRGB( height-1-j, i, img.getRGB(i,j) );;
        }
    }
    Graphics2D g2d = (Graphics2D) g;

    g2d.drawImage(newImage, 25, 25, null);
}

}

3 个答案:

答案 0 :(得分:1)

您还没有将rotateCW传递给图形对象。你的代码看起来像这样......

 Rotation r = new Rotation();
 Graphics graphics = f.getGraphics();
 r.rotateCw(img, graphics);
 graphics.dispose();

它需要看起来像这样..从JFrame获取一个Graphics对象以将结果绘制到。

{{1}}

我测试了你的代码并添加了它并且它有效:)在你的情况下,它会在丢失的Graphics对象上抛出一个异常,只留下空的JPanel。

答案 1 :(得分:0)

您可以通过以下方式执行此操作: 首先创建一个DraggableBitmap类

public class DraggableBitmap {
private boolean activated;
private Matrix currentMatrix;
public Bitmap mBitmap;
private int mId;
private Matrix marginMatrix;
private Matrix savedMatrix;
private boolean touched;

public DraggableBitmap(Bitmap b) {
    this.mId = -1;
    this.currentMatrix = null;
    this.savedMatrix = null;
    this.mBitmap = b;
    this.activated = false;
}

public void setCurrentMatrix(Matrix m) {
    this.currentMatrix = null;
    this.currentMatrix = new Matrix(m);
}

public void setSavedMatrix(Matrix m) {
    this.savedMatrix = null;
    this.savedMatrix = new Matrix(m);
}

public Matrix getCurrentMatrix() {
    return this.currentMatrix;
}

public Matrix getSavedMatrix() {
    return this.savedMatrix;
}

public void activate() {
    this.activated = true;
}

public void deActivate() {
    this.activated = false;
}

public boolean isActivate() {
    return this.activated;
}

public boolean isTouched() {
    return this.touched;
}

public void setTouched(boolean touched) {
    this.touched = touched;
}

public Matrix getMarginMatrix() {
    return this.marginMatrix;
}

public void setMarginMatrix(Matrix marginMatrix) {
    this.marginMatrix = null;
    this.marginMatrix = new Matrix(marginMatrix);
}

public int getmId() {
    return this.mId;
}

public void setmId(int mId) {
    this.mId = mId;
}
}

现在创建DraggableImageView,它扩展了imageview

public class DraggableImageView extends ImageView {

// some private variable use for detect multi touch
public enum EDITMODE {
    NONE, DRAG, ZOOM, ROTATE
}

private static final String TAG = "Draggable Bitmap";

private boolean mDrawOpacityBackground = false;
private Paint mPaint = new Paint();
private DraggableBitmap mActiveBitmap = null;
private RectF mInnerImageBounds = null;
private Stack<BitmapOperationMap> mOperationStack = new Stack<BitmapOperationMap>();
public Context context;

// list of stamp bitmaps
private List<DraggableBitmap> mOverlayBitmaps;

// constructors
public DraggableImageView(Context context) {
    super(context);
    initMembers();
    this.setOnTouchListener(touchListener);
    this.context=context;
}

public DraggableImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
    initMembers();
    this.setOnTouchListener(touchListener);
    this.context=context;
}

private void initMembers() {
    mOverlayBitmaps = new ArrayList<DraggableBitmap>();
}

// listeners
private OnTouchListener touchListener = new OnTouchListener() {
    // to get mode [drag, zoom, rotate]
    private EDITMODE mEditMode = EDITMODE.NONE;

    private float[] mLastEvent;
    private PointF mStart = new PointF();
    private PointF mMid = new PointF();
    private float mOldDistance;
    private float mNewRotation = 0f;
    private float mDist = 0f;

    // this variable use to deal with android odd touch behavior (MOVE -> UP
    // -> MOVE -> UP)
    private boolean touchMoveEndChecker = false;

    @Override
    public boolean onTouch(View v, MotionEvent event) {

        // switch finger events
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case (MotionEvent.ACTION_DOWN):
                touchMoveEndChecker = true;
                mDrawOpacityBackground = true;
                int activebmpIdx = getActiveBitmap(event.getX(), event.getY());

                if (activebmpIdx != -1) {
                    mActiveBitmap = mOverlayBitmaps.get(activebmpIdx);
                    rearrangeOverlayList();
                } else {
                    mActiveBitmap = null;
                    break;
                }
                mLastEvent = null;
                mEditMode = EDITMODE.DRAG;
                mStart.set(event.getX(), event.getY());

                if (mActiveBitmap != null) {
                    mActiveBitmap.setSavedMatrix(mActiveBitmap.getCurrentMatrix());
                }

                facePlacer.showInvisible(context);

                break;

            case (MotionEvent.ACTION_POINTER_DOWN):
                touchMoveEndChecker = false;
                mDrawOpacityBackground = true;
                if (mActiveBitmap != null) {
                    mOldDistance = spacing(event);
                    if (mOldDistance > 10f) {
                        mActiveBitmap.setSavedMatrix(mActiveBitmap.getCurrentMatrix());
                        midPoint(mMid, event);
                        mEditMode = EDITMODE.ZOOM;
                    }

                    mLastEvent = new float[4];
                    mLastEvent[0] = event.getX(0);
                    mLastEvent[1] = event.getX(1);
                    mLastEvent[2] = event.getY(0);
                    mLastEvent[3] = event.getY(1);

                    mDist = rotation(event);
                }
                break;

            case (MotionEvent.ACTION_POINTER_UP):
                mEditMode = EDITMODE.NONE;
                break;

            case (MotionEvent.ACTION_MOVE):
                touchMoveEndChecker = false;
                mDrawOpacityBackground = true;

                if (mActiveBitmap != null) {
                    if (mEditMode == EDITMODE.DRAG) {
                        mActiveBitmap.setCurrentMatrix(mActiveBitmap.getSavedMatrix());
                        mActiveBitmap.getCurrentMatrix().postTranslate(event.getX() - mStart.x,
                                event.getY() - mStart.y);
                    } else if (mEditMode == EDITMODE.ZOOM && event.getPointerCount() == 2) {
                        float newDistance = spacing(event);
                        mActiveBitmap.setCurrentMatrix(mActiveBitmap.getSavedMatrix());
                        if (newDistance > 10f) {
                            float scale = newDistance / mOldDistance;
                            mActiveBitmap.getCurrentMatrix()
                                    .postScale(scale, scale, mMid.x, mMid.y);
                        }

                        if (mLastEvent != null) {
                            mNewRotation = rotation(event);
                            float r = mNewRotation - mDist;
                            RectF rec = new RectF(0, 0, mActiveBitmap.mBitmap.getWidth(),
                                    mActiveBitmap.mBitmap.getHeight());
                            mActiveBitmap.getCurrentMatrix().mapRect(rec);
                            mActiveBitmap.getCurrentMatrix().postRotate(r,
                                    rec.left + rec.width() / 2, rec.top + rec.height() / 2);
                        }
                    }

                }

            case (MotionEvent.ACTION_UP):
                if (touchMoveEndChecker) { // means 2 continuous ACTION_UP, or
                    // real finger up after moving
                    mDrawOpacityBackground = false;
                    if (mActiveBitmap != null) {
                        // push a map to bitmap and clone of current matrix
                        mOperationStack
                                .push(new BitmapOperationMap(mActiveBitmap, new Matrix(
                                        mActiveBitmap.getCurrentMatrix()),
                                        BitmapOperationMap.OPERATION.ADD));
                        mActiveBitmap.deActivate();
                    }
                    facePlacer.showvisible(context);
                }
                touchMoveEndChecker = true;
            default:
                break;
        }

        invalidate();
        return true;
    }

};

public int addOverlayBitmap(DraggableBitmap dBitmap) {
    Matrix marginMtx = new Matrix();

    marginMtx.postTranslate(mInnerImageBounds.left, mInnerImageBounds.top);
    dBitmap.setMarginMatrix(marginMtx);

    Matrix curMtx = new Matrix();
    curMtx.postConcat(marginMtx);

    dBitmap.setCurrentMatrix(curMtx);
    mOperationStack
            .push(new BitmapOperationMap(dBitmap, null, BitmapOperationMap.OPERATION.NEW));
    mOperationStack.push(new BitmapOperationMap(dBitmap, dBitmap.getCurrentMatrix(),
            BitmapOperationMap.OPERATION.ADD));
    dBitmap.setmId(this.mOverlayBitmaps.size());
    mOverlayBitmaps.add(dBitmap);
    invalidate();
    return dBitmap.getmId();
}

private int getActiveBitmap(float event_x, float event_y) {
    int size = mOverlayBitmaps.size();
    int retidx = -1;
    DraggableBitmap retBmp = null;
    // search for all bitmap to find closest to finger
    for (int i = 0; i < size; i++) {
        DraggableBitmap dBmp = mOverlayBitmaps.get(i);
        dBmp.deActivate();
        float bmp_x = 0;
        float bmp_y = 0;
        RectF r = new RectF(0, 0, dBmp.mBitmap.getWidth(), dBmp.mBitmap.getHeight());
        Matrix mtx = dBmp.getCurrentMatrix() == null ? dBmp.getMarginMatrix() : dBmp
                .getCurrentMatrix();

        mtx.mapRect(r);
        bmp_x = r.left;
        bmp_y = r.top;

        if (event_x >= bmp_x && event_x < (bmp_x + r.width()) && event_y >= bmp_y
                && event_y < (bmp_y + r.height())) {
            retBmp = dBmp;
            retidx = i;
        }
    }
    if (retBmp != null) {
        if (!retBmp.isTouched()) {
            retBmp.setTouched(true);
        }
        retBmp.activate();
    }
    return retidx;
}

private float spacing(MotionEvent event) {
    float x = event.getX(0) - event.getX(1);
    float y = event.getY(0) - event.getY(1);
    return (float) Math.sqrt(x * x + y * y);
}

/**
 * Calculate the mid point of the first two fingers
 */
private void midPoint(PointF point, MotionEvent event) {
    float x = event.getX(0) + event.getX(1);
    float y = event.getY(0) + event.getY(1);
    point.set(x / 2, y / 2);
}

private float rotation(MotionEvent event) {
    double delta_x = (event.getX(0) - event.getX(1));
    double delta_y = (event.getY(0) - event.getY(1));
    double rad = Math.atan2(delta_y, delta_x);

    return (float) Math.toDegrees(rad);
}

public List<DraggableBitmap> getOverlayList() {
    return mOverlayBitmaps;
}

public void undo() {
    if (!mOperationStack.empty()) {
        BitmapOperationMap prev = mOperationStack.pop();
        if (!mOperationStack.empty()) { // current stack is final operation
            prev = mOperationStack.peek();
        }
        DraggableBitmap bmp = prev.getDraggableBitmap();
        Matrix mtx = prev.getOperationMatrix();

        switch (prev.getOption()) {
            case NEW: // if action is create new, then delete
                mOverlayBitmaps.remove(bmp);
                break;
            case ADD:
                bmp.setCurrentMatrix(mtx);
                break;
            case DELETE: // not implement yet
                break;
            default:
                break;
        }
    }
}

@Override
protected void onDraw(Canvas canvas) { // [TODO] khi xoay man hinh error
    super.onDraw(canvas);
    RectF bitmapRect = getInnerBitmapSize();
    if (bitmapRect == null) return;
    mInnerImageBounds = bitmapRect;
    canvas.clipRect(bitmapRect);

    // loop to draw all bitmap
    Enumeration<DraggableBitmap> e = Collections.enumeration(mOverlayBitmaps);
    while (e.hasMoreElements()) {
        DraggableBitmap dBmp = (DraggableBitmap) e.nextElement();
        if (true) {
            if (dBmp.getCurrentMatrix() != null) {
                canvas.drawBitmap(dBmp.mBitmap, dBmp.getCurrentMatrix(), null);
                RectF r = getStampBounding(dBmp);
                if (mDrawOpacityBackground && dBmp == mActiveBitmap) {
                    mPaint.setColor(0x00000000);
                    mPaint.setStyle(Style.FILL);
                    mPaint.setAlpha(20);
                    canvas.drawRect(r, mPaint);

                }
            }
        }
    }
}

public RectF getInnerBitmapSize() {
    RectF bitmapRect = new RectF();
    if (this.getDrawable() == null) return null;
    bitmapRect.right = this.getDrawable().getIntrinsicWidth();
    bitmapRect.bottom = this.getDrawable().getIntrinsicHeight();

    Matrix m = this.getImageMatrix();
    m.mapRect(bitmapRect);
    return bitmapRect;
}

private RectF getStampBounding(DraggableBitmap bmp) {
    if (bmp.mBitmap == null) return null;
    RectF r = new RectF(0, 0, bmp.mBitmap.getWidth(), bmp.mBitmap.getHeight());
    bmp.getCurrentMatrix().mapRect(r);
    return r;
}

public void deleteActiveBitmap() {
    if (mActiveBitmap == null) return;
    mOverlayBitmaps.remove(mActiveBitmap);
}

public void replaceOverlayBitmap(DraggableBitmap dBitmap, int replaceIndex) {
    if (replaceIndex <= this.mOverlayBitmaps.size()) {
        this.mActiveBitmap = (DraggableBitmap) this.mOverlayBitmaps.get(replaceIndex);
        dBitmap.setCurrentMatrix(this.mActiveBitmap.getCurrentMatrix());
        this.mOverlayBitmaps.add(replaceIndex, dBitmap);
        this.mOverlayBitmaps.remove(this.mActiveBitmap);
        this.mActiveBitmap = (DraggableBitmap) this.mOverlayBitmaps.get(replaceIndex);
        invalidate();
    }
}

public void flipActiveBitmap() {
    try {
        Matrix flipHorizontalMtx = new Matrix();
        flipHorizontalMtx.setScale(-1, 1);
        flipHorizontalMtx.postTranslate((float) (mActiveBitmap.mBitmap.getWidth()), (float) 0);
        Matrix mtx = mActiveBitmap.getCurrentMatrix();
        mtx.preConcat(flipHorizontalMtx);

        mActiveBitmap.setCurrentMatrix(mtx);
    } catch (NullPointerException e) {
        Log.v(TAG, "active bitmap is null");
    } catch (Exception e) {
        Log.v(TAG, "error ocurred");
    }
}

public void rearrangeOverlayList() {
    int idx = mOverlayBitmaps.indexOf(mActiveBitmap);
    mOverlayBitmaps.add(mActiveBitmap);
    mOverlayBitmaps.remove(idx);
}
public void removeAll() {
    mOverlayBitmaps.clear();
    mOverlayBitmaps = new ArrayList();
    invalidate();
}
}

现在扩展了imageview的ProportionalImageView

public class ProportionalImageView extends ImageView {

public ProportionalImageView(Context context) {
    super(context);
}

public ProportionalImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public ProportionalImageView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    Drawable d = getDrawable();
    if (d != null) {
        int w = MeasureSpec.getSize(widthMeasureSpec);
        int h = w * d.getIntrinsicHeight() / d.getIntrinsicWidth();
        setMeasuredDimension(w, h);
    } else super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}

现在只需将这些类用作

 DraggableBitmap stamp1 = new DraggableBitmap(thumbnail);
 replaceMap.put(1, canvasImage.addOverlayBitmap(stamp1));

Replacemap是用于存储图像的哈希映射。

答案 2 :(得分:0)

我只是添加另一个答案,向您展示如何使用您在其他答案中询问的旋转代码。我只需更改引用Picture类的代码即可使用BufferedImages。您还必须考虑制作新图像的大小。

public static void rotateCw( BufferedImage img, Graphics g, double degrees ) {
    int         width  = img.getWidth();
    int         height = img.getHeight();
    BufferedImage   newImage = new BufferedImage( width, height, img.getType() );

    double angle = Math.toRadians( degrees );
    double sin = Math.sin(angle);
    double cos = Math.cos(angle);
    double x0 = 0.5 * (width  - 1);     // point to rotate about
    double y0 = 0.5 * (height - 1);     // center of image

    // rotation
    for (int x = 0; x < width; x++) {
        for (int y = 0; y < height; y++) {
            double a = x - x0;
            double b = y - y0;
            int xx = (int) (+a * cos - b * sin + x0);
            int yy = (int) (+a * sin + b * cos + y0);

            if (xx >= 0 && xx < width && yy >= 0 && yy < height) {
                newImage.setRGB(x, y, img.getRGB(xx, yy));
            }
        }
    }
    Graphics2D g2d = (Graphics2D) g;
    g2d.drawImage(newImage, 0, 0, null);
}