当前位置:   article > 正文

vue实现调用摄像头百度ai人脸,实现人脸情绪识别_vue识别人脸表情

vue识别人脸表情
后面页面完整代码哦~~~
首先说一下,我这里用到了axios element-ui的loading

先看一下我的效果图吧

 

 说明:我这里是调用摄像头识别人脸,根据返回的信息,再加以描述,右边的小图片是,根据返回的人脸位置,宽度大小截取出来的

 首先我们得申请一个百度ai人脸识别的接口,并且获取key 和secret 这样才能后续使用。

 第一步:先写html

  1. <template>
  2. <div class="main">
  3. <div class="cam">
  4. <div class="video-box">
  5. <div class="videos">
  6. <video
  7. id="video"
  8. style="width: 100%;height: 100%; object-fit: fill;"
  9. preload
  10. autoplay
  11. loop
  12. muted
  13. ></video>
  14. </div>
  15. <div class="button-box" @click="submit()">
  16. <img src="../assets/cam.png" />
  17. </div>
  18. </div>
  19. <div class="title-box">
  20. 识别分析
  21. </div>
  22. <div class="right-box">
  23. <div
  24. ref="mainscroll"
  25. class="face-box"
  26. v-loading="loading"
  27. element-loading-text="拼命加载中"
  28. element-loading-spinner="el-icon-loading"
  29. element-loading-background="transparent"
  30. >
  31. <div
  32. class="details"
  33. v-for="(item, index) in threeImageArray"
  34. :key="index"
  35. >
  36. <div class="image-box">
  37. <img :src="item.image" />
  38. </div>
  39. <div class="list-box">
  40. <div class="sex-one">年龄:{{ item.age }}</div>
  41. </div>
  42. </div>
  43. </div>
  44. </div>
  45. <div class="canva-box">
  46. <canvas ref="canvas" id="canvas" width="1000" height="700"></canvas>
  47. </div>
  48. </div>
  49. </div>
  50. </template>

说明:因为需求时只显示摄像头,所以,我把截图的图片canvas部分放在了摄像头的底层,大家根据需求来写css样式

 第二步:写css

  1. <style scoped>
  2. .main {
  3. width: 100%;
  4. height: 100vh;
  5. display: flex;
  6. align-items: center;
  7. justify-content: center;
  8. }
  9. .cam {
  10. width: 50%;
  11. height: 90%;
  12. display: flex;
  13. flex-direction: column;
  14. align-items: center;
  15. background-color: #fff;
  16. border-radius: 20px;
  17. }
  18. .canva-box {
  19. width: 100%;
  20. display: flex;
  21. align-items: center;
  22. justify-content: center;
  23. position: absolute;
  24. top: 0;
  25. z-index: -99;
  26. }
  27. .button-box {
  28. position: absolute;
  29. top: 35%;
  30. border: 2px solid #fff;
  31. padding: calc(100vw * 20 / 1920);
  32. border-radius: 50%;
  33. }
  34. .button-box img {
  35. width: calc(100vw * 40 / 1920);
  36. height: calc(100vw * 40 / 1920);
  37. }
  38. .title-box {
  39. height: 5%;
  40. font-size: calc(100vw * 40 / 1920);
  41. font-weight: bold;
  42. width: 40%;
  43. }
  44. .right-box {
  45. width: 100%;
  46. height: 30%;
  47. display: flex;
  48. flex-direction: column;
  49. align-items: center;
  50. justify-content: space-evenly;
  51. }
  52. .video-box {
  53. width: 100%;
  54. height: 65%;
  55. display: flex;
  56. justify-content: center;
  57. }
  58. .videos {
  59. width: 100%;
  60. height: 100%;
  61. }
  62. .face-box {
  63. width: 100%;
  64. height: 100%;
  65. display: flex;
  66. flex-direction: column;
  67. align-items: center;
  68. overflow: auto;
  69. }
  70. .details {
  71. display: flex;
  72. width: 100%;
  73. height: 90%;
  74. margin-top: 4px;
  75. }
  76. .image-box {
  77. width: 30%;
  78. height: 100%;
  79. display: flex;
  80. justify-content: center;
  81. }
  82. .image-box img {
  83. width: calc(100vw * 150 / 1920);
  84. height: calc(100vw * 150 / 1920);
  85. }
  86. .list-box {
  87. width: 60%;
  88. height: calc(100vw * 300 / 1920);
  89. display: flex;
  90. flex-direction: column;
  91. text-indent: calc(100vw * 16 / 1920);
  92. font-size: calc(100vw * 18 / 1920);
  93. padding-bottom: 20px;
  94. }
  95. </style>

 第三步:下载axios   npm i axios

 第四步:下载element-ui 

                npm i element-ui

                //引入 使用

                import ElementUI from "element-ui";

                import "element-ui/lib/theme-chalk/index.css";

                // 引入echarts

                import * as echarts from "echarts";

                Vue.prototype.$echarts = echarts;

第五步:js部分

首先调用摄像头(这里我也是根据网上找的,但是忘记哪个文章了)

  1. //可以是点击方法,可以放在mounted()中,看自己的需求
  2. getCompetence() {
  3. var _this = this;
  4. this.thisCancas = document.getElementById("canvas");
  5. this.thisContext = this.thisCancas.getContext("2d");
  6. this.thisVideo = document.getElementById("video");
  7. // 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
  8. if (navigator.mediaDevices === undefined) {
  9. navigator.mediaDevices = {};
  10. }
  11. // 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象
  12. // 使用getUserMedia,因为它会覆盖现有的属性。
  13. // 这里,如果缺少getUserMedia属性,就添加它。
  14. if (navigator.mediaDevices.getUserMedia === undefined) {
  15. navigator.mediaDevices.getUserMedia = function(constraints) {
  16. // 首先获取现存的getUserMedia(如果存在)
  17. var getUserMedia =
  18. navigator.webkitGetUserMedia ||
  19. navigator.mozGetUserMedia ||
  20. navigator.getUserMedia;
  21. // 有些浏览器不支持,会返回错误信息
  22. // 保持接口一致
  23. if (!getUserMedia) {
  24. return Promise.reject(
  25. new Error("getUserMedia is not implemented in this browser")
  26. );
  27. }
  28. // 否则,使用Promise将调用包装到旧的navigator.getUserMedia
  29. return new Promise(function(resolve, reject) {
  30. getUserMedia.call(navigator, constraints, resolve, reject);
  31. });
  32. };
  33. }
  34. var constraints = {
  35. audio: false,
  36. video: {
  37. width: this.videoWidth,
  38. height: this.videoHeight,
  39. transform: "scaleX(-1)"
  40. }
  41. };
  42. navigator.mediaDevices
  43. .getUserMedia(constraints)
  44. .then(function(stream) {
  45. // 旧的浏览器可能没有srcObject
  46. if ("srcObject" in _this.thisVideo) {
  47. _this.thisVideo.srcObject = stream;
  48. } else {
  49. // 避免在新的浏览器中使用它,因为它正在被弃用。
  50. _this.thisVideo.src = window.URL.createObjectURL(stream);
  51. }
  52. _this.thisVideo.onloadedmetadata = function(e) {
  53. _this.thisVideo.play();
  54. };
  55. })
  56. .catch(err => {
  57. console.log(err);
  58. });
  59. },

 记得销毁调用摄像头哦!

  1. // 关闭摄像头 在vue生命周期的销毁页面中写
  2. this.trackerTask.closeCamera();

 接下来先把调用百度ai 部分写出来

  1. async detectFace(imageData) {
  2. //access_token需要通过申请的key 和secret来获取,登录百度ai文档中就有教程
  3. this.loading = true;
  4. try {
  5. const response = await axios.post(
  6. "https://aip.baidubce.com/rest/2.0/face/v3/detect?access_token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  7. {
  8. image: imageData,
  9. image_type: "BASE64",
  10. face_field: "age,gender,emotion,glasses,mask,expression",
  11. max_face_num: 10
  12. }
  13. );
  14. // 处理接口返回的结果
  15. if (response.data.error_code == 0) {
  16. //这里是接口返回的打印
  17. console.log("调用成功显示结果", response);
  18. this.faceInfomation = response.data.result;
  19. this.faceArray = response.data.result.face_list;
  20. //这里我用一个数组接收返回的人脸信息
  21. this.faceArray.forEach((item, i) => {
  22. console.log("item", item);
  23. //这里是人脸的位置宽高信息
  24. const left = parseInt(item.location.left);
  25. const top = parseInt(item.location.top);
  26. const width = parseInt(item.location.width);
  27. const height = parseInt(item.location.height);
  28. const faceCanvas = document.createElement("canvas");
  29. faceCanvas.width = width;
  30. faceCanvas.height = height;
  31. //将截取的人脸再重新铺到canvas画布上,好展示出来
  32. const faceCtx = faceCanvas.getContext("2d");
  33. faceCtx.drawImage(
  34. this.canvas,
  35. left,
  36. top,
  37. width,
  38. height,
  39. 0,
  40. 0,
  41. width,
  42. height
  43. );
  44. this.faceImg = faceCanvas.toDataURL("image/png");
  45. //将截取的头像放在新的数组中
  46. this.newImageArray.push(this.faceImg);
  47. });
  48. //因为截取的人脸头像和人脸文字描述不是一个数组,所以将两个数组合并一个数组了,这样在遍历循环列表的时候,更好的画css样式
  49. this.threeImageArray = this.faceArray.map((item, index) => {
  50. return { ...item, image: this.newImageArray[index] };
  51. });
  52. }
  53. } catch (error) {
  54. console.error(error);
  55. } finally {
  56. this.loading = false;
  57. }
  58. },

如果有不清晰的地方可以留言评论,我会会的,虽然不知道对不对哈哈

 摄像头获取的图片放在canvas是上后,转成接口可用的类型

  1. submit() {
  2. console.log("点击了这个");
  3. //每次点击的时候都清空一下上一次的内容
  4. this.newImageArray = [];
  5. this.faceArray = [];
  6. //loading加载
  7. this.fullscreenLoading = true;
  8. setTimeout(() => {
  9. this.fullscreenLoading = false;
  10. }, 2000);
  11. let that = this;
  12. let canvas = document.getElementById("canvas");
  13. let context = canvas.getContext("2d");
  14. let video = document.getElementById("video");
  15. //将摄像头拍下的照片放在canvas画布上
  16. context.drawImage(video, 0, 0, 1000, 700);
  17. //将图片转换成 接口需要的类型
  18. canvas.toBlob(blob => {
  19. var reader = new FileReader();
  20. reader.onloadend = () => {
  21. this.imageData = reader.result;
  22. this.newimage = this.imageData.replace(
  23. /^data:image\/\w+;base64,/,
  24. ""
  25. );
  26. //截取一下图片
  27. this.headerimg = this.imageData.slice(5, 15);
  28. this.imageArray.push(this.headerimg);
  29. //调用识别方法
  30. this.detectFace(this.newimage);
  31. };
  32. reader.readAsDataURL(blob);
  33. });
  34. },

完整代码 

  1. <template>
  2. <div class="main">
  3. <div class="cam">
  4. <div class="video-box">
  5. <div class="videos">
  6. <video
  7. id="video"
  8. style="width: 100%;height: 100%; object-fit: fill;"
  9. preload
  10. autoplay
  11. loop
  12. muted
  13. ></video>
  14. </div>
  15. <div class="button-box" @click="submit()">
  16. <img src="../assets/cam.png" />
  17. </div>
  18. </div>
  19. <div class="title-box">
  20. 识别分析
  21. </div>
  22. <div class="right-box">
  23. <div
  24. ref="mainscroll"
  25. class="face-box"
  26. v-loading="loading"
  27. element-loading-text="拼命加载中"
  28. element-loading-spinner="el-icon-loading"
  29. element-loading-background="transparent"
  30. >
  31. <div
  32. class="details"
  33. v-for="(item, index) in threeImageArray"
  34. :key="index"
  35. >
  36. <div class="image-box">
  37. <img :src="item.image" />
  38. </div>
  39. <div class="list-box">
  40. <div class="sex-one">年龄:{{ item.age }}</div>
  41. </div>
  42. </div>
  43. </div>
  44. </div>
  45. <div class="canva-box">
  46. <canvas ref="canvas" id="canvas" width="1000" height="700"></canvas>
  47. </div>
  48. </div>
  49. </div>
  50. </template>
  51. <script>
  52. import axios from "axios";
  53. export default {
  54. name: "testTracking",
  55. data() {
  56. return {
  57. loading: false,
  58. contentAnwer: false,
  59. contentShow: true,
  60. API_KEY: "这里是你申请的key",
  61. SECRET_KEY: "这里是你申请的secret",
  62. imageData: null,
  63. newimage: null,
  64. faceInfomation: {},
  65. faceArray: [],
  66. age: null,
  67. imageArray: [],
  68. headerimg: "",
  69. location: {},
  70. left: 0,
  71. top: 0,
  72. width: 0,
  73. height: 0,
  74. faceImg: null,
  75. canvas: null,
  76. newImageArray: [],
  77. threeImageArray: []
  78. };
  79. },
  80. methods: {
  81. submit() {
  82. console.log("点击了这个");
  83. //每次点击的时候都清空一下上一次的内容
  84. this.newImageArray = [];
  85. this.faceArray = [];
  86. //loading加载
  87. this.fullscreenLoading = true;
  88. setTimeout(() => {
  89. this.fullscreenLoading = false;
  90. }, 2000);
  91. let that = this;
  92. let canvas = document.getElementById("canvas");
  93. let context = canvas.getContext("2d");
  94. let video = document.getElementById("video");
  95. //将摄像头拍下的照片放在canvas画布上
  96. context.drawImage(video, 0, 0, 1000, 700);
  97. //将图片转换成 接口需要的类型
  98. canvas.toBlob(blob => {
  99. var reader = new FileReader();
  100. reader.onloadend = () => {
  101. this.imageData = reader.result;
  102. this.newimage = this.imageData.replace(
  103. /^data:image\/\w+;base64,/,
  104. ""
  105. );
  106. //截取一下图片
  107. this.headerimg = this.imageData.slice(5, 15);
  108. this.imageArray.push(this.headerimg);
  109. //调用识别方法
  110. this.detectFace(this.newimage);
  111. };
  112. reader.readAsDataURL(blob);
  113. });
  114. },
  115. //可以是点击方法,可以放在mounted()中,看自己的需求
  116. getCompetence() {
  117. var _this = this;
  118. this.thisCancas = document.getElementById("canvas");
  119. this.thisContext = this.thisCancas.getContext("2d");
  120. this.thisVideo = document.getElementById("video");
  121. // 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
  122. if (navigator.mediaDevices === undefined) {
  123. navigator.mediaDevices = {};
  124. }
  125. // 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象
  126. // 使用getUserMedia,因为它会覆盖现有的属性。
  127. // 这里,如果缺少getUserMedia属性,就添加它。
  128. if (navigator.mediaDevices.getUserMedia === undefined) {
  129. navigator.mediaDevices.getUserMedia = function(constraints) {
  130. // 首先获取现存的getUserMedia(如果存在)
  131. var getUserMedia =
  132. navigator.webkitGetUserMedia ||
  133. navigator.mozGetUserMedia ||
  134. navigator.getUserMedia;
  135. // 有些浏览器不支持,会返回错误信息
  136. // 保持接口一致
  137. if (!getUserMedia) {
  138. return Promise.reject(
  139. new Error("getUserMedia is not implemented in this browser")
  140. );
  141. }
  142. // 否则,使用Promise将调用包装到旧的navigator.getUserMedia
  143. return new Promise(function(resolve, reject) {
  144. getUserMedia.call(navigator, constraints, resolve, reject);
  145. });
  146. };
  147. }
  148. var constraints = {
  149. audio: false,
  150. video: {
  151. width: this.videoWidth,
  152. height: this.videoHeight,
  153. transform: "scaleX(-1)"
  154. }
  155. };
  156. navigator.mediaDevices
  157. .getUserMedia(constraints)
  158. .then(function(stream) {
  159. // 旧的浏览器可能没有srcObject
  160. if ("srcObject" in _this.thisVideo) {
  161. _this.thisVideo.srcObject = stream;
  162. } else {
  163. // 避免在新的浏览器中使用它,因为它正在被弃用。
  164. _this.thisVideo.src = window.URL.createObjectURL(stream);
  165. }
  166. _this.thisVideo.onloadedmetadata = function(e) {
  167. _this.thisVideo.play();
  168. };
  169. })
  170. .catch(err => {
  171. console.log(err);
  172. });
  173. },
  174. async detectFace(imageData) {
  175. //access_token需要通过申请的key 和secret来获取,登录百度ai文档中就有教程
  176. this.loading = true;
  177. try {
  178. const response = await axios.post(
  179. "https://aip.baidubce.com/rest/2.0/face/v3/detect?access_token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  180. {
  181. image: imageData,
  182. image_type: "BASE64",
  183. face_field: "age,gender,emotion,glasses,mask,expression",
  184. max_face_num: 10
  185. }
  186. );
  187. // 处理接口返回的结果
  188. if (response.data.error_code == 0) {
  189. //这里是接口返回的打印
  190. console.log("调用成功显示结果", response);
  191. this.faceInfomation = response.data.result;
  192. this.faceArray = response.data.result.face_list;
  193. //这里我用一个数组接收返回的人脸信息
  194. this.faceArray.forEach((item, i) => {
  195. console.log("item", item);
  196. //这里是人脸的位置宽高信息
  197. const left = parseInt(item.location.left);
  198. const top = parseInt(item.location.top);
  199. const width = parseInt(item.location.width);
  200. const height = parseInt(item.location.height);
  201. const faceCanvas = document.createElement("canvas");
  202. faceCanvas.width = width;
  203. faceCanvas.height = height;
  204. //将截取的人脸再重新铺到canvas画布上,好展示出来
  205. const faceCtx = faceCanvas.getContext("2d");
  206. faceCtx.drawImage(
  207. this.canvas,
  208. left,
  209. top,
  210. width,
  211. height,
  212. 0,
  213. 0,
  214. width,
  215. height
  216. );
  217. this.faceImg = faceCanvas.toDataURL("image/png");
  218. //将截取的头像放在新的数组中
  219. this.newImageArray.push(this.faceImg);
  220. });
  221. //因为截取的人脸头像和人脸文字描述不是一个数组,所以将两个数组合并一个数组了,这样在遍历循环列表的时候,更好的画css样式
  222. this.threeImageArray = this.faceArray.map((item, index) => {
  223. return { ...item, image: this.newImageArray[index] };
  224. });
  225. }
  226. } catch (error) {
  227. console.error(error);
  228. } finally {
  229. this.loading = false;
  230. }
  231. },
  232. },
  233. mounted() {
  234. this.getCompetence();
  235. this.canvas = this.$refs.canvas;
  236. },
  237. computed: {},
  238. destroyed() {
  239. // 关闭摄像头
  240. this.trackerTask.closeCamera();
  241. }
  242. };
  243. </script>
  244. <style scoped>
  245. .main {
  246. width: 100%;
  247. height: 100vh;
  248. display: flex;
  249. align-items: center;
  250. justify-content: center;
  251. }
  252. .cam {
  253. width: 50%;
  254. height: 90%;
  255. display: flex;
  256. flex-direction: column;
  257. align-items: center;
  258. background-color: #fff;
  259. border-radius: 20px;
  260. }
  261. .canva-box {
  262. width: 100%;
  263. display: flex;
  264. align-items: center;
  265. justify-content: center;
  266. position: absolute;
  267. top: 0;
  268. z-index: -99;
  269. }
  270. .button-box {
  271. position: absolute;
  272. top: 35%;
  273. border: 2px solid #fff;
  274. padding: calc(100vw * 20 / 1920);
  275. border-radius: 50%;
  276. }
  277. .button-box img {
  278. width: calc(100vw * 40 / 1920);
  279. height: calc(100vw * 40 / 1920);
  280. }
  281. .title-box {
  282. height: 5%;
  283. font-size: calc(100vw * 40 / 1920);
  284. font-weight: bold;
  285. width: 40%;
  286. }
  287. .right-box {
  288. width: 100%;
  289. height: 30%;
  290. display: flex;
  291. flex-direction: column;
  292. align-items: center;
  293. justify-content: space-evenly;
  294. }
  295. .video-box {
  296. width: 100%;
  297. height: 65%;
  298. display: flex;
  299. justify-content: center;
  300. }
  301. .videos {
  302. width: 100%;
  303. height: 100%;
  304. }
  305. .face-box {
  306. width: 100%;
  307. height: 100%;
  308. display: flex;
  309. flex-direction: column;
  310. align-items: center;
  311. overflow: auto;
  312. }
  313. .details {
  314. display: flex;
  315. width: 100%;
  316. height: 90%;
  317. margin-top: 4px;
  318. }
  319. .image-box {
  320. width: 30%;
  321. height: 100%;
  322. display: flex;
  323. justify-content: center;
  324. }
  325. .image-box img {
  326. width: calc(100vw * 150 / 1920);
  327. height: calc(100vw * 150 / 1920);
  328. }
  329. .list-box {
  330. width: 60%;
  331. height: calc(100vw * 300 / 1920);
  332. display: flex;
  333. flex-direction: column;
  334. text-indent: calc(100vw * 16 / 1920);
  335. font-size: calc(100vw * 18 / 1920);
  336. padding-bottom: 20px;
  337. }
  338. </style>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/701519
推荐阅读
相关标签
  

闽ICP备14008679号