|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745 |
- <template>
- <view class="modal bottom-modal" :class="show ? 'show' : ''">
- <view class="camera-con" :style="{'margin-top': top + 'px'}">
- <camera flash="off" :device-position="device" resolution="high" @stop="stop" @error="error"
- style="width: 100vw;height: 100vh; position: fixed;top:0;left: 0;z-index: -99;"
- :style="{'top': top + 'px',}">
- <cover-view class="cover">
- </cover-view>
- </camera>
- </view>
- <!-- 人脸轮廓 -->
- <!-- <cover-view class="face-con" :style="{'top': (Number(top)) + 'px',}">
- <cover-view class="title" style="text-align: center;">
- 【人脸正面请对准下面人脸框】
- </cover-view>
- <cover-view>
- <cover-image :src="faceImg" class="face-img"></cover-image>
- </cover-view>
- </cover-view> -->
-
- <!-- 检测提示 -->
- <cover-view class="face-tips">
- </cover-view>
-
- <cover-view class="camera-action">
- <cover-view class="action clooseimg" @click="closeImage">
- <cover-image :src="clooseimg" class="img"></cover-image>
- </cover-view>
- <cover-view class="action photoimg" @click="onGetPhoto">
- <cover-image :src="photoimg" class="img"></cover-image>
- </cover-view>
-
- <cover-view class="action QHimg" @click="deviceQH">
- <cover-image :src="QHimg" class="img"></cover-image>
- </cover-view>
- </cover-view>
- </view>
- </template>
-
- <script>
- // 人脸检测
- /**
- * @event {Function} photoChange 拍照完成事件
- * @event {Function} detectFailed 人脸检测失败
- * @event {Function} detectOver 人脸检测结束
- * @method {Function} initData 初始化人脸检测
- */
- export default {
- name: 'face-detect',
- data() {
- return {
- device: 'back',
- show: false,
- tipsText: '',
- isSuccess: false, //是否检测完成
- face: {},
- actionsList: null,
- context: "",
- tipsTextCss: "tipsTextCss",
- listener: null,
- VKSession: null,
- // 是否是人脸
- isFace: null,
- // 人脸识别加载是否成功
- loadingState: null,
- // QHimg
- QHimg: '',
- // photoimg
- photoimg: '',
- // clooseimg
- clooseimg: '',
- faceImg: '',
- }
- },
- props: {
- buildActionContainer: Function,
- actions: Function,
- hasSwitch: false,
- isDev: false,
- navbarTitle: String,
- isShowNavbar: true,
- top: String
- },
- onLoad() {
- /* this.initData(); */
- },
- onUnload() {
- this.VKSession.destroy();
- },
- mounted() {
-
- },
- methods: {
- onNavBack() {
- console.log("返回");
- this.$emit('onBack')
- },
- onLoadReset() {
- this.initData();
- },
- createdVKSession() {
- uni.showLoading({
- title: '相机加载中'
- })
- let count = 0;
- let that = this;
- this.context = uni.createCameraContext();
- this.listener = this.context.onCameraFrame((frame) => {
- /* count++;
- if (count === 10) {
- that.detectFace(frame);
- count = 0;
- } */
- });
- this.VKSession = wx.createVKSession({
- version: 'v1',
- track: {
- plane: {
- mode: 1
- },
- face: {
- mode: 2
- }
- },
- camera: 'back'
- })
-
- // 摄像头实时检测模式下,监测到人脸时,updateAnchors 事件会连续触发 (每帧触发一次)
- /* this.VKSession.on('updateAnchors', anchors => {
- anchors.forEach(anchor => {
- console.log('anchor.points', anchor.points)
- console.log('anchor.origin', anchor.origin)
- console.log('anchor.size', anchor.size)
- console.log('anchor.angle', anchor.angle)
- });
- this.isFace = true;
- }) */
-
- // 当人脸从相机中离开时,会触发 removeAnchors 事件
- /* this.VKSession.on('removeAnchors', () => {
- this.$u.toast('请将人脸对准屏幕', 1500)
- console.log("检测不到人脸", 'removeAnchors');
- this.isFace = false;
- }) */
-
-
- // 需要调用一次 start 以启动
- this.VKSession.start(errno => {
- if (errno) {
- console.log("初始化失败", errno);
- this.$u.toast('相机加载失败')
- this.loadingState = false;
- this.show = true;
- // 如果失败,将返回 errno
- setTimeout(() => {
- this.QHimg = 'https://telpo-healthy.oss-cn-hangzhou.aliyuncs.com/healthy/knowledge/202412/f5dd3ef3f3bc49a48aec330c43e638da.png',
- this.clooseimg = 'https://telpo-healthy.oss-cn-hangzhou.aliyuncs.com/healthy/knowledge/202412/2ef369bc619e4098b091cf7fefe26ecb.png',
- this.faceImg = 'https://telpo-healthy.oss-cn-hangzhou.aliyuncs.com/healthy/knowledge/202412/d8565c6b51404b4996820083d684a111.png',
- this.photoimg = this.$urls.takePhone
- }, 800)
- } else {
- console.log("初始化成功", errno);
- this.$u.toast('相机加载成功')
- this.loadingState = true;
- this.show = true;
- setTimeout(() => {
- this.QHimg = 'https://telpo-healthy.oss-cn-hangzhou.aliyuncs.com/healthy/knowledge/202412/f5dd3ef3f3bc49a48aec330c43e638da.png',
- this.clooseimg = 'https://telpo-healthy.oss-cn-hangzhou.aliyuncs.com/healthy/knowledge/202412/2ef369bc619e4098b091cf7fefe26ecb.png',
- this.faceImg = 'https://telpo-healthy.oss-cn-hangzhou.aliyuncs.com/healthy/knowledge/202412/d8565c6b51404b4996820083d684a111.png',
- this.photoimg = this.$urls.takePhone
- }, 800)
- // 否则,返回null,表示成功
- }
- });
- this.listener.start();
- },
- async detectFace(frame) {
- console.warn(frame.data);
- /* this.VKSession.detectFace({
- frameBuffer: frame.data,
- width: frame.width,
- height: frame.height,
- scoreThreshold: 0.8,
- sourceType: 0,
- modelMode: 1
- }); */
- },
- onGetPhoto() {
- let that = this;
- this.listener.stop()
- this.context.takePhoto({
- quality: 'high',
- success: (res) => {
- // 把地址缓存到本地
- /* that.$store.commit('setForKey', {
- key: 'detectFaceImg',
- value: res.tempImagePath,
- }) */
- that.compressImage(res.tempImagePath)
- /* that.$emit('photoChange', res.tempImagePath) */
- },
- fail: (e) => {
- console.log(e)
- },
- complete: (e) => {
- console.log(e)
- }
- });
- },
- closeImage() {
- let that = this;
- console.log("选择相片");
- uni.chooseImage({
- count: 1,
- sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
- sourceType: ['album'], //从相册选择
- success: function(res) {
- console.log("选择的图片地址", res);
- /* that.$store.commit('setForKey', {
- key: 'detectFaceImg',
- value: res.tempFilePaths[0],
- }) */
- that.VKSession.destroy()
- that.compressImage(res.tempFilePaths[0])
- /* that.$emit('photoChange', res.tempFilePaths[0]) */
- },
- fail: function(err) {
- console.log("选择图片失败", err.errMsg);
- }
- })
- },
- deviceQH() {
- console.log("点击切换");
- this.device = this.device == 'back' ? 'front' : 'back';
- },
- error() {
- // this.tipsText = '相机异常'
- // this.cameraError()
- },
- stop() {
- // this.tipsText = '相机异常'
- // this.cameraError()
- },
- // 核验失败
- cameraError(e) {
- this.t = setTimeout(() => {
- clearTimeout(this.t)
- this.hideModal()
- this.$emit('detectFailed', e)
- }, 2000);
- },
- close() {
- clearTimeout(this.t)
- this.hideModal()
- this.$emit('detectFailed')
- },
- // 关闭
- hideModal() {
- uni.stopFaceDetect()
- this.face = {}
- this.isSuccess = false
- },
- compressImage(imgPath) {
- let that = this;
- uni.compressImage({
- src: imgPath,
- quality: 80, // 压缩质量
- success: (res) => {
- console.log('压缩后的图片:', res);
- const compressedFilePath = res.tempFilePath;
- console.log('压缩后的图片路径:', compressedFilePath);
- that.$emit('photoChange', compressedFilePath);
- },
- fail: (err) => {
- console.error(err);
- }
- });
- },
- // 拍照
- takePhoto() {
- this.context.takePhoto({
- quality: 'high',
- success: (res) => {
- that.compressImage(res.tempImagePath)
- /* this.$emit('photoChange', res.tempImagePath); */
- // 停止监听
- },
- fail: (e) => {
- console.log(e)
- },
- complete: (e) => {
- console.log(e)
- }
- });
- },
-
- // 检测完成
- detectOver() {
- this.isSuccess = true
- let t = setTimeout(() => {
- this.hideModal()
- clearTimeout(t)
- this.$emit('detectOver')
- }, 3000);
- },
-
- initData() {
- uni.getSetting({
- success: (res) => {
- if (res.authSetting['scope.camera'] === true) {
- this.createdVKSession()
- } else if (res.authSetting['scope.camera'] === false) {
- this.getCameraAuth()
- } else {
- this.createdVKSession()
- }
- }
- })
- },
-
- getCameraAuth() {
- uni.showModal({
- title: '温馨提示',
- content: '需要获取您摄像头权限才能更好的为您服务!是否授权摄像头权限?',
- confirmText: '授权',
- confirmColor: '#f94218',
- success: (res) => {
- if (res.confirm) {
- // 选择弹框内授权
- uni.openSetting({
- success: (res) => {
- if (res.authSetting[
- 'scope.camera'
- ]) {
- this.createdVKSession()
- } else {
- this.tipsText = "您未授权摄像头权限"
- this.cameraError('noAuth')
- }
- }
- })
- } else if (res.cancel) {
- this.tipsText = "您未授权摄像头权限"
- this.cameraError('noAuth')
- }
- }
- })
- },
-
- showData(faceData) {
- this.$emit("showData", faceData)
- if (this.isDev) {
- let face = faceData.faceInfo[0].angleArray
- this.face = face
- }
- },
-
- }
- }
- </script>
-
- <style lang="scss" scoped>
- .modal {
- height: 100vh;
- position: fixed;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- z-index: 1000;
- opacity: 0.1;
- outline: 0;
- text-align: center;
- backface-visibility: hidden;
- perspective: 2000rpx;
- pointer-events: none;
- overflow: hidden;
-
- .back {
- position: absolute;
- top: 30rpx;
- left: 0;
- height: 60rpx;
- /* line-height: 60rpx; */
- width: 100vw;
- padding: 0 20rpx;
- z-index: 9999;
- display: flex;
- justify-content: flex-start;
- align-items: center;
- .back-img {
- height: 30rpx;
- width: 23rpx;
- }
- .back-text {
- padding-left: 12rpx;
- font-size: 30rpx;
- text-align: center;
- font-family: Alibaba PuHuiTi;
- }
- }
- .camera-con {
- /* position: relative; */
- z-index: 9999;
- }
- }
-
- .qhImage {
- background-color: #ccc;
- width: 80rpx;
- height: 80rpx;
- z-index: 1001;
- margin: 30rpx;
- border-radius: 50%;
- padding: 16rpx;
- }
-
- .modal::before {
- content: "";
- display: inline-block;
- height: 100%;
- vertical-align: middle;
- }
-
- .modal.show {
- opacity: 1;
- overflow-x: hidden;
- overflow-y: hidden;
- pointer-events: auto;
- }
-
- .modal.bottom-modal::before {
- vertical-align: bottom;
- }
-
- .modal.bottom-modal .dialog {
- width: 100%;
- border-radius: 0;
- }
-
- .modal.bottom-modal {
- margin-bottom: -1000rpx;
- }
-
- .modal.bottom-modal.show {
- margin-bottom: 0;
- }
-
- .dialog {
- position: fixed;
- display: inline-block;
- vertical-align: middle;
- margin-left: auto;
- margin-right: auto;
- /* width: 680rpx; */
- height: 80vh;
- width: 100vw;
- max-width: 100%;
- background-color: #f8f8f8;
- border-radius: 10rpx;
- overflow: hidden;
- left: 0;
- top: 0;
- }
-
- .bar {
- display: flex;
- position: relative;
- align-items: center;
- min-height: 90rpx;
- height: 90rpx;
- padding: 0rpx 40rpx;
- justify-content: space-between;
- }
-
- .bg-white {
- background-color: #ffffff;
- color: #666666;
- }
- .img {
- height: 60rpx;
- width: 60rpx;
- object-fit: contain;
- }
-
- .detectInfo {
- padding: 20rpx 0rpx;
- font-size: 34rpx;
- text-align: center;
- animation-duration: 1.5s;
- color: #000000;
- z-index: 999;
- }
-
- .faceContent {
- height: 700rpx;
- position: relative;
- }
-
- .successImage {
- overflow: hidden;
- width: 600rpx;
- height: 600rpx;
- border-radius: 50%;
- position: absolute;
- top: 0;
- left: 50%;
- z-index: 999;
- transform: translateX(-50%);
- }
-
- .tipsTextCss {
- animation: 1.5s tipsTextAnimation;
- animation-duration: 1.5s;
- }
-
- @keyframes tipsTextAnimation {
- 0% {
- transform: scale(1);
- }
-
- 20% {
- transform: scale(1.5);
- }
-
- 70% {
- transform: scale(1.5);
- }
-
- 100% {
- transform: scale(1);
- }
- }
-
- .cover {
- width: 100vw;
- height: 100vh;
- display: flex;
- flex-direction: column;
- /* overflow: hidden; */
- }
-
- .cover-bottom {
- height: 60rpx;
- display: flex;
- justify-content: center;
- }
-
- .cover-item {
- height: 60rpx;
- width: 100%;
- background-color: #FFFFFF;
- display: flex;
- justify-content: space-around;
- align-items: center;
-
- }
-
- .load-fail {
- position: absolute;
- top: 0;
- left: 0;
- height: 100vh;
- width: 100vw;
- overflow: hidden;
- display: flex;
- justify-content: center;
- align-items: center;
- }
-
- .load-reset {
- width: 260rpx;
- font-size: 28rpx;
- padding: 20rpx;
- color: #fff;
- background-color: #8f7aed;
- border-radius: 15rpx;
- box-shadow: 0rpx 0rpx 20rpx 0rpx rgba(0, 0, 0, 0.2);
- ;
- }
-
- .camera {
- width: 100vw;
- height: 100vh;
- transform: scale(1.05);
- z-index: 999;
- overflow: hidden;
- }
-
- .camera-tips {
- position: fixed;
- top: 50%;
- left: 0;
- height: 120rpx;
- width: 100%;
- background-color: #FFFFFF;
- display: flex;
- justify-content: space-around;
- align-items: center;
- }
-
- .camera-action {
- position: absolute;
- bottom: 0;
- left: 0;
- width: 100%;
- display: flex;
- justify-content: space-around;
- align-items: center;
- z-index: 99999;
- overflow: hidden;
- background: #333;
- padding: 10rpx 0;
- .action {
- .img {
- height: 51rpx;
- width: 58rpx;
- object-fit: contain;
- }
- &.photoimg {
- .img {
- height: 161rpx;
- width: 161rpx;
- }
- }
- &.QHimg {
- .img {
- height: 56rpx;
- width: 64rpx;
- }
- }
- }
- }
- .face-con {
- position: absolute;
- bottom: 22vh;
- left: 0;
- width: 100vw;
- z-index: 9999;
- display: flex;
- justify-content: space-between;
- align-items: center;
- flex-direction: column;
- .title {
- height: 200rpx;
- line-height: 200rpx;
- width: 100%;
- font-family: Alibaba PuHuiTi;
- font-weight: bold;
- font-size: 30rpx;
- color: #FFFFFF;
- text-align: center;
-
- }
- .face-img {
- padding: 0 70rpx;
- height: 826rpx;
- width: calc(100vw - 140rpx);
- /* z-index: 9999; */
- object-fit: contain;
- }
- }
- .face-tips {
- position: absolute;
- bottom: 15vh;
- left: 0;
- z-index: 9999;
- width: 100vw;
- .title {
- font-family: Alibaba PuHuiTi;
- font-weight: bold;
- font-size: 30rpx;
- color: #FFFFFF;
- line-height: 38rpx;
- }
- .tips-con {
- padding: 0 100rpx 0 100rpx;
- .tips-list {
- width: 100%;
- display: flex;
- justify-content: flex-start;
- align-items: center;
- flex-wrap: nowrap;
- .item {
- height: 120rpx;
- width: 30%;
- padding: 30rpx 0 0 0;
- /* margin-top: 30rpx; */
- display: flex;
- justify-content: space-between;
- align-items: center;
- flex-direction: column;
- margin: 0 20rpx;
- .item-img {
- height: 100%;
- width: 100%;
- object-fit: contain;
- &.phone {
- width: 36rpx;
- height: 52rpx;
- /* padding-bottom: 25rpx; */
- }
- &.line {
- width: 61rpx;
- height: 61rpx;
- padding-top: 10rpx;
- /* padding-bottom: 18rpx; */
- }
- &.smile {
- width: 56rpx;
- height: 56rpx;
- /* padding-bottom: 24rpx; */
- }
- &.brush {
- width: 56rpx;
- height: 61rpx;
- padding-top: 10rpx;
- /* padding-bottom: 12rpx; */
- }
- &.glasses {
- width: 62rpx;
- height: 39rpx;
- padding-top: 20rpx;
- }
- &.hat {
- width: 54rpx;
- height: 37rpx;
- padding-top: 20rpx;
- /* padding-bottom: 35rpx; */
- }
-
- }
- .item-text {
- width: auto;
- font-family: Alibaba PuHuiTi;
- font-weight: bold;
- font-size: 24rpx;
- color: #FFFFFF;
- line-height: 38rpx;
- }
- }
- }
- }
- }
- </style>
|