Chapter 46
2. 图片总结应用 Image captioning app
NotebookPython 3 (ipykernel)24 cells
第二章 图片总结应用 🖼️📝
加载HF API密钥和相关Python库
python
import os
import io
import IPython.display
from PIL import Image
import base64
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file
hf_api_key = os.environ['HF_API_KEY']python
# Helper functions
import requests, json
#Image-to-text endpoint
def get_completion(inputs, parameters=None, ENDPOINT_URL=os.environ['HF_API_ITT_BASE']):
headers = {
"Authorization": f"Bearer {hf_api_key}",
"Content-Type": "application/json"
}
data = { "inputs": inputs }
if parameters is not None:
data.update({"parameters": parameters})
response = requests.request("POST",
ENDPOINT_URL,
headers=headers,
data=json.dumps(data))
return json.loads(response.content.decode("utf-8"))由于本课程涉及到使用模型都需要使用科技手段,于是我们采用硅基流动的国内方案,以下代码都跟项目中的已有代码不同(我们保留原有代码),大家也可以在本地跑通。
In [4]python · cell 6
python
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
import re
import base64
import os
from dotenv import load_dotenv, find_dotenv
from openai import OpenAI
import imghdr
import IPython.display
from PIL import Image
from enum import EnumIn [5]python · cell 7
python
loaded = load_dotenv(find_dotenv(), override=True)
# 从环境变量中获取 OpenAI API Key 或者直接赋值
API_KEY = os.getenv("API_KEY")
# 如果您使用的是官方 API,就直接用 https://api.siliconflow.cn/v1 就行。
BASE_URL = "https://api.siliconflow.cn/v1"
# 基于openai的OpenAI实例
openai_client = OpenAI(api_key=API_KEY, base_url=BASE_URL, max_retries=3)In [6]python · cell 8
python
# 辅助函数
def image_to_base64(image_path):
"""
将指定路径的图片转换为 Base64 编码字符串。
:param image_path: 图片文件的路径
:return: 图片的 Base64 编码字符串,如果出现异常则返回 None
"""
try:
with open(image_path, "rb") as image_file:
# 读取图片文件内容
image_data = image_file.read()
# 将图片内容转换为 Base64 编码
base64_encoded = base64.b64encode(image_data).decode('utf-8')
return base64_encoded
except Exception as e:
print(f"转换图片到 Base64 编码时出错: {e}")
return None
def get_image_mime_type(image_path):
"""
获取图片的 MIME 类型。
:param image_path: 图片文件的路径
:return: 图片的 MIME 类型,如果无法识别则返回 'jpeg'
"""
image_type = imghdr.what(image_path)
if image_type:
return f"image/{image_type}"
return "image/jpeg"In [7]python · cell 9
python
class InputImageType(Enum):
IMAGE_URL = 'IMAGE_URL'
IMAGE_BASE64 = 'IMAGE_BASE64'
IMAGE_FILE = 'IMAGE_FILE'
def get_completion(input_image_type, image_input, text_input=None, model_endpoint="Qwen/Qwen2.5-VL-72B-Instruct"):
"""
从图像中提取文本信息。
:param image_input: 图像输入,可以是图片路径或图片 URL
:param text_input: 文字输入
:param model_endpoint: 模型名称
"""
text_input = text_input or "请用一段文字描述这张图片。"
image_info = {
"type": "image_url",
"image_url": {
"type": "image_url",
"image_url": {
"url": "URL_ADDRESS",
"detail": "auto"
}
}
}
if input_image_type == InputImageType.IMAGE_FILE:
# 传入的是图片文件
base64_image = image_to_base64(image_input)
# 获取图片的 MIME 类型
mime_type = get_image_mime_type(image_input)
image_info = {
"type": "image_url",
"image_url": {
"url": f"data:{mime_type};base64,{base64_image}",
"detail": "auto"
}
}
if input_image_type == InputImageType.IMAGE_URL:
# 传入的是图片 URL
image_info = {
"type": "image_url",
"image_url": {
"url": image_input,
"detail": "auto"
}
}
if input_image_type == InputImageType.IMAGE_BASE64:
# 传入的是图片的base64编码
image_info = {
"type": "image_url",
"image_url": {
"url": f"data:image/png;base64,{image_input}",
"detail": "auto"
}
}
# 构造包含图像信息的消息
messages = [
{
"role": "user",
"content": [
{
"type": "text",
"text": text_input
},
image_info
]
}
]
response = openai_client.chat.completions.create(model=model_endpoint,
messages=messages,
n=1, temperature=0, seed=42,
presence_penalty=0, frequency_penalty=0,
max_tokens=4096
)
return response.choices[0].message.content.strip()一、构建一个图片标题App
在这里,我们使用一个Inference Endpoint用于“Salesforce/blip-image-caption-base”一个14M参数的图面总结模型。
如果在本地运行而不是从API,代码需要稍作修改。同学们可以查看Pipelines文档页面。
此处笔者选择使用本地模型,模型下载地址:https://huggingface.co/Salesforce/blip-image-captioning-base
python
# 导入所需的库
from transformers import pipeline
# 创建一个图像描述生成的pipeline,使用预训练模型"Salesforceblip-image-captioning-base"
get_completion = pipeline("image-to-text", model="Salesforce/blip-image-captioning-base")
# 定义一个函数用于生成图像描述
def generate_image_caption(input):
# 使用pipeline生成图像描述
output = get_completion(input)
# 返回生成的图像描述
return output[0]['generated_text']这是一个免费的图片网站(需要一点点magic~): https://free-images.com/
python
# 图像URL
image_url = "https://free-images.com/sm/9596/dog_animal_greyhound_983023.jpg"
# # 显示图像
display(IPython.display.Image(url=image_url))
# 创建图像描述生成的pipeline,使用预训练模型"Salesforceblip-image-captioning-base"
get_completion(image_url)以下代码都跟项目中的已有代码不同(我们保留原有代码),大家也可以在本地跑通。
In [8]python · cell 18
python
# 图像URL
image_url = "https://free-images.com/sm/9596/dog_animal_greyhound_983023.jpg"
# 显示图像
display(IPython.display.Image(url=image_url))
content = "生成10个字以内的标题。"
print("图片描述:", get_completion(InputImageType.IMAGE_URL, image_url))
print("图片标题:", get_completion(InputImageType.IMAGE_URL, image_url, content))Output
<IPython.core.display.Image object>

图片描述: 这张图片展示了一只戴着圣诞帽的狗。这只狗看起来像是一只灵缇犬,它的毛色是浅棕色,脸上有白色的斑纹。它戴着一顶红色的圣诞帽,帽子上有一个绿色的装饰和一个白色的绒球。狗的脖子上还围着一条红色的围巾,显得非常可爱和节日气氛浓厚。背景是纯白色的,突出了狗的形象和节日装饰。 图片标题: 圣诞狗狗的可爱瞬间
二、图片标题APP gr.Interface()
2.1 参数解析
- fn=captioner: 这是用于处理输入的函数,即图像描述生成函数 captioner。
- inputs=[gr.Image(label="Upload image", type="pil")]: 这定义了输入部分。使用 gr.Image 部件来允许用户上传图像,label 参数设置了输入部件的标签,type 参数指定输入类型为PIL图像。
- outputs=[gr.Textbox(label="Caption")]: 这定义了输出部分。使用 gr.Textbox 部件来显示生成的图像描述,label 参数设置了输出部件的标签。
- title="Image Captioning with BLIP": 这是界面的标题,将显示在界面的顶部。
- description="Caption any image using the BLIP model": 这是界面的描述,提供有关界面功能的更多信息。
- allow_flagging="never": 这设置了不允许标记内容,确保不会显示标记不恰当内容的选项。
- examples=[...]: 这提供了一组示例图像文件名,用于展示界面功能。用户可以从这些示例中选择图像来查看生成的描述。
In [9]python · cell 21
python
# 导入所需的库
import base64
import io
import gradio as gr
import requests
from PIL import ImageIn [10]python · cell 22
python
# 将PIL图像转换为base64编码的字符串
def image_to_base64_str(pil_image):
byte_arr = io.BytesIO()
pil_image.save(byte_arr, format='PNG')
byte_arr = byte_arr.getvalue()
return str(base64.b64encode(byte_arr).decode('utf-8'))
# 从URL获取图片
def get_image_from_url(image_url):
try:
response = requests.get(image_url)
response.raise_for_status()
return Image.open(io.BytesIO(response.content))
except Exception as e:
print(f"获取图片失败: {e}")
return None
# 图像描述生成函数,修改为支持图片文件和图片URL
def captioner(image, image_url, prompt):
if image and image_url:
return "请上传图片或输入图片URL,不要同时上传", None
if image:
# 处理上传的图片文件
base64_image = image_to_base64_str(image)
display_image = image
result = get_completion(InputImageType.IMAGE_BASE64, base64_image, text_input=prompt)
elif image_url:
# 处理图片URL
pil_image = get_image_from_url(image_url)
if pil_image:
display_image = pil_image
else:
return "无法获取图片,请检查URL", None
result = get_completion(InputImageType.IMAGE_URL, image_url, text_input=prompt)
else:
return "请上传图片或输入图片URL", None
return result, display_image
# 关闭之前的Gradio界面(如果有的话)
gr.close_all()
# 创建Gradio界面,接受上传的图像并显示描述
demo = gr.Interface(
fn=captioner, # 指定用于处理输入的函数
inputs=[
gr.Image(label="上传图片(Image upload)", type="pil"),
gr.Textbox(label="图片URL(Image URL)", placeholder="请输入图片URL地址"),
gr.Textbox(label="提示词(Prompt)", placeholder="请输入提示词")
], # 输入部分的设置,允许上传图像和输入图片URL
outputs=[
gr.Textbox(label="Caption"),
gr.Image(label="Displayed Image", type="pil")
], # 输出部分的设置,显示生成的图像描述和展示图片
title="Image Captioning with BLIP", # 界面标题
description="Caption any image using the BLIP model", # 界面描述
flagging_mode="never", # 设置不允许标记内容
)
# 启动共享模式的界面,允许其他用户访问
demo.launch(share=True)Output
* Running on local URL: http://127.0.0.1:7861 Could not create share link. Missing file: C:\Users\hurui\.cache\huggingface\gradio\frpc\frpc_windows_amd64_v0.3. Please check your internet connection. This can happen if your antivirus software blocks the download of this file. You can install manually by following these steps: 1. Download this file: https://cdn-media.huggingface.co/frpc-gradio-0.3/frpc_windows_amd64.exe 2. Rename the downloaded file to: frpc_windows_amd64_v0.3 3. Move the file to this location: C:\Users\hurui\.cache\huggingface\gradio\frpc
<IPython.core.display.HTML object>
In [11]python · cell 24
python
gr.close_all()Output
Closing server running on port: 7861
