123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- <template>
- <div class="game-container">
- <canvas ref="canvasRef" :width="clientObj.width" :height="clientObj.height"></canvas>
- </div>
- </template>
- <script setup name="HumanBody" lang="ts">
- const { proxy } = getCurrentInstance() as any;
- const router = useRouter();
- const canvasRef = ref(null);
- const data = reactive<any>({
- bodyposeData: {},//姿态信息
- clientObj: {},//浏览器对象
- boxes: [],//四个点坐标
- proportion: null,//人框和屏幕比例
- });
- const { bodyposeData, clientObj, boxes, proportion } = toRefs(data);
- /**
- * 初始化
- */
- const getInit = (e: any) => {
- let arr = e.data.result.keypoints;
- let result = [];
- for (let i = 0; i < arr.length; i += 3) {
- result.push(arr.slice(i, i + 2));
- }
- console.log("result", result)
- bodyposeData.value = result;
- if (boxes.value.length == 0) {
- // speckText("识别成功");
- // proxy?.$modal.msgWarning(`识别成功`);
- let arr = e.data.result.boxes;
- boxes.value = [{ x: arr[0], y: arr[3] }, { x: arr[0], y: arr[1] }, { x: arr[2], y: arr[1] }, { x: arr[2], y: arr[3] }]
- proportion.value = (clientObj.value.height / (arr[3] - arr[1])).toFixed(2);
- }
- //绘制图案
- getCanvas();
- };
- /**
- * 绘图
- */
- const getCanvas = () => {
- const canvas: any = canvasRef.value;
- const ctx = canvas.getContext('2d');
- // 清空整个画布
- ctx.clearRect(0, 0, canvas.width, canvas.height);
- // 保存当前状态
- ctx.save();
- function calculateOffset(a: any, b: any) {
- return {
- x: b.x - a.x,
- y: b.y - a.y
- };
- }
- const pointA = { x: clientObj.value.width / 2, y: clientObj.value.height / 2 };
- const pointB = { x: (boxes.value[2].x + boxes.value[0].x) / 2, y: (boxes.value[3].y + boxes.value[1].y) / 2 };
- const offset = calculateOffset(pointA, pointB);
- ctx.translate(-offset.x, -offset.y);
- // console.log("Canvas分辨率", clientObj.value);
- // console.log("人体图片四点坐标", boxes.value)
- // console.log("Canvas中心", pointA);
- // console.log("人体中心", pointB);
- // console.log("offset", offset)
- // console.log("proportion.value",proportion.value)
- const originalPoints = bodyposeData.value;
- // 计算缩放后坐标
- const postData = originalPoints.map((point: any) => {
- const newX = (point[0] - pointB.x) * proportion.value + pointB.x;
- const newY = (point[1] - pointB.y) * proportion.value + pointB.y;
- return [newX, newY];
- });
- // console.log("原始坐标:", originalPoints);
- // console.log("缩放后坐标:", postData);
- //绘制头部
- const point1 = { x: postData[4][0], y: postData[4][1] };
- const point2 = { x: postData[3][0], y: postData[3][1] };
- // 计算椭圆参数
- const centerX = (point1.x + point2.x) / 2; // 椭圆中心X
- const centerY = (point1.y + point2.y) / 2; // 椭圆中心Y
- const distance = Math.sqrt(
- Math.pow(point2.x - point1.x, 2) +
- Math.pow(point2.y - point1.y, 2)
- ); // 两个焦点之间的距离
- const radiusX = distance * 0.5; // 水平半径(可调整)
- const radiusY = distance * 0.6; // 垂直半径(可调整)
- // 1. 绘制填充椭圆
- ctx.beginPath();
- ctx.ellipse(centerX, centerY, radiusX, radiusY, 0, 0, Math.PI * 2);
- ctx.fillStyle = 'red'; // 填充颜色
- ctx.fill(); // 填充
- // 2. 绘制边框
- ctx.strokeStyle = 'red';
- ctx.lineWidth = 5;
- ctx.stroke();
- // 绘制每个点
- postData.forEach((point: any, index: number) => {
- //眼睛鼻子不显示
- if (![0, 1, 2].includes(index)) {
- const [x, y] = point;
- ctx.beginPath();
- ctx.arc(x, y, 5, 0, Math.PI * 2); // 绘制半径为5的圆点
- ctx.fillStyle = 'red';
- ctx.fill();
- ctx.lineWidth = 1;
- ctx.stroke();
- }
- });
- // 根据点关系连线
- const arr = [[10, 8], [8, 6], [6, 5], [5, 7], [7, 9], [6, 12], [5, 11], [12, 11], [12, 14], [14, 16], [11, 13], [13, 15]]
- arr.forEach((point: any) => {
- let index1 = point[0];
- let index2 = point[1];
- //连线
- const dian1 = { x: postData[index1][0], y: postData[index1][1] };
- const dian2 = { x: postData[index2][0], y: postData[index2][1] };
- // 绘制连线
- ctx.beginPath();
- ctx.moveTo(dian1.x, dian1.y); // 起点
- ctx.lineTo(dian2.x, dian2.y); // 终点
- ctx.strokeStyle = 'red'; // 线条颜色
- ctx.lineWidth = 3; // 线条宽度
- ctx.stroke(); // 描边
- });
- ctx.restore(); // 恢复状态
- };
- onBeforeMount(() => {
- });
- onMounted(() => {
- clientObj.value = {
- width: document.querySelector('.game-container').offsetWidth,
- height: document.querySelector('.game-container').offsetHeight,
- }
- })
- onBeforeUnmount(() => {
- });
- //暴露给父组件用
- defineExpose({
- getInit
- })
- </script>
- <style lang="scss" scoped>
- .game-container {
- background: #000000;
- position: relative;
- width: 100%;
- height: 100vh;
- margin: 0 auto;
- overflow: hidden;
- }
- </style>
|