当前位置: 首页 > news >正文

python图像彩色数字化

效果展示:

目录结构:

alphabets.py

GENERAL = {"simple": "@%#*+=-:. ","complex": "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. "
}
# Full list could be found here https://github.com/tsroten/zhon/tree/develop/zhon/cedict
CHINESE = {"standard": "龘䶑瀰幗獼鑭躙䵹觿䲔釅欄鐮䥯鶒獭鰽襽螻鰱蹦屭繩圇婹歜剛屧磕媿慪像僭堳噞呱棒偁呣塙唑浠唼刻凌咄亟拮俗参坒估这聿布允仫忖玗甴木亪女去凸五圹亐囗弌九人亏产斗丩艹刂彳丬了5丄三亻讠厂丆丨1二宀冖乛一丶、",
}KOREAN = {"standard": "ㄱㄴㄷㄹㅁㅂㅅㅇㅈㅊㅋㅌㅍㅎㅏㅑㅓㅕㅗㅛㅜㅠㅡㅣ"
}JAPANESE = {"hiragana": "あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわをん","katakana": "アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン"
}ENGLISH = {"standard": "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
}RUSSIAN = {"standard": "АаБбВвГгДдЕеЁёЖжЗзИиЙйКкЛлМмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщЪъЫыЬьЭэЮюЯя"
}GERMAN = {"standard": "AaÄäBbßCcDdEeFfGgHhIiJjKkLlMmNnOoÖöPpQqRrSsTtUuÜüVvWwXxYyZz"
}FRENCH = {"standard": "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZzÆæŒœÇçÀàÂâÉéÈèÊêËëÎîÎïÔôÛûÙùŸÿ"
}SPANISH = {"standard": "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZzÑñáéíóú¡¿"
}ITALIAN = {"standard": "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZzÀÈàèéìòù"
}PORTUGUESE = {"standard": "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZzàÀáÁâÂãÃçÇéÉêÊíÍóÓôÔõÕúÚ"
}POLISH = {"standard": "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpRrSsTtUuWwYyZzĄąĘęÓóŁłŃńŻżŚśĆ揟"
}

app.py

import os
import hashlib
import argparse
import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageOps
from flask import Flask, request, send_file, render_template_string
from utils import get_dataapp = Flask(__name__)# 确保上传和输出目录存在
if not os.path.exists("uploads"):os.makedirs("uploads")
if not os.path.exists("outputs"):os.makedirs("outputs")# 文件处理常量
ALLOWED_EXTENSIONS = {'jpg', 'jpeg', 'png', 'gif', 'bmp'}
MAX_FILE_SIZE = 5 * 1024 * 1024  # 最大文件大小为5MBdef get_args():"""获取命令行参数"""parser = argparse.ArgumentParser("Image to ASCII")parser.add_argument("--input", type=str, default="uploads/input.jpg", help="输入图片路径")parser.add_argument("--output", type=str, default="outputs/output.jpg", help="输出图片路径")parser.add_argument("--language", type=str, default="english")  # 使用的字符语言parser.add_argument("--mode", type=str, default="standard")  # ASCII 模式parser.add_argument("--background", type=str, default="black", choices=["black", "white"],help="背景颜色")parser.add_argument("--num_cols", type=int, default=300, help="输出图片的宽度字符数")parser.add_argument("--scale", type=int, default=2, help="输出图片的缩放比例")args = parser.parse_args()return argsdef md5_filename(filename):"""返回文件名的MD5哈希值,用于生成唯一的文件名"""hash_md5 = hashlib.md5()hash_md5.update(filename.encode('utf-8'))  # 更新哈希值return hash_md5.hexdigest()def allowed_file(filename):"""检查文件是否具有允许的扩展名"""return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONSdef convert_image_to_ascii(opt):"""将图像转换为ASCII字符图像:param opt: 命令行参数对象,包含转换的配置"""# 根据背景颜色设置背景if opt.background == "white":bg_code = (255, 255, 255)else:bg_code = (0, 0, 0)# 获取字符列表、字体和缩放参数char_list, font, sample_character, scale = get_data(opt.language, opt.mode)num_chars = len(char_list)num_cols = opt.num_cols# 检查输入文件是否存在if not os.path.exists(opt.input):print(f"错误:文件 {opt.input} 不存在!")return# 读取图像并验证image = cv2.imread(opt.input, cv2.IMREAD_COLOR)if image is None:print(f"错误:无法加载图片 {opt.input}")return# 将图像从BGR格式转换为RGB格式image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)# 获取图像尺寸height, width, _ = image.shapecell_width = width / opt.num_colscell_height = scale * cell_widthnum_rows = int(height / cell_height)# 如果列数或行数过多,使用默认设置if num_cols > width or num_rows > height:print("列数或行数过多,使用默认设置。")cell_width = 6cell_height = 12num_cols = int(width / cell_width)num_rows = int(height / cell_height)# 获取字符的宽度和高度char_width, char_height = font.getsize(sample_character)out_width = char_width * num_colsout_height = scale * char_height * num_rows# 创建输出图像out_image = Image.new("RGB", (out_width, out_height), bg_code)draw = ImageDraw.Draw(out_image)# 逐个处理图像区域,转换为字符for i in range(num_rows):for j in range(num_cols):partial_image = image[int(i * cell_height):min(int((i + 1) * cell_height), height),int(j * cell_width):min(int((j + 1) * cell_width), width), :]partial_avg_color = np.sum(np.sum(partial_image, axis=0), axis=0) / (cell_height * cell_width)partial_avg_color = tuple(partial_avg_color.astype(np.int32).tolist())# 根据平均色值选择合适的字符char = char_list[min(int(np.mean(partial_image) * num_chars / 255), num_chars - 1)]draw.text((j * char_width, i * char_height), char, fill=partial_avg_color, font=font)# 根据背景颜色裁剪图像if opt.background == "white":cropped_image = ImageOps.invert(out_image).getbbox()else:cropped_image = out_image.getbbox()out_image = out_image.crop(cropped_image)out_image.save(opt.output)@app.route('/')
def index():"""渲染首页HTML,用户可以上传图片"""return render_template_string("""<html><head><style>body {font-family: Arial, sans-serif;background-color: #f4f4f9;margin: 0;padding: 0;display: flex;justify-content: center;align-items: center;height: 100vh;}.container {background-color: #fff;padding: 30px;border-radius: 8px;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);width: 300px;text-align: center;}h1 {font-size: 24px;color: #333;}form {margin-top: 20px;}input[type="file"] {display: block;margin: 10px auto;padding: 10px;border: 1px solid #ccc;border-radius: 4px;width: 100%;}input[type="submit"] {background-color: #4CAF50;color: white;border: none;padding: 12px 20px;border-radius: 4px;cursor: pointer;width: 100%;font-size: 16px;}input[type="submit"]:hover {background-color: #45a049;}.footer {margin-top: 20px;font-size: 14px;color: #777;}</style></head><body><div class="container"><h1>彩色图片转化器YFREE</h1><form action="/upload" method="POST" enctype="multipart/form-data"><input type="file" name="image" required><input type="submit" value="上传图片"></form><div class="footer"><p>支持开源 <a href="https://github.com/vietnh1009/ASCII-generator" target="_blank">github</a></p></div></div></body></html>""")@app.route('/upload', methods=['POST'])
def upload():"""处理上传的图片,将其转换为ASCII图像并返回"""if 'image' not in request.files:return '没有文件上传'file = request.files['image']if file.filename == '':return '没有选择文件'# 检查文件扩展名if not allowed_file(file.filename):return '无效的文件类型,请上传图片。'# 检查文件大小file.seek(0, os.SEEK_END)file_size = file.tell()if file_size > MAX_FILE_SIZE:return '文件太大,最大支持文件大小为5MB。'file.seek(0)  # 重置文件指针# 保存文件md5_filename_value = md5_filename(file.filename)filename = os.path.join("uploads", md5_filename_value + os.path.splitext(file.filename)[1])file.save(filename)if not os.path.exists(filename):return '文件上传失败。'# 获取参数并处理图像opt = get_args()opt.input = filenameopt.output = os.path.join("outputs", f"output_{md5_filename_value}.jpg")# 调用转换函数convert_image_to_ascii(opt)return send_file(opt.output, as_attachment=True)if __name__ == '__main__':app.run(port=8979)

Dockerfile 和 requestments.txt

# 使用python的官方镜像作为基础镜像
FROM python:3.6-slim# 设置工作目录
WORKDIR /app# 复制requirements.txt到容器中
COPY requirements.txt .# 安装python依赖
RUN pip install --no-cache-dir -r requirements.txt# 复制项目的所有文件到容器
COPY . .# 暴露端口
EXPOSE 8979# 指定启动命令
CMD ["python", "app.py"]click==8.0.4
colorama==0.4.5
dataclasses==0.8
Flask==2.0.3
importlib-metadata==4.8.3
itsdangerous==2.0.1
Jinja2==3.0.3
MarkupSafe==2.0.1
numpy==1.19.5
opencv-contrib-python==4.6.0.66
Pillow==8.4.0
typing_extensions==4.1.1
Werkzeug==2.0.3
zipp==3.6.0
opencv-python-headless

utils.py

import numpy as np
from PIL import Image, ImageFont, ImageDraw, ImageOpsdef sort_chars(char_list, font, language):if language == "chinese":char_width, char_height = font.getsize("制")elif language == "korean":char_width, char_height = font.getsize("ㅊ")elif language == "japanese":char_width, char_height = font.getsize("あ")elif language in ["english", "german", "french", "spanish", "italian", "portuguese", "polish"]:char_width, char_height = font.getsize("A")elif language == "russian":char_width, char_height = font.getsize("A")num_chars = min(len(char_list), 100)out_width = char_width * len(char_list)out_height = char_heightout_image = Image.new("L", (out_width, out_height), 255)draw = ImageDraw.Draw(out_image)draw.text((0, 0), char_list, fill=0, font=font)cropped_image = ImageOps.invert(out_image).getbbox()out_image = out_image.crop(cropped_image)brightness = [np.mean(np.array(out_image)[:, 10 * i:10 * (i + 1)]) for i in range(len(char_list))]char_list = list(char_list)zipped_lists = zip(brightness, char_list)zipped_lists = sorted(zipped_lists)result = ""counter = 0incremental_step = (zipped_lists[-1][0] - zipped_lists[0][0]) / num_charscurrent_value = zipped_lists[0][0]for value, char in zipped_lists:if value >= current_value:result += charcounter += 1current_value += incremental_stepif counter == num_chars:breakif result[-1] != zipped_lists[-1][1]:result += zipped_lists[-1][1]return resultdef get_data(language, mode):if language == "general":from alphabets import GENERAL as characterfont = ImageFont.truetype("fonts/DejaVuSansMono-Bold.ttf", size=20)sample_character = "A"scale = 2elif language == "english":from alphabets import ENGLISH as characterfont = ImageFont.truetype("fonts/DejaVuSansMono-Bold.ttf", size=20)sample_character = "A"scale = 2elif language == "german":from alphabets import GERMAN as characterfont = ImageFont.truetype("fonts/DejaVuSansMono-Bold.ttf", size=20)sample_character = "A"scale = 2elif language == "french":from alphabets import FRENCH as characterfont = ImageFont.truetype("fonts/DejaVuSansMono-Bold.ttf", size=20)sample_character = "A"scale = 2elif language == "italian":from alphabets import ITALIAN as characterfont = ImageFont.truetype("fonts/DejaVuSansMono-Bold.ttf", size=20)sample_character = "A"scale = 2elif language == "polish":from alphabets import POLISH as characterfont = ImageFont.truetype("fonts/DejaVuSansMono-Bold.ttf", size=20)sample_character = "A"scale = 2elif language == "portuguese":from alphabets import PORTUGUESE as characterfont = ImageFont.truetype("fonts/DejaVuSansMono-Bold.ttf", size=20)sample_character = "A"scale = 2elif language == "spanish":from alphabets import SPANISH as characterfont = ImageFont.truetype("fonts/DejaVuSansMono-Bold.ttf", size=20)sample_character = "A"scale = 2elif language == "russian":from alphabets import RUSSIAN as characterfont = ImageFont.truetype("fonts/DejaVuSansMono-Bold.ttf", size=20)sample_character = "Ш"scale = 2elif language == "chinese":from alphabets import CHINESE as characterfont = ImageFont.truetype("fonts/simsun.ttc", size=10)sample_character = "制"scale = 1elif language == "korean":from alphabets import KOREAN as characterfont = ImageFont.truetype("fonts/arial-unicode.ttf", size=10)sample_character = "ㅊ"scale = 1elif language == "japanese":from alphabets import JAPANESE as characterfont = ImageFont.truetype("fonts/arial-unicode.ttf", size=10)sample_character = "お"scale = 1else:print("Invalid language")return None, None, None, Nonetry:if len(character) > 1:char_list = character[mode]else:char_list = character["standard"]except:print("Invalid mode for {}".format(language))return None, None, None, Noneif language != "general":char_list = sort_chars(char_list, font, language)return char_list, font, sample_character, scale

支持开源:

vietnh1009/ASCII-generator: ASCII generator (image to text, image to image, video to video) (github.com)

相关文章:

python图像彩色数字化

效果展示&#xff1a; 目录结构&#xff1a; alphabets.py GENERAL {"simple": "%#*-:. ","complex": "$B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_~<>i!lI;:,\"^. " } # Full list could be found here…...

cesium 3dtile ClippingPlanes 多边形挖洞ClippingPlaneCollection

原理就是3dtiles里面的属性clippingPlanes 采用ClippingPlaneCollection&#xff0c;构成多边形来挖洞。 其次就是xyz法向量挖洞 clippingPlanes: new this.ffCesium.Cesium.ClippingPlaneCollection({unionClippingRegions: true, // true 表示多个切割面能合并为一个有效的…...

docker 僵尸进程问题

docker僵尸进程 子进程结束后&#xff0c;父进程没有回收该进程资源&#xff08;父进程可能没有wait&#xff09;&#xff0c;子进程残留资源存放与内核中&#xff0c;就变为僵尸进程(zombie) 场景分析&#xff1a;python脚本A中执行B应用&#xff0c;将A部署在docker中&#…...

微软要求 Windows Insider 用户试用备受争议的召回功能

拥有搭载 Qualcomm Snapdragon 处理器的 Copilot PC 的 Windows Insider 计划参与者现在可以试用 Recall&#xff0c;这是一项臭名昭著的快照拍摄 AI 功能&#xff0c;在今年早些时候推出时受到了很多批评。 Windows 营销高级总监 Melissa Grant 上周表示&#xff1a;“我们听…...

husky,commit规范,生成CHANGELOG.md,npm发版

项目git提交工程化&#xff08;钩子&#xff0c;提交信息commit message&#xff09;&#xff0c;npm修改版本&#xff0c;需要涉及到的包&#xff1a; husky&#xff0c;允许在git钩子中执行不同的脚步&#xff0c;如commitlint&#xff0c;eslint&#xff0c;prettier&#…...

DETR:一种新颖的端到端目标检测与分割框架

DETR&#xff1a;一种新颖的端到端目标检测与分割框架 摘要&#xff1a; 随着深度学习技术的发展&#xff0c;目标检测和图像分割任务取得了显著的进步。然而&#xff0c;传统的基于区域提名的方法在处理这些问题时存在一定的局限性。为此&#xff0c;Facebook AI Research&am…...

前端js面试知识点思维导图(脑图)

如果看着不清晰可以去https://download.csdn.net/download/m0_73761441/90058523访问下载&#xff0c;无需积分 使用百度脑图制作&#xff0c;可以一键导入下面的文本生成自己的脑图 js相关面试题、知识点 数据类型 1. 数据类型分类&#xff1f;分别包含&#xff…...

【Java基础入门篇】一、变量、数据类型和运算符

Java基础入门篇 一、变量、数据类型和运算符 1.1 变量 计算机中的数据表示方式是&#xff1a;“二进制(0/1)”&#xff0c;但是同时也可以兼容其他进制&#xff0c;例如八进制、十进制、十六进制等。 Java变量的本质是&#xff1a;存储在固定空间的内容&#xff0c;变量名是…...

【llamafactory】安装与环境配置

拉取镜像 git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git cd LLaMA-Factory创建虚拟环境 conda create -n llamafactory python3.10 conda activate llamafactory安装所需依赖 pip install -e ".[torch,vllm,optimum,auto_gptq]"...

Vue 3 + Vuex 埋点实现指南

在现代前端开发中&#xff0c;数据分析和用户行为追踪是不可或缺的部分。本文将介绍如何在 Vue 3 项目中实现埋点功能&#xff0c;具体使用 Vuex 进行状态管理&#xff0c;并通过自定义 Hook 实现埋点逻辑。 目录 项目结构实现埋点逻辑使用埋点功能总结 1.项目结构 我们将创…...

电子应用设计方案-30:智能扫地机器人系统方案设计

智能扫地机器人系统方案设计 一、引言 随着人们生活节奏的加快和对生活品质的追求&#xff0c;智能家居产品越来越受到消费者的青睐。智能扫地机器人作为一种能够自动清扫地面的智能设备&#xff0c;为人们节省了大量的时间和精力。本方案旨在设计一款功能强大、智能化程度高、…...

HTML飞舞的爱心(完整代码)

写在前面 HTML语言实现飞舞的爱心完整代码。 完整代码 <!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><title>飞舞爱心</title><style>* {margin: 0;padding: 0;}html,body {overflow: hidd…...

android shader gl_Position是几个分量

在Android的OpenGL ES中&#xff0c;gl_Position是顶点着色器&#xff08;Vertex Shader&#xff09;的一个内置输出变量&#xff0c;它用于指定顶点在裁剪空间&#xff08;Clip Space&#xff09;中的位置。gl_Position是一个四维向量&#xff08;4-component vector&#xff…...

spine 动画层 动态权重

前奏.业务背景 这边想实现一个功能&#xff0c;项目中有 一只猫 猫的头会盯着逗猫棒移动。因为素材还没到所以这里使用了 spine 自带的猫头鹰。他的动画 刚好挺有针对性&#xff1a;&#xff08;关联上篇&#xff09;https://blog.csdn.net/nicepainkiller/article/details/144…...

《Python基础》之Python中可以转换成json数据类型的数据

目录 一、JSON简介 JSON有两种基本结构 1、对象&#xff08;Object&#xff09; 2、数组&#xff08;Array&#xff09; 二、将数据装换成json数据类型方法 三、在Python中&#xff0c;以下数据类型可以直接转换为JSON数据类型 1、字典&#xff08;Dictionary&#xff09…...

在oracle下载jdk显示400 Bad Request Request Header Or Cookie Too Large

下载JDK17&#xff0c;官网地址&#xff1a;【https://www.oracle.com/cn/java/technologies/downloads/#jdk17-windows】 问题&#xff1a; 出现 400 Bad Request: Request Header Or Cookie Too Large 错误&#xff0c;通常是由于浏览器存储的 Cookies 或请求头过大所导致的…...

MongoDB注入攻击测试与防御技术深度解析

MongoDB注入攻击测试与防御技术深度解析 随着NoSQL数据库的兴起&#xff0c;MongoDB作为其中的佼佼者&#xff0c;因其灵活的数据模型和强大的查询能力&#xff0c;受到了众多开发者的青睐。然而&#xff0c;与任何技术一样&#xff0c;MongoDB也面临着安全威胁&#xff0c;其…...

【Java基础入门篇】前言

Java基础入门篇 本系列内容主要针对Java基础知识&#xff0c;总共包含四大部分内容&#xff1a; 变量、数据类型和运算符控制语句和递归算法面向对象和JVM底层分析数组和排序 学习需要具备&#xff1a; IDEA编译器 JDK1.8版本 写在前面 在Java入门的最开始&#xff0c;我们需…...

Oracle 建表的存储过程

建表的存储过程 下面是建表的存储过程&#xff0c;用途&#xff1a;通过不同的表&#xff0c;根据不同过滤条件&#xff0c;得到某个字段&#xff0c;例如neid&#xff0c;然后创建一个新表T&#xff0c;表T的表名为拼接XXXX_XXX_neid&#xff0c;表T的字段自行添加 xxx&…...

【Debug】hexo-github令牌认证 Support for password authentication was removed

title: 【Debug】hexo-github令牌认证 date: 2024-07-19 14:40:54 categories: bug解决日记 description: “Support for password authentication was removed on August 13, 2021.” cover: https://pic.imgdb.cn/item/669b38ebd9c307b7e9f3e5e0.jpg 第一章 第一篇博客记录一…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录

ASP.NET Core 是一个跨平台的开源框架&#xff0c;用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录&#xff0c;以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

Spring Boot 实现流式响应(兼容 2.7.x)

在实际开发中&#xff0c;我们可能会遇到一些流式数据处理的场景&#xff0c;比如接收来自上游接口的 Server-Sent Events&#xff08;SSE&#xff09; 或 流式 JSON 内容&#xff0c;并将其原样中转给前端页面或客户端。这种情况下&#xff0c;传统的 RestTemplate 缓存机制会…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明&#xff1a;server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

基于PHP的连锁酒店管理系统

有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...

C语言中提供的第三方库之哈希表实现

一. 简介 前面一篇文章简单学习了C语言中第三方库&#xff08;uthash库&#xff09;提供对哈希表的操作&#xff0c;文章如下&#xff1a; C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理

在城市的某个角落&#xff0c;一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延&#xff0c;滚滚浓烟弥漫开来&#xff0c;周围群众的生命财产安全受到严重威胁。就在这千钧一发之际&#xff0c;消防救援队伍迅速行动&#xff0c;而豪越科技消防一体化安全管控平台构建的消防“…...