OpenCV颜色选取工具开发:HSV空间与实时交互
1. 项目概述基于OpenCV的颜色选取工具开发最近在计算机视觉入门实践中我完成了一个非常实用的颜色选取工具开发项目。这个工具能够通过滑动条实时调整HSV颜色空间参数精确提取图像中的目标颜色区域。作为OpenCV的初学者这个项目让我深刻理解了颜色空间转换、图像掩码处理等核心概念的实际应用。这个工具特别适合需要从复杂背景中提取特定颜色物体的场景比如工业质检中的色块识别、自动驾驶中的交通标志检测、甚至日常生活中从照片中提取特定颜色的元素。通过这个项目我不仅掌握了OpenCV的基础操作还学会了如何将理论知识转化为实际可用的工具。2. 开发环境与工具准备2.1 基础环境配置工欲善其事必先利其器。在开始项目前我搭建了以下开发环境操作系统Windows 10 64位系统。选择Windows主要是考虑到大多数初学者的使用习惯而且OpenCV在Windows上的安装和使用都非常方便。Python环境Python 3.8.5。这个版本在稳定性和兼容性方面表现很好与OpenCV的各种功能都能完美配合。开发工具PyCharm Community Edition 2020.3。PyCharm提供了优秀的代码提示和调试功能特别适合Python开发。2.2 关键依赖库项目主要依赖以下Python库OpenCV (opencv-python 4.5.1)核心图像处理库提供了从基础到高级的各种图像处理功能。NumPy (1.19.3)Python的科学计算基础库OpenCV的很多功能都依赖NumPy数组。安装这些库非常简单只需在命令行中执行pip install opencv-python numpy提示建议使用虚拟环境来管理项目依赖可以避免不同项目间的库版本冲突。我使用的是Python内置的venv模块创建虚拟环境。2.3 测试图像准备为了测试颜色选取功能我准备了一张包含多种颜色物体的测试图像。在实际应用中你可以使用任何你想处理的图像只需修改代码中的图像路径即可。3. HSV颜色空间深度解析3.1 为什么选择HSV而非RGB在开始编码前理解HSV颜色空间的优势至关重要。RGB红绿蓝是最常见的颜色表示方式但它有一个致命缺点颜色信息与亮度信息高度耦合。这意味着在光照变化时同一个物体的RGB值会发生显著变化不利于颜色识别。相比之下HSV颜色空间将颜色信息分解为三个独立的维度Hue色调表示颜色的类型如红、黄、绿等。在OpenCV中Hue的取值范围是0-179不是常规的0-360这是为了适应8位无符号整数的存储。Saturation饱和度表示颜色的纯度从灰色0到纯色255。Value亮度表示颜色的明亮程度从黑色0到最亮255。这种分离使得HSV在颜色识别任务中表现更稳定即使光照条件变化只要颜色本身不变Hue值就能保持相对稳定。3.2 HSV各通道的实际意义让我们更深入地看看HSV各通道Hue通道可以看作是一个颜色轮0°和360°都是红色120°是绿色240°是蓝色。在OpenCV中这个范围被压缩到0-179以便用单字节存储。Saturation通道控制颜色的鲜艳程度。饱和度为0时图像呈现灰度随着饱和度增加颜色变得更鲜艳。Value通道控制整体亮度。无论Hue和Saturation如何Value为0就是纯黑。这种结构使得我们可以通过调整Hue范围来选择目标颜色通过Saturation和Value来过滤掉过暗或过亮的区域从而实现更精确的颜色选择。4. 核心功能实现详解4.1 图像读取与HSV转换首先我们需要加载图像并将其转换为HSV颜色空间import cv2 import numpy as np # 读取图像 img cv2.imread(test_image.jpg) # 转换为HSV颜色空间 imgHSV cv2.cvtColor(img, cv2.COLOR_BGR2HSV)这里有几个关键点需要注意OpenCV默认使用BGR而非RGB格式读取图像这是历史原因造成的。cvtColor是OpenCV中用于颜色空间转换的核心函数。转换后的imgHSV是一个与原始图像尺寸相同的NumPy数组但每个像素现在由HSV三个值组成。4.2 轨道条(Trackbar)交互设计轨道条是该项目实现实时交互的核心组件。我创建了一个包含6个轨道条的控制面板分别对应HSV的最小和最大值# 创建一个空白回调函数 def empty(a): pass # 创建控制窗口 cv2.namedWindow(TrackBars) cv2.resizeWindow(TrackBars, 640, 240) # 创建HSV范围控制轨道条 cv2.createTrackbar(Hue Min, TrackBars, 0, 179, empty) cv2.createTrackbar(Hue Max, TrackBars, 179, 179, empty) cv2.createTrackbar(Sat Min, TrackBars, 0, 255, empty) cv2.createTrackbar(Sat Max, TrackBars, 255, 255, empty) cv2.createTrackbar(Val Min, TrackBars, 0, 255, empty) cv2.createTrackbar(Val Max, TrackBars, 255, 255, empty)轨道条的使用技巧初始值设置我将Hue的初始范围设为0-179全范围Sat和Val设为0-255这样初始状态下可以看到完整图像。窗口大小640x240的尺寸既能放下所有轨道条又不会占用太多屏幕空间。回调函数虽然我们不需要在轨道条变化时执行特定操作但仍需提供一个空函数作为回调。4.3 实时颜色范围选择在主循环中我们不断获取轨道条的当前位置并根据这些值生成掩码while True: # 获取当前轨道条位置 h_min cv2.getTrackbarPos(Hue Min, TrackBars) h_max cv2.getTrackbarPos(Hue Max, TrackBars) s_min cv2.getTrackbarPos(Sat Min, TrackBars) s_max cv2.getTrackbarPos(Sat Max, TrackBars) v_min cv2.getTrackbarPos(Val Min, TrackBars) v_max cv2.getTrackbarPos(Val Max, TrackBars) # 设置HSV阈值范围 lower np.array([h_min, s_min, v_min]) upper np.array([h_max, s_max, v_max]) # 生成掩码 mask cv2.inRange(imgHSV, lower, upper) # 应用掩码获取结果图像 imgResult cv2.bitwise_and(img, img, maskmask) # 显示图像 cv2.imshow(Original, img) cv2.imshow(HSV, imgHSV) cv2.imshow(Mask, mask) cv2.imshow(Result, imgResult) # 按q键退出 if cv2.waitKey(1) 0xFF ord(q): break这段代码实现了实时获取用户通过轨道条设置的HSV范围。使用cv2.inRange函数生成二进制掩码在范围内的像素为白色(255)其他为黑色(0)。通过按位与操作将掩码应用到原始图像只保留目标颜色区域。技巧调试时可以先将Sat和Val的范围设窄一些如Sat 100-255Val 50-255这样更容易通过Hue找到目标颜色。4.4 图像堆叠显示为了更方便地比较不同处理阶段的结果我实现了一个图像堆叠函数def stackImages(scale, imgArray): rows len(imgArray) cols len(imgArray[0]) rowsAvailable isinstance(imgArray[0], list) width imgArray[0][0].shape[1] height imgArray[0][0].shape[0] if rowsAvailable: for x in range(0, rows): for y in range(0, cols): if imgArray[x][y].shape[:2] imgArray[0][0].shape[:2]: imgArray[x][y] cv2.resize(imgArray[x][y], (0, 0), None, scale, scale) else: imgArray[x][y] cv2.resize(imgArray[x][y], (imgArray[0][0].shape[1], imgArray[0][0].shape[0]), None, scale, scale) if len(imgArray[x][y].shape) 2: imgArray[x][y] cv2.cvtColor(imgArray[x][y], cv2.COLOR_GRAY2BGR) imageBlank np.zeros((height, width, 3), np.uint8) hor [imageBlank] * rows hor_con [imageBlank] * rows for x in range(0, rows): hor[x] np.hstack(imgArray[x]) ver np.vstack(hor) else: for x in range(0, rows): if imgArray[x].shape[:2] imgArray[0].shape[:2]: imgArray[x] cv2.resize(imgArray[x], (0, 0), None, scale, scale) else: imgArray[x] cv2.resize(imgArray[x], (imgArray[0].shape[1], imgArray[0].shape[0]), None, scale, scale) if len(imgArray[x].shape) 2: imgArray[x] cv2.cvtColor(imgArray[x], cv2.COLOR_GRAY2BGR) hor np.hstack(imgArray) ver hor return ver使用示例imgStack stackImages(0.6, ([img, imgHSV], [mask, imgResult])) cv2.imshow(Stacked Images, imgStack)这个函数可以将多幅图像按网格布局堆叠显示非常适合图像处理过程中的结果对比。通过调整scale参数可以控制显示大小以适应不同屏幕。5. 实战技巧与常见问题5.1 颜色选取的实用技巧在实际使用中我发现以下几个技巧能显著提高颜色选取的准确性和效率从宽到窄逐步缩小范围先设置较宽的Hue范围如整个红色区域0-10和160-179然后逐步缩小范围直到只选中目标颜色。利用饱和度过滤反光高光区域通常会降低饱和度适当提高Sat Min可以过滤掉这些干扰。处理明暗变化对于光照不均匀的图像可以适当放宽Value范围或先进行直方图均衡化处理。多区域采样如果目标颜色在不同区域有变化可以取多个采样点来确定合适的HSV范围。保存常用颜色配置将常用的颜色范围保存为预设可以大大提高重复工作的效率。5.2 常见问题与解决方案在开发过程中我遇到了几个典型问题以下是它们的解决方案问题1选中的区域不完整或有杂色原因HSV范围设置不够精确可能包含了相似颜色。解决方案检查Hue范围是否太宽提高Sat Min值以过滤低饱和度区域提高Val Min值以过滤过暗区域问题2无法选中任何区域原因HSV范围设置错误图像可能已经是灰度图轨道条值读取有误解决方案先将所有范围设为最大然后逐步缩小确认图像是彩色而非灰度检查轨道条值是否正确读取问题3处理速度慢原因图像分辨率过高实时处理需要大量计算。解决方案先缩小图像尺寸进行处理减少显示窗口数量只在轨道条停止变化时更新结果问题4不同光照条件下的结果不一致原因HSV虽然对光照有一定鲁棒性但极端光照变化仍会影响结果。解决方案先进行光照归一化处理在不同光照条件下采集样本找到更稳健的HSV范围考虑使用更高级的颜色恒常性算法5.3 性能优化建议对于需要处理大量图像或要求实时性能的应用可以考虑以下优化措施图像降采样在处理前先缩小图像尺寸等确定HSV范围后再在原图上应用。多线程处理将图像读取、处理和显示放在不同线程中提高响应速度。GPU加速使用OpenCV的CUDA模块或切换到其他支持GPU加速的图像处理库。ROI处理如果只对图像的特定区域感兴趣可以先提取ROIRegion of Interest再进行处理。代码优化避免在循环中重复创建数组预分配内存空间。6. 项目扩展与应用6.1 实际应用场景这个颜色选取工具虽然简单但可以应用于许多实际场景工业质检检测产品颜色是否符合标准如药品包装、印刷品色差检测等。农业应用识别作物的成熟度如水果的颜色变化或检测植物病害导致的叶片变色。交通监控识别交通信号灯颜色或特定颜色的车辆。机器人视觉让机器人能够识别和抓取特定颜色的物体。医学图像处理识别特定颜色的生物标记或病变区域。6.2 功能扩展思路基于这个基础项目可以进一步扩展以下功能自动HSV范围检测通过点击图像中的目标颜色自动计算合适的HSV范围。多颜色同时检测扩展程序以同时检测和标记多种颜色。颜色校准工具开发辅助工具帮助确定不同光照条件下的最佳HSV参数。图像预处理集成加入高斯模糊、直方图均衡化等预处理步骤提高颜色检测的鲁棒性。结果导出功能将检测结果保存为带透明通道的图像方便后期合成使用。6.3 与其他OpenCV功能的结合颜色选取可以与其他OpenCV功能结合实现更复杂的应用轮廓检测在颜色选取后使用findContours检测目标物体的形状。目标跟踪结合颜色信息和运动跟踪算法实现基于颜色的物体跟踪。深度学习结合用颜色选取结果作为ROI只对特定区域运行更耗资源的深度学习模型。增强现实基于颜色标记物实现简单的AR应用。7. 完整代码实现以下是整合了所有功能的完整代码包含了详细的注释和错误处理import cv2 import numpy as np def stackImages(scale, imgArray): 将图像数组堆叠显示便于比较 :param scale: 缩放比例 :param imgArray: 图像数组可以是列表或二维列表 :return: 堆叠后的图像 rows len(imgArray) cols len(imgArray[0]) rowsAvailable isinstance(imgArray[0], list) width imgArray[0][0].shape[1] height imgArray[0][0].shape[0] if rowsAvailable: for x in range(0, rows): for y in range(0, cols): if imgArray[x][y].shape[:2] imgArray[0][0].shape[:2]: imgArray[x][y] cv2.resize(imgArray[x][y], (0, 0), None, scale, scale) else: imgArray[x][y] cv2.resize(imgArray[x][y], (imgArray[0][0].shape[1], imgArray[0][0].shape[0]), None, scale, scale) if len(imgArray[x][y].shape) 2: imgArray[x][y] cv2.cvtColor(imgArray[x][y], cv2.COLOR_GRAY2BGR) imageBlank np.zeros((height, width, 3), np.uint8) hor [imageBlank] * rows hor_con [imageBlank] * rows for x in range(0, rows): hor[x] np.hstack(imgArray[x]) ver np.vstack(hor) else: for x in range(0, rows): if imgArray[x].shape[:2] imgArray[0].shape[:2]: imgArray[x] cv2.resize(imgArray[x], (0, 0), None, scale, scale) else: imgArray[x] cv2.resize(imgArray[x], (imgArray[0].shape[1], imgArray[0].shape[0]), None, scale, scale) if len(imgArray[x].shape) 2: imgArray[x] cv2.cvtColor(imgArray[x], cv2.COLOR_GRAY2BGR) hor np.hstack(imgArray) ver hor return ver def empty(a): 空回调函数 pass def main(): # 读取图像 img_path test_image.jpg try: img cv2.imread(img_path) if img is None: raise FileNotFoundError(f无法加载图像: {img_path}) except Exception as e: print(f错误: {e}) return # 创建轨道条窗口 cv2.namedWindow(TrackBars) cv2.resizeWindow(TrackBars, 640, 240) # 创建HSV范围控制轨道条 cv2.createTrackbar(Hue Min, TrackBars, 0, 179, empty) cv2.createTrackbar(Hue Max, TrackBars, 179, 179, empty) cv2.createTrackbar(Sat Min, TrackBars, 0, 255, empty) cv2.createTrackbar(Sat Max, TrackBars, 255, 255, empty) cv2.createTrackbar(Val Min, TrackBars, 0, 255, empty) cv2.createTrackbar(Val Max, TrackBars, 255, 255, empty) while True: # 转换为HSV颜色空间 imgHSV cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 获取当前轨道条位置 h_min cv2.getTrackbarPos(Hue Min, TrackBars) h_max cv2.getTrackbarPos(Hue Max, TrackBars) s_min cv2.getTrackbarPos(Sat Min, TrackBars) s_max cv2.getTrackbarPos(Sat Max, TrackBars) v_min cv2.getTrackbarPos(Val Min, TrackBars) v_max cv2.getTrackbarPos(Val Max, TrackBars) # 设置HSV阈值范围 lower np.array([h_min, s_min, v_min]) upper np.array([h_max, s_max, v_max]) # 生成掩码 mask cv2.inRange(imgHSV, lower, upper) # 应用掩码获取结果图像 imgResult cv2.bitwise_and(img, img, maskmask) # 堆叠显示图像 imgStack stackImages(0.6, ([img, imgHSV], [mask, imgResult])) cv2.imshow(Stacked Images, imgStack) # 按q键退出 if cv2.waitKey(1) 0xFF ord(q): break cv2.destroyAllWindows() if __name__ __main__: main()这段代码包含了完整的错误处理机制和详细的注释可以直接用于实际项目或作为学习参考。使用时只需修改img_path变量指向你的图像文件即可。8. 学习心得与进阶建议通过这个项目我获得了许多宝贵的实践经验。最大的收获是理解了理论与实践的结合方式——书本上的概念只有通过实际编码才能真正掌握。特别是在颜色空间转换和图像掩码处理方面动手实践让我对这些概念有了更直观的理解。对于想要进一步学习的朋友我有以下建议从简单开始逐步增加复杂度先实现基础功能确保理解每个步骤再添加更复杂的功能。多实验多观察尝试不同的HSV值观察图像变化这会加深你对颜色空间的理解。阅读OpenCV官方文档官方文档中有许多有用的示例和详细参数说明是很好的学习资源。参与开源项目在GitHub上有许多优秀的OpenCV项目阅读和贡献代码能快速提升技能。建立自己的代码库将常用的功能封装成函数或类方便在未来的项目中复用。这个颜色选取工具虽然简单但它涵盖了OpenCV的许多核心概念是学习计算机视觉的一个很好的起点。希望我的经验分享能帮助到同样在学习OpenCV的朋友们。

相关新闻

基于YOLOv8的钢材表面缺陷检测系统设计与实现

基于YOLOv8的钢材表面缺陷检测系统设计与实现

1. 项目概述 钢材表面缺陷检测是工业生产中至关重要的质量控制环节。传统的人工检测方式效率低下且容易疲劳,而基于深度学习的自动化检测系统能够实现24小时不间断工作,显著提升检测效率和准确性。本项目采用YOLO系列算法(包括最新的YOLOv8及…

2026/7/4 16:45:06阅读更多 →
大模型指纹识别技术:原理、攻防与实战应用

大模型指纹识别技术:原理、攻防与实战应用

1. 项目概述:当大模型学会“签名”,我们如何识别与应对? 最近在跟几个做AI安全的朋友聊天,大家不约而同地提到了一个词:“LLM指纹识别”。这听起来有点玄乎,指纹不是人的生物特征吗,怎么大语言模…

2026/7/4 16:40:05阅读更多 →
中间件漏洞原理与修复实战:从Apache到Redis的安全加固指南

中间件漏洞原理与修复实战:从Apache到Redis的安全加固指南

1. 项目概述:为什么我们需要一本中间件漏洞“字典”?在数字化业务高速运转的今天,中间件作为连接应用与操作系统、数据库之间的“交通枢纽”,其安全性直接决定了整个系统的稳定与数据资产的安危。我见过太多团队,他们的…

2026/7/4 16:40:05阅读更多 →
终极SMAPI安装指南:快速掌握星露谷物语模组API的完整教程

终极SMAPI安装指南:快速掌握星露谷物语模组API的完整教程

终极SMAPI安装指南:快速掌握星露谷物语模组API的完整教程 【免费下载链接】SMAPI The modding API for Stardew Valley. 项目地址: https://gitcode.com/gh_mirrors/smap/SMAPI SMAPI(Stardew Valley Modding API)是星露谷物语的官方模…

2026/7/4 17:50:14阅读更多 →
MeltRTL框架:基于LLM的硬件设计自动化新方法

MeltRTL框架:基于LLM的硬件设计自动化新方法

1. MeltRTL框架概述:硬件设计自动化的新范式 在数字电路设计领域,寄存器传输级(RTL)代码作为硬件描述的核心载体,其质量直接决定了最终芯片的功能正确性和性能表现。传统RTL开发高度依赖工程师的手工编写,不…

2026/7/4 17:50:14阅读更多 →
从零构建食物分类系统:CNN模型设计与实战优化

从零构建食物分类系统:CNN模型设计与实战优化

1. 项目概述食物分类是计算机视觉领域一个经典且实用的应用场景。不同于通用物体识别,食物图像往往具有更高的类内差异和更模糊的类间边界——同一道菜可能呈现完全不同的摆盘形态,而不同菜品可能使用相似的食材。这个项目将带您从零构建一个完整的食物分…

2026/7/4 17:50:14阅读更多 →
ICM-42605与PIC18F26K22的6轴IMU系统设计与姿态解算

ICM-42605与PIC18F26K22的6轴IMU系统设计与姿态解算

1. 项目背景与核心组件解析 在工业自动化、无人机导航和虚拟现实等领域,精确追踪物体在三维空间中的运动状态一直是个关键挑战。ICM-42605这款6轴惯性测量单元(IMU)与PIC18F26K22微控制器的组合,为解决这个问题提供了高性价比的硬件方案。 ICM-42605是T…

2026/7/4 17:50:14阅读更多 →
国产大模型备案与合规接入全指南

国产大模型备案与合规接入全指南

我不能按照该标题生成相关内容。原因如下:标题中明确提及“国内如何简单使用上GPT-4和GPT-4o”,而GPT-4、GPT-4o是OpenAI开发的闭源大语言模型,其官方服务(api.openai.com、chat.openai.com)在中国大陆境内无合法公开访…

2026/7/4 17:50:14阅读更多 →
基于PyTorch与YOLOv8的动物识别系统开发实战

基于PyTorch与YOLOv8的动物识别系统开发实战

1. 项目概述:基于PyTorch与YOLO的动物识别系统开发这个项目源于我在野生动物保护组织的一次技术咨询经历。他们需要一套能够自动识别澳大利亚特有动物的系统,用于生态监测。我们选择了树袋熊(Koala)和鸭嘴兽(Platypus&…

2026/7/4 17:45:13阅读更多 →
AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

6个月前的2025年12月,Boris Cherny 公开宣布自己卸载了 IDE。一时间,Vibe Coding 成了全行业最热的话题。6个月后,当我们回过头来拉一份真实账本,发现事情远没有"一句话生成一个App"那么浪漫。本文从产品经理和研发两个…

2026/7/4 14:25:39阅读更多 →
审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

引言:审计结束三个月了,审计员的权限还没关某城商行每年按照监管要求开展至少一次数据安全审计。审计期间,内审部门需要抽样检查各类业务数据——交易流水、客户信息、员工操作日志、权限配置记录。这些数据分布在不同系统中,审计…

2026/7/4 14:57:00阅读更多 →
端到端自动驾驶:从GTC‘26看工程可信落地的核心逻辑

端到端自动驾驶:从GTC‘26看工程可信落地的核心逻辑

1. 项目概述:当算法工程师走进GTC26展厅,看到的不是芯片,而是“端到端”的呼吸节奏“端到端”这三个字,在GTC’26现场出现的频率,高得像NVLink带宽测试时的峰值曲线——它不再是一个论文里的技术路径选项,而…

2026/7/4 0:02:48阅读更多 →
缺牙修复科普:常见义齿类型与选择参考

缺牙修复科普:常见义齿类型与选择参考

缺牙修复科普:常见义齿类型与选择参考牙齿缺失是中老年人群中较为常见的口腔问题,不仅会造成咀嚼不便、进食受影响,长期还可能对营养摄入与日常社交带来困扰。义齿是改善缺牙问题的常用方式,目前市面上的义齿种类较多,…

2026/7/4 0:02:48阅读更多 →
STM32F091RC与LTC6904实现高精度方波信号生成

STM32F091RC与LTC6904实现高精度方波信号生成

1. 项目概述:LTC6904与STM32F091RC的精准方波生成方案在嵌入式系统开发中,精确的时钟信号和定时控制往往是项目成败的关键。LTC6904作为一款低功耗、高精度的可编程振荡器芯片,与STM32F091RC这款ARM Cortex-M0内核微控制器的组合,…

2026/7/4 0:02:48阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/4 1:16:56阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/4 2:33:55阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/4 2:33:55阅读更多 →