AI项目二:基于mediapipe的虚拟绘画

news2024/12/24 21:39:26

若该文为原创文章,转载请注明原文出处。

一、项目介绍

随着人工智能时代的到来,许多技术得到了空前的发展,让人们更加认识到了线上虚拟技术的强大。

通过mediapipe识别手的关键点,检测中指,实现隔空画画的操作。

通过两个手指的间距,实现点击选择颜色或橡皮檫。

二、运行

 1、环境

环境搭建使用的是上一篇搭建的环境mediapipe_env

打开终端,输入下面命令,激活环境:

conda activate mediapipe

这次使用的是pycharm,软件自行安装,安装社区版本。

建立一个目录,把项目导入到pycharm里,然后设置环境

点击Add New Interpreter

 选择环境的python.exe

 终端选择,一定要powershell.exe

 设置好可以在pycharm里的终端操作

 2、运行

导入代码,右键运行

3 、结果

三、代码

这里不介绍原理及过程,想学习的人不会因为这些而去不学习,所以需要自行了解,项目难度不大,代码也相对的不复杂。直接上源码

一共两个文件,AiVirtualPainter.py和HandTrackingModule.py

AiVirtualPainter.py实现的是绘画功能,HandTrackingModule.py实现的是手关键点识别。

AiVirtualPainter.py

import cv2
import HandTrackingModule as htm
import os
import numpy as np


folderPath = "PainterImg/"
mylist = os.listdir(folderPath)
overlayList = []
for imPath in mylist:
    image = cv2.imread(f'{folderPath}/{imPath}')
    overlayList.append(image)
header = overlayList[0]
color = [255, 0, 0]
brushThickness = 15
eraserThickness = 40

cap = cv2.VideoCapture(0)  # 若使用笔记本自带摄像头则编号为0  若使用外接摄像头 则更改为1或其他编号
cap.set(3, 1280)
cap.set(4, 720)
# cap.set(3, 800)
# cap.set(4, 500)
detector = htm.handDetector()
xp, yp = 0, 0
imgCanvas = np.zeros((720, 1280, 3), np.uint8)  # 新建一个画板
# imgCanvas = np.zeros((500, 800, 3), np.uint8)  # 新建一个画板

while True:
    # 1.import image
    success, img = cap.read()
    img = cv2.flip(img, 1)  # 翻转

    # 2.find hand landmarks
    img = detector.findHands(img)
    lmList = detector.findPosition(img, draw=True)

    if len(lmList) != 0:
        x1, y1 = lmList[8][1:]
        x2, y2 = lmList[12][1:]

        # 3. Check which fingers are up
        fingers = detector.fingersUp()

        # 4. If Selection Mode – Two finger are up
        if fingers[1] and fingers[2]:
            if y1 < 153:
                if 0 < x1 < 320:
                    header = overlayList[0]
                    color = [50, 128, 250]
                elif 320 < x1 < 640:
                    header = overlayList[1]
                    color = [0, 0, 255]
                elif 640 < x1 < 960:
                    header = overlayList[2]
                    color = [0, 255, 0]
                elif 960 < x1 < 1280:
                    header = overlayList[3]
                    color = [0, 0, 0]
        img[0:1280][0:153] = header

        # 5. If Drawing Mode – Index finger is up
        if fingers[1] and fingers[2] == False:
            cv2.circle(img, (x1, y1), 15, color, cv2.FILLED)
            print("Drawing Mode")
            if xp == 0 and yp == 0:
                xp, yp = x1, y1

            if color == [0, 0, 0]:
                cv2.line(img, (xp, yp), (x1, y1), color, eraserThickness)  # ??
                cv2.line(imgCanvas, (xp, yp), (x1, y1), color, eraserThickness)
            else:
                cv2.line(img, (xp, yp), (x1, y1), color, brushThickness)   # ??
                cv2.line(imgCanvas, (xp, yp), (x1, y1), color, brushThickness)

        xp, yp = x1, y1
        # Clear Canvas when all fingers are up
        # if all (x >= 1 for x in fingers):
        #     imgCanvas = np.zeros((720, 1280, 3), np.uint8)

    # 实时显示画笔轨迹的实现
    imgGray = cv2.cvtColor(imgCanvas, cv2.COLOR_BGR2GRAY)
    _, imgInv = cv2.threshold(imgGray, 50, 255, cv2.THRESH_BINARY_INV)
    imgInv = cv2.cvtColor(imgInv, cv2.COLOR_GRAY2BGR)
    img = cv2.bitwise_and(img, imgInv)
    img = cv2.bitwise_or(img, imgCanvas)
    img[0:1280][0:153] = header

    cv2.imshow("Image", img)
    # cv2.imshow("Canvas", imgCanvas)
    # cv2.imshow("Inv", imgInv)
    cv2.waitKey(1)

HandTrackingModule.py

import cv2
import mediapipe as mp
import time
import math

class handDetector():
    def __init__(self, mode=False, maxHands=2, detectionCon=0.8, trackCon=0.8):
        self.mode = mode
        self.maxHands = maxHands
        self.detectionCon = detectionCon
        self.trackCon = trackCon

        self.mpHands = mp.solutions.hands
        self.hands = self.mpHands.Hands(self.mode, self.maxHands, self.detectionCon, self.trackCon)
        self.mpDraw = mp.solutions.drawing_utils
        self.tipIds = [4, 8, 12, 16, 20]

    def findHands(self, img, draw=True):
        imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        self.results = self.hands.process(imgRGB)

        print(self.results.multi_handedness)  # 获取检测结果中的左右手标签并打印

        if self.results.multi_hand_landmarks:
            for handLms in self.results.multi_hand_landmarks:
                if draw:
                    self.mpDraw.draw_landmarks(img, handLms, self.mpHands.HAND_CONNECTIONS)
        return img

    def findPosition(self, img, draw=True):
        self.lmList = []
        if self.results.multi_hand_landmarks:
            for handLms in self.results.multi_hand_landmarks:
                for id, lm in enumerate(handLms.landmark):
                    h, w, c = img.shape
                    cx, cy = int(lm.x * w), int(lm.y * h)
                    # print(id, cx, cy)
                    self.lmList.append([id, cx, cy])
                    if draw:
                        cv2.circle(img, (cx, cy), 12, (255, 0, 255), cv2.FILLED)
        return self.lmList

    def fingersUp(self):
        fingers = []
        # 大拇指
        if self.lmList[self.tipIds[0]][1] > self.lmList[self.tipIds[0] - 1][1]:
            fingers.append(1)
        else:
            fingers.append(0)

        # 其余手指
        for id in range(1, 5):
            if self.lmList[self.tipIds[id]][2] < self.lmList[self.tipIds[id] - 2][2]:
                fingers.append(1)
            else:
                fingers.append(0)

        # totalFingers = fingers.count(1)
        return fingers

    def findDistance(self, p1, p2, img, draw=True, r=15, t=3):
        x1, y1 = self.lmList[p1][1:]
        x2, y2 = self.lmList[p2][1:]
        cx, cy = (x1 + x2) // 2, (y1 + y2) // 2

        if draw:
            cv2.line(img, (x1, y1), (x2, y2), (255, 0, 255), t)
            cv2.circle(img, (x1, y1), r, (255, 0, 255), cv2.FILLED)
            cv2.circle(img, (x2, y2), r, (255, 0, 255), cv2.FILLED)
            cv2.circle(img, (cx, cy), r, (0, 0, 255), cv2.FILLED)
            length = math.hypot(x2 - x1, y2 - y1)

        return length, img, [x1, y1, x2, y2, cx, cy]


def main():
    pTime = 0
    cTime = 0
    cap = cv2.VideoCapture(0)
    detector = handDetector()
    while True:
        success, img = cap.read()
        img = detector.findHands(img)        # 检测手势并画上骨架信息

        lmList = detector.findPosition(img)  # 获取得到坐标点的列表
        if len(lmList) != 0:
            print(lmList[4])

        cTime = time.time()
        fps = 1 / (cTime - pTime)
        pTime = cTime

        cv2.putText(img, 'fps:' + str(int(fps)), (10, 70), cv2.FONT_HERSHEY_PLAIN, 3, (255, 0, 255), 3)
        cv2.imshow('Image', img)
        cv2.waitKey(1)


if __name__ == "__main__":
    main()

源码网上有很多,有不懂可以联系博主,一起相互交流。

学习永无止境,AI是未来的发展方向,每天进步一点点,实现终身学习。

如有侵权,或需要完整代码,请及时联系博主。

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

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

相关文章

Linux/Ubuntu 的日常升级和安全更新,如何操作?

我安装的是Ubuntu 20.04.6 LTS的Windows上Linux子系统版本&#xff0c;启动完成后显示&#xff1a; Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.15.90.4-microsoft-standard-WSL2 x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.c…

ros小车实现slam_gmapping建图

ros小车2d建图&#xff0c;如果有雷达&#xff0c;那么使用gmapping方式建图&#xff0c;其实就一个命令&#xff0c;启动建图程序&#xff0c;它默认会启动小车&#xff0c;之后&#xff0c;我们通过手柄或者键盘控制小车就可以有地图产生&#xff0c;然后就需要保存地图&…

【高级IO】- 五种 IO 模型 | 多路转接 - select

IO的基本概念 I/O&#xff08;Input / output&#xff09;就是输入和输出&#xff0c;在冯诺依曼体系中&#xff0c;将数据从输入设备拷贝到内存叫做输入&#xff0c;将数据从内存拷贝到输出设备叫做输出。 对文件进行的读写操作本质就是一种IO&#xff0c;文件IO对应的外设就…

【2023最新爬虫】爬取知乎任意问题下的全部回答

老规矩&#xff0c;先上结果&#xff1a; 爬取了前200多页&#xff0c;每页5条数据&#xff0c;共1000多条回答。&#xff08;程序设置的自动判断结束页&#xff0c;我是手动break的&#xff09; 共爬到13个字段&#xff0c;包含&#xff1a; 问题id,页码,答主昵称,答主性别,…

【Python】json文件的读取

文章目录 1. json简介2.json的使用规范3.json文件的书写4.json文件的读取 1. json简介 JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;常用于将结构化数据进行传输和存储。它基于JavaScript语法&#xff0c;但可以被多种编程…

玩机搞机----面具模块的组成 制作模块

root面具相信很多玩家都不陌生。早期玩友大都使用第三方卡刷补丁来对系统进行各种修复和添加功能。目前面具补丁代替了这些操作。今天的帖子了解下面具各种模块的组成和几种普遍的代码组成。 Magisk中运行的每个单独的shell脚本都将在内部的BusyBox的shell中执行。对于与第三方…

(排序) 剑指 Offer 21. 调整数组顺序使奇数位于偶数前面 ——【Leetcode每日一题】

❓剑指 Offer 21. 调整数组顺序使奇数位于偶数前面 难度&#xff1a;简单 输入一个整数数组&#xff0c;实现一个函数来调整该数组中数字的顺序&#xff0c;使得所有奇数在数组的前半部分&#xff0c;所有偶数在数组的后半部分。 示例&#xff1a; 输入&#xff1a;nums [1…

绘制原型图的常用工具之墨刀

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于OA项目的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.墨刀是什么 二.墨刀的作用 三.墨刀界…

opencv-手势识别

# HandTrackingModule.py import cv2 import mediapipe as mpclass HandDetector:"""使用mediapipe库查找手。导出地标像素格式。添加了额外的功能。如查找方式&#xff0c;许多手指向上或两个手指之间的距离。而且提供找到的手的边界框信息。"""…

【MySQL】JSON 格式字段处理

MySQL 5.7 版本后已支持 JSON 格式&#xff0c;这虽是 MySQL 的一小步&#xff0c;但可以说是程序开发的一大步&#xff0c;再也不用将 JSON 内容塞到 VARCHAR 类型字段了&#xff0c;程序设计也会变得更加灵活。网上大多只针对JSONObject 对象类型&#xff0c;本文也将详解 JS…

Linux网络服务之iptables防火墙工具

I P T A B L E S 一、防火墙简介1.1 netfilter1.2 firewalld和iptables 二、iptables工具简述2.1 定义2.2 三种报文流向2.3 iptables的表、链结构&#xff08;非常重要&#xff09;2.3.1 "四表" ----- 规则表2.3.2 "五链" ----- 规则链 三、iptables配置3.…

适合低成本兼职的十个职业,做得好可能比上班挣得还多

这个年头干点什么兼职或者副业比较合适的&#xff0c;其实做兼职和副业就那么几条原则&#xff1a;最好是轻资产或者不投入资金&#xff0c;因为这个年代是现金流和储蓄为王&#xff0c;不能乱投资&#xff0c;一旦出了差错&#xff0c;更是雪上加霜。还有就是最好在网络上做兼…

对话音视频牛哥:开发RTSP|RTMP直播播放器难不难?难在哪?

我关注的播放器指标 好多开发者跟我交流音视频相关技术的时候&#xff0c;经常问我的问题是&#xff0c;多久可以开发个商业级别的RTMP或RTSP播放器&#xff1f;你们是怎样做到毫秒级延迟的&#xff1f;为什么一个播放器&#xff0c;会被你们做到那么复杂&#xff1f;带着这些…

一文详解4种聚类算法及可视化(Python)

在这篇文章中&#xff0c;基于20家公司的股票价格时间序列数据。根据股票价格之间的相关性&#xff0c;看一下对这些公司进行聚类的四种不同方式。 苹果&#xff08;AAPL&#xff09;&#xff0c;亚马逊&#xff08;AMZN&#xff09;&#xff0c;Facebook&#xff08;META&…

裴蜀定理-拓展欧几里得算法--夏令营

题目 知识点 1.裴蜀定理&#xff1a; 欧几里得算法gcd辗转相除法 拓展欧几里得算法exgcd裴蜀定理 2.证明&#xff1a; 3.. 代码&#xff1a; int exgcd(int a, int b, int& x, int& y) {if (!b){x 1, y 0;return a;}int d exgcd(b, a % b, y, x);y - a / b * x;…

rabbitMq安装后无法启动可视化页面http://localhost:15672处理

本次安装环境信息&#xff1a; 系统&#xff1a;win10 64位专业版 erlang&#xff1a;otp_win64_23.0 rabbitMQ&#xff1a;rabbitmq-server-3.8.5 安装rabbitMQ需要依赖erlang语言环境&#xff0c;所以需要我们下载erlang的环境安装程序。 一、下载安装程序 rabbitMQ安装…

Lombok 同时使用 @Data 和 @Builder 的巨坑,千万别乱用!

1、Lombok 使用演示 Lombok 使⽤同时使⽤ Data 和 Builder &#xff0c;构建无参构造器报错&#xff01;编译不通过。如下图&#xff1a; Lombok 使⽤ Data 可以自动⽣成⽆参构造和类⾥⾯所有属性的 getter/setter ⽅法。可以简化我们代码的开发。&#xff08;IDEA 需要安装 L…

Redis主从复制搭建

Redis主从复制搭建 Redis虽然拥有非常高的性能&#xff0c;但是在实际的生产环境中&#xff0c;使用单机模式还是会产生不少问题的&#xff0c;比如说容易出现 单机故障&#xff0c;容量瓶颈&#xff0c;以及QPS瓶颈等问题。通常环境下&#xff0c;主从复制、哨兵模式、Redis…

从关键新闻和最新技术看AI行业发展(2023.6.23-7.9第二期) |【WeThinkIn老实人报】

Rocky Ding 公众号&#xff1a;WeThinkIn 写在前面 【WeThinkIn老实人报】是WeThinkIn的全新栏目&#xff0c;旨在整理&挖掘AI行业的关键新闻和最新技术&#xff0c;同时Rocky会对这些关键信息进行解读&#xff0c;力求让读者们能从容跟随AI科技潮流。也欢迎大家提出宝贵的…

中国大学生服务外包创新创业大赛丨借 AI 之力,助“记账”难题

一、中国大学生服务外包创新创业大赛 赛事介绍 中国大学生服务外包创新创业大赛&#xff0c;是响应国家关于鼓励服务外包产业发展、加强服务外包人才培养的相关战略举措与号召&#xff0c;举办的每年一届的全国性竞赛。 大赛均由中华人民共和国教育部、中华人民共和国商务部…