123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- <template>
- <div class="emotion">
- <el-switch v-model="value" size="large" inactive-text="打开摄像头" @change="change" />
- <el-row :gutter="20">
- <el-col :span="12">
- <p>网络摄像头:</p>
- <video ref="videoEl" style="width: 300px;height: 260px;" v-if="switchCamera"></video>
- <div v-else class="video_img">
- 请先打开摄像头
- </div>
- </el-col>
- <el-col :span="12">
- <p>最新的快照:</p>
- <canvas ref="canvasEl" v-if="switchCamera"></canvas>
- <div v-else class="video_img">
- 你的快照将会呈现在这里
- </div>
- </el-col>
- </el-row>
- <el-button @click="photoRecognition" style="margin-top: 10px;">拍照识别</el-button>
- <el-row class="emotion_result">
- <el-col :span="24">
- <p class="emotion_result_p">脸部分析结果:</p>
- </el-col>
- <el-col :span="12">
- <span class="emotion_result_span">年龄:</span>{{ resultEmotion.age || "未识别到结果" }}
- </el-col>
- <el-col :span="12">
- <span class="emotion_result_span">情绪:</span>{{ resultEmotion.emotion || "未识别到结果" }}
- </el-col>
- <el-col :span="12">
- <span class="emotion_result_span">性别:</span>{{ resultEmotion.gender || "未识别到结果" }}
- </el-col>
- <el-col :span="12">
- <span class="emotion_result_span">眼镜:</span>{{ resultEmotion.glasses || "未识别到结果" }}
- </el-col>
- <el-col :span="12">
- <span class="emotion_result_span">表情:</span>{{ resultEmotion.expression || "未识别到结果" }}
- </el-col>
- <p style="width:100%;border-bottom: 1px solid rgba(0, 0, 0, 0.4);margin: 10px 0;"></p>
- <el-col :span="24">
- <span class="emotion_result_span">表情:</span>smile(微笑)、laugh(大笑)、none(无)
- </el-col>
- <el-col :span="24">
- <span
- class="emotion_result_span">情绪:</span>angry(愤怒)、disgust(厌恶)、fear(恐惧)、happy(快乐)、sad(悲伤)、surprise(惊讶)、neutral(中性)、pouty(撅嘴)、grimace(鬼脸)
- </el-col>
- </el-row>
- <el-row>
- <el-switch v-model="cloudValue" size="large" inactive-text="是否发送到云端" @change="rendCloud" />
- <el-col>
- <p>请选择一个 CocoCloud 项目,分析后的数据将会发送至该项目
- <img src="../../assets/img/刷新.png" @click="refreshCloud" alt="">
- </p>
- </el-col>
- <el-col>
- <el-select name="select" id="" v-model="apiMode" @change="getApiKey">
- <!-- <option value="" v-for="item in cloudList" v-model="item.url">{{ item.value }}</option> -->
- <el-option v-for="item in cloudList" :key="item.url" :label="item.value" :value="item.url" />
- </el-select>
- </el-col>
- </el-row>
- </div>
- </template>
- <script setup>
- import { ref, onMounted } from 'vue';
- import axios from 'axios';
- import userInfo from '@/stores/modules/userInfo';
- const value = ref(false);
- const videoEl = ref(HTMLVideoElement); // 摄像头video
- const canvasEl = ref(HTMLCanvasElement); // 画布canvas
- const switchCamera = ref(false);
- const yekReverse = "NmJhZjc4NzUzMmVmNGVlYzhiYzkzYzg4NTE4Yjg5MTY="
- const hans = {
- "angry": "angry(愤怒)",
- "disgust": "disgust(厌恶)",
- "fear": "fear(恐惧)",
- "happy": "happy(快乐)",
- "sad": "sad(悲伤)",
- "surprise": "surprise(惊讶)",
- "neutral": "neutral(中性)",
- "pouty": "pouty(撅嘴)",
- "grimace": "grimace(鬼脸)"
- }
- const hant = {
- "angry": "angry(憤怒)",
- "disgust": "disgust(厭惡)",
- "fear": "fear(恐懼)",
- "happy": "happy(快樂)",
- "sad": "sad(悲傷)",
- "surprise": "surprise(驚訝)",
- "neutral": "neutral(中性)",
- "pouty": "pouty(撅嘴)",
- "grimace": "grimace(鬼臉)"
- }
- const cloudList = ref();
- const resultEmotion = ref({});
- const cloudValue = ref(false);
- const apiMode = ref("");
- const rendCloud = (val) => {
- if (val) {
- cloudValue.value = true;
- } else {
- cloudValue.value = false;
- }
- }
- const change = (val) => {
- if (val) {
- getCamera();
- switchCamera.value = true;
- } else {
- videoEl.value.srcObject = null;
- switchCamera.value = false;
- }
- }
- onMounted(() => {
- console.log(userInfo().userInfo)
- if (userInfo().userInfo) {
- refreshCloud()
- }
- })
- // 打开摄像头
- const getCamera = async () => {
- const navigator = window.navigator.mediaDevices;
- // 获取所有设备
- const devices = await navigator.enumerateDevices();
- if (devices) {
- const stream = await navigator.getUserMedia({
- audio: false,
- video: {
- width: 300, // 设置视频宽度
- height: 260, // 设置视频高度
- facingMode: "user", // 使用前置摄像头
- },
- });
- if (videoEl.value) {
- videoEl.value.srcObject = stream;
- videoEl.value.play();
- }
- }
- }
- const photoRecognition = () => {
- // 检查视频元素和canvas 是否存在
- if (videoEl.value && canvasEl.value) {
- console.log(videoEl.value);
- canvasEl.value.width = 300;
- canvasEl.value.height = 260;
- // 获取画布上下文对象
- const ctx = canvasEl.value.getContext('2d');
- // 绘制图像到画布上
- ctx?.drawImage(videoEl.value, 0, 0, 300, 260);
- // 将画布内容转换为base64格式
- const imagebase64 = canvasEl.value.toDataURL('image/jpeg', 1).split(";");
- var contentType = imagebase64[0].split(":")[1];
- var realData = imagebase64[1].split(",")[1];
- const blob = b64toBlob(realData, contentType);
- const formData = new FormData();
- formData.append('image', blob);
- // https://ai-api.cocorobo.cn/face 人脸识别接口
- const headers = {
- 'Ocp-Apim-Subscription-Key': atob(yekReverse)
- }
- axios.post('https://ai-api.cocorobo.cn/face', {
- image: realData
- }, { headers }).then(res => {
- console.log(res.data.data);
- const datas = res.data.data;
- if (datas.error_code == 0) {
- let data = datas.result
- let obj = {
- emotion: hans[data.face_list[0].emotion.type],
- age: data.face_list[0].age,
- gender: data.face_list[0].gender.type + (data.face_list[0].gender.type == "male" ? "(男)" : "(女)"),
- glasses: data.face_list[0].glasses.type + (data.face_list[0].glasses.type == "common" ? "(有)" : "(无)"),
- expression: data.face_list[0].expression.type + (data.face_list[0].expression.type == "smile" ? "(微笑)" : data.face_list[0].expression.type == "smile" ? "(大笑)" : "(无)")
- }
- resultEmotion.value = obj
- if (cloudValue.value) {
- sendCloud()
- }
- }
- // if (res.status == 200) {
- // console.log(res.data);
- // }
- })
- }
- }
- const b64toBlob = (b64Data, contentType, sliceSize = 512) => {
- contentType = contentType || '';
- sliceSize = sliceSize || 512;
- var byteCharacters = atob(b64Data);
- var byteArrays = [];
- for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
- var slice = byteCharacters.slice(offset, offset + sliceSize);
- var byteNumbers = new Array(slice.length);
- for (var i = 0; i < slice.length; i++) {
- byteNumbers[i] = slice.charCodeAt(i);
- }
- var byteArray = new Uint8Array(byteNumbers);
- byteArrays.push(byteArray);
- }
- var blob = new Blob(byteArrays, { type: contentType });
- return blob;
- }
- const refreshCloud = () => {
- const apiKey = userInfo().userInfo.apiKey
- const event = window.location.host.indexOf("cocorobo.hk") > -1 ? `https://api.cocorobo.hk/iot/data/apikey/${apiKey.value}/event/` : `https://api.cocorobo.cn/iot/data/apikey/${apiKey}/event/`
- axios.get(event).then(res => {
- // console.log(res)
- if (res.data.length > 0) {
- let list = []
- res.data.map(x => {
- let obj = {
- id: x.eventAPIKey,
- value: x.name,
- url: x.url
- }
- list.push(obj)
- return x
- })
- apiMode.value = list[0].value
- apiKeyModel.value = list[0].id
- apiUrl.value = list[0].url
- cloudList.value = list
- }
- })
- }
- const getApiKey = (e) => {
- apiMode.value = e
- }
- const sendCloud = () => {
- console.log(apiMode.value)
- let data = resultEmotion.value
- axios.post(apiMode.value, JSON.stringify(data)).then(res => {
- console.log(res)
- })
- }
- </script>
- <style scoped lang="scss">
- .emotion {
- .video_img {
- width: 300px;
- height: 260px;
- background: #f0f0f0;
- border-radius: 6px;
- text-align: center;
- line-height: 260px;
- color: rgba(0, 0, 0, .4);
- }
- .emotion_result {
- text-align: left;
- border-radius: 6px;
- border: 1px solid rgba(0, 0, 0, .075);
- padding: 15px;
- background-color: rgba(0, 0, 0, .02);
- margin-bottom: 15px;
- margin-top: 10px;
- color: rgba(0, 0, 0, .4);
- .emotion_result_p {
- font-weight: 200;
- margin-bottom: 10px;
- color: #000;
- }
- .emotion_result_span {
- font-weight: 600;
- color: #000;
- }
- }
- select {
- margin: 10px 0;
- width: 100%;
- padding: 8px;
- border-radius: 5px;
- }
- img {
- width: 25px;
- float: right;
- cursor: pointer;
- }
- }
- </style>
|