万物皆可分割——用OpenVINO™加速SAM (Segment Anything Model)

ChatGPT的火爆让大家看到了通用AI大模型的威力,也带动了近期一批自然语言处理(NLP)领域大模型的不断被推出。你方唱罢我登场,最近,计算机视觉领域也迎来了自己的物体分割大模型,由Meta开源的 “万物可分割 (Segment Anything, SAM)”物体分割模型。

物体分割是计算机视觉中的核心任务之一,旨在识别图像中属于特定对象的像素。通常实现图像分割的方法有两种,即交互式分割和自动分割。交互式分割可以对任何类别的对象进行分割,但需要人工引导,并通过反复精细化掩码来完成。而自动分割可以对预定义的特定对象类别进行分割,但需要大量手动标注的对象进行训练,同时需要大量的计算资源和具有技术专业知识的人员来训练分割模型。然而,这两种方法都没有提供一种通用的、完全自动的分割方法。

SAM是这两种方法的泛化,它是一个单一的模型,可以轻松地执行交互式分割和自动分割。SAM可以从输入提示(例如点或框)生成高质量的对象掩码,并且可以用于生成图像中所有对象的掩码。它已经在一个包含1.1亿个掩码的1100万个图像数据集上进行了训练,并且在各种分割任务上具有较强的零样本性能。它创建了一个通用的物体分割模型,可以在从分析科学图像到编辑照片各种应用程序中使用。

这个强大的通用分割模型,我们的OpenVINO™当然也是可以对它进行优化以及推理的加速,使其可以方便快速地在英特尔®的CPU上部署运行起来。为了方便各位开发者的使用,我们同样提供了Jupyter Notebook形式的源代码,大家只需要跟随我们代码里的步骤,就可以在自己的机器上运行SAM,对图像进行任意分割了。

SAM模型由三个部分组成。

  • 图像编码器(Image Encoder):这是一个Vision Transformer模型(VIT),使用Masked Auto Encoders方法(MAE)对图像进行编码,将图像转换为嵌入空间。图像编码器对每个图像运行一次,可以在向模型输入提示之前应用它。

  • 提示编码器(Prompt Encoder ):这是一个用于分割条件的编码器。可以使用以下条件进行分割提示:
    • 点(points)- 与应分割的对象相关的一组点。Prompt编码器使用位置编码将点转换为嵌入值。
    • 框(boxes)- 应分割的对象所在的边界框。类似于points,边界框的坐标通过位置编码来进行编码。
    • 分割掩码-由用户提供的分割掩码使用卷积进行嵌入,并与图像嵌入进行element-wise求和。
    • 文本(text)- 由CLIP模型编码的文本表示。
  • 掩码解码器(Mask Decoder) : 掩码解码器有效地将图像嵌入、提示嵌入和输出标记映射到掩码。

下图描述了SAM生成掩码的流程图。

接下来,我们一起来看看运行利用OpenVINO™来优化加速SAM的推理有哪些重点步骤吧。

注意:以下步骤中的所有代码来自OpenVINO Notebooks开源仓库中的237-segment-anything notebook 代码示例,您可以点击以下链接直达源代码。openvino_notebooks/notebooks/237-segment-anything at main · openvinotoolkit/openvino_notebooks · GitHub  

第一步: 安装相应工具包、加载模型并转换为OpenVINO IR格式

本次代码示例需要首先安装SAM相应工具包。

1.	!pip install -q "segment_anything" "gradio>=3.25"

 然后下载及加载相应的PyTorch模型。

有几个SAM  checkpoint可供下载。在本次代码示例中,我们将使用基于vit_b的模型,但模型加载的方法是通用的,也适用于其他SAM模型。将下面的模型URL、保存checkpoint的路径和模型类型设置为对应的SAM模型checkpoint,然后使用SAM_model_registry加载模型。

1.	import sys
2.	
3.	sys.path.append("../utils")
4.	from notebook_utils import download_file
5.	
6.	checkpoint = "sam_vit_b_01ec64.pth"
7.	model_url = "https://dl.fbaipublicfiles.com/segment_anything/sam_vit_b_01ec64.pth"
8.	model_type = "vit_b"
9.	
10.	download_file(model_url)

加载模型

1.	from segment_anything import sam_model_registry
2.	
3.	sam = sam_model_registry[model_type](checkpoint=checkpoint)

正如我们已经讨论过的,每个图像可以使用一次图像编码器,然后可以多次运行更改提示、提示编码器和掩码解码器来从同一图像中检索不同的对象。考虑到这一事实,我们将模型分为两个独立的部分:image_encoder和mask_pr预测器(提示编码器和掩码解码器的组合)。

第二步: 定义图像编码器和掩码预测器

  • 图像编码器输入是NCHW格式的形状为1x3x1024x1024的张量,包含用于分割的图像。图像编码器输出为图像嵌入,张量形状为1x256x64x64。代码如下
1.	import warnings
2.	from pathlib import Path
3.	import torch
4.	from openvino.tools import mo
5.	from openvino.runtime import serialize, Core
6.	
7.	core = Core()
8.	
9.	ov_encoder_path = Path("sam_image_encoder.xml")
10.	
11.	if not ov_encoder_path.exists():
12.	    onnx_encoder_path = ov_encoder_path.with_suffix(".onnx")
13.	    if not onnx_encoder_path.exists():
14.	        with warnings.catch_warnings():
15.	            warnings.filterwarnings("ignore", category=torch.jit.TracerWarning)
16.	            warnings.filterwarnings("ignore", category=UserWarning)
17.	
18.	            torch.onnx.export(sam.image_encoder, torch.zeros(1,3,1024,1024), onnx_encoder_path)
19.	
20.	    ov_encoder_model = mo.convert_model(onnx_encoder_path, compress_to_fp16=True)
21.	    serialize(ov_encoder_model, str(ov_encoder_path))
22.	else:
23.	    ov_encoder_model = core.read_model(ov_encoder_path)
24.	ov_encoder = core.compile_model(ov_encoder_model)
  • 掩码预测器

本次代码示例需要导出的模型带有参数return_single_mask=True。这意味着模型将只返回最佳掩码,而不是返回多个掩码。对于高分辨率图像,这可以在放大掩码开销大的情况下提升运行时速度。

组合提示编码器和掩码解码器模型具有以下输入列表:

    • image_embeddings:从image_encoder中嵌入的图像。具有长度为1的批索引。
    • point_coords:稀疏输入提示的坐标,对应于点输入和框输入。方框使用两个点进行编码,一个用于左上角,另一个用于右下角。坐标必须已转换为长边1024。具有长度为1的批索引。
    • point_labels:稀疏输入提示的标签。0是负输入点,1是正输入点,2是左上角,3是右下角,-1是填充点。*如果没有框输入,则应连接标签为-1且坐标为(0.0,0.0)的单个填充点。

模型输出:

    • 掩码-预测的掩码大小调整为原始图像大小,以获得二进制掩码,应与阈值(通常等于0.0)进行比较。
    • iou_predictions-并集预测上的交集。
    • low_res_masks-后处理之前的预测掩码,可以用作模型的掩码输入。

第三步: 在交互式分割模式下运行OpenVINO 推理

加载分割用的测试图片。

1.	import numpy as np
2.	import cv2
3.	import matplotlib.pyplot as plt
4.	
5.	download_file("https://raw.githubusercontent.com/facebookresearch/segment-anything/main/notebooks/images/truck.jpg")
6.	image = cv2.imread('truck.jpg')
7.	image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

原始图片如下

2.	plt.imshow(image)
3.	plt.axis('off')
4.	plt.show()

 

  • 预处理及可视化函数定义:

为图像编码器准备输入,包含以下步骤:

  • 将BGR图像转换为RGB
  • 调整图像保存纵横比,其中最长尺寸等于图像编码器输入尺寸1024。
  • 归一化图像减去平均值(123.675、116.28、103.53)并除以标准差(58.395、57.12、57.375)
  • 将HWC数据布局转换为CHW并添加批次维度。
  • 根据图像编码器预期的输入形状,按高度或宽度(取决于纵横比)向输入张量添加零填充。

  • 视频编码

要开始处理图像,我们应该对其进行预处理,并使用ov_encoder获得图像嵌入。我们将在所有实验中使用相同的图像,因此可以运行一次视频编码、生成一次图像嵌入,然后重用它们。

1.	preprocessed_image = preprocess_image(image)
2.	encoding_results = ov_encoder(preprocessed_image)
3.	
4.	image_embeddings = encoding_results[ov_encoder.output(0)]

现在,我们可以尝试为掩码生成提供不同的提示。

  • 点输入举例

在本例中,我们选择一个点作为输入(input_point)。绿色星形符号在下图中显示了它的位置。

添加一个批索引,连接一个填充点,并将其转换为输入张量坐标系。

1.	coord = np.concatenate([input_point, np.array([[0.0, 0.0]])], axis=0)[None, :, :]
2.	label = np.concatenate([input_label, np.array([-1])], axis=0)[None, :].astype(np.float32)
3.	coord = resizer.apply_coords(coord, image.shape[:2]).astype(np.float32)

将输入打包以在掩码预测器中运行.

1.	inputs = {
2.	    "image_embeddings": image_embeddings,
3.	    "point_coords": coord,
4.	    "point_labels": label,
5.	}

预测一个掩码并设置阈值以获得二进制掩码(0-无对象,1-对象)。

1.	results = ov_predictor(inputs)
2.	
3.	masks = results[ov_predictor.output(0)]
4.	masks = postprocess_masks(masks, image.shape[:-1])
5.	masks = masks > 0.0

绘制结果如下

  • 多点输入举例
1.	input_point = np.array([[500, 375], [1125, 625], [575, 750])
2.	input_label = np.array([1, 1, 1])

 

像上面单点输入的例子一样,讲输入点变换为张量坐标系,进而将输入打包成所需格式,最后获得的分割结果如下图所示

  • 带负标签的框和点输入

在这个例中,我们使用边界框和边界框内的点来定义输入提示。边界框表示为其左上角和右下角的一组点。点的标签0表示该点应从掩码中排除。

1.	input_box = np.array([425, 600, 700, 875])
2.	input_point = np.array([[575, 750]])
3.	input_label = np.array([0])

反映在测试图片中为

添加批次索引,连接方框和点输入,为方框角添加适当的标签,然后进行变换。本次没有填充点,因为输入包括一个框输入。

1.	box_coords = input_box.reshape(2, 2)
2.	box_labels = np.array([2,3])
3.	
4.	coord = np.concatenate([input_point, box_coords], axis=0)[None, :, :]
5.	label = np.concatenate([input_label, box_labels], axis=0)[None, :].astype(np.float32)
6.	
7.	coord = resizer.apply_coords(coord, image.shape[:2]).astype(np.float32)

打包输入,并进行预测

1.	inputs = {
2.	    "image_embeddings": image_embeddings,
3.	    "point_coords": coord,
4.	    "point_labels": label,
5.	}
6.	
7.	results = ov_predictor(inputs)
8.	
9.	masks = results[ov_predictor.output(0)]
10.	masks = postprocess_masks(masks, image.shape[:-1])
11.	masks = masks > 0.0

结果如图所示 

第四步: 在自动分割模式下运行OpenVINO 推理

由于SAM可以有效地处理提示,因此可以通过在图像上采样大量提示来生成整个图像的掩码。automatic_mask_generation函数实现了这一功能。它的工作原理是在图像上的网格中对单点输入提示进行采样,SAM可以从每个提示中预测多个掩码。然后,对掩码进行质量过滤,并使用非最大抑制进行去重复。额外的选项允许进一步提高掩模的质量和数量,例如对图像的多个裁剪进行预测,或对掩模进行后处理以去除小的断开区域和孔洞。

1.	from segment_anything.utils.amg import (
2.	    MaskData, 
3.	    generate_crop_boxes, 
4.	    uncrop_boxes_xyxy, 
5.	    uncrop_masks, 
6.	    uncrop_points, 
7.	    calculate_stability_score, 
8.	    rle_to_mask, 
9.	    batched_mask_to_box, 
10.	    mask_to_rle_pytorch, 
11.	    is_box_near_crop_edge,
12.	    batch_iterator,
13.	    remove_small_regions,
14.	    build_all_layer_point_grids,
15.	    box_xyxy_to_xywh,
16.	    area_from_rle
17.	)
18.	from torchvision.ops.boxes import batched_nms, box_area
19.	from typing import Tuple, List, Dict, Any

在自动掩码生成中有几个可调参数,用于控制采样点的密度以及去除低质量或重复掩码的阈值。此外,生成可以在图像的裁剪上自动运行,以提高对较小对象的性能,后处理可以去除杂散像素和孔洞。

定义自动分割函数

1.	def automatic_mask_generation(
2.	    image: np.ndarray, min_mask_region_area: int = 0, points_per_side: int = 32, crop_n_layers: int = 0, crop_n_points_downscale_factor: int = 1, crop_overlap_ratio: float = 512 / 1500, box_nms_thresh: float = 0.7, crop_nms_thresh: float = 0.7
3.	) -> List[Dict[str, Any]]:
4.	    """
5.	    Generates masks for the given image.
6.	
7.	    Arguments:
8.	      image (np.ndarray): The image to generate masks for, in HWC uint8 format.
9.	
10.	    Returns:
11.	       list(dict(str, any)): A list over records for masks. Each record is
12.	         a dict containing the following keys:
13.	           segmentation (dict(str, any) or np.ndarray): The mask. If
14.	             output_mode='binary_mask', is an array of shape HW. Otherwise,
15.	             is a dictionary containing the RLE.
16.	           bbox (list(float)): The box around the mask, in XYWH format.
17.	           area (int): The area in pixels of the mask.
18.	           predicted_iou (float): The model's own prediction of the mask's
19.	             quality. This is filtered by the pred_iou_thresh parameter.
20.	           point_coords (list(list(float))): The point coordinates input
21.	             to the model to generate this mask.
22.	           stability_score (float): A measure of the mask's quality. This
23.	             is filtered on using the stability_score_thresh parameter.
24.	           crop_box (list(float)): The crop of the image used to generate
25.	             the mask, given in XYWH format.
26.	    """
27.	    point_grids = build_all_layer_point_grids(
28.	        points_per_side,
29.	        crop_n_layers,
30.	        crop_n_points_downscale_factor,
31.	    )
32.	    mask_data = generate_masks(
33.	        image, point_grids, crop_n_layers, crop_overlap_ratio, crop_nms_thresh)
34.	
35.	    # Filter small disconnected regions and holes in masks
36.	    if min_mask_region_area > 0:
37.	        mask_data = postprocess_small_regions(
38.	            mask_data,
39.	            min_mask_region_area,
40.	            max(box_nms_thresh, crop_nms_thresh),
41.	        )
42.	
43.	    mask_data["segmentations"] = [
44.	        rle_to_mask(rle) for rle in mask_data["rles"]]
45.	
46.	    # Write mask records
47.	    curr_anns = []
48.	    for idx in range(len(mask_data["segmentations"])):
49.	        ann = {
50.	            "segmentation": mask_data["segmentations"][idx],
51.	            "area": area_from_rle(mask_data["rles"][idx]),
52.	            "bbox": box_xyxy_to_xywh(mask_data["boxes"][idx]).tolist(),
53.	            "predicted_iou": mask_data["iou_preds"][idx].item(),
54.	            "point_coords": [mask_data["points"][idx].tolist()],
55.	            "stability_score": mask_data["stability_score"][idx].item(),
56.	            "crop_box": box_xyxy_to_xywh(mask_data["crop_boxes"][idx]).tolist(),
57.	        }
58.	        curr_anns.append(ann)
59.	
60.	    return curr_anns

 运行自动分割

1.	prediction = automatic_mask_generation(image)

以上automatic_mask_generation函数返回一个掩码列表,其中每个掩码都是一个包含有关掩码的各种数据的字典:

    • 分割:掩码
    • 面积:掩码的面积(以像素为单位)
    • bbox:XYWH格式的掩码的边界框
    • predicted_out:模型自己对掩模质量的预测
    • point_coords:生成此掩码的采样输入点
    • 稳定性核心:衡量掩码质量的一个附加指标
    • crop_box:用于以XYWH格式生成此掩码的图像的裁剪

查看掩码的信息

1.	print(f"Number of detected masks: {len(prediction)}")
2.	print(f"Annotation keys: {prediction[0].keys()}")

获得如下效果

 绘制最后的分割结果

1.	from tqdm.notebook import tqdm
2.	
3.	def draw_anns(image, anns):
4.	    if len(anns) == 0:
5.	        return
6.	    segments_image = image.copy()
7.	    sorted_anns = sorted(anns, key=(lambda x: x['area']), reverse=True)
8.	    for ann in tqdm(sorted_anns):
9.	        mask = ann["segmentation"]
10.	        mask_color = np.random.randint(0, 255, size=(1, 1, 3)).astype(np.uint8)
11.	        segments_image[mask] = mask_color
12.	    return cv2.addWeighted(image.astype(np.float32), 0.7, segments_image.astype(np.float32), 0.3, 0.0)
1.	import PIL
2.	
3.	out = draw_anns(image, prediction)
4.	cv2.imwrite("result.png", out[:, :, ::-1])
5.	
6.	PIL.Image.open("result.png")

 

看看这些分割的效果,是不是非常的惊艳呢。其实除了以上我们介绍的代码内容,在我们的Jupyter  Notebook代码里,还为大家提供了窗口式鼠标点击输入提示的交互式分割体验,甚至可以在手机端输入URL地址体验即时的互动效果,如下图所示

这么多有趣又快速的OpenVINO运行物体分割的方式,快在你本地的机器上克隆我们的代码示例,自己动手试试SAM的效果吧。

小结:

整个的步骤就是这样!现在就开始跟着我们提供的代码和步骤,动手试试用Open VINO和SAM吧。

关于英特尔OpenVINOTM开源工具套件的详细资料,包括其中我们提供的三百多个经验证并优化的预训练模型的详细资料,请您点击https://www.intel.com/content/www/us/en/developer/tools/openvino-toolkit/overview.html

除此之外,为了方便大家了解并快速掌握OpenVINOTM的使用,我们还提供了一系列开源的Jupyter notebook demo。运行这些notebook,就能快速了解在不同场景下如何利用OpenVINOTM实现一系列、包括计算机视觉、语音及自然语言处理任务。OpenVINOTM notebooks的资源可以在GitHub这里下载安装:https://github.com/openvinotoolkit/openvino_notebooks 。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

张亚勤对话朱民:颠覆认知的AI时代及产业机遇

来源:财经ThinkTank 4月28日,清华大学智能产业研究院院长、中国工程院外籍院士张亚勤与清华大学国家金融研究院院长、著名经济学家朱民进行对话。 张亚勤表示,对于ChatGPT横空出世,自己有三个感悟,一是人类历史上第一次…

清华大学张亚勤对话朱民:颠覆认知的AI时代及产业机遇

来源:财经ThinkTank 4月28日,清华大学智能产业研究院院长、中国工程院外籍院士张亚勤与清华大学国家金融研究院院长、著名经济学家朱民进行对话。 张亚勤表示,对于ChatGPT横空出世,自己有三个感悟,一是人类历史上第一次…

摘掉 Chat 标签,GPT-4 将释放更大生产力

相比 ChatGPT 能力有大进化,多模态上有突破但不多。 作者丨李梅 黄楠 编辑丨岑峰 今日,多模态大模型 GPT-4 震撼登场! GPT-4 能够接受图像和文本输入,输出文本,在各项测试和基准上的表现已经与人类水平相当。 OpenAI 一…

AI 图像生成工具可以取代摄影师吗?让我们从原理开始聊聊

AI 的风已经吹向了每一个人,在这篇文章中我们一起来聊一聊 AI 图像生成的原理以及未来。 作为一个非职业的摄影爱好者,我通常会在 Instagram 上面搜罗各种各样的优质图片并将其放进我的收藏夹。其中,有一位我关注了很久的德国摄影师&#xff…

只限今日免费,Midjourney 5.1震撼更新!逼真到给跪,中国情侣细节惊艳,3D视频大片马上来...

点击上方“AI遇见机器学习”,选择“星标”公众号 第一时间获取价值内容 编辑:桃子 拉燕 【导读】全新升级的Midjourney让全网又疯狂了,创造力解禁,出图更逼真。重要的是,限时免费到今天,要玩的抓紧了。 一个…

GPT4震撼发布,哈佛教授:程序员职业3年内将被终结

全球科技界又有重磅消息!GPT-4,横空出世了! 此前,火遍全球的CHATGPT是在GPT-3.5基础上的产品,而GPT-4就是在GPT-3.5等老一代AI上迭代出来的。 OpenAI老板也抑制不住激动的宣布:“这是我们迄今为止功能最强…

量化学习——跟随龙虎榜交易

import pandas as pd import numpy as np #efinance是金融数据包,可免费爬取东方财富交易数据 #直接使用pip install efinance安装 import efinance as ef import matplotlib.pyplot as plt #seaborn、plotly可视化包 import seaborn as sns import plotly_express …

公司拿到了量化交易模型, 交易员和策略师就可滚蛋了?

作者:天启大烁哥 源自:天启量投(ID:QDLG001) 在知乎上看到了一个很有趣的问题。 在这个问题下面,提问者留了一些自己的看法: 有种感觉,资本一直试图用电脑代替人,把人的…

国内量化平台不完全汇总

开始量化交易的第一步就是对比、选择各家量化平台了,这里列出一些面向个人的平台,仅供大家参考: 1、Ptrade 恒生出品,国内最主流的量化平台之一,合作券商多,5w甚至更低即可开权限。支持python&#xff0c…

七天学会python量化交易(一)

七天学会python量化交易 1、程序下载安装后,先补充一下历史数据 2、核心代码部分:(核心代码注意的一个事项,用价格与MA对比的时候,记住一个是close[-1]一个是close[-2] #-------------------------------------------…

运用Python开通量化交易实盘介绍

目前可以接通实盘的量化平台来说,聚宽、果仁、讯投qmt等都是用户量比较多的平台,带有模拟盘功能,可以开通试用账户,但具体如何选择需要根据自身的编程基础情况和资金情况来定。 如果是有一定的计算机语言基础,有编程基…

经典的量化交易算法

作者:徐Jebs 来源:知乎 加权平均价格算法(VMAP):以每一次交易的成交量为权重,一段时间内成交价格的加权平均值。该策略即利用历史成交量数据,将大段时间内的订单分割,成…

十次 CV 论文会议投稿的经验总结

文章目录 导语论文生产发表流程写好论文的意义创新点和论文核心论文的写作要点笔者的论文投稿常见的负面审稿意见总结 导语 2021年来,笔者在多次论文被拒稿期间,开始研究和反思顶会论文生产到投稿的全流程,并全程参与了十几篇论文的审稿。近…

高效工作的关键:这14个AI工具能让您事半功倍!

随着ChatGPT最近在国内的广泛应用,越来越多的AI工具如雨后春笋般涌现。对于各行各业的人来说,使用AI工具来提升工作效率将成为一种趋势。这些好用的AI工具能够快速帮助大家创作出理想的素材,使工作变得更加轻松。 我想向大家介绍14款非常实用…

创作纪念日让 AI 与我共同记录下今天 — 【第五周年、1460天】

今天正是五一,收到一条消息? 五一还要我加班 😏? 喔,原来是 CSDN 给我发的消息呀!我在 CSDN 不知不觉已经开启第五周年啦! 目录 1.机缘2.收获3.日常4.我与 AI 的“合作”part Ipart II Super al…

中国域名根服务器设立 | 历史上的今天

整理 | 王启隆 透过「历史上的今天」,从过去看未来,从现在亦可以改变未来。 今天是 2023 年 6 月 26 日,在 1911 年的今天,计算机先驱弗雷德里克威廉姆斯(Frederic Williams)出生。威廉姆斯是一位英国工程师…

【工具】1658- 拯救设计师的神器!15 款 AI 工具让你设计更高效、更优秀!

关注 “AI 工具派” 探索最新 AI 工具,发现 AI 带来的无限可能性! 🎉 最近 ChatGPT 在国内爆火 🔥,带来了越来越多的 AI 工具,🌱 如雨后春笋般不断涌现。相信很多设计师小伙伴也开始意识到&…

100天精通Python(可视化篇)——第95天:Pyecharts绘制多种炫酷气泡图参数说明+代码实战

文章目录 专栏导读1. 什么是气泡图?2. 散点图与气泡图的区别3. 基础气泡图4. 气泡按颜色显示5. 气泡大小根据值大小显示6. 自定义气泡图颜色7. 设置Y轴百分比8. 添加涟漪效果9. 修改气泡形状书籍推荐 专栏导读 🔥🔥本文已收录于《100天精通P…

春天又来了,做好自己的一年之计(chatGPT生产的博文)

春天来了,温暖的阳光普照大地。百花争艳,正如一幅五彩斑斓的画卷,一遍又一遍将景色熠熠生辉。新鲜的空气中充满了花草树木的香味,令人感到神清气爽。春意盎然,鲜花释放出浓郁的芬芳,伴随着小鸟鸣叫令人心旷…

CHAT GPT在Intellij IDEA中怎么配置

求助:CHAT GPT在Intellij IDEA中怎么配置 我使用的是最新版Intellij IDEA 2023.1,我在openai官网申请了CHATGPT密钥并填入IDEA中,但是为什么不能在IDEA中使用CHATGPT。 CHATGPT显示Something went wrong. Please try again later. 我可以正常…