OpenCV图像基础
目录
显示窗口
创建空白图像
保存图片
图像裁剪
调整图片大小
图像绘制
绘制圆形
绘制矩形
绘制直线
绘制文本
中文乱码
控制鼠标
视频处理
显示窗口
cv2.namedWindow(winname, flags=None)
创建一个命名窗口,以便在该窗口中显示图像或进行其他图形操作。
参数说明
-
winname (str): 窗口的名称。这个名称必须是唯一的,因为它是用来标识窗口的。
-
flags (int, 可选): 窗口的标志,用于设置窗口的行为。默认值为cv2.WINDOW_AUTOSIZE
flags 常见的标志包括:
-
cv2.WINDOW_NORMAL: 允许调整窗口大小。 -
cv2.WINDOW_AUTOSIZE: 窗口大小根据图像大小自动调整,不能手动调整。
-
# 创建一个名为 "IMG" 的窗口,cv2.WINDOW_NORMAL设置允许调整大小
cv2.namedWindow('IMG', cv2.WINDOW_NORMAL)
# 2 设置名字和窗口大小(width,height)
cv2.resizeWindow('IMG', (500, 300))
# 读取图片
# 1.支持相对路径和绝对路径,2.图片路径不能包含中文
try:img = cv2.imread('pic/test1.jpg')# 显示图像cv2.imshow('IMG', img)# 等待用户按键cv2.waitKey(0)# 释放资源cv2.destroyAllWindows()except Exception as e:print(e)print("图片不存在")
创建空白图像
np.zeros((height, width, 3))
创建一个全零数组,这个数组可以表示一个空白图像。数组的形状应该符合图像的尺寸和通道数,例如,对于 RGB 图像,形状应为 (height, width, 3)
image = np.zeros((300, 500, 3), dtype=np.uint8)
cv2.imshow('img',image)
cv2.waitKey(0)
保存图片
cv2.imwrite(filename, img[, params])
用于将图像保存到文件中。
参数说明
-
filename (str): 要保存的文件路径和名称。支持的文件格式包括
.jpg,.png,.bmp,.tiff等。 -
img (numpy.ndarray): 要保存的图像。通常是一个二维或三维的 NumPy 数组,表示图像的像素值。
返回值
-
bool: 成功保存图像返回
True,否则返回False。
import cv2# 读取图片
img = cv2.imread("images/car.png")
# 保存图片
rs = cv2.imwrite("save_image/car.png", img)
if rs:print("图像保存成功!")
else:print("图像保存失败!")
注意:
确保提供的文件路径是有效的,如果路径不存在,OpenCV 会尝试创建它,但如果权限不足则会保存失败。
图像裁剪
img[y:y+h, x:x+w]
在 OpenCV 中,图像切片用于从图像中提取一个子区域(矩形区域)。比如在目标检测、ROI(Region of Interest,感兴趣区域)提取等任务有用。
说明:
图像 img,类型: numpy.ndarray。
-
x: 子区域左上角的 x 坐标。
-
y: 子区域左上角的 y 坐标。
-
w: 子区域的宽度。
-
h: 子区域的高度。
img = cv2.imread('pic/test2.png')# 定义坐标
x=100
y=150
w=150
h=100sub_img =img[y:y+h,x:x+w]
cv2.imshow("sub_img",sub_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
注意:
-
边界检查:确保
(x, y)和(x+w, y+h)都在图像的边界内,否则会导致数组索引越界错误。 -
数据类型:
img通常是numpy.ndarray类型,切片操作返回的也是numpy.ndarray类型。
调整图片大小
cv2.resize(src, dsize, dst)
用于调整图像的大小,对图像进行缩放、放大或缩小以适应不同需求。
参数说明
-
src (numpy.ndarray): 输入图像,通常是一个二维或三维的 NumPy 数组。
-
dsize (tuple): 输出图像的尺寸,是一个二元组
(width, height)
返回值
-
dst (numpy.ndarray): 缩放后的图像。
import cv2img = cv2.imread("images/car.png")
#获取图片的像素和通道数
height, width, channels = img.shape
print(f"高度:{height},宽度:{width},通道数:{channels}")
#调整图片的大小
img = cv2.resize(img, (300, 300))
height, width, channels = img.shape
print(f"调整后:高度:{height},宽度:{width},通道数:{channels}")
#保存图片
cv2.imwrite("save_image/car.png", img)
图像绘制
绘制圆形
cv2.circle(img, center, radius, color, thickness)
参数:
-
img:要绘制圆形的图像。 -
center:圆心的坐标。 -
radius:圆的半径。 -
color:圆的颜色,通常是一个表示BGR颜色的元组,例如(255, 0, 0)表示蓝色。 -
thickness:圆的边界线条的厚度,如果为负值或cv2.FILLED,表示填充整个圆。
img = cv2.imread('pic/test2.png')center = (150, 150)
radius = 100
color = (158, 56, 200)
thickness = 25
circle_img = cv2.circle(img, center, radius, color, thickness)
cv2.imshow("circle_img", circle_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
绘制矩形
cv2.rectangle(img, pt1, pt2, color[, thickness[, lineType[, shift]]])
参数:
-
img:要绘制矩形的图像。 -
pt1:矩形的一个顶点。 -
pt2:矩形对角线上的另一个顶点。 -
color:矩形的颜色,通常是一个表示BGR颜色的元组,例如(255, 0, 0)表示蓝色。 -
thickness:矩形边框的厚度,如果为负值或cv2.FILLED,表示填充整个矩形内部。
img = cv2.imread('pic/test.jpg')left_top = (100,100)
right_bottom = (300,400)
color = (151,48,12)
thickness=10
img_rectangle = cv2.rectangle(img,[100,200,300,400],color,thickness)
cv2.imshow("img_rectangle", img_rectangle)
cv2.waitKey(0)
cv2.destroyAllWindows()
绘制直线
cv2.line(img, pt1, pt2, color, thickness lineType)
参数:
-
img: 输出图像,即要在这张图上绘制直线的图像。通常是一个 NumPy 数组。
-
pt1: 直线的一个端点,是一个包含两个元素(x, y)的元组,代表该点的坐标。
-
pt2: 直线的另一个端点,也是一个包含两个元素(x, y)的元组,代表该点的坐标。
-
color: 直线的颜色,对于 BGR 图像,这应该是一个包含三个整数的元组,分别对应蓝色、绿色和红色的强度(例如
(255, 0, 0)表示纯蓝色)。对于灰度图像,只需要一个整数值即可。 -
thickness: 可选参数,定义直线的宽度。默认值是 1。
返回值
-
img: 返回的是经过修改后的图像,实际上就是传入的图像本身,因为
cv2.line()是直接在原图上操作的。
import cv2img = cv2.imread("images/car.png")# 定义直线的起点和终点
start_point = (50, 50) # 起点坐标 (x1, y1)
end_point = (450, 450) # 终点坐标 (x2, y2)# 定义颜色 (B, G, R) 和线条粗细
color = (255, 0, 0) # 蓝色
thickness = 2 # 线条的宽度# 使用 cv2.line() 在图像上绘制直线
cv2.line(img, start_point, end_point, color, thickness)# 显示图像
cv2.imshow('Image with Line', img)# 等待按键,然后关闭窗口
cv2.waitKey(0)
cv2.destroyAllWindows()
绘制文本
cv2.putText(img, text, org, fontFace, fontScale, color[, thickness[, lineType[, bottomLeftOrigin]]])
用于在图像上添加文本。用于标注图像、显示信息或调试时。
参数:
-
img (numpy.ndarray): 输入图像,通常是一个二维或三维的 NumPy 数组。
-
text (str): 要添加的文本字符串。
-
org (tuple): 文本的起始位置,是一个二元组
(x, y),表示文本左下角的坐标。 -
fontFace
(int): 字体类型,常见的字体类型包括:
-
cv2.FONT_HERSHEY_SIMPLEX: 正常大小的无衬线字体 -
cv2.FONT_HERSHEY_PLAIN: 小号的无衬线字体 -
cv2.FONT_HERSHEY_DUPLEX: 正常大小的无衬线字体,比FONT_HERSHEY_SIMPLEX更粗 -
cv2.FONT_HERSHEY_COMPLEX: 正常大小的有衬线字体 -
cv2.FONT_HERSHEY_TRIPLEX: 正常大小的有衬线字体,比FONT_HERSHEY_COMPLEX更粗 -
cv2.FONT_HERSHEY_SCRIPT_SIMPLEX: 手写风格的字体 -
cv2.FONT_HERSHEY_SCRIPT_COMPLEX: 手写风格的字体,比FONT_HERSHEY_SCRIPT_SIMPLEX更粗 -
cv2.FONT_ITALIC: 斜体修饰符,可以与其他字体类型组合使用
-
-
fontScale (float): 字体大小的比例因子。
-
color (tuple): 文本颜色,是一个三元组
(B, G, R),表示蓝色、绿色和红色的值。 -
thickness (int, 可选): 文本线条的厚度,默认值为 1。
-
lineType
(int, 可选): 线条类型,常见的线条类型包括:
-
cv2.LINE_4: 4 连通线 -
cv2.LINE_8: 8 连通线 -
cv2.LINE_AA: 抗锯齿线(默认值)
-
返回值
-
img (numpy.ndarray): 添加文本后的图像。
import cv2
import numpy as npimage = cv2.imread("images/car.png")# 定义文本内容和位置
text = "hello world!"
# 文本的左下角位置
position = (50, 200)
# 设置字体类型
font = cv2.FONT_HERSHEY_SIMPLEX
#字体大小
font_scale = 1
#字体颜色
font_color = (0, 255, 0)
#字体线条的粗细
line_type = 2# 在图像上绘制文本
cv2.putText(image, text, position, font, font_scale, font_color, line_type)
# 显示图像
cv2.imshow(' Text', image)
cv2.waitKey(0)
cv2.destroyAllWindows()# 保存图像(可选)
cv2.imwrite('output_image.png', image)
中文乱码
(1)安装库:
pip install opencv-python pillow
(2)下载一个中文字体文件,常见的中文字体文件有 simhei.ttf、simsun.ttc 等。你可以从系统中找到这些字体文件,或者从互联网下载。
(3)定义 put_text 函数
示例:
def put_text(image, text, position, font_path, font_size, color):# 将Opencv图像转换为PIL图像pil_image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))# 创建一个在给定图像绘图的对象draw = ImageDraw.Draw(pil_image)# 加载字体font = ImageFont.truetype(font_path, font_size)# 在图像上绘制文字draw.text(position, text, fill=color, font=font)# 将PIL图像转回Opencv图像image_with_text = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR)return image_with_textdef show(even, x, y, flag, param):global img2global numif even == cv2.EVENT_LBUTTONDOWN:num += 1text1 = f'老铁们,上火箭,火箭数:{num}'img2 = put_text(img, text1, (10, 10), 'simhei.ttf',20, (225, 241, 14))img = cv2.imread('pic/test.jpg')
img2 =img
# 火箭数
num = 0win_name = 'IMG'
cv2.namedWindow(win_name)
cv2.setMouseCallback(win_name, show)
while True:cv2.imshow(win_name, img2 )if cv2.waitKey(1) == 27:break
cv2.destroyAllWindows()
控制鼠标
cv2.setMouseCallback()
允许用户定义一个回调函数,当鼠标事件发生时(如点击、释放、移动等),该回调函数会被调用。
def act(even, x, y, flag, param):global condif even == cv2.EVENT_LBUTTONDOWN:print("鼠标左键按下")cond = Trueelif even == cv2.EVENT_LBUTTONUP:print("鼠标左键释放")cond = Falseelif even == cv2.EVENT_MOUSEMOVE:print("鼠标移动")if cond:cv2.circle(img, (x, y), 5, (150, 125, 205), -1)else:print("无法识别")img = cv2.imread('pic/test.jpg')win_name = 'IMG'
cv2.namedWindow(win_name, cv2.WINDOW_NORMAL)
cv2.resizeWindow(win_name, (500, 400))
# 活动信号
cond = False
cv2.setMouseCallback(win_name, act)while True:cv2.imshow(win_name, img)if cv2.waitKey(10) == 27:cv2.imwrite('save_img.jpg', img)break
cv2.destroyAllWindows()
视频处理
cv2.VideoCapture()
是 OpenCV 库中的一个类,用于从摄像头或视频文件中捕获视频帧。这个类提供了多种方法来控制视频捕获的过程,包括打开视频文件、读取视频帧、获取视频属性等。
常用方法
(1)read()
用于从视频源中读取下一帧。它返回一个布尔值和图像帧。布尔值表示是否成功读取了帧,图像帧是一个 NumPy 数组。
ret, frame = cap.read()
if not ret:print("Failed to grab frame")break
(2)release()
用于释放视频捕获资源。在完成视频处理后,必须调用此方法来释放摄像头或视频文件。
cap.release()
(3)isOpened()
用于检查视频捕获对象是否已经成功打开。
if not cap.isOpened():print("Error opening video stream or file")
(4)get() 和 set()
get() 和 set() 方法用于获取和设置视频捕获属性。常用的属性包括帧宽、帧高、帧率等。
# 获取帧宽
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)# 获取帧高
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)# 获取帧率
fps = cap.get(cv2.CAP_PROP_FPS)# 设置帧宽
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)# 设置帧高
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
示例:
import cv2# 打开视频文件或摄像头
# 使用 0 打开默认摄像头,或者替换为视频文件路径,例如 'video.mp4'
video_capture = cv2.VideoCapture('video/1.mp4') # 0 表示使用摄像头
if not video_capture.isOpened():print("视频没有打开")exit()
# 获取视频的帧率
fps = video_capture.get(cv2.CAP_PROP_FPS)
delay = int(1000 / fps) # 计算帧间延迟
while True:# 逐帧读取视频ret, frame = video_capture.read()# 显示当前帧cv2.imshow('Video', frame)# 按下 'q' 键退出if cv2.waitKey(delay) & 0xFF == ord('q'):break
# 释放视频捕获对象和关闭所有窗口
video_capture.release()
cv2.destroyAllWindows()
相关文章:
OpenCV图像基础
目录 显示窗口 创建空白图像 保存图片 图像裁剪 调整图片大小 图像绘制 绘制圆形 绘制矩形 绘制直线 绘制文本 中文乱码 控制鼠标 视频处理 显示窗口 cv2.namedWindow(winname, flagsNone) 创建一个命名窗口,以便在该窗口中显示图像或进行其他图形操作…...
基于MATLAB的图像拼接技术
实验名称:基于MATLAB的图像拼接技术实验目的:利用图像拼接技术得到超宽视角的图像,用来虚拟实际场景。实验原理: 基于相位相关的图像拼接技术是一种基于频域的方法,通过求得图像在频域上是相位相关特点来找到特征位置…...
ComfyUI 快速入门(环境搭建)
ComfyUI 是一个现代化、灵活的用户界面(UI)工具,专为 AI 模型和深度学习框架设计,能够快速实现可视化操作和定制化界面。在本教程中,我们将介绍如何在本地机器上快速搭建 ComfyUI 环境,帮助你开始使用这一工…...
将HTML项目上传至Gitee仓库(详细教程)
1.登录giett giett地址链接:Gitee - 基于 Git 的代码托管和研发协作平台 2.新建一个giett仓库 创建后得到远程仓库: 3、在本地项目文件夹右击鼠标点击 Open Git Bash Here 4、输入命令 命令:git init,这个目录变成git可以管理的仓库,会出…...
如何应对Oracle SQL语句的数据去重问题,应该考虑哪几个方面?
引言 在数据管理和数据库设计中,数据去重是一个重要的课题。随着信息技术的快速发展,数据的产生速度和数量都在急剧增加,如何有效地管理和维护这些数据成为了一个亟待解决的问题。 数据去重不仅可以减少存储空间的占用,还可以提高数据查询的效率,确保数据的准确性和一致…...
论负载均衡技术在Web系统中的应用论文
一、概要叙述软件项目及其主要工作 在2023年,我有幸参与了某公司电子商务平台的研发项目,担任系统架构设计师一职。该项目旨在构建一个高性能、高可用性的电子商务平台,以支撑公司日益增长的在线业务需求。作为系统架构设计的核心成员&#…...
NumPy 数据类型
1.常用 NumPy 基本类型 (1)bool_:布尔型数据类型(True 或者 False) (2)int_:默认的整数类型(类似C 语言long,int32 或 int64) (3&a…...
JavaScript——(4)
【DOM】 一、DOM基本概念 DOM(Document Object Model,文档对象模型)是 JavaScript 操作 HTML 文档的接口,使文档操作变得非常优雅、简便。 DOM 最大的特点就是将 HTML 文档表示为 “节点树”。 DOM 元素/节点:就是…...
每日一练 | DHCP Relay(DHCP 中继)
01 真题题目 DHCP Relay 又称为 DHCP 中继,下列关于 DHCP Relay 的说法正确的是(多选): A. DHCP 协议多采用广播报文,如果出现多个子网则无法穿越,所以需要 DHCP Relay 设备。 B. DHCP Relay 一定是一台交…...
`psdparse`:解锁Photoshop PSD文件的Python密钥
文章目录 psdparse:解锁Photoshop PSD文件的Python密钥背景:为何选择psdparse?psdparse是什么?如何安装psdparse?简单函数使用方法应用场景常见Bug及解决方案总结 psdparse:解锁Photoshop PSD文件的Python密…...
考研要求掌握的C语言程度(插入排序)
插入排序是啥类型的排序 插入类型的 插入排序经常用在啥类型场景下 用在有序序列下的基础上插入新数据 时间复杂度分析 如果是有序的基础下,最好的时间复杂度是O(n); 普通情况下是O(n^2) 插入排序的原理是啥&am…...
mybatis源码解析-sql执行流程
1 执行器的创建 1. SimpleExecutor 描述:最基本的执行器,每次查询都会创建新的语句对象,并且不会缓存任何结果。 特点: 每次查询都会创建新的 PreparedStatement 对象。 不支持一级缓存。 适用于简单的查询操作,不…...
Golang | Leetcode Golang题解之第538题把二叉搜索树转换为累加树
题目: 题解: func getSuccessor(node *TreeNode) *TreeNode {succ : node.Rightfor succ.Left ! nil && succ.Left ! node {succ succ.Left}return succ }func convertBST(root *TreeNode) *TreeNode {sum : 0node : rootfor node ! nil {if n…...
【linux】HTTPS 协议原理
1. 了解 HTTPS 协议原理 (一)认识 HTTPS HTTPS 也是一种应用层协议,是在 HTTP 协议的基础上引入了一个加密层 因为 HTTP协议的内容都是按照文本的方式进行传输的,这个过程中,可能会出现一些篡改的情况 (…...
安利一款开源企业级的报表系统SpringReport
SpringReport是一款企业级的报表系统,支持在线设计报表,并绑定动态数据源,无需写代码即可快速生成想要的报表,可以支持excel报表和word报表两种格式,同时还可以支持excel多人协同编辑,后续考虑实现大屏设计…...
数据安全-接口数据混合加密笔记
接口数据传输安全设计方案 采用非对称加密对称加密混合方式,接口混合加、解密过程梳理: 后端准备sm2公钥和私钥后端将SM2公钥传输到前端前端生成SM4密钥前端使用SM2公钥加密SM4秘钥,获得密文使用SM4秘钥加密数据将密文和加密数据传输至后端…...
JeecgBoot入门
最近在了解低代码平台,其中关注到gitee上开源项目JeecgBoot,JeecgBoot官方也有比较完整的入门教学文档,这里我们将耕者官方教程学习,并将其记录下来。 一、项目简介 JeecgBoot 是一款基于代码生成器的低代码开发平台拥有零代码能力…...
用 Vue.js 打造炫酷的动态数字画廊:展示学生作品的创意之旅
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...
【YOLO学习】YOLOv8改进举例
文章目录 1. ODConv1.1 修改1.2 原yaml文件1.3 修改yaml文件样式11.4 修改yaml文件样式2 2. DAT3. 在train下修改模型 1. ODConv 1.1 修改 1. 在ultralytics/nn/models里创建ODConv.py文件。 2. 在ultralytics/nn/task.py中导入from .modules.ODConv import C2f_ODConv,ODConv…...
文心一言 VS 讯飞星火 VS chatgpt (383)-- 算法导论24.5 3题
三、对引理 24.10 的证明进行改善,使其可以处理最短路径权重为 ∞ ∞ ∞ 和 − ∞ -∞ −∞ 的情况。引理 24.10(三角不等式)的内容是:设 G ( V , E ) G(V,E) G(V,E) 为一个带权重的有向图,其权重函数由 w : E → R w:E→R w:E→R 给出&…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...
学习一下用鸿蒙DevEco Studio HarmonyOS5实现百度地图
在鸿蒙(HarmonyOS5)中集成百度地图,可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API,可以构建跨设备的定位、导航和地图展示功能。 1. 鸿蒙环境准备 开发工具:下载安装 De…...
通过MicroSip配置自己的freeswitch服务器进行调试记录
之前用docker安装的freeswitch的,启动是正常的, 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...
SQL Server 触发器调用存储过程实现发送 HTTP 请求
文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...
第八部分:阶段项目 6:构建 React 前端应用
现在,是时候将你学到的 React 基础知识付诸实践,构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段,你可以先使用模拟数据,或者如果你的后端 API(阶段项目 5)已经搭建好,可以直接连…...
RFID推动新能源汽车零部件生产系统管理应用案例
RFID推动新能源汽车零部件生产系统管理应用案例 一、项目背景 新能源汽车零部件场景 在新能源汽车零部件生产领域,电子冷却水泵等关键部件的装配溯源需求日益增长。传统 RFID 溯源方案采用 “网关 RFID 读写头” 模式,存在单点位单独头溯源、网关布线…...
