Spaces:
Runtime error
Runtime error
# import subprocess | |
# subprocess.call("mim install 'mmengine>=0.6.0'", shell=True) | |
# subprocess.call("mim install 'mmcv>=2.0.0rc4,<2.1.0'", shell=True) | |
# subprocess.call("min install 'mmdet>=3.0.0,<4.0.0'", shell=True) | |
# subprocess.call("mim install 'mmyolo'", shell=True) | |
# subprocess.call("mim install 'mmpose'", shell=True) | |
# subprocess.call("mim install 'mmpretrain'", shell=True) | |
import numpy as np | |
import gradio as gr | |
import requests | |
import base64 | |
import pandas as pd | |
import cv2 | |
from typing import Tuple | |
from PIL import Image | |
from io import BytesIO | |
from skimage import color | |
import os | |
from Model.Model6.model6_inference import main as model6_inferencer | |
from mmyolo.utils import register_all_modules | |
register_all_modules() | |
def get_access_token(refatch=False) -> str: | |
"""获取百度AI的access_token | |
:param refatch:是否重新获取access_token | |
:return:返回access_token""" | |
if refatch: | |
# client_id 为官网获取的AK, client_secret 为官网获取的SK | |
client_id = '7OtH60uo01ZNYN4yPyahlRSx' | |
client_secret = 'D5AxcUpyQyIA7KgPplp7dnz5tM0UIljy' | |
host = 'https://aip.baidubce.com/oauth/2.0/token?' \ | |
'grant_type=client_credentials&client_id=%s&client_secret=%s' % (client_id, client_secret) | |
response = requests.get(host) | |
# print(response) | |
if response: | |
return response.json()['access_token'] | |
else: | |
r""" | |
{"refresh_token":"25.24b9368ce91f9bd62c8dad38b3436800.315360000.2007815067.282335-30479502", | |
"expires_in":2592000, | |
"session_key": | |
"9mzdWT\/YmQ7oEi9WCRWbXd0YCcrSYQY6kKZjObKunlcKcZt95j9\/q1aJqbVXihpQOXK84o5WLJ8e7d4cXOi0VUJJcz5YEQ==", | |
"access_token":"24.becefee37aba38ea43c546fc154d3016.2592000.1695047067.282335-30479502", | |
"scope":"public brain_all_scope brain_body_analysis brain_body_attr brain_body_number brain_driver_behavior | |
brain_body_seg brain_gesture_detect brain_body_tracking brain_hand_analysis wise_adapt | |
lebo_resource_base lightservice_public hetu_basic lightcms_map_poi kaidian_kaidian | |
ApsMisTest_Test\u6743\u9650 vis-classify_flower lpq_\u5f00\u653e cop_helloScope | |
ApsMis_fangdi_permission smartapp_snsapi_base smartapp_mapp_dev_manage iop_autocar oauth_tp_app | |
smartapp_smart_game_openapi oauth_sessionkey smartapp_swanid_verify smartapp_opensource_openapi | |
smartapp_opensource_recapi fake_face_detect_\u5f00\u653eScope | |
vis-ocr_\u865a\u62df\u4eba\u7269\u52a9\u7406 idl-video_\u865a\u62df\u4eba\u7269\u52a9\u7406 | |
smartapp_component smartapp_search_plugin avatar_video_test b2b_tp_openapi b2b_tp_openapi_online | |
smartapp_gov_aladin_to_xcx","session_secret":"5c8c3dbb80b04f58bb33aa8077758679" | |
} | |
""" | |
access_token = "24.becefee37aba38ea43c546fc154d3016.2592000.1695047067.282335-30479502" | |
return access_token | |
def resize_image(img, max_length=2048, min_length=50) -> Tuple[np.ndarray, bool]: | |
"""Ensure that the longest side is shorter than 524px and the shortest side is longer than 50px. | |
:param img: 前端传入的图片 | |
:param max_length: 最长边像素 | |
:param min_length: 最短边像素 | |
:return: 返回处理后的图片和是否进行了resize的标志 | |
""" | |
flag = False | |
max_side = max(img.shape[0], img.shape[1]) | |
min_side = min(img.shape[0], img.shape[1]) | |
if max_side > max_length: | |
scale = max_length / max_side | |
img = cv2.resize(img, (int(img.shape[1] * scale), int(img.shape[0] * scale))) | |
flag = True | |
if min_side < min_length: | |
scale = min_length / min_side | |
img = cv2.resize(img, (int(img.shape[1] * scale), int(img.shape[0] * scale))) | |
flag = True | |
return img, flag | |
def model1_det(x): | |
"""人体检测与属性识别 | |
:param x:前端传入的图片 | |
:return:返回检测结果 | |
""" | |
def _Baidu_det(img): | |
"""调用百度AI接口进行人体检测与属性识别 | |
:param img:前端传入的图片,格式为numpy.ndarray | |
:return:返回检测结果 | |
""" | |
request_url = "https://aip.baidubce.com/rest/2.0/image-classify/v1/body_attr" | |
# 保存图片到本地 | |
cv2.imwrite('test.jpg', img) | |
# 二进制方式打开图片文件 | |
f = open('test.jpg', 'rb') | |
hex_image = base64.b64encode(f.read()) | |
# 选择二进制图片和需要输出的属性(12个) | |
params = { | |
"image": hex_image, | |
"type": "gender,age,upper_wear,lower_wear,upper_color,lower_color," | |
"orientation,upper_cut,lower_cut,side_cut,occlusion,is_human" | |
} | |
access_token = get_access_token() | |
request_url = request_url + "?access_token=" + access_token | |
headers = {'content-type': 'application/x-www-form-urlencoded'} | |
response = requests.post(request_url, data=params, headers=headers) | |
if response: | |
return response.json() | |
def _get_attributes_list(r) -> dict: | |
"""获取人体属性列表 | |
:param r:百度AI接口返回的json数据 | |
:return:返回人体属性列表 | |
""" | |
all_humans_attributes_list = {} | |
person_num = r['person_num'] | |
print('person_num:', person_num) | |
for human_idx in range(person_num): | |
attributes_dict = r['person_info'][human_idx]['attributes'] | |
attributes_list = [] | |
for key, value in attributes_dict.items(): | |
attribute = [key, value['name'], value['score']] | |
attributes_list.append(attribute) | |
new_value = ['attribute', 'attribute_value', 'accuracy'] | |
attributes_list.insert(0, new_value) | |
df = pd.DataFrame(attributes_list[1:], columns=attributes_list[0]) | |
all_humans_attributes_list[human_idx] = df | |
return all_humans_attributes_list | |
def _show_img(img, bboxes): | |
"""显示图片 | |
:param img:前端传入的图片 | |
:param bboxes:检测框坐标 | |
:return:处理完成的图片 """ | |
line_width = int(max(img.shape[1], img.shape[0]) / 400) | |
for bbox in bboxes: | |
left, top, width, height = bbox['left'], bbox['top'], bbox['width'], bbox['height'] | |
right, bottom = left + width, top + height | |
for i in range(left, right): | |
img[top:top + line_width, i] = [255, 0, 0] | |
img[bottom - line_width:bottom, i] = [255, 0, 0] | |
for i in range(top, bottom): | |
img[i, left:left + line_width] = [255, 0, 0] | |
img[i, right - line_width:right] = [255, 0, 0] | |
return img | |
result = _Baidu_det(x) | |
HAs_list = _get_attributes_list(result) | |
locations = [] | |
for i in range(len(result['person_info'])): | |
locations.append(result['person_info'][i]['location']) | |
return _show_img(x, locations), f"模型检测到的人数为:{result['person_num']}人" | |
def model2_rem(x): | |
"""背景消除 | |
:param x: 前端传入的图片 | |
:return: 返回处理后的图片 | |
""" | |
def _Baidu_rem(img): | |
"""调用百度AI接口进行背景消除 | |
:param img: 前端传入的图片,格式为numpy.ndarray | |
:return: 返回处理后的图片 | |
""" | |
request_url = "https://aip.baidubce.com/rest/2.0/image-classify/v1/body_seg" | |
bgr_image = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) | |
cv2.imwrite('test.jpg', bgr_image) | |
f = open('test.jpg', 'rb') | |
hex_image = base64.b64encode(f.read()) | |
params = {"image": hex_image} | |
access_token = get_access_token() | |
request_url = request_url + "?access_token=" + access_token | |
headers = {'content-type': 'application/x-www-form-urlencoded'} | |
response = requests.post(request_url, data=params, headers=headers) | |
if response: | |
encoded_image = response.json()["foreground"] | |
decoded_image = base64.b64decode(encoded_image) | |
image = Image.open(BytesIO(decoded_image)) | |
image_array = np.array(image) | |
return image_array | |
resized_x, resized_f = resize_image(x) | |
new_img = _Baidu_rem(resized_x) | |
if resized_f: | |
resized_f = "图片尺寸已被修改至合适大小" | |
else: | |
resized_f = "图片尺寸无需修改" | |
return new_img, resized_f | |
def model3_ext(x: np.ndarray, num_clusters=8): | |
"""主色调提取 | |
:param x: 前端传入的图片 | |
:param num_clusters: 聚类的数量 | |
:return: 返回处理后的图片,是否进行了resize的标志,颜色列表""" | |
def _find_name(r, g, b): | |
"""根据颜色值查找颜色名称。 | |
:param r: 红色值 | |
:param g: 绿色值 | |
:param b: 蓝色值 | |
:return:返回颜色名称 | |
""" | |
# turn RGB to Lab | |
lab = color.rgb2lab([[r / 255, g / 255, b / 255]])[0] | |
for i in range(len(df)): | |
# culcuate the minimum chromatic distance | |
df['distance'] = np.sqrt((df['L'] - lab[0]) ** 2 + (df['a'] - lab[1]) ** 2 + (df['b'] - lab[2]) ** 2) | |
# find the color name, whose chromatic distance is the minimum, and the corresponding distance | |
name = df[df['distance'] == df['distance'].min()]['name'].values[0] | |
distance = df[df['distance'] == df['distance'].min()]['distance'].values[0] | |
return name, distance | |
def _cluster(img, NUM_CLUSTERS): | |
"""K-means 聚类提取主色调 | |
:param img: 前端传入的图片 | |
:param NUM_CLUSTERS: 聚类的数量 | |
:return: 返回聚类结果 | |
""" | |
h, w, ch = img.shape | |
reshaped_x = np.float32(img.reshape((-1, 4))) | |
new_data_list = [] | |
for i in range(len(reshaped_x)): | |
if reshaped_x[i][3] < 100: | |
continue | |
else: | |
new_data_list.append(reshaped_x[i]) | |
reshaped_x = np.array(new_data_list) | |
reshaped_x = np.delete(reshaped_x, 3, axis=1) | |
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0) | |
NUM_CLUSTERS = NUM_CLUSTERS | |
ret, label, center = cv2.kmeans(reshaped_x, NUM_CLUSTERS, None, criteria, | |
NUM_CLUSTERS, cv2.KMEANS_RANDOM_CENTERS) | |
clusters = np.zeros([NUM_CLUSTERS], dtype=np.int32) | |
for i in range(len(label)): | |
clusters[label[i][0]] += 1 | |
clusters = np.float32(clusters) / float(len(reshaped_x)) | |
center = np.int32(center) | |
x_offset = 0 | |
card = np.zeros((50, w, 3), dtype=np.uint8) | |
color_list = [] | |
for c in np.argsort(clusters)[::-1]: | |
dx = int(clusters[c] * w) | |
r = center[c][0] | |
g = center[c][1] | |
b = center[c][2] | |
cv2.rectangle(card, (x_offset, 0), (x_offset + dx, 50), | |
(int(r), int(g), int(b)), -1) | |
color_list.append([r, g, b, str(round(clusters[c]*100, 2)) + '%']) | |
x_offset += dx | |
return card, resized_f, color_list | |
file = '中国传统色_集合.xlsx' | |
df = pd.read_excel(file, sheet_name='Sheet1')[['name', 'L', 'a', 'b']] | |
resized_x, resized_f = resize_image(x) | |
card, resized_f, c_list = _cluster(resized_x, num_clusters) | |
for c in c_list: | |
c_name, c_distance = _find_name(c[0], c[1], c[2]) | |
c.append(c_name) | |
c.append(c_distance) | |
if resized_f: | |
resized_f = "图片尺寸已被修改至合适大小" | |
else: | |
resized_f = "图片尺寸无需修改" | |
c_df = pd.DataFrame(c_list, columns=['R', 'G', 'B', '比例', '颜色名称', '色差ΔE']) | |
return card, resized_f, c_df | |
def model4_clo(x_path: str): | |
def _get_result(input_path: str, cls_results: dict) -> pd.DataFrame: | |
"""convert the results of model6_2 to a dataframe | |
:param input_path: the (absolute) path of the image | |
:param cls_results: the results of model6_2 | |
:return: a dataframe to display on the web | |
""" | |
result_pd = [] | |
img_name = os.path.basename(input_path) | |
pred_profile = cls_results[img_name][0]['pred_class'] | |
pred_score = round(cls_results[img_name][0]['pred_score'], 2) | |
result_pd.append([img_name, pred_profile, pred_score]) | |
df = pd.DataFrame(result_pd, columns=None) | |
return df | |
output_path_root = 'upload_to_web_tmp' | |
if not os.path.exists(output_path_root): | |
os.mkdir(output_path_root) | |
cls_result = model6_inferencer(x_path, output_path_root) | |
if cls_result: | |
# use np to read image· | |
x_name = os.path.basename(x_path) | |
pred_x = np.array(Image.open(os.path.join(output_path_root, 'visualizations', x_name))) | |
return pred_x, _get_result(x_path, cls_result), "识别成功!" | |
# TODO: 完善识别失败时的处理(model6_inference.py中)[important] | |
return x_path, pd.DataFrame(), "未检测到服装" | |
with gr.Blocks() as demo: | |
gr.Markdown("# 服装图像识别模块——功能演示") | |
with gr.Tab("人体检测模型"): | |
with gr.Row(): | |
model1_input = gr.Image(height=400) | |
model1_output_img = gr.Image(height=400) | |
# model1_output_df = gr.DataFrame() | |
model1_button = gr.Button("开始检测") | |
with gr.Tab("背景消除模型"): | |
with gr.Row(): | |
model2_input = gr.Image(height=400) | |
model2_output_img = gr.Image(height=400) | |
model2_button = gr.Button("开始消除") | |
with gr.Tab('主色调提取'): | |
with gr.Row(): | |
with gr.Column(): | |
model3_input = gr.Image(height=400, image_mode='RGBA') | |
model3_slider = gr.Slider(minimum=1, maximum=20, step=1, value=8, | |
min_width=400, label="聚类数量") | |
with gr.Column(): | |
model3_output_img = gr.Image(height=100) | |
model3_output_df = gr.DataFrame(headers=['R', 'G', 'B', '比例', '颜色名称', '色差ΔE'], | |
datatype=['number', 'number', 'number', 'str', 'str', 'number']) | |
model3_button = gr.Button("开始提取") | |
with gr.Tab("廓形识别"): | |
with gr.Row(): | |
model4_input = gr.Image(height=400, type="filepath") | |
model4_output_img = gr.Image(height=400) | |
model4_output_df = gr.DataFrame(headers=['img_name', 'pred_profile', 'pred_score'], | |
datatype=['str', 'str', 'number']) | |
model4_button = gr.Button("开始识别") | |
# 设置折叠内容 | |
with gr.Accordion("模型运行信息"): | |
running_info = gr.Markdown("等待输入和运行...") | |
model1_button.click(model1_det, inputs=model1_input, outputs=[model1_output_img, running_info]) | |
model2_button.click(model2_rem, inputs=model2_input, outputs=[model2_output_img, running_info]) | |
model3_button.click(model3_ext, | |
inputs=[model3_input, model3_slider], | |
outputs=[model3_output_img, running_info, model3_output_df]) | |
model4_button.click(model4_clo, inputs=model4_input, outputs=[model4_output_img, model4_output_df, running_info]) | |
demo.launch() | |