一、自定义属性

    <declare-styleable name="SingleTouchView"><attr name="src" format="reference" />            <!-- 用于缩放旋转的图标 --><attr name="editable" format="boolean"/>          <!-- 是否处于可编辑状态 --><attr name="frameColor" format="color" />         <!-- 边框颜色 --><attr name="frameWidth" format="dimension" />     <!-- 边框线宽度 --><attr name="framePadding" format="dimension" />   <!-- 边框与图片的间距 --><attr name="degree" format="float" />             <!-- 旋转角度 --><attr name="scale" format="float" />              <!-- 缩放比例 --><attr name="controlDrawable" format="reference"/> <!-- 控制图标 --><attr name="controlLocation">                     <!-- 控制图标的位置 --><enum name="left_top" value="0" /><enum name="right_top" value="1" /><enum name="right_bottom" value="2" /><enum name="left_bottom" value="3" /></attr></declare-styleable>

二、自定义控件代码

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.FloatMath;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;/*** 单手对图片进行缩放,旋转,平移操作,详情请查看*/
public class SingleTouchView extends View {/*** 图片的最大缩放比例*/public static final float MAX_SCALE = 4.0f;/*** 图片的最小缩放比例*/public static final float MIN_SCALE = 0.3f;/*** 控制缩放,旋转图标所在四个点得位置*/public static final int LEFT_TOP = 0;public static final int RIGHT_TOP = 1;public static final int RIGHT_BOTTOM = 2;public static final int LEFT_BOTTOM = 3;/*** 一些默认的常量*/public static final int DEFAULT_FRAME_PADDING = 8;public static final int DEFAULT_FRAME_WIDTH = 2;public static final int DEFAULT_FRAME_COLOR = Color.WHITE;public static final float DEFAULT_SCALE = 1.0f;public static final float DEFAULT_DEGREE = 0;public static final int DEFAULT_CONTROL_LOCATION = RIGHT_TOP;public static final boolean DEFAULT_EDITABLE = true;public static final int DEFAULT_OTHER_DRAWABLE_WIDTH = 50;public static final int DEFAULT_OTHER_DRAWABLE_HEIGHT = 50;/*** 用于旋转缩放的Bitmap*/private Bitmap mBitmap;/*** SingleTouchView的中心点坐标,相对于其父类布局而言的*/private PointF mCenterPoint = new PointF();/*** View的宽度和高度,随着图片的旋转而变化(不包括控制旋转,缩放图片的宽高)*/private int mViewWidth, mViewHeight;/*** 图片的旋转角度*/private float mDegree = DEFAULT_DEGREE;/*** 图片的缩放比例*/private float mScale = DEFAULT_SCALE;/*** 用于缩放,旋转,平移的矩阵*/private Matrix matrix = new Matrix();/*** SingleTouchView距离父类布局的左间距*/private int mViewPaddingLeft;/*** SingleTouchView距离父类布局的上间距*/private int mViewPaddingTop;/*** 图片四个点坐标*/private Point mLTPoint;private Point mRTPoint;private Point mRBPoint;private Point mLBPoint;/*** 用于缩放,旋转的控制点的坐标*/private Point mControlPoint = new Point();/*** 用于缩放,旋转的图标*/private Drawable controlDrawable;/*** 缩放,旋转图标的宽和高*/private int mDrawableWidth, mDrawableHeight;/*** 画外围框的Path*/private Path mPath = new Path();/*** 画外围框的画笔*/private Paint mPaint ;/*** 初始状态*/public static final int STATUS_INIT = 0;/*** 拖动状态*/public static final int STATUS_DRAG = 1;/*** 旋转或者放大状态*/public static final int STATUS_ROTATE_ZOOM = 2; /*** 当前所处的状态*/private int mStatus = STATUS_INIT;/*** 外边框与图片之间的间距, 单位是dip*/private int framePadding = DEFAULT_FRAME_PADDING;/*** 外边框颜色*/private int frameColor = DEFAULT_FRAME_COLOR;/*** 外边框线条粗细, 单位是 dip*/private int frameWidth = DEFAULT_FRAME_WIDTH;/*** 是否处于可以缩放,平移,旋转状态*/private boolean isEditable = DEFAULT_EDITABLE;private DisplayMetrics metrics;private PointF mPreMovePointF = new PointF();private PointF mCurMovePointF = new PointF();/*** 图片在旋转时x方向的偏移量*/private int offsetX;/*** 图片在旋转时y方向的偏移量*/private int offsetY;/*** 控制图标所在的位置(比如左上,右上,左下,右下)*/private int controlLocation = DEFAULT_CONTROL_LOCATION;public SingleTouchView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public SingleTouchView(Context context) {this(context, null);}public SingleTouchView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);obtainStyledAttributes(attrs);init();}/*** 获取自定义属性* @param attrs*/private void obtainStyledAttributes(AttributeSet attrs){metrics = getContext().getResources().getDisplayMetrics();framePadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_FRAME_PADDING, metrics);frameWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_FRAME_WIDTH, metrics);TypedArray mTypedArray = getContext().obtainStyledAttributes(attrs,R.styleable.SingleTouchView);Drawable srcDrawble = mTypedArray.getDrawable(R.styleable.SingleTouchView_src);mBitmap = drawable2Bitmap(srcDrawble);framePadding = mTypedArray.getDimensionPixelSize(R.styleable.SingleTouchView_framePadding, framePadding);frameWidth = mTypedArray.getDimensionPixelSize(R.styleable.SingleTouchView_frameWidth, frameWidth);frameColor = mTypedArray.getColor(R.styleable.SingleTouchView_frameColor, DEFAULT_FRAME_COLOR);mScale = mTypedArray.getFloat(R.styleable.SingleTouchView_scale, DEFAULT_SCALE);mDegree = mTypedArray.getFloat(R.styleable.SingleTouchView_degree, DEFAULT_DEGREE);controlDrawable = mTypedArray.getDrawable(R.styleable.SingleTouchView_controlDrawable);controlLocation = mTypedArray.getInt(R.styleable.SingleTouchView_controlLocation, DEFAULT_CONTROL_LOCATION);isEditable = mTypedArray.getBoolean(R.styleable.SingleTouchView_editable, DEFAULT_EDITABLE);mTypedArray.recycle();}private void init(){mPaint = new Paint();mPaint.setAntiAlias(true);mPaint.setColor(frameColor);mPaint.setStrokeWidth(frameWidth);mPaint.setStyle(Style.STROKE);if(controlDrawable == null){controlDrawable = getContext().getResources().getDrawable(R.drawable.st_rotate_icon);}mDrawableWidth = controlDrawable.getIntrinsicWidth();mDrawableHeight = controlDrawable.getIntrinsicHeight();transformDraw(); }@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);//获取SingleTouchView所在父布局的中心点ViewGroup mViewGroup = (ViewGroup) getParent();if(null != mViewGroup){int parentWidth = mViewGroup.getWidth();int parentHeight = mViewGroup.getHeight();mCenterPoint.set(parentWidth/2, parentHeight/2);}}/*** 调整View的大小,位置*/private void adjustLayout(){int actualWidth = mViewWidth + mDrawableWidth;int actualHeight = mViewHeight + mDrawableHeight;int newPaddingLeft = (int) (mCenterPoint.x - actualWidth /2);int newPaddingTop = (int) (mCenterPoint.y - actualHeight/2);if(mViewPaddingLeft != newPaddingLeft || mViewPaddingTop != newPaddingTop){mViewPaddingLeft = newPaddingLeft;mViewPaddingTop = newPaddingTop;//         layout(newPaddingLeft, newPaddingTop, newPaddingLeft + actualWidth, newPaddingTop + actualHeight);}layout(newPaddingLeft, newPaddingTop, newPaddingLeft + actualWidth, newPaddingTop + actualHeight);}/*** 设置旋转图* @param bitmap*/public void setImageBitamp(Bitmap bitmap){this.mBitmap = bitmap;transformDraw();}/*** 设置旋转图* @param drawable*/public void setImageDrawable(Drawable drawable){this.mBitmap = drawable2Bitmap(drawable);transformDraw();}/*** 从Drawable中获取Bitmap对象* @param drawable* @return*/private Bitmap drawable2Bitmap(Drawable drawable) {try {if (drawable == null) {return null;}if (drawable instanceof BitmapDrawable) {return ((BitmapDrawable) drawable).getBitmap();}int intrinsicWidth = drawable.getIntrinsicWidth();int intrinsicHeight = drawable.getIntrinsicHeight();Bitmap bitmap = Bitmap.createBitmap(intrinsicWidth <= 0 ? DEFAULT_OTHER_DRAWABLE_WIDTH: intrinsicWidth,intrinsicHeight <= 0 ? DEFAULT_OTHER_DRAWABLE_HEIGHT: intrinsicHeight, Config.ARGB_8888);Canvas canvas = new Canvas(bitmap);drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());drawable.draw(canvas);return bitmap;} catch (OutOfMemoryError e) {return null;}}/*** 根据id设置旋转图* @param resId*/public void setImageResource(int resId){Drawable drawable = getContext().getResources().getDrawable(resId);setImageDrawable(drawable);}@Overrideprotected void onDraw(Canvas canvas) {//每次draw之前调整View的位置和大小super.onDraw(canvas);if(mBitmap == null) return;canvas.drawBitmap(mBitmap, matrix, mPaint);//处于可编辑状态才画边框和控制图标if(isEditable){mPath.reset();mPath.moveTo(mLTPoint.x, mLTPoint.y);mPath.lineTo(mRTPoint.x, mRTPoint.y);mPath.lineTo(mRBPoint.x, mRBPoint.y);mPath.lineTo(mLBPoint.x, mLBPoint.y);mPath.lineTo(mLTPoint.x, mLTPoint.y);mPath.lineTo(mRTPoint.x, mRTPoint.y);canvas.drawPath(mPath, mPaint);//画旋转, 缩放图标controlDrawable.setBounds(mControlPoint.x - mDrawableWidth / 2,mControlPoint.y - mDrawableHeight / 2, mControlPoint.x + mDrawableWidth/ 2, mControlPoint.y + mDrawableHeight / 2);controlDrawable.draw(canvas);}adjustLayout();}/*** 设置Matrix, 强制刷新*/private void transformDraw(){if(mBitmap == null) return;int bitmapWidth = (int)(mBitmap.getWidth() * mScale);int bitmapHeight = (int)(mBitmap.getHeight()* mScale);computeRect(-framePadding, -framePadding, bitmapWidth + framePadding, bitmapHeight + framePadding, mDegree);//设置缩放比例matrix.setScale(mScale, mScale);//绕着图片中心进行旋转matrix.postRotate(mDegree % 360, bitmapWidth/2, bitmapHeight/2);//设置画该图片的起始点matrix.postTranslate(offsetX + mDrawableWidth/2, offsetY + mDrawableHeight/2);adjustLayout();}public boolean onTouchEvent(MotionEvent event) {if(!isEditable){return super.onTouchEvent(event);}switch (event.getAction() ) {case MotionEvent.ACTION_DOWN:mPreMovePointF.set(event.getX() + mViewPaddingLeft, event.getY() + mViewPaddingTop);mStatus = JudgeStatus(event.getX(), event.getY());break;case MotionEvent.ACTION_UP:mStatus = STATUS_INIT;break;case MotionEvent.ACTION_MOVE:mCurMovePointF.set(event.getX() + mViewPaddingLeft, event.getY() + mViewPaddingTop);if (mStatus == STATUS_ROTATE_ZOOM) {float scale = 1f;int halfBitmapWidth = mBitmap.getWidth() / 2;int halfBitmapHeight = mBitmap.getHeight() /2 ;//图片某个点到图片中心的距离float bitmapToCenterDistance = FloatMath.sqrt(halfBitmapWidth * halfBitmapWidth + halfBitmapHeight * halfBitmapHeight);//移动的点到图片中心的距离float moveToCenterDistance = distance4PointF(mCenterPoint, mCurMovePointF);//计算缩放比例scale = moveToCenterDistance / bitmapToCenterDistance;//缩放比例的界限判断if (scale <= MIN_SCALE) {scale = MIN_SCALE;} else if (scale >= MAX_SCALE) {scale = MAX_SCALE;}// 角度double a = distance4PointF(mCenterPoint, mPreMovePointF);double b = distance4PointF(mPreMovePointF, mCurMovePointF);double c = distance4PointF(mCenterPoint, mCurMovePointF);double cosb = (a * a + c * c - b * b) / (2 * a * c);if (cosb >= 1) {cosb = 1f;}double radian = Math.acos(cosb);float newDegree = (float) radianToDegree(radian);//center -> proMove的向量, 我们使用PointF来实现PointF centerToProMove = new PointF((mPreMovePointF.x - mCenterPoint.x), (mPreMovePointF.y - mCenterPoint.y));//center -> curMove 的向量  PointF centerToCurMove = new PointF((mCurMovePointF.x - mCenterPoint.x), (mCurMovePointF.y - mCenterPoint.y));//向量叉乘结果, 如果结果为负数, 表示为逆时针, 结果为正数表示顺时针float result = centerToProMove.x * centerToCurMove.y - centerToProMove.y * centerToCurMove.x;if (result < 0) {newDegree = -newDegree;} mDegree = mDegree + newDegree;mScale = scale;transformDraw();}else if (mStatus == STATUS_DRAG) {// 修改中心点mCenterPoint.x += mCurMovePointF.x - mPreMovePointF.x;mCenterPoint.y += mCurMovePointF.y - mPreMovePointF.y;System.out.println(this + "move = " + mCenterPoint);adjustLayout();}mPreMovePointF.set(mCurMovePointF);break;}return true;}/*** 获取四个点和View的大小* @param left* @param top* @param right* @param bottom* @param degree*/private void computeRect(int left, int top, int right, int bottom, float degree){Point lt = new Point(left, top);Point rt = new Point(right, top);Point rb = new Point(right, bottom);Point lb = new Point(left, bottom);Point cp = new Point((left + right) / 2, (top + bottom) / 2);mLTPoint = obtainRoationPoint(cp, lt, degree);mRTPoint = obtainRoationPoint(cp, rt, degree);mRBPoint = obtainRoationPoint(cp, rb, degree);mLBPoint = obtainRoationPoint(cp, lb, degree);//计算X坐标最大的值和最小的值int maxCoordinateX = getMaxValue(mLTPoint.x, mRTPoint.x, mRBPoint.x, mLBPoint.x);int minCoordinateX = getMinValue(mLTPoint.x, mRTPoint.x, mRBPoint.x, mLBPoint.x);;mViewWidth = maxCoordinateX - minCoordinateX ;//计算Y坐标最大的值和最小的值int maxCoordinateY = getMaxValue(mLTPoint.y, mRTPoint.y, mRBPoint.y, mLBPoint.y);int minCoordinateY = getMinValue(mLTPoint.y, mRTPoint.y, mRBPoint.y, mLBPoint.y);mViewHeight = maxCoordinateY - minCoordinateY ;//View中心点的坐标Point viewCenterPoint = new Point((maxCoordinateX + minCoordinateX) / 2, (maxCoordinateY + minCoordinateY) / 2);offsetX = mViewWidth / 2 - viewCenterPoint.x;offsetY = mViewHeight / 2 - viewCenterPoint.y;int halfDrawableWidth = mDrawableWidth / 2;int halfDrawableHeight = mDrawableHeight /2;//将Bitmap的四个点的X的坐标移动offsetX + halfDrawableWidthmLTPoint.x += (offsetX + halfDrawableWidth);mRTPoint.x += (offsetX + halfDrawableWidth);mRBPoint.x += (offsetX + halfDrawableWidth);mLBPoint.x += (offsetX + halfDrawableWidth);//将Bitmap的四个点的Y坐标移动offsetY + halfDrawableHeightmLTPoint.y += (offsetY + halfDrawableHeight);mRTPoint.y += (offsetY + halfDrawableHeight);mRBPoint.y += (offsetY + halfDrawableHeight);mLBPoint.y += (offsetY + halfDrawableHeight);mControlPoint = LocationToPoint(controlLocation);}/*** 根据位置判断控制图标处于那个点* @return*/private Point LocationToPoint(int location){switch(location){case LEFT_TOP:return mLTPoint;case RIGHT_TOP:return mRTPoint;case RIGHT_BOTTOM:return mRBPoint;case LEFT_BOTTOM:return mLBPoint;}return mLTPoint;}/*** 获取变长参数最大的值* @param array* @return*/public int getMaxValue(Integer...array){List<Integer> list = Arrays.asList(array);Collections.sort(list);return list.get(list.size() -1);}/*** 获取变长参数最大的值* @param array* @return*/public int getMinValue(Integer...array){List<Integer> list = Arrays.asList(array);Collections.sort(list);return list.get(0);}/*** 获取旋转某个角度之后的点* @param viewCenter* @param source* @param degree* @return*/public static Point obtainRoationPoint(Point center, Point source, float degree) {//两者之间的距离Point disPoint = new Point();disPoint.x = source.x - center.x;disPoint.y = source.y - center.y;//没旋转之前的弧度double originRadian = 0;//没旋转之前的角度double originDegree = 0;//旋转之后的角度double resultDegree = 0;//旋转之后的弧度double resultRadian = 0;//经过旋转之后点的坐标Point resultPoint = new Point();double distance = Math.sqrt(disPoint.x * disPoint.x + disPoint.y * disPoint.y);if (disPoint.x == 0 && disPoint.y == 0) {return center;// 第一象限} else if (disPoint.x >= 0 && disPoint.y >= 0) {// 计算与x正方向的夹角originRadian = Math.asin(disPoint.y / distance);// 第二象限} else if (disPoint.x < 0 && disPoint.y >= 0) {// 计算与x正方向的夹角originRadian = Math.asin(Math.abs(disPoint.x) / distance);originRadian = originRadian + Math.PI / 2;// 第三象限} else if (disPoint.x < 0 && disPoint.y < 0) {// 计算与x正方向的夹角originRadian = Math.asin(Math.abs(disPoint.y) / distance);originRadian = originRadian + Math.PI;} else if (disPoint.x >= 0 && disPoint.y < 0) {// 计算与x正方向的夹角originRadian = Math.asin(disPoint.x / distance);originRadian = originRadian + Math.PI * 3 / 2;}// 弧度换算成角度originDegree = radianToDegree(originRadian);resultDegree = originDegree + degree;// 角度转弧度resultRadian = degreeToRadian(resultDegree);resultPoint.x = (int) Math.round(distance * Math.cos(resultRadian));resultPoint.y = (int) Math.round(distance * Math.sin(resultRadian));resultPoint.x += center.x;resultPoint.y += center.y;return resultPoint;}/*** 弧度换算成角度* * @return*/public static double radianToDegree(double radian) {return radian * 180 / Math.PI;}/*** 角度换算成弧度* @param degree* @return*/public static double degreeToRadian(double degree) {return degree * Math.PI / 180;}/*** 根据点击的位置判断是否点中控制旋转,缩放的图片, 初略的计算* @param x* @param y* @return*/private int JudgeStatus(float x, float y){PointF touchPoint = new PointF(x, y);PointF controlPointF = new PointF(mControlPoint);//点击的点到控制旋转,缩放点的距离float distanceToControl = distance4PointF(touchPoint, controlPointF);//如果两者之间的距离小于 控制图标的宽度,高度的最小值,则认为点中了控制图标if(distanceToControl < Math.min(mDrawableWidth/2, mDrawableHeight/2)){return STATUS_ROTATE_ZOOM;}return STATUS_DRAG;}public float getImageDegree() {return mDegree;}/*** 设置图片旋转角度* @param degree*/public void setImageDegree(float degree) {if(this.mDegree != degree){this.mDegree = degree;transformDraw();}}public float getImageScale() {return mScale;}/*** 设置图片缩放比例* @param scale*/public void setImageScale(float scale) {if(this.mScale != scale){this.mScale = scale;transformDraw();};}public Drawable getControlDrawable() {return controlDrawable;}/*** 设置控制图标* @param drawable*/public void setControlDrawable(Drawable drawable) {this.controlDrawable = drawable;mDrawableWidth = drawable.getIntrinsicWidth();mDrawableHeight = drawable.getIntrinsicHeight();transformDraw();}public int getFramePadding() {return framePadding;}public void setFramePadding(int framePadding) {if(this.framePadding == framePadding)return;this.framePadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, framePadding, metrics);transformDraw();}public int getFrameColor() {return frameColor;}public void setFrameColor(int frameColor) {if(this.frameColor == frameColor)return;this.frameColor = frameColor;mPaint.setColor(frameColor);invalidate();}public int getFrameWidth() {return frameWidth;}public void setFrameWidth(int frameWidth) {if(this.frameWidth == frameWidth) return;this.frameWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, frameWidth, metrics);mPaint.setStrokeWidth(frameWidth);invalidate();}/*** 设置控制图标的位置, 设置的值只能选择LEFT_TOP ,RIGHT_TOP, RIGHT_BOTTOM,LEFT_BOTTOM* @param controlLocation*/public void setControlLocation(int location) {if(this.controlLocation == location)return;this.controlLocation = location;transformDraw();}public int getControlLocation() {return controlLocation;}public PointF getCenterPoint() {return mCenterPoint;}/*** 设置图片中心点位置,相对于父布局而言* @param mCenterPoint*/public void setCenterPoint(PointF mCenterPoint) {this.mCenterPoint = mCenterPoint;adjustLayout();}public boolean isEditable() {return isEditable;}/*** 设置是否处于可缩放,平移,旋转状态* @param isEditable*/public void setEditable(boolean isEditable) {this.isEditable = isEditable;invalidate();}/*** 两个点之间的距离* @param x1* @param y1* @param x2* @param y2* @return*/private float distance4PointF(PointF pf1, PointF pf2) {float disX = pf2.x - pf1.x;float disY = pf2.y - pf1.y;return FloatMath.sqrt(disX * disX + disY * disY);}}

三、使用

<merge xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><com.example.singletouchview.SingleTouchViewxmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/SingleTouchView"android:layout_width="match_parent"android:layout_height="match_parent"app:scale="1.2"app:src="@drawable/photo"app:frameColor="#0022ff"app:controlLocation="right_top"/>
</merge>

View复用: http://files.cnblogs.com/files/andlp/com.maneater.picscreator.zip

文档:https://www.cnblogs.com/andlp/p/5972260.html

Android自定义控件篇 图片进行平移,缩放,旋转相关推荐

  1. iOS图片添加平移/缩放/旋转多个手势

    // // UIImageView+Utils.h // OpenWorkr // // Created by 冰凉的枷锁 on 2017/3/6. // Copyright © 2017年 Eden ...

  2. [Python从零到壹] 三十八.图像处理基础篇之图像几何变换(平移缩放旋转)

    欢迎大家来到"Python从零到壹",在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界.所有文章都将结合案例.代码和作者的经验讲 ...

  3. qgraphicsview鼠标移动图片_交互式QGraphicsView(平移/缩放/旋转)-阿里云开发者社区...

    简述 Graphics View提供了一个平台用于大量自定义 2D 图元的管理与交互框架包括一个事件传播架构支持场景 Scene 中的图元 Item 进行精确的双精度交互功能.Item 可以处理键盘事 ...

  4. C语言数字图像处理---1.5图像基本变换之平移缩放旋转

    本篇作为新年到来前的最后一篇,提前祝大家新年快乐! 图像几何变换又叫做图像基本变换,主要包括图像平移.图像缩放和图像旋转几个部分,当然还有图像镜像等简单的内容.图像基本变换是图像处理的基本内容,是学习 ...

  5. 用C#编写一个图片浏览器,实现鼠标控制图片的平移缩放与图片的灰度化

    1. 界面设计 如图1 所示:一个名为ImView 的Form 只中包含有一个名为picturebox 的Picturebox.图2 是它的运行结果.该程序的界面设计较为简单,主要根据鼠标行为及键盘按 ...

  6. 线性代数:矩阵变换图形(三维平移缩放旋转)

    紧接上一篇:http://blog.csdn.net/yinhun2012/article/details/79544205 这篇博文我只是准备对上一篇博文的内容进行扩展,因为上一篇我写完二维xy仿射 ...

  7. [Python图像处理] 三十六.OpenCV图像几何变换万字详解(平移缩放旋转、镜像仿射透视)

    该系列文章是讲解Python OpenCV图像处理知识,前期主要讲解图像入门.OpenCV基础用法,中期讲解图像处理的各种算法,包括图像锐化算子.图像增强技术.图像分割等,后期结合深度学习研究图像识别 ...

  8. opengl矩阵变换与平移缩放旋转

    2019独角兽企业重金招聘Python工程师标准>>> 坐标系: 1.右手坐标系 2.左手坐标系 左手坐标系是X轴向右,Y轴向上,Z轴向前,右手坐标系的Z轴正好相反,是指向" ...

  9. 变换矩阵_平移 缩放 旋转及统一变换

    1. 位移(translation) 对于一个三维坐标(x, y, z),我们想让它往x轴正方向移动1个单位,往y轴正方向移动1个单位,往z轴正方向移动1个单位,则可以让它加上一个向量(1, 1, 1 ...

最新文章

  1. 什么是SESSION?(一)
  2. PCIE的事务类型:posted和non posted transaction
  3. ThreadLocal的使用及原理分析
  4. 理解JVM如何使用Windows和Linux上的本机内存
  5. 2019-10-14 无约束条件的泛函极值问题的举例说明
  6. 移除添加的文件_文件压缩教程-文件批量压缩
  7. 关于Echarts的填坑之旅
  8. 大数据使用及现状调研报告
  9. Discord 公司如何使用 Cassandra 存储上亿条线上数据
  10. 关于计算机硬盘属性对话框中,计算机文化基础练习题(2).docx
  11. mysql主从有关参数_mysql主从复制配置
  12. Halcon——点胶机胶水路径应用(2)
  13. 华为服务器系统图标,监控服务器图标
  14. python怎么写阶乘_python阶乘怎么写
  15. excel高级筛选怎么用_Excel筛选功能这样用,再多数据我也不惧了!
  16. R语言使用rnorm函数生成正太分布数据、使用stem函数可视化茎叶图、茎叶图很直观的表现出数据的分布情况
  17. 山东标梵讲解APP开发与技术公司之间的联系
  18. java练习(金额转换)
  19. 终于我用JOL打破了你对java对象的所有想象
  20. 聊天机器人系统的组成结构及关键技术

热门文章

  1. python_强化学习算法DQN_玩五子棋游戏
  2. computer-01 CPU
  3. vue axios跨域问题
  4. html5 文字向下滚动,HTML5实现文字滚动
  5. (5)内存注册机的使用
  6. BZOJ1746 DP
  7. CSS3媒体查询适配不同型号的手机 IphoneX/IphoneXR等
  8. VS 2019 专业版 下载安装教程
  9. 苹果最新审核条例学习
  10. python hashlib_python import hashlib出现问题