个人中心--圆形头像--拍照--裁剪

微信小程序拍照功能实战:从权限申请到圆形头像裁剪全流程 本文详细解析了微信小程序中实现拍照功能的完整流程,重点涵盖摄像头权限的申请与管理策略、Camera组件的深度定制与优化,以及使用Canvas进行圆形头像裁剪的实战技巧。文章提供了从权限检查、用户引导到图片处理与性能优化的全链路代码示例,帮助开发者构建流畅、专业的用户头像上传体验。 阅读详情

本篇文章总结下app个人中心里面圆形头像,拍照,相册,裁剪功能。
(lll¬ω¬),最近项目要做二期,所以只好把之前写过的头像类整理下发出来(( ̄▽ ̄)”懒)

废话不多说了,直接上代码,简单明了。
首先我们得自定义个圆形的CircleImageView继承于ImageView,实现圆形头像效果。
先放简单的CircleImageView ,文章结尾附上附上在微信上看到的大神写的CircleImageView。

CircleImageView

package 。。自己的包名。。;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;

import com.ccqlk.dx.R;

import org.xutils.common.util.DensityUtil;


/**
 * 圆形图片,并有边框
 * Created by RYX on 2017/9/14.
 */
public class CircleImageView extends android.support.v7.widget.AppCompatImageView {
    private Paint mPaintCircle;             //画圆形图片的笔
    private Paint mPaintBorder;             //画圆形边框的笔

    private int mCircleBorderWidth;        //边框宽度
    private int mCirlcleBorderColor;       //边框颜色

    public CircleImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.widget_circle_image_view);
        mCircleBorderWidth = (int) typedArray.getDimension(R.styleable.widget_circle_image_view_borderWidth, DensityUtil.dip2px(2));  // 获取设置的边框宽度
        mCirlcleBorderColor = typedArray.getColor(R.styleable.widget_circle_image_view_borderColor, Color.parseColor("#FF5BAFE4"));// 获取设置的边框颜色
        typedArray.recycle();

        init();
    }

    private void init() {
        // 初始化圆的画笔
        mPaintCircle = new Paint();
        mPaintCircle.setAntiAlias(true);                    //抗锯齿

        //初始化边框的画笔
        mPaintBorder = new Paint();
        mPaintBorder.setAntiAlias(true);                    //抗锯齿
        mPaintBorder.setStyle(Paint.Style.STROKE);
        mPaintBorder.setStrokeWidth(mCircleBorderWidth); //设置边框粗细
        mPaintBorder.setColor(mCirlcleBorderColor);      //设置边框颜色
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Drawable drawable = getDrawable();
        if (drawable == null) return;

        int mWidth = getWidth();
        int mHeight = getHeight();
        int mRadius = Math.min(mWidth, mHeight) / 2;

        Bitmap bitmap = getBitmap(drawable);

        float scaleW = mWidth * 1.0F / bitmap.getWidth();
        float scaleH = mHeight * 1.0F / bitmap.getHeight();
        float scale = Math.min(scaleW, scaleH);

        Matrix mMatrix = new Matrix();
        mMatrix.setScale(scale, scale);

        /** 将bitmap放进图像着色器,缩放模式:拉伸 */
        BitmapShader mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        mBitmapShader.setLocalMatrix(mMatrix);

        mPaintCircle.setShader(mBitmapShader);

        canvas.drawCircle(mWidth / 2, mHeight / 2, mRadius - mCircleBorderWidth, mPaintCircle);
        canvas.drawCircle(mWidth / 2, mHeight / 2, mRadius - mCircleBorderWidth / 2, mPaintBorder);
    }

    private Bitmap getBitmap(Drawable drawable) {
        if (drawable instanceof BitmapDrawable) {
            return ((BitmapDrawable) getDrawable()).getBitmap();
        } else {
            Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
            Canvas mCanvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
            drawable.draw(mCanvas);
            return bitmap;
        }
    }

}

自定义的CircleImageView到此就算完成了,接下来看看

打开相机拍照:


//相机权限
    protected String[] needPermissions = {
            Manifest.permission.RECORD_AUDIO
    };
//相机权限请求码
private static final int PERMISSON_REQUESTCODE = 1;

/*
 *打开相机
 */
 private void getCamera() {
 //权限申请
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ) {
            requestPermissions(needPermissions, PERMISSON_REQUESTCODE);
        } else {
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

            // 判断存储卡是否可以用,可用进行存储
            if (hasSdcard()) {
                file = new File(Environment.getExternalStorageDirectory(), MainActivity.PHOTO_FILE_NAME);
                // 从文件中创建uri
                Uri uri = Uri.fromFile(file);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
            }
            // 开启一个带有返回值的Activity,请求码为PHOTO_REQUEST_CAREMA
            getActivity().startActivityForResult(intent, PHOTO_REQUEST_CAREMA);
        }

    }

   /*
     * 判断sdcard是否被挂载
     */
    private boolean hasSdcard() {
        //判断SD卡手否是安装好的   media_mounted
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            return true;
        } else {
            return false;
        }
    }

打开相册

 /*
     *相册,选择一张图片
     */
    private void getPhoto() {

        Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setType("image/*");
        // 开启一个带有返回值的Activity,请求码为PHOTO_REQUEST_GALLERY
        getActivity().startActivityForResult(intent, MainActivity.PHOTO_REQUEST_GALLERY);
    }

裁剪图片

  /*
  * 剪切图片
  */
    private void crop(Uri uri, int outWith, int outHeight) {
        // 裁剪图片意图
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, "image/*");
        intent.putExtra("crop", "true");
        // 裁剪框的比例,1:1
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        // 裁剪后输出图片的尺寸大小
        intent.putExtra("outputX", outWith);
        intent.putExtra("outputY", outHeight);

        intent.putExtra("outputFormat", "JPEG");// 图片格式
        intent.putExtra("noFaceDetection", true);// 取消人脸识别
        intent.putExtra("return-data", true);
        // 开启一个带有返回值的Activity,请求码为PHOTO_REQUEST_CUT
        startActivityForResult(intent, MainActivity.PHOTO_REQUEST_CUT);
    }

重写onActivityResult

 @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         if (requestCode == MainActivity.PHOTO_REQUEST_CAREMA) {
            // 从相机返回的数据
            if (hasSdcard()) {
                crop(Uri.fromFile(new File(Environment.getExternalStorageDirectory(), MainActivity.PHOTO_FILE_NAME)), 100, 100);
            } else {
                Toast.makeText(this, "未找到存储卡,无法存储照片!", Toast.LENGTH_SHORT).show();
            }
        } else if (requestCode == MainActivity.PHOTO_REQUEST_GALLERY) {
            // 从相册返回的数据
            if (data != null) {
                // 得到图片的全路径
                Uri uri = data.getData();
                crop(uri, 100, 100);
            }
        } else if (requestCode == MainActivity.PHOTO_REQUEST_CUT) {
            // 从剪切图片返回的数据
            if (data != null) {
                Bitmap bitmap = data.getParcelableExtra("data");
                //防止低版本没有办法获取数据,导致奔溃
                if (bitmap == null) {
                    return;
                }
                /**
                 * 获得图片
                 */
                this.user_image.setImageBitmap(bitmap);

                //保存图片
                //第一步:将Bitmap压缩至字节数组输出流ByteArrayOutputStream
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                bitmap.compress(Bitmap.CompressFormat.PNG, 80, byteArrayOutputStream);
                //第二步:利用Base64将字节数组输出流中的数据转换成字符串String
                byte[] byteArray = byteArrayOutputStream.toByteArray();
                String imageString = new String(Base64.encodeToString(byteArray, Base64.DEFAULT));
                //第三步:将String保持至SharedPreferences
                SharedPreferences sharedPreferences = this.getSharedPreferences("user_image", Context.MODE_PRIVATE);
                SharedPreferences.Editor editor = sharedPreferences.edit();
                editor.putString("image", imageString);
                editor.commit();

            }
        } else {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }

以上就是功能实现的代码了,其它根据需求自己稍作修改即可。

附上完整代码:
点击头像的弹窗布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:background="@color/white">


    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#c8c7cc" />

    <TextView
        android:id="@+id/camera"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:background="@color/white"
        android:layout_marginBottom="2dp"
        android:gravity="center"
        android:text="拍照"
        android:textColor="#515151"
        android:textSize="16dp" />

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#c8c7cc" />

    <TextView
        android:id="@+id/photo"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:background="@color/white"
        android:gravity="center"
        android:text="相册"
        android:layout_marginBottom="2dp"
        android:textColor="#515151"
        android:textSize="16dp" />


    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#c8c7cc" />

    <TextView
        android:id="@+id/cancel"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:background="#bfbfbf"
        android:gravity="center"
        android:text="取消"
        android:textColor="#2c2c2c"
        android:textSize="16dp" />
</LinearLayout>

自定义底部弹窗

public class MenuDialog extends Dialog {
    public MenuDialog(@NonNull Context context) {
        super(context,R.style.Dialog_Transparent);
        this.setContentView(R.layout.dialog_menu_photo);
        this.setGravityBottom();
    }

    /**
     * 设置dialog的位置在底部
     */
    private void setGravityBottom() {
        WindowManager.LayoutParams lp = getWindow().getAttributes();

        lp.width = WindowManager.LayoutParams.MATCH_PARENT;
        lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
        lp.gravity = Gravity.BOTTOM;

        getWindow().setAttributes(lp);
    }

}

其中style 是我自己定义的,如下:

<style name="Dialog.Transparent">
        <item name="android:windowFrame">@null</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:backgroundDimEnabled">true</item>
        <item name="android:windowBackground">@android:color/transparent</item>
    </style>

Activity:

@ContentView(R.layout.activity_main)
public class MainrActivity extends BaseActivity {

    //相机权限请求码
    private static final int PERMISSON_REQUESTCODE = 1;

    //相机权限
    protected String[] needPermissions = {
            Manifest.permission.RECORD_AUDIO
    };

    private File file;

    @Override
    public View onCreateView(String name, Context context, AttributeSet attrs) {
        return super.onCreateView(name, context, attrs);
    }

    /**
     * 头像 点击事件
     *
     * @param view
     */
    @Event(R.id.user_image)
    private void user_image(View view) {
        final MenuDialog menuDialog = new MenuDialog(this);

        //相机
        menuDialog.findViewById(R.id.camera).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                menuDialog.dismiss();
                getCamera();
            }
        });

        //相册
        menuDialog.findViewById(R.id.photo).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                menuDialog.dismiss();
                getPhoto();
            }
        });

        //取消
        menuDialog.findViewById(R.id.cancel).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                menuDialog.dismiss();
            }
        });

        menuDialog.show();
    }

    /*
    *相机
    */
    private void getCamera() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            requestPermissions(needPermissions, PERMISSON_REQUESTCODE);
        } else {
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

            // 判断存储卡是否可以用,可用进行存储
            if (MainActivity.hasSdcard()) {
                file = new File(Environment.getExternalStorageDirectory(), MainActivity.PHOTO_FILE_NAME);
                // 从文件中创建uri
                Uri uri = Uri.fromFile(file);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
            }
            // 开启一个带有返回值的Activity,请求码为PHOTO_REQUEST_CAREMA
           startActivityForResult(intent, MainActivity.PHOTO_REQUEST_CAREMA);
        }

    }

    /*
    *相册,选择一张图片
    */
    private void getPhoto() {

        Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setType("image/*");
        // 开启一个带有返回值的Activity,请求码为PHOTO_REQUEST_GALLERY
        startActivityForResult(intent, MainActivity.PHOTO_REQUEST_GALLERY);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == PERMISSON_REQUESTCODE) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

                // 判断存储卡是否可以用,可用进行存储
                if (MainActivity.hasSdcard()) {
                    file = new File(Environment.getExternalStorageDirectory(), MainActivity.PHOTO_FILE_NAME);
                    // 从文件中创建uri
                    Uri uri = Uri.fromFile(file);
                    intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
                }
                // 开启一个带有返回值的Activity,请求码为PHOTO_REQUEST_CAREMA
                startActivityForResult(intent, MainActivity.PHOTO_REQUEST_CAREMA);
            } else {

                Toast.makeText(this, "取消授权", Toast.LENGTH_SHORT).show();
            }
            return;
        }
    }

    /*
  * 剪切图片
  */
    private void crop(Uri uri, int outWith, int outHeight) {
        // 裁剪图片意图
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, "image/*");
        intent.putExtra("crop", "true");
        // 裁剪框的比例,1:1
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        // 裁剪后输出图片的尺寸大小
        intent.putExtra("outputX", outWith);
        intent.putExtra("outputY", outHeight);

        intent.putExtra("outputFormat", "JPEG");// 图片格式
        intent.putExtra("noFaceDetection", true);// 取消人脸识别
        intent.putExtra("return-data", true);
        // 开启一个带有返回值的Activity,请求码为PHOTO_REQUEST_CUT
        startActivityForResult(intent, MainActivity.PHOTO_REQUEST_CUT);
    }

    /*
     * 判断sdcard是否被挂载
     */
    private boolean hasSdcard() {
        //判断SD卡手否是安装好的   media_mounted
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == MainActivity.PHOTO_REQUEST_CAREMA) {
            // 从相机返回的数据
            if (hasSdcard()) {
                crop(Uri.fromFile(new File(Environment.getExternalStorageDirectory(), MainActivity.PHOTO_FILE_NAME)), 100, 100);
            } else {
                Toast.makeText(this, "未找到存储卡,无法存储照片!", Toast.LENGTH_SHORT).show();
            }
        } else if (requestCode == MainActivity.PHOTO_REQUEST_GALLERY) {
            // 从相册返回的数据
            if (data != null) {
                // 得到图片的全路径
                Uri uri = data.getData();
                crop(uri, 100, 100);
            }
        } else if (requestCode == MainActivity.PHOTO_REQUEST_CUT) {
            // 从剪切图片返回的数据
            if (data != null) {
                Bitmap bitmap = data.getParcelableExtra("data");
                //防止低版本没有办法获取数据,导致奔溃
                if (bitmap == null) {
                    return;
                }
                /**
                 * 获得图片
                 */
                user_image.setImageBitmap(bitmap);

                //保存图片
                //第一步:将Bitmap压缩至字节数组输出流ByteArrayOutputStream
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                bitmap.compress(Bitmap.CompressFormat.PNG, 80, byteArrayOutputStream);
                //第二步:利用Base64将字节数组输出流中的数据转换成字符串String
                byte[] byteArray = byteArrayOutputStream.toByteArray();
                String imageString = new String(Base64.encodeToString(byteArray, Base64.DEFAULT));
                //第三步:将String保持至SharedPreferences
                SharedPreferences sharedPreferences = this.getSharedPreferences("user_image", Context.MODE_PRIVATE);
                SharedPreferences.Editor editor = sharedPreferences.edit();
                editor.putString("image", imageString);
                editor.commit();

            }
        } else {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }
}

PS:大神们写的CircleImageView

package com.example.library;

import com.example.circleimageviewdemo_1.R;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.support.annotation.ColorRes;
import android.support.annotation.DrawableRes;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
  * 流程控制的比较严谨,比如setup函数的使用
  * updateShaderMatrix保证图片损失度最小和始终绘制图片正中央的那部分
  * 作者思路是画圆用渲染器位图填充,而不是把Bitmap重绘切割成一个圆形图片。
  */
public class CircleImageView extends ImageView {
    //缩放类型
    private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;
    private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
    private static final int COLORDRAWABLE_DIMENSION = 2;
    // 默认边界宽度
    private static final int DEFAULT_BORDER_WIDTH = 0;
    // 默认边界颜色
    private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
    private static final boolean DEFAULT_BORDER_OVERLAY = false;

    private final RectF mDrawableRect = new RectF();
    private final RectF mBorderRect = new RectF();

    private final Matrix mShaderMatrix = new Matrix();
    //这个画笔最重要的是关联了mBitmapShader 使canvas在执行的时候可以切割原图片(mBitmapShader是关联了原图的bitmap的)
    private final Paint mBitmapPaint = new Paint();
    //这个描边,则与本身的原图bitmap没有任何关联,
    private final Paint mBorderPaint = new Paint();
    //这里定义了 圆形边缘的默认宽度和颜色
    private int mBorderColor = DEFAULT_BORDER_COLOR;
    private int mBorderWidth = DEFAULT_BORDER_WIDTH;

    private Bitmap mBitmap;
    private BitmapShader mBitmapShader; // 位图渲染
    private int mBitmapWidth;   // 位图宽度
    private int mBitmapHeight;  // 位图高度

    private float mDrawableRadius;// 图片半径
    private float mBorderRadius;// 带边框的的图片半径

    private ColorFilter mColorFilter;
    //初始false
    private boolean mReady;
    private boolean mSetupPending;
    private boolean mBorderOverlay;
    //构造函数
    public CircleImageView(Context context) {
        super(context);
        init();
    }
    //构造函数
    public CircleImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    /**
     * 构造函数
     */
    public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        //通过obtainStyledAttributes 获得一组值赋给 TypedArray(数组) , 这一组值来自于res/values/attrs.xml中的name="CircleImageView"的declare-styleable中。
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);
        //通过TypedArray提供的一系列方法getXXXX取得我们在xml里定义的参数值;
        // 获取边界的宽度
        mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_border_width, DEFAULT_BORDER_WIDTH);
        // 获取边界的颜色
        mBorderColor = a.getColor(R.styleable.CircleImageView_border_color, DEFAULT_BORDER_COLOR);
        mBorderOverlay = a.getBoolean(R.styleable.CircleImageView_border_overlay, DEFAULT_BORDER_OVERLAY);
        //调用 recycle() 回收TypedArray,以便后面重用
        a.recycle();
        System.out.println("CircleImageView -- 构造函数");  
        init();
    }
    /**
     * 作用就是保证第一次执行setup函数里下面代码要在构造函数执行完毕时调用 
     */
    private void init() {
        //在这里ScaleType被强制设定为CENTER_CROP,就是将图片水平垂直居中,进行缩放。
        super.setScaleType(SCALE_TYPE);
        mReady = true;

        if (mSetupPending) {
            setup();
            mSetupPending = false;
        }
    }

    @Override
    public ScaleType getScaleType() {
        return SCALE_TYPE;
    }
    /**
          * 这里明确指出 此种imageview 只支持CENTER_CROP 这一种属性
          *
          * @param scaleType
          */
    @Override
    public void setScaleType(ScaleType scaleType) {
        if (scaleType != SCALE_TYPE) {
            throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));
        }
    }

    @Override
    public void setAdjustViewBounds(boolean adjustViewBounds) {
        if (adjustViewBounds) {
            throw new IllegalArgumentException("adjustViewBounds not supported.");
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //如果图片不存在就不画
        if (getDrawable() == null) {
            return;
        }
        //绘制内圆形 图片 画笔为mBitmapPaint
        canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius, mBitmapPaint);
      //如果圆形边缘的宽度不为0 我们还要绘制带边界的外圆形 边界画笔为mBorderPaint
        if (mBorderWidth != 0) {
            canvas.drawCircle(getWidth() / 2, getHeight() / 2, mBorderRadius, mBorderPaint);
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        setup();
    }

    public int getBorderColor() {
        return mBorderColor;
    }

    public void setBorderColor(int borderColor) {
        if (borderColor == mBorderColor) {
            return;
        }

        mBorderColor = borderColor;
        mBorderPaint.setColor(mBorderColor);
        invalidate();
    }

    public void setBorderColorResource(@ColorRes int borderColorRes) {
        setBorderColor(getContext().getResources().getColor(borderColorRes));
    }

    public int getBorderWidth() {
        return mBorderWidth;
    }

    public void setBorderWidth(int borderWidth) {
        if (borderWidth == mBorderWidth) {
            return;
        }

        mBorderWidth = borderWidth;
        setup();
    }

    public boolean isBorderOverlay() {
        return mBorderOverlay;
    }

    public void setBorderOverlay(boolean borderOverlay) {
        if (borderOverlay == mBorderOverlay) {
            return;
        }

        mBorderOverlay = borderOverlay;
        setup();
    }

    /**
     * 以下四个函数都是
     * 复写ImageView的setImageXxx()方法 
     * 注意这个函数先于构造函数调用之前调用
     * @param bm
     */
    @Override
    public void setImageBitmap(Bitmap bm) {
        super.setImageBitmap(bm);
        mBitmap = bm;
        setup();
    }

    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        mBitmap = getBitmapFromDrawable(drawable);
        System.out.println("setImageDrawable -- setup");  
        setup();
    }

    @Override
    public void setImageResource(@DrawableRes int resId) {
        super.setImageResource(resId);
        mBitmap = getBitmapFromDrawable(getDrawable());
        setup();
    }

    @Override
    public void setImageURI(Uri uri) {
        super.setImageURI(uri);
        mBitmap = getBitmapFromDrawable(getDrawable());
        setup();
    }

    @Override
    public void setColorFilter(ColorFilter cf) {
        if (cf == mColorFilter) {
            return;
        }

        mColorFilter = cf;
        mBitmapPaint.setColorFilter(mColorFilter);
        invalidate();
    }
    /**
     * Drawable转Bitmap
     * @param drawable
     * @return
     */
    private Bitmap getBitmapFromDrawable(Drawable drawable) {
        if (drawable == null) {
            return null;
        }

        if (drawable instanceof BitmapDrawable) {
             //通常来说 我们的代码就是执行到这里就返回了。返回的就是我们最原始的bitmap
            return ((BitmapDrawable) drawable).getBitmap();
        }

        try {
            Bitmap bitmap;

            if (drawable instanceof ColorDrawable) {
                bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
            } else {
                bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
            }

            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            drawable.draw(canvas);
            return bitmap;
        } catch (OutOfMemoryError e) {
            return null;
        }
    }
    /**
     * 这个函数很关键,进行图片画笔边界画笔(Paint)一些重绘参数初始化:
     * 构建渲染器BitmapShader用Bitmap来填充绘制区域,设置样式以及内外圆半径计算等,
     * 以及调用updateShaderMatrix()函数和 invalidate()函数;
     */
    private void setup() {
        //因为mReady默认值为false,所以第一次进这个函数的时候if语句为真进入括号体内
        //设置mSetupPending为true然后直接返回,后面的代码并没有执行。
        if (!mReady) {
            mSetupPending = true;
            return;
        }
        //防止空指针异常
        if (mBitmap == null) {
            return;
        }
        // 构建渲染器,用mBitmap位图来填充绘制区域 ,参数值代表如果图片太小的话 就直接拉伸
        mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        // 设置图片画笔反锯齿
        mBitmapPaint.setAntiAlias(true);
        // 设置图片画笔渲染器
        mBitmapPaint.setShader(mBitmapShader);
        // 设置边界画笔样式
        mBorderPaint.setStyle(Paint.Style.STROKE);//设画笔为空心
        mBorderPaint.setAntiAlias(true);
        mBorderPaint.setColor(mBorderColor);    //画笔颜色
        mBorderPaint.setStrokeWidth(mBorderWidth);//画笔边界宽度
        //这个地方是取的原图片的宽高
        mBitmapHeight = mBitmap.getHeight();
        mBitmapWidth = mBitmap.getWidth();
        // 设置含边界显示区域,取的是CircleImageView的布局实际大小,为方形,查看xml也就是160dp(240px)  getWidth得到是某个view的实际尺寸
        mBorderRect.set(0, 0, getWidth(), getHeight());
        //计算 圆形带边界部分(外圆)的最小半径,取mBorderRect的宽高减去一个边缘大小的一半的较小值(这个地方我比较纳闷为什么求外圆半径需要先减去一个边缘大小)
        mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2, (mBorderRect.width() - mBorderWidth) / 2);
        // 初始图片显示区域为mBorderRect(CircleImageView的布局实际大小)
        mDrawableRect.set(mBorderRect);
        if (!mBorderOverlay) {
            //demo里始终执行
            //通过inset方法  使得图片显示的区域从mBorderRect大小上下左右内移边界的宽度形成区域,查看xml边界宽度为2dp(3px),所以方形边长为就是160-4=156dp(234px)
            mDrawableRect.inset(mBorderWidth, mBorderWidth);
        }
        //这里计算的是内圆的最小半径,也即去除边界宽度的半径
        mDrawableRadius = Math.min(mDrawableRect.height() / 2, mDrawableRect.width() / 2);
        //设置渲染器的变换矩阵也即是mBitmap用何种缩放形式填充
        updateShaderMatrix();
        //手动触发ondraw()函数 完成最终的绘制
        invalidate();
    }
    /**
    * 这个函数为设置BitmapShader的Matrix参数,设置最小缩放比例,平移参数。
    * 作用:保证图片损失度最小和始终绘制图片正中央的那部分
    */
    private void updateShaderMatrix() {
        float scale;
        float dx = 0;
        float dy = 0;

        mShaderMatrix.set(null);
        // 这里不好理解 这个不等式也就是(mBitmapWidth / mDrawableRect.width()) > (mBitmapHeight / mDrawableRect.height())
        //取最小的缩放比例
        if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
            //y轴缩放 x轴平移 使得图片的y轴方向的边的尺寸缩放到图片显示区域(mDrawableRect)一样)
            scale = mDrawableRect.height() / (float) mBitmapHeight;
            dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
        } else {
            //x轴缩放 y轴平移 使得图片的x轴方向的边的尺寸缩放到图片显示区域(mDrawableRect)一样)
            scale = mDrawableRect.width() / (float) mBitmapWidth;
            dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
        }
        // shaeder的变换矩阵,我们这里主要用于放大或者缩小。
        mShaderMatrix.setScale(scale, scale);
        // 平移
        mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top);
        // 设置变换矩阵
        mBitmapShader.setLocalMatrix(mShaderMatrix);
    }

}

为了向别人、向世界证明自己而努力拼搏,而一旦你真的取得了成绩,才会明白:人无须向别人证明什么,只要你能超越自己。

uniapp [全端兼容] - 详细实现头像裁剪功能,用户手机拍照或本机相册选取后对图片进行裁剪上传头像,选择图像裁剪后设置成头像效果,选择头像后对图片进行裁剪调整,最强头像裁剪插件组件全平台通用组件 uniapp,h5移动端网页,微信小程序,支付宝小程序,Android安卓,苹果ios,app,nvue,头像裁剪,图片裁剪,头像裁切,图像裁剪,上传图片前裁剪功能,实现图片头像裁剪,小程序头像裁剪上传,裁剪后生成临时文件上传到服务器,头像修改,如何在uniapp中实现图片裁剪效果,临时文件路径,照相,相片,圆形头像,圆弧,裁剪圆形,调整裁剪比例,裁剪插件,uniApp通用兼容的头像裁剪插件,示例代码,详细教程,app端做头像裁剪并上传,头像上传后进行裁切,手势缩放,选择图片裁剪设置用户头像,手机相册,摄像 阅读详情

相关推荐

Android圆形头像的实现与交互设计

在Android应用开发中,图像处理是一项基本且重要的技能。从加载图片到修改图片格式、从基本的滤镜效果到复杂的图像变换,图像处理模块在用户界面中扮演着核心角色。掌握图像处理不仅能够提升用户体验,还能增强应用的视觉吸引力。在Android开发中,Glide是一个广泛使用的库,用于加载和展示网络图片、本地图片等。Glide的使用非常简单,只需要添加依赖库并调用几行代码,就可以实现图片的加载。以下是一个基本使用Glide加载图片的示例代码:// 在build.gradle文件中添加Glide依赖。

weixin_35752233的博客 871

微信小程序裁剪图片成圆形

前言最近在开发小程序,产品经理提了一个需求,要求微信小程序换头像,用户剪裁图片必须是圆形,也在github上看了一些例子,一般剪裁图片用的都是方形,所以自己打算写一个小组件,可以把图片剪裁成圆形,主要思路就是使用canvas绘图,把剪裁的图片绘制成圆形,另外剪裁图片的窗口还可以移动放大缩小,这个功能就用了微信组件movable-view,好了,该说的也说完了,下面咱们开始撸代码。movable-v...

weixin_33770878的博客 609

圆形头像剪切

仿qq、微信的头像剪切、是圆形头像剪切。可以看我的博文。

Android 设置头像 - 裁剪及圆形头像

通过裁剪和圆形头像的实现更加深入的对ActivityResultLauncher进行了学习,并在实现的过程中对Intent有了更加深入的思考,如果本文内容存在问题欢迎各位大佬进行斧正。总结本文内容。Ucrop工具实现图片裁剪Intent系统默认裁剪实现类intent深入思考Gilde圆形图片的实现。

zyppxx的博客 2313

ImageEditor:在image截取圆形头像,可调整大小

ImageEditor 在image截取圆形头像,可调整大小

个人设置页面圆形头像实用

非常实用,套来就能用

实现各种尺寸的图片裁剪成圆形头像

效果图: <a href="#">   <div class="jqthumb" style="width: 200px; height: 200px; opacity: 1;">     <div style="width: 100%; height: 100%; border-radius: 100%; margin: 3px auto; curso...

weixin_34306593的博客 634

从零开始的立绘拆包教程

蓝毒小天使天下第一! 本文拆包教程不限于明日方舟,在后面也会给出其他手游的拆包教程,例如少女前线 首先拆包最简单的无非就是拆取游戏资源,例如游戏立绘,音频,视频等,再深层次一点有拆取游戏配置文件,apk反编译得到部分源码 在本文,我们只介绍拆取游戏资源和对游戏资源的后期处理(因为另外两个讲道理我也没太搞懂,虽然可以提取游戏配置文件,但似乎大部分重要的数据都有加密,反编译出来的源码也只是部分,...

Conyrol的博客 9万+

【HarmonyOS】模仿个人中心头像图片,调用系统相机拍照,从系统相册选择图片和圆形裁剪显示 (一)

模仿个人中心,实现头像图片的裁剪展示,图片调用系统相机拍照获取,调用系统相册选择图片。

路漫漫亦无涯 1561

【HSPiP应用指南】从理论到实践:如何利用汉森溶解度参数优化配方设计

本文深入解析了汉森溶解度参数(HSP)理论及其在配方设计中的核心价值,并详细介绍了如何利用HSPiP软件工具从理论走向实践。文章通过匹配溶解度参数、计算汉森距离(Ra),系统阐述了如何解决溶剂选择、颜料分散稳定性及扩散行为预测等关键问题,并结合界面气相色谱(IGC)等实验方法提升预测精度,旨在帮助配方师实现配方设计的可视化、可量化与高效优化。

weixin_29305313的博客 1643

agent-browser OpenClaw 的最佳搭档

agent-browser 是专为 AI Agent 设计的浏览器自动化工具,目前被公认为 OpenClaw 的最佳配套方案。这份技术文档完整记录了其架构、协议、性能调优与常见问题处理,非常适合想让OpenClaw 真正“上手”互联网的开发者与老用户。

liu_zhiyi的博客 1779

【HarmonyOS】模仿个人中心头像图片,调用系统相机拍照,从系统相册选择图片和圆形裁剪显示 (二)

模仿个人中心头像图片,调用系统相机拍照获得图片,图片圆形裁剪,圆形取景框画布绘制。

路漫漫亦无涯 1327

实战游戏项目管理1-规划篇

1、前言 做研发管理10多年,进游戏行业8年,经验下来项目管理就是一门技术,结合不同行业不同项目加以不同管理方法,但原理基本一样,这里总结下游戏项目的管理一些实操方法 一般游戏确定立项前都需要做,项目预研产出一个游戏Demo,通过公司的立项评审,这个过程的项目管理相对简单一般由制作人或其他项目经理兼任,只有控制好总体时间与成本就好,这里按立项后开始讲。 2、游戏项目规划 ...

pengdali的专栏 2万+

相册获取、相机拍摄,裁剪圆形头像

相册获取、相机拍摄,裁剪圆形头像 应用场景 很多应用都有个人中心,个人中心就会有头像,现在一般都流行圆形头像,那么怎么设置呢 使用步骤 这里参考了网上各位大神的文章,因为中途遇到几个坑,折磨了一天,快要疯了,因为本人也是菜鸟,所以被虐是必然了,当然我们看到新人遇到问题时,不要觉得那个问题是简单的,当初如果你没有遇到这种需求或没接触过那些坑时,或许也会感到不简单的。 因为遇

贤鱼 1382

【DEIM创新改进】独家下采样创新改进篇 | ECCV 2026 | DEIM 引入FSD-Down频域-空间动态下采样,在下采样过程中保留小目标的高频信息、助力小目标检测、遥感小目标检测有效涨点

🔥本文提出了一种名为FSD-Down的频域-空间动态下采样模块,用于改进DEIM网络模型在小目标检测中的性能。FSD-Down通过小波分解显式保留低频语义和高频细节,结合分组卷积、动态通道权重和可学习缩放因子,自适应强化目标边缘与纹理特征。该模块能有效减轻传统下采样造成的频率混叠和细节丢失,提升对小目标、密集目标和低对比度目标的检测能力。实验表明,FSD-Down计算开销可控,在保持实时性的同时显著提升检测精度,特别是在VisDrone和AITODv2数据集上对小目标的检测性能提升显著。

Ai缝合怪、助力小伙伴高效发论文 82

Python 爬虫实战:亚马逊 + eBay 商品信息跨平台抓取(价格 / 销量 / 评价对比)

亚马逊和 eBay 是全球知名的电商平台,拥有海量的商品信息。对于消费者来说,比较不同平台上的商品价格、销量和用户评价可以帮助他们找到性价比最高的商品。对于商家而言,了解竞争对手的商品信息有助于优化自身的产品策略和定价策略。然而,手动在两个平台上逐一比较商品信息是非常耗时且低效的。因此,开发一个能够自动抓取并对比这两个平台商品信息的爬虫工具具有重要的实际意义。

yansideyucsdn的博客 615

Android实现从相册选择或者直接拍照来设置圆形的头像CircleImageView

本人第一次写技术博客,只是为了对自己平时遇到的一些问题进行一个总结,可以让以后能更好的翻看学习,也可以让更多的人借鉴。 废话不多说,正题开始: 首先先说明如何进行从相册选择或者直接拍照来设置头像,然后在进行圆形头像的设置。具体的界面效果如下所示:                实现底部弹出的代码如下SelectPickPopupWindow.class,需要集成PopupWindow,代码

唯一郭大侠 5127

导航系统 | 全球四大卫星导航系统(2025)核心能力对比分析

北斗系统通过GEO卫星(80°E、110.5°E、140°E)实现区域增强,其IGSO卫星在亚太地区形成"8"字形轨迹,使该区域可见卫星数量比GPS多4-6颗,显著提升复杂环境下的定位可用性[13]。北斗短报文功能在2025年云南地震救援中发挥关键作用,被困人员通过北斗终端发送120字求救信息,实现"位置+状态"一体化上报,救援响应时间缩短40%[15]。北斗通过三频信号(B1C/B2a/B3)消除电离层延迟误差,在城市峡谷环境下定位连续性达99.98%,优于GPS的99.95%[5]。

尘世冰封的专栏 2611

ios 裁剪圆形头像_详解iOS 裁剪圆形图像并显示(类似于微信头像)

本文主要讲解如何从照片库选择一张照片后将其裁剪成圆形头像并显示,类似于微信头像那种模式。本文的方法也适用于当时拍照获取的图像,方法类似,所以不再赘述。本文主要是在iOS 10环境下使用,此时如果要使用使用系统照片库、照相机等功能需要授权,授权方法如下:右键点击工程目录中的“Info.plist文件——>Open As ——>Source Code”,打开复制以下你在应用中使用的隐私权限...

weixin_39586395的博客 466

【知识分享】车载以太网PCB布局设计指南

本文将深入探讨在设计车载以太网设备的印刷电路板(PCB)时需要着重考虑的若干关键主题。这些主题广泛涵盖了数据布线设计,以确保其符合信号完整性(SI)和电磁兼容性(EMC)标准;外部元器件的合理摆放;以及采取有效的抗电磁干扰(EMI)布局策略等方面。通过全面且细致地处理这些关键环节,能够显著提升车载以太网设备的性能与可靠性。

一只豌豆象的博客 1352

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

android 仿微信头像裁剪,Android仿微信QQ设置图形头像裁剪功能

最近在做毕业设计,想有一个功能和QQ一样可以裁剪头像并设置圆形头像,额,这是设计狮的一种潮流。而纵观现在主流的APP,只要有用户系统这个功能,这个需求一般都是在(bu)劫(de)难(bu)逃(xue)!图片裁剪实现方式有两种,一种是利用系统自带的裁剪工具,一种是使用开源工具Cropper。本节就为大家带来如何使用系统自带的裁剪工具进行图片裁剪~还是先来个简单的运行图。额,简单说下,我待会会把代码写...

weixin_42126749的博客 692

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

java裁切圆形_android 更换头像(圆形裁剪)亲测可用

【实例简介】经测试,从相册选择以及 拍照 裁剪 均可用(测试环境:android 4.4)【实例截图】【核心代码】package com.zhy.clippic;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;imp...

weixin_42279592的博客 268

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

ios 裁剪圆形头像_iOS 裁剪圆形图像并显示(类似于微信头像)

本文主要讲解如何从照片库选择一张照片后将其裁剪成圆形头像并显示,类似于微信头像那种模式。本文的方法也适用于当时拍照获取的图像,方法类似,所以不再赘述。本文主要是在iOS 10环境下使用,此时如果要使用使用系统照片库、照相机等功能需要授权,授权方法如下:右键点击工程目录中的“Info.plist文件——>Open As ——>Source Code”,打开复制以下你在应用中使用的隐私权限...

weixin_39993623的博客 312

Android开发之用户头像上传

一,概述 本篇博客总结一下自己在开发过程中应用到的一些知识,在本篇博客中带领大家完成用户头像选择或者拍照上传,并对图片进行大小的压缩,和形状的控制,可以将用户选择到的图片裁剪成圆形上传。 ok,我们开始写一个小的demo,完成用户圆形头像的选取,在写即将实现的效果之前我们看一下即将要实现的效果图二,实现代码activity_main.xml<LinearLayout xmlns:android=

宿罪的博客 3万+

php 微信头像 圆形,详解iOS 裁剪圆形图像并显示(类似于微信头像)

本文主要讲解如何从照片库选择一张照片后将其裁剪成圆形头像并显示,类似于微信头像那种模式。本文的方法也适用于当时拍照获取的图像,方法类似,所以不再赘述。本文主要是在ios 10环境下使用,此时如果要使用使用系统照片库、照相机等功能需要授权,授权方法如下:右键点击工程目录中的“info.plist文件——>open as ——>source code”,打开复制以下你在应用中使用的隐私权限...

weixin_27033895的博客 366
上一篇: google的gson三方包混淆问题,附上通用proguard-rules.pro
下一篇: Android 获取应用版本号与版本名
皮小智
博客等级 码龄10年 56粉丝 34原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值