Android:绘制自定义View人脸识别框

news2024/12/24 3:24:47

一.绘制矩形框实现

项目开发需要自定义View实现一个人脸框,代码实现很平常,一些细节记录一下,方便以后查阅。

代码实现:

1.1 自定义人脸识别框:

FaceView.java

package com.android.example.ui.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import com.android.example.R;

import java.util.List;

public class FaceView extends View {

    //人脸识别框数组
    private List<Rect> mRectList;
    //画笔
    private Paint mPaint;

    public FaceView(Context context) {
        super(context);
        init();
    }

    /* 这个构造函数不能缺失,否则会编译报错
     * View走的构造函数也是这个,第一个构造函数反而没走
     */
    public FaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public FaceView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mPaint = new Paint();
        //设置抗锯齿
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(3);
        mPaint.setColor(Color.RED);
    }

    public void setFaceRects(List<Rect> mRectList) {
        this.mRectList = mRectList;
        //请求更新,View会自动执行onDraw进行绘制
        invalidate();
        //同样是请求更新,该方法表示在主线程发起绘制请求
        //postInvalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mRectList != null) {
            for (Rect rect : mRectList) {
                canvas.drawRect(rect, mPaint);
            }
        }
    }
}

1.2 布局文件中添加FaceView:

<com.android.example.ui.view.FaceView
    android:id="@+id/face_rects_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

注意:

这里我把FaceView的layout_width、layout_height都设置成了"match_parent"

这里面有个容易踩到
本次开发时,xml中FaceView控件往上一直到第一层父布局宽、高的设置都是:
layout_width="match_parent"
layout_height="wrap_content"

导致View的width、height无法确定,所以onDraw()一直不被执行
后来才发现是这里的问题
将控件FaceView控件宽高设置为固定大小就可以了

<com.android.example.ui.view.FaceView
    android:id="@+id/face_rects_view"
    android:layout_width="800dp"
    android:layout_height="800dp"/>

也就是说如果自定义View的宽高无法被确定,OnDraw()是不会执行的
这时候就需要排查设置宽高,或者修改布局配置使其值能够被确定。

1.3 代码调用:

List<Rect> rectlist = new ArrayList<Rect>();
Rect rect1 = new Rect(300, 300, 500, 500);
rectlist.add(rect1);

FaceView faceRectsView = findViewById(R.id.face_rects_view);
faceRectsView.setFaceRects(rectlist);

1.4 实现效果

一个完整的自定义人脸识别框FaceView到此就实现了

顺带手在onDraw里可以做出其他不同的效果

二.绘制线段实现

使用canvas.drawLine()函数绘制线段,使用实现一个只显示四个角的人脸识别框

2.1 代码:

@Override
protected void onDraw(Canvas canvas) {
	super.onDraw(canvas);

	if (mRectList != null) {
		for (Rect rect : mRectList) {
			/*左上角竖线*/
			canvas.drawLine(rect.left, rect.top, rect.left, rect.top + 20, mPaint);
			/*左上角横线*/
			canvas.drawLine(rect.left, rect.top, rect.left + 20, rect.top, mPaint);
			/*右上角竖线*/
			canvas.drawLine(rect.right, rect.top, rect.right - 20, rect.top, mPaint);
			/*右上角横线*/
			canvas.drawLine(rect.right, rect.top, rect.right, rect.top + 20, mPaint);
			/*左下角竖线*/
			canvas.drawLine(rect.left, rect.bottom, rect.left, rect.bottom - 20, mPaint);
			/*左下角横线*/
			canvas.drawLine(rect.left, rect.bottom, rect.left + 20, rect.bottom, mPaint);
			/*右下角竖线*/
			canvas.drawLine(rect.right, rect.bottom, rect.right, rect.bottom - 20, mPaint);
			/*右下角横线*/
			canvas.drawLine(rect.right, rect.bottom, rect.right - 20, rect.bottom, mPaint);
		}
	}
}

2.2 效果

还有其他有趣的效果:圆形、椭圆等,就不一一列举了。

三.绘制Bitmap实现

3.1 实现过程

上一节讲述的都是用画布Cavas、画笔Paint自带的绘制线段、矩形等Api实现人脸框

这一节讲怎么使用UI设计的图片绘制人脸框,其实也就是onDraw()中绘制Bitmap

人脸框图片facerect.png:

onDraw()绘制Bitmap代码:

package com.android.example.ui.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import com.android.example.R;

import java.util.List;

public class FaceView extends View {

    private List<Rect> mRectList;
    private Paint mPaint;
    private Bitmap mFaceRectBitmap;

    public FaceView(Context context) {
        super(context);
        init();
    }

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

    public FaceView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mPaint = new Paint();
        //不需要再配置画笔
        /*mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(3);
        mPaint.setColor(Color.RED);*/

        /*图片解析成Bitmap
         *Android不允许直接修改res里面的图片,所以要用copy方法*/
        mFaceRectBitmap = BitmapFactory.decodeResource(getResources(),
                R.mipmap.perception_facerect).copy(Bitmap.Config.ARGB_8888, true);
    }

    public void setFaceRects(List<Rect> mRectList) {
        this.mRectList = mRectList;
        invalidate();
    }

    //不需要再绘制时调用,销毁资源
    public void clear() {
        mRectList = null;
        mFaceRectBitmap.recycle();
        mFaceRectBitmap = null;
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mRectList != null && mFaceRectBitmap != null) {
            for (Rect rect : mRectList) {
                //drawBitmap()有多个重载,接下来会详细讨论
                canvas.drawBitmap(mFaceRectBitmap, rect.left, rect.top, mPaint);
            }
        }
    }
}

注: 画笔Paint只需要有一个实例对象就行,不需要再进行配置

3.2 实现效果

 

四.canvas.drawBitmap()

上一节代码注释中提到了,canvas.drawBitmap()这个函数有多个重载

下面就来详细研究一下Canvas里关于绘制Bitmap的方法:

  1. drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)
  2. drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint)
  3. drawBitmap(Bitmap bitmap, float left, float top, Paint paint)
  4. drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)

方法1方法2只有dst参数类型 Rect 和 RectF 的区别
这两个方法要实现的功能都是把Bitmap的src区域绘制到画布dst区域内
如果dst无法完全覆盖src,而src和dst比例不对称,就会出现拉伸或缩放

方法3是把(left, top)作为Bitmap的左上角进行绘制,不拉伸也不压缩,如果超出了画布就不绘制,佛系绘制。

方法4是使用矩阵matrix绘制Bitmap,绘制前先设置matrix的属性
该方法主要是对图片进行缩放旋转平移等操作时使用
示例:在坐标点(100,100),顺时针旋转45°绘制图片
关键代码:

//配置矩阵
Matrix matrix = new Matrix();
matrix.postTranslate(100f, 100f);
matrix.preRotate(45f);
//绘制       
canvas.drawBitmap(mFaceRectBitmap, matrix, mPaint);

实现效果:

 

五.onDraw()不执行问题

在前文1.2小节里有提到,onDraw()出现不执行问题

实现自定义View时,这也是个常见的问题,一般可以尝试如下几种方法:

  • 主动调用invalidate()
  • 在构造方法里增加setWillNotDraw(false)方法
  • View的宽高是否能被系统确定,如果不能就需要设置确定的宽高,或者修改布局使其能被系统确定
  • 在onMeasure()方法中没设置控件的宽和高
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

 

六.结束

到此自定义人脸识别框FaceView及drawBitmap()相关扩展就讲解完了

canvas有十分丰富的功能,能实现多种多样的自定义View,这就要在实际开发中去具体运用了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/656708.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

018:vue中自定义el-table 表头和单元格的样式

第018个 el-table 用于展示多条结构类似的数据&#xff0c;可对数据进行排序、筛选、对比或其他自定义操作。 vue在使用element UI table的是经常要用到的&#xff0c;由于原有的表头和单元格的样式不能满足项目的需要&#xff0c;需要自己来自定义样式。同时这里也做了个overf…

B/S版医院检验科lis系统源码 云lis系统

LIS系统为实验室服务对象提供检验申请、采集标本、结果查询等功能&#xff1b;为实验室工作人员的核收标本、分送标本、传送资料、分析前处理、质量控制、单向或双向通讯、分析后处理、结果审核、打印报告、结果查询等标本检测过程提供全面的技术支持。 .Net Core LIS系统源码…

python代码性能分析

基准测试可以发现程序变慢了&#xff0c;那么是因为什么原因导致性能变慢的&#xff0c;需要进一步做代码性能分析。python同样提供了性能分析工具。 cProfile cProfile是python默认的性能分析器&#xff0c;他只测量CPU时间&#xff0c;并不关心内存消耗和其他与内存相关联的…

逻辑越权之找回机制及接口安全(35)

会涉及到这三个内容 验证会涉及到&#xff0c;暴力测试&#xff0c;绕过测试 找回会涉及到&#xff0c;客户端回显&#xff0c;respponse状态值&#xff0c;找回流程绕过 接口会涉及到&#xff0c;调用便利 找回就像是忘记密码那种&#xff0c;然后会有验证&#xff0c;手机…

知识图谱实战应用16-知识图谱在化学物质结构上的应用,快速查找化学分子式与结构

大家好,我是微学AI,今天给大家介绍一下知识图谱实战应用16-知识图谱在化学物质结构上的应用,快速查找化学分子式与结构。在化学领域,知识图谱可以应用于化学物质结构上。化学物质结构主要指分子结构和化学键的组成情况。知识图谱可以将化学物质结构的相关数据以图谱的形式展…

oVirt 4.4.10三节点超融合集群安装配置及集群扩容(三)

本篇主要记录安装及使用过程中遇到的问题<包含4.4.x, 4.5.x> 设置engine管理页面可以通过IP访问ssh连接engine服务器并在/etc/ovirt-engine/engine.conf.d新建99-custom-sso-setup.conf,添加engine节点的IP或出口IPSSO_ALTERNATE_ENGINE_FQDNS="engine103.cluster.…

MySQL 索引与事务

MySQL 索引相关知识详解与事务的详解 一、索引的概念二、索引的作用索引的副作用 三、索引是如何实现的四、创建索引的原则依据五、索引的优缺点1、优点2、缺点 六、索引的分类和创建1、普通索引2、唯一索引3、主键索引4、组合索引5、全文索引 七、索引的查看八、索引的删除1、…

操作系统2:进程的描述与控制

目录 1、什么是前驱图&#xff1f; 2、进程的定义和描述 &#xff08;1&#xff09;什么是进程&#xff1f; &#xff08;2&#xff09;进程的基本状态及转换 &#xff08;3&#xff09;挂起操作和进程状态的转换 3、进程管理中的数据结构 &#xff08;1&#xff09;进程…

楼宇照明系统在图书馆的应用介绍 安科瑞 许敏

【摘要】EIB总线作为楼宇家居自动化控制技术的主流&#xff0c;具有适应性好、功能强大与可靠性高等多方面优点&#xff0c;能很 好地满足定时、合成照度、人体检测和手控等不同的照明控制需求。通过智能化的自动控制实现了楼宇的舒适照 明和节能照明两大目标&#xff0c;克服传…

一、DSMP/OLS等夜间灯光数据贫困地区识别——理论

一、前言 对于贫困的定量研究,前人多实用传统的社会经济统计数据构建模型,但是该数据存在统计口径多源、样本获取受限等不足,不能较好的反映区域贫困的时间按序列编号。随着遥感技术的不断发展,DMSP/OLS等夜间灯光数据的广泛应用为了大范围、动态的区域贫困监测提供一种新…

c++系列之string类的常用接口函数

&#x1f497; &#x1f497; 博客:小怡同学 &#x1f497; &#x1f497; 个人简介:编程小萌新 &#x1f497; &#x1f497; 如果博客对大家有用的话&#xff0c;请点赞关注再收藏 &#x1f31e; string string时表示字符串的字符类 //使用 string类包含#include 头文件 以及…

基于Java人事管理信息系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a; ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精…

fast admin 使用百度富文本编辑器添加赋值

这篇文章为大家介绍一下fastadmin框架如何引入并使用百度富文本 文章目录 前言下载文件编辑文件配置上传图片添加代码总结 前言 在学习fastadmin的时候需要使用到富文本编辑器&#xff0c;于是查阅了一下资料&#xff0c;实现后将我的经验分享给大家 一、下载文件并放入自己的…

es6的模块化 import()方法进行动态加载模块

import 语句和import()方法是不一样的 import 语句是在编译的时候起作用&#xff0c;if&#xff08;&#xff09;{import 语句} 这句话在编译的时候不会执行if语句&#xff0c;会报错 import 语句无法在运行时加载模块&#xff0c;在语法上&#xff0c;按条件加载模块是不行…

Andriod开发 fragment

1.fragment fragment是一个可以嵌入到Activity中的可重用UI组件。它可以让你在一个Activity中展示多个界面&#xff0c;并且可以在运行时动态地添加、移除、替换和组合不同的fragment&#xff0c;从而实现复杂的UI交互效果。 与Activity类似&#xff0c;Fragment也有自己的生…

Linux监控Raid磁盘健康状态

Raid卡型号与操作 Raid卡市场主要是LSI、Adaptec、Highpoint、Promise等厂商提供。Adaptac被PMC收购后&#xff0c;提供的Raid卡即为PMC,简称为P卡。LSI公司提供的Raid卡&#xff0c;即为L卡。 Raid卡配置操作方式 Raid配置可以通过BIOS启动后进入Raid的配置页面进行配置&#…

【Proteus仿真】74HC192功能验证

前言 74HC192是一种四位可向上或向下计数的计数器芯片&#xff0c;可用于电子设备中的计数器、定时器和频率计等应用。74HC192的模式可以分为4种&#xff0c;向上计数&#xff0c;向下计数&#xff0c;并行输入&#xff0c;重置。还有就是&#xff0c;仿真中一些引脚的名称可能…

【硬件】嵌入式电子设计基础之单片机

本篇文章介绍了基于单片机平台开发的一些基本理论知识&#xff0c;包括了硬件最小系统的说明以及基于单片机开发的过程。文中还额外介绍了ARM体系架构&#xff0c;帮助读者从更深层次去熟悉我们平常最容易接触的开发平台&#xff0c;熟悉这些寄存器定义和处理器模式能够帮助我们…

为什么说网络安全是IT行业最后的红利?

前言 “没有网络安全就没有国家安全”。当前&#xff0c;网络安全已被提升到国家战略的高度&#xff0c;成为影响国家安全、社会稳定至关重要的因素之一。 网络安全行业特点 1、就业薪资非常高&#xff0c;涨薪快 2021年猎聘网发布网络安全行业就业薪资行业最高人均33.77万…