云天 发表于 2023-12-24 20:48:04

用树莓派AI人像变换给自己一次“跨越年龄的体验”

本帖最后由 云天 于 2023-12-24 21:06 编辑

【项目背景】
      互联网时代,日新月异的技术更迭让大众的娱乐方式变得更加多元化。越来越多线上娱乐体验成为新潮流,出现了AI人像特效、VR游景点、可交互影视剧、元宇宙等。
      想要通过照片看到以前的自己或者未来几十年后的自己,放在之前肯定是没有办法实现,但是现在随着科技进步,AI技术已经融入到生活中的方方面面甚至是角角落落,不管在哪一个领域都能够看到它的存在,图片修复软件也会在AI技术之下变得更加完善。通过各种不同的特效,能够将我们照片更换出不一样的风格,也能够一键将人带到60年之后,看一看未来的自己究竟长得什么样。
【项目设计】

      今天,我就用树莓派结合腾讯云AI人脸变换,把你带到未来,也能够把你带到以前。这主要是通过AI技术改变照片上人物的容貌而去推算出未来的自己将会变得怎么样。许多人在试用我这个项目特效之前,最初的意思是想看一看变老之后会是否依然美丽帅气,但是在体验的过程当中画风逐渐跑偏,很多人在看到自己变老后的样子被逗笑了,也有很多人看到之后被感动的哭的,有的朋友表示看到自己变老的照片,想到了自己已故的亲人。
      通过智能识别照片中人的五官,然后一键能够改变照片中人物的年龄,甚至是6~85岁都能够看得到。下面请大家跟随我通过项目制作过程,踏上穿越的时光之旅,感受自己幼年到老年的变化。

【演示视频】
      先上视频,看一下自测试效果。

https://www.bilibili.com/video/BV1Lu4y1T7ii/?share_source=copy_web【硬件设备】
      树莓派,显示屏,usb摄像头,电源(手机充电器),乐高积木件。


【硬件搭建】
      1.组合树莓派和显示屏


      2.乐高积木搭建框架

      3.安装摄像头

【供电开机】
      下载最新的Raspberry Pi OS,安装在SD卡上,插入树莓派,通电开机。

【安装Mind+】
      在树莓派上安装“Mind+客户端下载for Linux”,Mind+官方下载- Mind+图形化编程软件 (mindplus.cc)。
      Mind+的V1.7.3版本支持arm64架构的CPU如树莓派,且安装了Linux相关系统,例如ubuntu、debian。
【安装库】
      Mind+的V1.7.3版本Linux版,Python模式,已安装好opencv-python库(自已在树莓派中安装这个库,很麻烦)。通过库管理,手动安装“tencentcloud-sdk-python”。



【编写程序】
      1.利用opencv库获取摄像头图像

#导入所需的模块:
import cv2
#创建视频对象并打开摄像头:
cap = cv2.VideoCapture(0) # 参数为0表示默认摄像头设备
#读取每一帧图像并显示:
while True:
    ret, frame = cap.read() # 从摄像头读取当前帧图像
    if not ret:
      break # 若无法成功读取图像,则退出循环
    cv2.imshow('Camera', frame) # 显示当前帧图像
    if cv2.waitKey(1) == ord('q'): # 等待用户按下'q'键退出程序
      break
#关闭视频对象和窗口:
cap.release()
cv2.destroyAllWindows()
      2.使用Haar级联分类器来检测人脸

import cv2
import numpy as np

# 创建面部分类器对象。使用Haar级联分类器来检测人脸。
cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
cap = cv2.VideoCapture(0)
while True:
    ret, image = cap.read()
    # 转换为灰度图像
   
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)



    # 检测人脸。使用detectMultiScale()函数来找到图像中的人脸区域。这会返回包含每个人脸位置信息的列表:
    faces = cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))

    # 标记人脸。使用rectangle()函数在原始图像上绘制边界框来标记检测到的人脸
    for (x, y, w, h) in faces:
      cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 3)

    # 显示结果。最后,使用imshow()函数显示带有标记人脸的图像
    cv2.imshow("Face Detection", image)
    cv2.waitKey(1)
cv2.destroyAllWindows()


      3.实现中文提醒,及设置基准框
import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageFont
# 加载Haar级联分类器模型(预训练好的)
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
# 从文件或者视频流中获取图像数据
cap = cv2.VideoCapture(0)
sum1=0
sum2=0
bs=0
while True:
    ret, img = cap.read()
    height, width, _ = img.shape
    print("图像的高度为:", height)
    print("图像的宽度为:", width)
    if ret:

       gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
       # 对图像进行人脸检测
       faces = face_cascade.detectMultiScale(gray, scaleFactor=1.3, minNeighbors=5, flags=cv2.CASCADE_SCALE_IMAGE)
       # 标记并显示检测到的人脸区域
       if len(faces)!=0:
         sum2=0
         if bs==0:
             sum1=sum1+1
             if sum1>100:
                bs=1
       else:
         sum1=0
         if bs==1:
             sum2=sum2+1
             if sum2>100:
               bs=0
       x1=260
       y1=170
       w1=200
       h1=200      
       cv2.rectangle(img, (x1, y1), (x1+w1, y1+h1), (0, 255, 0), 3)
       for (x, y, w, h) in faces:
          cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 3)
          # 展示结果图片
       if abs(x-x1)<20 and abs(y-y1)<20 and abs(w-w1)<20 and abs(h-h1)<20:
         print("ok")
         cv2img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
         pilimg = Image.fromarray(cv2img)
         # PIL图片上打印汉字
         draw = ImageDraw.Draw(pilimg) # 图片上打印
         #simsun 宋体
         font = ImageFont.truetype("SIMHEI.ttf", 40, encoding="utf-8")
         #位置,文字,颜色==红色,字体引入
         draw.text((40, 430), "人脸年龄渐变正在生成中……", (255, 0, 0), font=font)
         # PIL图片转cv2 图片
         img = cv2.cvtColor(np.array(pilimg), cv2.COLOR_RGB2BGR)
       cv2.imshow("Result", img)
       cv2.waitKey(1)
cv2.destroyAllWindows()

【开通人像变换服务】
      1.注册腾讯云, 获取API调用秘钥,在访问管理里可以获取到当前账号的SecretId和SecretKey,以便于后面调用云服务的前面验证。这个一定要保管好,泄露出去有被人盗刷的风险。已废弃或者有暴露风险的Secret也可以禁用,最大程度降低风险。

      2.正式使用人像变换服务好像要开通下现有服务,和腾讯云其他产品比较像。点击下开通即可。

      3.使用 API Explorer,可以在上面自动生成代码,同时也配备有签名调试工具。
      4.用本地图片测试

import json
import base64
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.ft.v20200304 import ft_client, models

# 读一个本地测试文件转换为base64编码
f = open('./test2.jpg', 'rb')
base64_data = base64.b64encode(f.read())
SecretId="*********************"
SecretKey="*********************"
try:
    # 实例化一个认证对象,入参需要传入腾讯云账户secretId,secretKey,此处还需注意密钥对的保密
    # 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取
    cred = credential.Credential(SecretId, SecretKey)      # 传入自己的秘钥
    # 实例化一个http选项,可选的,没有特殊需求可以跳过
    httpProfile = HttpProfile()
    httpProfile.endpoint = "ft.tencentcloudapi.com"

    # 实例化一个client选项,可选的,没有特殊需求可以跳过
    clientProfile = ClientProfile()
    clientProfile.httpProfile = httpProfile
    # 实例化要请求产品的client对象,clientProfile是可选的
    client = ft_client.FtClient(cred, "ap-guangzhou", clientProfile)

    # 实例化一个请求对象,每个接口都会对应一个request对象
    req = models.ChangeAgePicRequest()
    params = {
      "Image": base64_data.decode("utf-8"),   # python里的bytes类型要转成string才可使用
      "AgeInfos": [
            {
                "Age":80      # 可以测试不同的年龄看效果
            }
      ],
      "RspImgType": "url"
    }
    req.from_json_string(json.dumps(params))

    # 返回的resp是一个ChangeAgePicResponse的实例,与请求对象对应
    resp = client.ChangeAgePic(req)
    # 输出json格式的字符串回包
    print(resp.to_json_string())

except TencentCloudSDKException as err:
    print(err)

      5.组合变年龄与渐变
      进一步了解了一下,人像变换产品下还有很多其他有意思的能力,我在想这些能力如果可以组合一下,应该会很有意思。比如人脸年龄变换+人像渐变,应该可以做成年龄渐变的效果。

import json
import sys
import time
import base64
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.ft.v20200304 import ft_client, models

# 读一个本地测试文件转换为base64编码
def read_file(filename):
    f = open(filename, 'rb')
    base64_data = base64.b64encode(f.read())
    return base64_data

# 变年龄
def change_age(client, img, age):
    req = models.ChangeAgePicRequest()
    params = {
      "Image": img.decode("utf-8"),   # python里的bytes类型要转成string才可使用
      "AgeInfos": [
            {
                "Age": int(age)
            }
      ],
      "RspImgType": "base64"
    }
    req.from_json_string(json.dumps(params))
    resp = client.ChangeAgePic(req)
    return resp

# 人像渐变
def morph_face(client, imgs):
    req = models.MorphFaceRequest()
    params = {
      "Images": imgs,
      # 更多细节可通过参数调节
      # "GradientInfos": [
      #   {
      #         "Tempo": 1,
      #         "MorphTime": 1
      #   }
      # ],
      "Fps": 25
    }
    req.from_json_string(json.dumps(params))
    resp = client.MorphFace(req)
    print(resp.to_json_string())
    return resp

# 查询人像渐变结果
def query_morph_face(client, job_id):
    req = models.QueryFaceMorphJobRequest()
    params = {
      "JobId": job_id
    }
    req.from_json_string(json.dumps(params))
    resp = client.QueryFaceMorphJob(req)
    print(resp.to_json_string())
    return resp


try:
    # 实例化一个认证对象,入参需要传入腾讯云账户secretId,secretKey,此处还需注意密钥对的保密
    # 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取
    cred = credential.Credential("YourSecretId", "YourSecretKey")
    # 实例化一个http选项,可选的,没有特殊需求可以跳过
    httpProfile = HttpProfile()
    httpProfile.endpoint = "ft.tencentcloudapi.com"

    # 实例化一个client选项,可选的,没有特殊需求可以跳过
    clientProfile = ClientProfile()
    clientProfile.httpProfile = httpProfile
    # 实例化要请求产品的client对象,clientProfile是可选的
    client = ft_client.FtClient(cred, "ap-guangzhou", clientProfile)

    # 读取图片
    data = read_file(sys.argv)

    ages =

    # 批量变年龄
    imgs = []
    for age in ages:
      resp=change_age(client, data, age)
      imgs.append(resp.ResultImage)

      # 将图片集合起来调人像渐变
    resp = morph_face(client, imgs)
    job_id = resp.JobId

    # 轮询查结果
    resp=query_morph_face(client, job_id)
    while resp.JobStatusCode != 7:
      resp=query_morph_face(client, job_id)
      time.sleep(2)
   

except TencentCloudSDKException as err:
    print(err)
【生成渐变视频二维码】

import cv2
importqrcode
from PIL import Image, ImageDraw, ImageFont
# 打开视频文件
url='http://bda-video-bodyseg-1254418846.cos.ap-guangzhou.myqcloud.com/video_morph_prod/1/1259541656/20231223235411_ff84a3ff-8046-4e75-9f26-ca751e9287e6_result.mp4'
imgqrc = qrcode.make(url,version=1,border=4,box_size=1)
imgqrc.save('output_image.jpg')
imgqrc = cv2.imread("output_image.jpg")
imgqrc = cv2.resize(imgqrc,(200,200))
cv2.namedWindow("Resultqrc", cv2.WINDOW_NORMAL)
cv2.resizeWindow("Resultqrc", 220, 220)
cv2.moveWindow("Resultqrc", 800, 500)
cv2.imshow("Resultqrc", imgqrc)
cv2.waitKey(10000)
cv2.destroyAllWindows()
【完整代码】

import json,cv2
import numpy as np
import base64
import time
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.ft.v20200304 import ft_client, models
importqrcode
from PIL import Image, ImageDraw, ImageFont
# cv2转base64
def cv2_to_base64(img):
    img = cv2.imencode('.jpg', img)
    image_code = str(base64.b64encode(img))

    return image_code
# 变年龄
def change_age(client, img, age):
    # 实例化一个请求对象,每个接口都会对应一个request对象
    req = models.ChangeAgePicRequest()
    params = {
      "Image": img,   # python里的bytes类型要转成string才可使用
      "AgeInfos": [
            {
                "Age": int(age)
            }
      ],
      "RspImgType": "base64"
    }
    req.from_json_string(json.dumps(params))
   
    # 返回的resp是一个ChangeAgePicResponse的实例,与请求对象对应
    resp = client.ChangeAgePic(req)
    # 输出json格式的字符串回包
    image_base64 = resp.ResultImage
    image_data = base64.b64decode(image_base64)
    np_array=np.frombuffer(image_data,np.uint8)
    image=cv2.imdecode(np_array,cv2.IMREAD_COLOR)
    cv2.imshow("Result", image)
    cv2.waitKey(1)
    return resp
# 人像渐变
def morph_face(client, imgs):
    req = models.MorphFaceRequest()
    params = {
      "Images": imgs,
      # 更多细节可通过参数调节
      # "GradientInfos": [
      #   {
      #         "Tempo": 1,
      #         "MorphTime": 1
      #   }
      # ],
      "Fps": 25
    }
    req.from_json_string(json.dumps(params))
    resp = client.MorphFace(req)

    #print(resp.to_json_string())
    return resp
# 查询人像渐变结果
def query_morph_face(client, job_id):
    req = models.QueryFaceMorphJobRequest()
    params = {
      "JobId": job_id
    }
    req.from_json_string(json.dumps(params))
    resp = client.QueryFaceMorphJob(req)
    #print(resp.to_json_string())
    return resp
# 加载Haar级联分类器模型(预训练好的)
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

# 从文件或者视频流中获取图像数据
cap = cv2.VideoCapture(0)
sum1=0
sum2=0
bs=0
#ages =
ages =
SecretId="#################"
SecretKey="####################"
# 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密
# 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议采用更安全的方式来使用密钥,请参见:https://cloud.tencent.com/document/product/1278/85305
# 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
cred = credential.Credential(SecretId, SecretKey)
# 实例化一个http选项,可选的,没有特殊需求可以跳过
httpProfile = HttpProfile()
httpProfile.endpoint = "ft.tencentcloudapi.com"

# 实例化一个client选项,可选的,没有特殊需求可以跳过
clientProfile = ClientProfile()
clientProfile.httpProfile = httpProfile
# 实例化要请求产品的client对象,clientProfile是可选的
client = ft_client.FtClient(cred, "ap-beijing", clientProfile)
x3=220
y3=140
w3=200
h3=200      

while True:
    ret, img = cap.read()
    if ret:
      
       gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
       # 对图像进行人脸检测
       faces = face_cascade.detectMultiScale(gray, scaleFactor=1.3, minNeighbors=5, flags=cv2.CASCADE_SCALE_IMAGE)
       # 标记并显示检测到的人脸区域
       if len(faces)!=0:
         
         sum2=0
         if bs==0:
            for (x, y, w, h) in faces:
             if abs(x-x3)<20 and abs(y-y3)<20 and abs(w-w3)<20 and abs(h-h3)<20:#当识别到的人脸区域与基准区域接近时,启动人脸年龄变换
            sum1=sum1+1
            if sum1>10:
                bs=1
                data=cv2_to_base64(img)
                imgs = []
                for age in ages:
                  resp=change_age(client, data, age)
                  imgs.append(resp.ResultImage)
                  time.sleep(30)
                  print(age)
                # 将图片集合起来调人像渐变
                cv2img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
                pilimg = Image.fromarray(cv2img)
                # PIL图片上打印汉字
                draw = ImageDraw.Draw(pilimg) # 图片上打印
                #simsun 宋体
                font = ImageFont.truetype("SIMHEI.TTF", 40, encoding="utf-8")
                #位置,文字,颜色==红色,字体引入
                draw.text((5, 430), "人脸年龄渐变视频正在生成中……", (255, 0, 0), font=font)
                # PIL图片转cv2 图片
                img = cv2.cvtColor(np.array(pilimg), cv2.COLOR_RGB2BGR)
                cv2.imshow("Result", img)
                cv2.waitKey(1)
                resp = morph_face(client, imgs)
                job_id = resp.JobId

                # 轮询查结果
                resp=query_morph_face(client, job_id)
                while resp.JobStatusCode != 7:
                   resp=query_morph_face(client, job_id)
                  
                   time.sleep(2)
                #生成渐变视频二维码
                url=resp.FaceMorphOutput.MorphUrl
                imgqrc = qrcode.make(url,version=1,border=4,box_size=1)
                imgqrc.save('output_image.jpg')
                imgqrc = cv2.imread("output_image.jpg")
                imgqrc = cv2.resize(imgqrc,(200,200))
                cv2.namedWindow("Resultqrc", cv2.WINDOW_NORMAL)
                cv2.resizeWindow("Resultqrc", 220, 220)
                cv2.moveWindow("Resultqrc", 800, 500)
                cv2.imshow("Resultqrc", imgqrc)
                cv2.waitKey(1)
                cap1 = cv2.VideoCapture(url)
                print(resp.FaceMorphOutput.MorphUrl)
                print(cap1.get(cv2.CAP_PROP_FRAME_WIDTH))
                print(cap1.get(cv2.CAP_PROP_FRAME_HEIGHT))
                for i in range(8):
                  cap1.set(cv2.CAP_PROP_POS_FRAMES,0)
                  ret, img1 = cap1.read()
                  while ret:
                  # 设置区域位置
                  x1, y1 = 0, 380    # 左上角点的 x、y 坐标
                  x2, y2 = 720, 910   # 右下角点的 x、y 坐标
                  # 提取指定区域的子图像
                  img1 = img1
                  cv2.imshow("Result", img1)
                  cv2.waitKey(1)
                  ret, img1 = cap1.read()
                cv2.destroyAllWindows("Resultqrc")
         for (x, y, w, h) in faces:
                cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 3)

       else:
         sum1=0
         if bs==1:
             sum2=sum2+1
             if sum2>100:
               bs=0
       print(sum1,sum2)

       # 展示结果图片
       cv2.rectangle(img, (x3, y3), (x3+w3, y3+h3), (255, 0, 255), 4)
       cv2.imshow("Result", img)
       cv2.waitKey(1)
cv2.destroyAllWindows()











页: [1]
查看完整版本: 用树莓派AI人像变换给自己一次“跨越年龄的体验”