《Cocos Creator游戏实战》AIGC之将草稿内容转为真实内容

这篇具有很好参考价值的文章主要介绍了《Cocos Creator游戏实战》AIGC之将草稿内容转为真实内容。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

前言

训练AI

从识别结果中提取必要数据

发送图片并生成最终代码

总结与提高

资源下载


前言

当创作灵感来的时候,我们可能会先把灵感记录在草稿上,之后再去实现它。比方说有一天,我突然来了游戏创作灵感,想着那可以先把一些简单的组件和布局设计出来,于是就在草稿上画了几个框。

《Cocos Creator游戏实战》AIGC之将草稿内容转为真实内容

注:L代表Label组件,B代表Button组件,S代表Sprite组件。

几天过去了,就算当时的灵感再好,我也不想打开电脑,所以草稿还是只是草稿。我想着,如果有一个AI能够识别我画的草稿,然后自动生成对应组件以及布局的话该有多好啊。

《Cocos Creator游戏实战》AIGC之将草稿内容转为真实内容

于是,我决定训练一个AI,准确来说是一个图像目标检测AI模型,我将用它来识别并定位我草稿上的各个方框。

训练AI

首先第一步,制作数据集,花了我半天时间画了很多大大小小的方框,草稿数量为150张。有在便利贴上画的,有在纸巾上画的,还有在白纸上画的。

《Cocos Creator游戏实战》AIGC之将草稿内容转为真实内容

用于训练的图片已经有了,接下来又花了半天时间去进行标注,不得不说想要训练AI,首先就要训练自己的毅力。

《Cocos Creator游戏实战》AIGC之将草稿内容转为真实内容

训练集已经做好,接下来就是丢给yolov5训练,训练结果如下。

《Cocos Creator游戏实战》AIGC之将草稿内容转为真实内容

验证之后,识别效果还是可以的,现在AI可以大概率将我画的SLB三个方框识别出来。 

注:由于时间有限,我就先实现三种组件:Sprite,Label以及Button,如果加入更多组件的话就需要更多数据。

《Cocos Creator游戏实战》AIGC之将草稿内容转为真实内容

从识别结果中提取必要数据

AI在识别之后可以生成一个txt文件,其中保存着各个矩形的数据,如下所示。

《Cocos Creator游戏实战》AIGC之将草稿内容转为真实内容

1 0.682994 0.452703 0.127743 0.0981199
2 0.683777 0.452115 0.123041 0.0992949
2 0.562696 0.65188 0.12069 0.103995
2 0.5721 0.343713 0.125392 0.0963572
0 0.290752 0.341657 0.111285 0.0887192
1 0.302116 0.543772 0.0979624 0.0851939
1 0.320533 0.73913 0.111285 0.0951821

第一列中的数字0,1,2分别代表Button方框,Sprite方框和Label方框;第二列是矩形中心的x坐标(归一化后的,下同);第二列是矩形中心的y坐标;第三列是矩形宽度;第四列是矩形高度。通过这些数据我们能够得出各个矩形方框在图片上的真实坐标以及大小。代码编写如下:

def get_rect_list_from_detect_result(pic_path, detect_result_path):
    """从预测结果中得出各个矩形的真实大小和位置数据"""
    with open(detect_result_path, "r", encoding="utf-8") as f:
        result = f.readlines()

    pic_width, pic_height = Image.open(pic_path).size
    class_dict = {"0": "B", "1": "S", "2": "L"}
    rect_list = []

    for line in result:
        _class, x_center_norm, y_center_norm, width_norm, height_norm = line.strip().split(" ")
        rect_width = round(float(width_norm)*pic_width, 2)
        rect_height = round(float(height_norm)*pic_height, 2)
        rect_x = round(float(x_center_norm)*pic_width, 2) - rect_width/2
        rect_y = round(float(y_center_norm)*pic_height, 2) - rect_height/2
        rect_list.append({
            "type": class_dict[_class],
            "width": rect_width,
            "height": rect_height,
            "x": rect_x,
            "y": rect_y
        })
    
    return rect_list

为了在Cocos场景的Canvas画布上生成组件,我们需要先确定画布大小和方向。初始大小我们可以用960和640这两个值,但是方向呢?是采用横向还是竖向?我这里采用的解决方案是:找出草稿上最左边和最右边的矩形,然后得出横向距离,接着找出最上边和最下边的矩形并得出纵向距离。比较横向距离和纵向距离,假如前者大,则画布为横向,反之则为竖向。代码编写如下:

def decide_canvas_size(rect_list):
    """通过各个矩形的最小和最大x/y值来确定画布尺寸"""
    
    # 获取所有矩形中的最小x值
    min_x = min(rect_list, key=lambda rect: rect["x"])["x"]
    max_x = max(rect_list, key=lambda rect: rect["x"])["x"]
    min_y = min(rect_list, key=lambda rect: rect["y"])["y"]
    max_y = max(rect_list, key=lambda rect: rect["y"])["y"]

    # 根据x和y的距离差判断是要横屏还是竖屏
    distance_x = max_x - min_x
    distance_y = max_y - min_y

    if distance_x >= distance_y:
        canvas_width = 960
        canvas_height = 640
    else:
        canvas_width = 640
        canvas_height = 960

    width_prop = distance_x / canvas_width if canvas_width > distance_x else canvas_width / distance_x
    height_prop = distance_y / canvas_height if canvas_height > distance_y else canvas_height / distance_y

    return canvas_width, canvas_height, width_prop, height_prop

AI在识别时,是以图片左上角为原点的,往右为x轴正方向,往下为y轴正方向。

《Cocos Creator游戏实战》AIGC之将草稿内容转为真实内容

但是Cocos Creator的坐标原点在画布中心,所以我们肯定要将得到的矩形坐标进行转换,否则生成的组件将会都排布在画布右上角。

《Cocos Creator游戏实战》AIGC之将草稿内容转为真实内容

另外在草稿上画方框时,我们可能是想着让几个矩形对齐,还有几个矩形的大小应该是一样的。但是在画的时候并不会太精准,所以我们还应该将位置和大小相近的矩形进行调整,让它们的x或y值或宽高相等。代码编写如下:

注:关于其他方面的调整,我就不再赘述了,读者可以看下注释。

def adjust_rect_data(rect_list, canvas_width, canvas_height, width_prop, height_prop):
    """调整各个矩形的值"""
    # 找到最小x和最小y值(也就是找到最左上角的矩形的x和y值)
    # 然后其他将其他矩形的x和y坐标减去最小x和最小y,求出相对距离
    # 所有相对距离包括宽高全部乘以宽高比例
    # 同时将坐标转换为Cocos类型,以画布中心为原点
    min_x = min(rect_list, key=lambda rect: rect["x"])["x"]
    min_y = min(rect_list, key=lambda rect: rect["y"])["y"]

    for rect in rect_list:
        rect["x"] = (rect["x"] - min_x) * width_prop - canvas_width/2
        rect["y"] = canvas_height/2 - (rect["y"] - min_y) * height_prop
        rect["width"] *= width_prop
        rect["height"] *= height_prop

    # 算出下边和右边的空白距离,将所有矩形往下和往右平移空白距离/2个像素点
    max_x = max(rect_list, key=lambda rect: rect["x"])["x"]
    min_y = min(rect_list, key=lambda rect: rect["y"])["y"]
    right_distance = (canvas_width/2 - max_x) / 2
    bottom_distance = abs(-canvas_height/2 - min_y) / 2

    for rect in rect_list:
        rect["x"] += right_distance
        rect["y"] -= bottom_distance

    # 将x或y坐标距离不相差15像素的矩形对齐
    diff = 15
    for rect1 in rect_list:
        for rect2 in rect_list:
            if rect1 == rect2:
                continue
                
            if abs(rect1["x"] - rect2["x"]) <= diff:
                average_x = (rect1["x"] + rect2["x"]) / 2
                rect1["x"] = average_x
                rect2["x"] = average_x
            
            if abs(rect1["y"] - rect2["y"]) <= diff:
                average_y = (rect1["y"] + rect2["y"]) / 2
                rect1["x"] = average_y
                rect2["x"] = average_y

            if abs(rect1["width"] - rect2["width"]) <= diff:
                average_width = (rect1["width"] + rect2["width"]) / 2
                rect1["width"] = average_width
                rect2["width"] = average_width
            
            if abs(rect1["height"] - rect2["height"]) <= diff:
                average_height= (rect1["height"] + rect2["height"]) / 2
                rect1["height"] = average_height
                rect2["height"] = average_height

    # 四舍五入保留整数
    for rect in rect_list:
        rect["x"] = round(rect["x"])
        rect["y"] = round(rect["y"])
        rect["width"] = round(rect["width"])
        rect["height"] = round(rect["height"])
    
    return rect_list

数据调整完毕后,我们就可以把画布数据和各个矩形数据一同返回。我这里用flask框架开发了一个后端,完整代码如下:

import os
import uuid
from PIL import Image
from pathlib import Path
from flask import Flask, request


app = Flask(__name__)
app.config["UPLOAD_FOLDER"] = str(Path(__file__).parent / "upload")
app.config["SECRET_KEY"] = "SECRET_KEY"


@app.route("/d2r", methods=["POST"])
def draft_to_reality():
    """将草稿转成真实布局所需要的数据格式"""

    # 从前端获取图片
    file = request.files.get("file")
    if not file.filename.endswith(".png") and not file.filename.endswith(".jpg") and not file.filename.endswith("jpeg"):
        return {
            "code": "1",
            "message": "图片格式错误"
        }
    
    # 保存图片
    pic_path = Path(app.config["UPLOAD_FOLDER"]) / f"{uuid.uuid4()}.jpg"
    file.save(pic_path)

    # 目标识别
    is_ok, detect_result_path = detect(pic_path)
    if not is_ok:
        return {
             "code": "2",
             "message": "图片识别失败"
        }
    
    # 制作数据
    rect_list = get_rect_list_from_detect_result(pic_path, detect_result_path)
    canvas_width, canvas_height, width_prop, height_prop = decide_canvas_size(rect_list)
    rect_list = adjust_rect_data(rect_list, canvas_width, canvas_height, width_prop, height_prop)
    final_data = make_final_data(rect_list, canvas_width, canvas_height)
    
    return {
        "code": "0",
        "message": final_data
    }


def detect(pic_path):
    os.system(f"python ./yolov5/detect.py --weights ./yolov5/best.pt --source {pic_path} --save-txt --exist-ok")
    
    # 如果识别成功,则会生成一个txt文件
    detect_result_path = f"./yolov5/runs/detect/exp/labels/{Path(pic_path).name.split('.')[0]}.txt"
    if Path(detect_result_path).exists():
        return True, detect_result_path
    else:
        return False, None
    

def get_rect_list_from_detect_result(pic_path, detect_result_path):
    """从预测结果中得出各个矩形的真实大小和位置数据"""
    with open(detect_result_path, "r", encoding="utf-8") as f:
        result = f.readlines()

    pic_width, pic_height = Image.open(pic_path).size
    class_dict = {"0": "B", "1": "S", "2": "L"}
    rect_list = []

    for line in result:
        _class, x_center_norm, y_center_norm, width_norm, height_norm = line.strip().split(" ")
        rect_width = round(float(width_norm)*pic_width, 2)
        rect_height = round(float(height_norm)*pic_height, 2)
        rect_x = round(float(x_center_norm)*pic_width, 2) - rect_width/2
        rect_y = round(float(y_center_norm)*pic_height, 2) - rect_height/2
        rect_list.append({
            "type": class_dict[_class],
            "width": rect_width,
            "height": rect_height,
            "x": rect_x,
            "y": rect_y
        })
    
    return rect_list


def decide_canvas_size(rect_list):
    """通过各个矩形的最小和最大x/y值来确定画布尺寸"""
    
    # 获取所有矩形中的最小x值
    min_x = min(rect_list, key=lambda rect: rect["x"])["x"]
    max_x = max(rect_list, key=lambda rect: rect["x"])["x"]
    min_y = min(rect_list, key=lambda rect: rect["y"])["y"]
    max_y = max(rect_list, key=lambda rect: rect["y"])["y"]

    # 根据x和y的距离差判断是要横屏还是竖屏
    distance_x = max_x - min_x
    distance_y = max_y - min_y

    if distance_x >= distance_y:
        canvas_width = 960
        canvas_height = 640
    else:
        canvas_width = 640
        canvas_height = 960

    width_prop = distance_x / canvas_width if canvas_width > distance_x else canvas_width / distance_x
    height_prop = distance_y / canvas_height if canvas_height > distance_y else canvas_height / distance_y

    return canvas_width, canvas_height, width_prop, height_prop


def adjust_rect_data(rect_list, canvas_width, canvas_height, width_prop, height_prop):
    """调整各个矩形的值"""
    # 找到最小x和最小y值(也就是找到最左上角的矩形的x和y值)
    # 然后其他将其他矩形的x和y坐标减去最小x和最小y,求出相对距离
    # 所有相对距离包括宽高全部乘以宽高比例
    # 同时将坐标转换为Cocos类型,以画布中心为原点
    min_x = min(rect_list, key=lambda rect: rect["x"])["x"]
    min_y = min(rect_list, key=lambda rect: rect["y"])["y"]

    for rect in rect_list:
        rect["x"] = (rect["x"] - min_x) * width_prop - canvas_width/2
        rect["y"] = canvas_height/2 - (rect["y"] - min_y) * height_prop
        rect["width"] *= width_prop
        rect["height"] *= height_prop

    # 算出下边和右边的空白距离,将所有矩形往下和往右平移空白距离/2个像素点
    max_x = max(rect_list, key=lambda rect: rect["x"])["x"]
    min_y = min(rect_list, key=lambda rect: rect["y"])["y"]
    right_distance = (canvas_width/2 - max_x) / 2
    bottom_distance = abs(-canvas_height/2 - min_y) / 2

    for rect in rect_list:
        rect["x"] += right_distance
        rect["y"] -= bottom_distance

    # 将x或y坐标距离不相差15像素的矩形对齐
    diff = 15
    for rect1 in rect_list:
        for rect2 in rect_list:
            if rect1 == rect2:
                continue
                
            if abs(rect1["x"] - rect2["x"]) <= diff:
                average_x = (rect1["x"] + rect2["x"]) / 2
                rect1["x"] = average_x
                rect2["x"] = average_x
            
            if abs(rect1["y"] - rect2["y"]) <= diff:
                average_y = (rect1["y"] + rect2["y"]) / 2
                rect1["x"] = average_y
                rect2["x"] = average_y

            if abs(rect1["width"] - rect2["width"]) <= diff:
                average_width = (rect1["width"] + rect2["width"]) / 2
                rect1["width"] = average_width
                rect2["width"] = average_width
            
            if abs(rect1["height"] - rect2["height"]) <= diff:
                average_height= (rect1["height"] + rect2["height"]) / 2
                rect1["height"] = average_height
                rect2["height"] = average_height

    # 四舍五入保留整数
    for rect in rect_list:
        rect["x"] = round(rect["x"])
        rect["y"] = round(rect["y"])
        rect["width"] = round(rect["width"])
        rect["height"] = round(rect["height"])
    
    return rect_list


def make_final_data(rect_list, canvas_width, canvas_height):
    return {
        "canvas": {
            "width": canvas_width,
            "height": canvas_height
        },
        "rects": rect_list
    }



if __name__ == "__main__":
    app.run()

发送图片并生成最终代码

后端代码已经开发完毕,前端功能的话我们就用Cocos插件来实现,插件界面如下。

《Cocos Creator游戏实战》AIGC之将草稿内容转为真实内容

选择一张草稿图片,然后点击生成。

《Cocos Creator游戏实战》AIGC之将草稿内容转为真实内容

此时后端就会识别上传的图片,然后返回画布和矩形数据。

《Cocos Creator游戏实战》AIGC之将草稿内容转为真实内容

{ 
  canvas: { height: 960, width: 640 }, 
  rects: [ 
    { height: 93, type: 'S', width: 122, x: 215, y: 128 }, 
    { height: 208, type: 'B', width: 241, x: 193, y: -165 }, 
    { height: 119, type: 'S', width: 148, x: -171, y: -56 }, 
    { height: 119, type: 'L', width: 148, x: -215, y: 165 } 
  ] 
} 

最后插件会根据该数据在assets中生成一个d2r.ts文件,我们将该ts文件挂载到画布上然后运行就可以看到效果了。

《Cocos Creator游戏实战》AIGC之将草稿内容转为真实内容

注:resources文件夹是插件在开启时自动生成的,其中包含着用于Sprite和Button组件的初始图片。

运行效果如下:

《Cocos Creator游戏实战》AIGC之将草稿内容转为真实内容

《Cocos Creator游戏实战》AIGC之将草稿内容转为真实内容

总结与提高

我们通过AI将草稿内容识别了出来,然后提取并调整了必要数据,最后得到了一个可以生成真实组件和布局的代码。

有待提高的点:

1. 用于AI的训练数据量可以再大一些,这样可以提高识别精度,也可以生成更多种类的组件。

2. 个别草稿识别出来的结果不是很满意,有些组件在草稿上是分开的,但生成后却是重合的,还有方框的大小比例还需要更精确。所以在对提取的数据做调整时,调整方面的算法还有待改进。

3. 目前AI的作用就在识别,并不能很好的体现AIGC的魅力。可以加入自然语言处理(NLP)技术,获取用户意向,然后再用爬虫爬取相应的图片资源,生成一个更好看更完善的内容。

资源下载

后端代码下载地址,需要安装的库已经写在yolov5/requirements.txt文件中。因为包含AI模型以及训练图片,所以文件会比较大:

链接:https://pan.baidu.com/s/1Z-q2mc2jsX5h_fWD_QjaOA 
提取码:cr9t

前端插件下载地址,Cocos Creator版本要>=3.6.0:

链接:https://pan.baidu.com/s/141gpeSjGunKMf9SlqY0H7Q 
提取码:9e6t文章来源地址https://www.toymoban.com/news/detail-484587.html

到了这里,关于《Cocos Creator游戏实战》AIGC之将草稿内容转为真实内容的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 最新开源方案!Cocos Creator 写一个ECS框架+行为树,实现格斗游戏 AI

    引言: 实现游戏 AI 的方式有很多,目前最为常用的主要有有限状态机和行为树。和有限状态机相比,行为树有更好的可扩展性和灵活性,能实现更复杂的 AI 需求。开发者  honmono 在 Cocos Creator 中用一个  ECS + BehaviorTree 框架 实现了一个格斗 AI Demo,一起来看看他的方案。 De

    2024年02月12日
    浏览(50)
  • 用23种设计模式打造一个cocos creator的游戏框架----(十四)观察者模式

    模式名称:观察者模式 模式分类:行为型 模式意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 结构图: 适用于: 1、当一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两者封装在

    2024年02月04日
    浏览(50)
  • 【Cocos Creator 项目实战 】消灭星星加强版(附带完整源码工程)

    本文乃Siliphen原创,转载请注明出处 目录 游戏介绍 概述 游戏整体流程 游戏框架设计 单一职责的类 主要流程控制类 核心玩法模块 UI: 游戏世界: 本文项目的代码组织结构 作者项目实践总结 场景只有一个入口脚本 尽量少在节点上挂载脚本 构建游戏世界 ECS 设计 消除物 棋

    2024年02月13日
    浏览(99)
  • Cocos Creator小游戏-文字斗争(H5、小程序)益智类 项目展示+完整项目源码

    文字斗争(H5、小程序)益智类 项目展示+完整项目源码 玩家有着自己的战场,可以作为进攻方去挑战其他战场,也可以作为防守方抵御其他玩家的进攻。 玩家可以挑战游戏里设置的各个关卡,提高自己的指挥能力和布局能力,最终可以战胜其他玩家的同时能够不被其他玩家

    2024年02月08日
    浏览(72)
  • Cocos Creator小游戏-2048(PC、安卓、H5)益智类 项目展示+完整项目源码

    Cocos Creator小游戏-2048 在棋盘上,每次会增加一个 小 动物,你可以选择四个方向 滑动 ,然后 小 动物会按方向移动,遇到相同的 小 动物就会 合并,看谁合并的最多。 1 .初始化格子小动物的位置。 2.手势滑屏移动屏幕中的小动物。 3.自动寻找棋盘中没有小动物的格子,自动

    2024年02月12日
    浏览(60)
  • cocos creator上架字节跳动(抖音)小游戏注意事项(匿名登录、录屏、分享等踩坑记录)

    常见拒绝原因1:小游戏无录屏功能,不符合平台要求 2:小游戏录屏时间小于3S,分享按钮点击无反应或提示错误文案,不符合平台要求 3:小游戏录屏时间大于300S,分享按钮点击无反应或无法正常分享录屏,不符合平台要求 不久前写了款小游戏,最近上架了字节跳动小游戏平

    2024年01月16日
    浏览(50)
  • Cocos Creator3.8 项目实战(八)2D UI DrawCall优化详解(上)

    游戏开发的朋友都知道,在游戏开发过程中,DrawCall 是我们优化性能的一个非常重要的指标,直接影响游戏的整体性能表现,DrawCall数量越多,帧率会降低,能明显感觉到卡顿。 那今天我们就来聊一聊,2D UI DrawCall优化方法。 本文的主要内容: 什么是Draw call ? Draw Call 中造成

    2024年02月08日
    浏览(42)
  • cocos creator对接字节跳动(抖音)小游戏激励视频广告注意事项(审核不通过,次数不一致和重复获得奖励等)

    首先是官方文档里的对接方式:(https://developer.open-douyin.com/docs/resource/zh-CN/mini-app/develop/api/open-interface/ads/rewarded-video/tt-createRewardedVideoAd) 在cocos creator开发的小游戏中,把onLoad换成start就差不多了,场景初始化的时候把视频对象初始化好,事件绑定好,如果是单场景的游戏确

    2024年02月16日
    浏览(52)
  • AIGC 加持 Cocos,游戏开发需要几步?

    近日,游戏行业知名的 B2B 大会 WN 2023 大会于土耳其首都伊斯坦布尔顺利举办。本次大会邀请了来自全球的游戏开发商、媒体、发行商、分发平台等行业决策者,共同探讨游戏行业未来发展态势,进一步拓展业务,并在世界范围内寻找新的合作伙伴,Cocos 受邀出席本次大会。

    2024年02月09日
    浏览(75)
  • Cocos Creator问题汇总

    [Window] Cannot read property ‘cameraPriority’ of null node.on(Node.EventType.TOUCH_END, this.onBlockClicked, this); 解决 :监听的时候,node节点上必须有UITransform组件 Camera priority error - Cocos Creator - Cocos Forums 新建的prefab在运行的时候ui不显示,只能看到按钮上的label文本内容。 解决 :检查是否有C

    2024年02月13日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包