Python 搭建车道智能检测系统
作者 | 李秋键
责编 | 寇雪芹
出品 | AI科技大本营(ID:rgznai100)
引言:
本文将利用opencv实现对复杂场景下车道线的实时检测;所使用的图像处理方法主要是在读取图片的基础上,进行多种边缘检测,然后对不同的检测结果进行融合以提取出道路图像,去除其他噪声。然后对提取的连通区域进行判断,找寻最大连通区域最终定为提取的道路。然后根据提取的道路图像,再次利用边缘检测,提取车道线信息,然后利用透视变换将视角变成俯视图,其中透视变换矩阵的四个点由提取道路图像的角点组成。然后对俯视图进行滑动窗口多项式拟合画出车道线,并显示图片和保存成视频!文末附源码。
图1 效果图
系统概述
1.1 对所给数据图像的车道线进行检测。
其中所给数据图像如下图可见:
图2 数据图像
下面我将对所用到的功能和原理将分别阐述。
(1)边缘特征提取:
边缘特征的提取使用的是多种边缘检测算法,其中包括Sobel单方向梯度算子函数、hls阈值分割、lab阈值分割、luv阈值分割、Sobel多方向阈值分割、Sobel多方向梯度算子函数。然后对他们提取的特征进行融合作为最终提取的特征信息。如下图可见,分别是各自边缘特征算法提取出的特征图像
(2)特征融合:
根据不同算法提取到的特征,对其中我们需要保留的特征筛选,即保留白色共同区域。
图3 融合效果图
(3)最大连通区域:
根据所提取到的特征融合图像,可以知道我们需要寻找的是最大的白色区域,此时正好是为道路特征。为了防止过远处的干扰,对图像的一半进行判断即可。
图4 最大连通区域图
然后对提取到的最大连通区域进行原始像素值覆盖即可保留原来的道路图像。
图5 提取的道路图
(4)道路提取图像再次边缘检测:
利用拉普拉斯算子再次对处理后的图像进行边缘检测。并对其进行腐蚀和膨胀消除噪声。
图6道路拉普拉斯边缘提取图
图7道路边缘去除噪声图
(5)对道路区域寻找角点:
建立新的变量使得道路区域变成白色,其他区域为黑色,来提取角点坐标。
图8 道路提取角点图
(6)对道路部分图像透视变换:
在找到角点后,就可以利用角点坐标计算变换矩阵。并对图像进行透视变换操作。
图9 透视变换转为俯视图
(7)滑动窗口多项式拟合曲线
通过对透视变换后的图像计算统计直方图,确认三个车道的坐标,然后利用滑动窗口进行拟合。
图10 滑动窗口拟合图
(8)直线拟合窗口绘制:
在获取到三车道的坐标后,分别将不同车道赋值不同颜色。但是考虑到又的时候只能找到两个车道或没有车道,需要加入一系列判断。
图11 直线拟合滑动窗口图
(9)转回原始图片处理:
再次透视变换反变换回原图,并对图片进行判断覆盖掉黑色和白色像素点。但是其中边缘检测造成某些值不都是黑白,所以加上范围判断赋值。
图12 原图绘制恢复效果
1.2 GUI窗口的搭建:
对图像处理后保存的视频读取显示,与按钮控件绑定即可。主要功能有训练保存视频、显示视频和关闭窗口功能。
图13 程序布局图
(1)识别训练功能:
当点击识别训练时,会弹出cmd命令行,并显示处理过程。
图14 视频训练点击效果图
(2)视频播放功能:
当结束cmd执行过程后,会在本地文件夹下生成四个视频文件,这时候点击播放按钮就可以在GUI上播放视频。
图15 视频播放按钮点击效果图
并在点击按钮后,更换按钮颜色,此时按钮变成“关闭”,可以关闭视频播放
图16 关闭按钮点击效果图
(3)退出界面功能:
点击退出后会弹窗是否退出,点击退出即可。
图17 退出按钮点击效果图
代码功能实现
2.1 系统环境描述:
系统所使用的环境是python3.6.5,opencv3.14.8版本,windows10系统。编程工具使用的是pycharm专业版。所用到的python其他库有os,在这里用来寻找本地图片文件等操作;numpy库用来当对读取到的图片矩阵进行运算处理;pyqt5库用来创建GUI窗口程序等。
2.2 功能模块划分:
按照前面所描述的,所划分的模块总的可以分为图像处理模式识别模块和GUI窗口程序两个部分。其中每个部分又可以分为好几个部分,具体已经在前面有所阐述。
2.3 实现原理:
利用图像处理技术,分割出道路图像,然后对分割出的道路图像再次边缘检测,找出车道,然后透视变换和滑动窗口拟合成曲线,然后处理显示在原场景下。
功能模块的程序实现
3.1 图像处理模式识别部分:
(1)sobel算子函数单方向梯度边缘检测:
Sobel算子是一种一阶微分算子,它利用像素邻近区域的梯度值来计算1个像素的梯度,然后根据一定的绝对值来取舍。Sobel算子使用的是3*3算子模板。这里分别用的是x方向的和多方向的不同计算阈值算子。最终运算结果是一幅边缘幅度图像。对应代码如下:
1#Sobel算子函数2def abs_sobel_thresh(img, orient='x', thresh_min=10, thresh_max=100):3 # 转换为灰度图4 gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)5 # 使用OpenCV Sobel()函数应用x或y梯度然后取绝对值6 if orient == 'x':7 abs_sobel = np.absolute(cv2.Sobel(gray, cv2.CV_64F, 1, 0))8 if orient == 'y':9 abs_sobel = np.absolute(cv2.Sobel(gray, cv2.CV_64F, 0, 1))
10 # 重新缩放回8位整数
11 scaled_sobel = np.uint8(255 * abs_sobel / np.max(abs_sobel))
12 # 创建一个副本并应用阈值
13 binary_output = np.zeros_like(scaled_sobel)
14 # 这里我使用的是包容性(>=,<=)阈值
15 # print(scaled_sobel[:,50])
16 binary_output[(scaled_sobel >= thresh_min) & (scaled_sobel <= thresh_max)] = 255
17 #cv2.imshow("abs_sobel_thresh", binary_output)
18 return binary_output
19def dir_threshold(img, sobel_kernel=3, thresh=(0.8, np.pi / 2)):
20 gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
21 # 计算x和y的梯度
22 sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=sobel_kernel)
23 sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=sobel_kernel)
24 # 取梯度方向的绝对值
25 # 应用一个阈值,并创建一个二值图像结果
26 absgraddir = np.arctan2(np.absolute(sobely), np.absolute(sobelx))
27 # print(absgraddir[:,50])
28 binary_output = np.zeros_like(absgraddir)
29 binary_output[(absgraddir >= thresh[0]) & (absgraddir <= thresh[1])] = 255
30 #cv2.imshow("dir_threshold", binary_output)
31 return binary_output
32def mag_thres(img, sobel_kernel=9, mag_thresh=(20, 255)):
33 # 转换为灰度图
34 gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
35 # 使用Sobel x和y梯度
36 sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=sobel_kernel)
37 sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=sobel_kernel)
38 # 计算梯度大小
39 gradmag = np.sqrt(sobelx ** 2 + sobely ** 2)
40 # 重新缩放到8位
41 scale_factor = np.max(gradmag) / 255
42 gradmag = (gradmag / scale_factor).astype(np.uint8)
43 # print(gradmag[:, 50])
44 # 创建一个二值图像,在阈值满足时为255,否则为0
45 binary_output = np.zeros_like(gradmag)
46 binary_output[(gradmag >= mag_thresh[0]) & (gradmag <= mag_thresh[1])] = 255
47 #cv2.imshow("mag_thresh", binary_output)
48 return binary_output
图18 Sobel函数挑选效果图
(2)各种阈值分割:
这里使用了hls、Lab和LUV空间的阈值分割。通过尝试不同的参数,最终选择的参数在代码部分可以很清晰看出为110到255之间。
HLS 和 HSV 的区别就是最后一个分量不同,HLS 的是 light(亮度),HSV 的是 value(明度)。可以到这个 网页 尝试一下。
HLS 中的 L 分量为亮度,亮度为100,表示白色,亮度为0,表示黑色;HSV 中的 V 分量为明度,明度为100,表示光谱色,明度为0,表示黑色。
下面是 HLS 颜色空间圆柱体:
图19 HSL颜色空间图
Lab是由一个亮度通道(channel)和两个颜色通道组成的。在Lab颜色空间中,每个颜色用L、a、b三个数字表示,各个分量的含义是这样的:
L*代表亮度
a*代表从绿色到红色的分量
b*代表从蓝色到黄色的分量
图20 LAB颜色空间图
LUV色彩空间全称CIE 1976(L*,u*,v*)(也作CIELUV)色彩空间,L*表示物体亮度,u*和v*是色度。于1976年由国际照明委员会(International Commission on Illumination)提出,由CIE XYZ空间经简单变换得到,具视觉统一性。类似的色彩空间有CIELAB。对于一般的图像,u*和v*的取值范围为-100到+100,亮度为0到100。
图21 LUV颜色空间图
对应代码如下:
1def hls_select(img, channel='l', thresh=(110, 255)):2 hls = cv2.cvtColor(img, cv2.COLOR_RGB2HLS)3 if channel == 'h':4 channel = hls[:, :, 0]5 elif channel == 'l':6 channel = hls[:, :, 1]7 else:8 channel = hls[:, :, 2]9 binary_output = np.zeros_like(channel)
10 # print(channel[:,50])
11 binary_output[(channel > thresh[0]) & (channel <= thresh[1])] = 255
12 #cv2.imshow("hls_select", binary_output)
13 return binary_output
14def lab_select(img, thresh=(110, 255)):
15 lab = cv2.cvtColor(img, cv2.COLOR_RGB2Lab)
16 b_channel = lab[:, :, 0]
17 # print(b_channel[:,50])
18 binary_output = np.zeros_like(b_channel)
19 binary_output[(b_channel > thresh[0]) & (b_channel <= thresh[1])] = 255
20 #cv2.imshow("lab_select", binary_output)
21 return binary_output
22def luv_select(img, thresh=(110, 255)):
23 luv = cv2.cvtColor(img, cv2.COLOR_RGB2LUV)
24 l_channel = luv[:, :, 0]
25 # print(l_channel[:,50])
26 binary_output = np.zeros_like(l_channel)
27 binary_output[(l_channel > thresh[0]) & (l_channel <= thresh[1])] = 255
28 #cv2.imshow("luv_select", binary_output)
29 return binary_output
(3)阈值融合:
再进行完不同的边缘检测后,将各自的结果共同的白色区域保留。代码如下:
1def thresholding(img):2 x_thresh = abs_sobel_thresh(img, orient='x', thresh_min=10, thresh_max=100)3 mag_thresh = mag_thres(img, sobel_kernel=9, mag_thresh=(20, 255))4 dir_thresh = dir_threshold(img, sobel_kernel=3, thresh=(0.7, 1.3))5 hls_thresh = hls_select(img, channel='l', thresh=(110, 255))6 lab_thresh = lab_select(img, thresh=(110, 255))7 luv_thresh = luv_select(img, thresh=(110, 255))8 threshholded = np.zeros_like(x_thresh)9 threshholded[((x_thresh == 255) & (mag_thresh == 255)) | ((dir_thresh == 255) & (hls_thresh == 255)) | (
10 lab_thresh == 255) | (luv_thresh == 255)] = 255
11 #cv2.imshow("thresholding", threshholded)
12 return threshholded
(4)找出最大连通区域为道路位置:
1abel0 = abs1[int(abs1.shape[0] / 2):abs1.shape[0], :]2label_img, number = measure.label(label0, neighbors=8, background=0, return_num=True, connectivity=2)3'''找出最大连通区域'''4max_label = 15max_num = 06for i in range(1, number + 1):7 if np.sum(label_img == i) > max_num:8 max_num = np.sum(label_img == i)9 max_label = i
10dst = color.label2rgb(label_img)
11for i in range(label_img.shape[0]):
12 for j in range(label_img.shape[1]):
13 if label_img[i, j] == max_label:
14 abs1[int(abs1.shape[0] / 2) + i, j] = img[int(abs1.shape[0] / 2) + i, j][2]
15 mid_img[int(abs1.shape[0] / 2) + i, j] = 255
16 else:
17 abs1[int(abs1.shape[0] / 2) + i, j] = 0
18 mid_img[int(abs1.shape[0] / 2) + i, j] = 0
19#道路特征图
20#cv2.imshow("road", abs1)
(5)角点寻找:
创建一个新的变量,保留着道路部分为白色,其他部分为黑色,用多边形拟合寻找角点。
1mid_img = cv2.erode(mid_img, kernel, iterations=1)2cv2.imshow("cut", abs1)3for i in range(abs1.shape[0]):4 for j in range(abs1.shape[1]):5 if abs1[i, j] == 255:6 abs1[i, j] = 07mid_img[mid_img.shape[0] - 1] = 08mid_img[:, 0] = 09mid_img[0] = 0
10mid_img[:, mid_img.shape[1] - 1] = 0
11# 边缘检测
12laplacian = cv2.Laplacian(abs1, cv2.CV_16S, ksize=7)
13dst = cv2.convertScaleAbs(laplacian)
14#cv2.imshow("laplacian", dst)
15# 形态学梯度,膨胀和腐蚀的差别,看上去像轮廓
16kernel = np.ones((7, 7), np.uint8)
17tt = cv2.morphologyEx(abs1, cv2.MORPH_GRADIENT, kernel)
18tt[(tt > 5) & (tt <= 200)] = 255
(6)滑动窗口拟合曲线:
利用边缘检测找出车道信息,然后统计直方图中左右中依次最大为左中右车道。然后创建滑动窗口,数量为50,宽度为20。为了更好地效果,设置寻找最小值为0即可。代码见文末源码。
测试和调试
调试效果图如下可见:
图22 视频训练点击效果图
图23 视频播放按钮点击效果图
源码
有任何问题欢迎评论区留言~完整代码链接如下:
https://pan.baidu.com/s/1I7in6ys2hq9RK7owyUdoFg
提取码:nl6x
作者简介:李秋键,CSDN博客专家,CSDN达人课作者。硕士在读于中国矿业大学,开发有taptap竞赛获奖等。
点击这里 ???? 关注我们~~~
更多精彩推荐
☞RedHat 年度报告:只索取不贡献的开源消费“大户”不受待见☞腾讯:这可是一只“骨骼清奇”的狗☞用数据分析《你好,李焕英》“斐妈”爆红的真相☞“踢爆”职场焦虑、玩机车、文科转大厂程序媛,乘风破浪的 IT 女神太飒了!
点分享点收藏点点赞点在看
相关文章:

ASP.NET弹出窗口技术之增加网站流量方法
作为Microsoft的最新建立动态Web网站的工具,ASP.NET相对于ASP和JSP在改变原始的Web编程方式方面有了长足的长进。它的代码与页面分离技术(CodeBehind)以及完善的Web服务器控件为程序员提供了一个更加符合传统编程的Web服务器端开发方式。但Web编程还是有着与传统编程不相同的特…

检查是否支持 SO_REUSEPORT
为什么80%的码农都做不了架构师?>>> int reuse_port(int sockfd) {#ifndef SO_REUSEPORT#define SO_REUSEPORT (15)#endifconst int on 1;return setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)); } 转载于:https://my.oschina.n…

nginx的tmp文件过大导致磁盘空间不足一例
个人微博:http://weibo.com/h2fly欢迎技术交流现象:8月23之后,时不时收到服务器的/usrused > 90%的报警排查:1、du发现磁盘/usr使用不大,而报警使用的df》明显是有文件删除了空间没释放。注:du和df的实现机制不同&a…
10年Java老兵宝藏资料,吐血奉献!
2021都说工作不好找,也对开发人员的要求变高。前段时间自己有整理了一些Java后端开发面试常问的高频考点问题做成一份PDF文档(1000道高频题),同时也整理一些图文解析及笔记,今天在这免费分享给大家,希望大家…

IOCP , kqueue , epoll ... 有多重要?
原文地址:http://blog.codingnow.com/2006/04/iocp_kqueue_epoll.html设计 mmo 服务器,我听过许多老生常谈,说起处理大量连接时, select 是多么低效。我们应该换用 iocp (windows), kqueue(freebsd), 或是 epoll(linux) 。的确&am…

[故障解决]图文:python启动报错:api-ms-win-crt-runtime-l1-1-0.dll丢失解决
python启动报错:api-ms-win-crt-runtime-l1-1-0.dll丢失解决 环境 Windows 7 SP1 x64python3.6.1报错 解决办法 1.下载VC redist(安装时读条卡在:正在处理:Windows7_MSU_x64)2.到C:\ProgramData\Package Cache\里面搜索࿰…

ASP.NET设计应用程序的七大绝招
随着微软.NET的流行,ASP.NET越来越为广大开发人员所接受。作为ASP.NET的开发人员,我们不仅需要掌握其基本的原理,更要多多实践,从实践中获取真正的开发本领。在我们的实际开发中,往往基本的原理满足不了开发需求&#…

Chromium之各国语言切换
在\src\build\Debug\locales\目录下存放着各国语言所需要的资源文件xx.pak,我这边共有53中语言支持。 命令行进入src\build\Debug目录,敲:chrome.exe --langzh-CN就能用中文简体,zh-CN可以根据需要换成各种语言版本。 Chrome的整个solution中,每种语言都会有个相应的…

程序员每天工作摸鱼俩小时,月薪35K?
职场上有很多奇奇怪怪的事。比如说有人爆肝996,工资却还养不活自己。有人每天工作摸鱼,但是却月薪数万。前端时间,小编在某职场社交平台上看到这么一则帖子#程序员摸鱼2小时月入35k#仔细看下,该员工每天的工作日常就是摸鱼的间隙工…

JAVA的get post 区别
1. get 是从服务器上获取数据,post 是向服务器传送数据。 get 请求返回 request - URI 所指出的任意信息。Post 请求用来发送电子邮件、新闻或发送能由交互用户填写的表格。这是唯一需要在请求中发送body的请求。使用Post请求时需要在报文首部 Content - Length 字段…

多些时间能少写些代码(转自酷壳 – CoolShell.cn)
我在我的微博上说过这样一段话,我想在这里把我的这个观点阐述地更完整一些。左耳朵耗子:聪明的程序员使用50%-70%的时间用来思考,尝试和权衡各种设计和实现,而用30% – 50%的时间是在忙碌着编码,调试和测试。聪明的老板…

HTTP协议之Chunked解析
在网上找了好一会,始终没发现有解析Chunked编码的文章,那就自己写一个吧,呵呵。网上使用Chunked编码的网站似乎并不是很多,除了那些使用GZip压缩的网站,例:google.com,还有就是大部分打开GZip压…
关于深度学习编译器,这些知识你需要知道
作者 | 小O妹出品 | AI科技大本营(ID:rgznai100)神经网络编译器概览近年来,以机器学习、深度学习为核心的AI技术得到迅猛发展,深度神经网络在各行各业得到广泛应用: 1. CV(计算机视觉)…

checkbox点击切换选中状态
2019独角兽企业重金招聘Python工程师标准>>> function cboxChecked(ele) {$(ele).click(function () {var isChecked $(ele).attr(checked);if (!isChecked) {$(ele).attr(checked, true)} else {$(ele).attr(checked, false)}})} 转载于:https://my.oschina.net/u…

提升Hadoop计算能力的并行框架
集算器是新型并行计算框架,它支持读写HDFS中的文件,可以通过并行框架将计算任务分担到多个节点中。它专注于加强Hadoop的计算能力,从而实现计算性能和开发效率更高的大数据应用。更强的计算能力。Hadoop所使用的计算语言为JAVA,JA…

在ASP.NET 2.0中建立站点导航层次
站点导航提供程序--ASP.NET 2.0中的站点导航提供程序暴露了应用程序中的页面的导航信息,它允许你单独地定义站点的结构,而不用考虑页面的实际物理布局。默认的站点导航提供程序是基于XML的,但是你也可以通过编写自定义的提供程序,…

加速数据中心变革,Xilinx推出软件定义、硬件加速型 Alveo SmartNIC
近日,为满足现代数据中心发展需求,赛灵思公司宣布推出一系列全新数据中心产品及解决方案,包括全新 Alveo SmartNIC 系列、smart world (智能世界) AI 视频分析应用、一款能够实现亚微秒级交易的加速算法交易参考设计&a…

跟阿里云技术专家阙寒一起深度了解视频直播CDN技术
网络直播平台现下已经十分火热,很多常见的直播平台都采用了阿里云直播CDN来搭建自身业务。今天,我们请来了阿里云CDN团队技术专家阙寒,来介绍下视频的一些基础知识和视频直播的架构。在进入正题之前,我们先来了解视频直播相关的名…

一个ASP.NET中使用的MessageBox类
/// <summary>/// 自定义信息对话框/// </summary>public class MessageBox{/// <summary>/// 定义一个web页面,用来显示用户自定错误提示信息/// </summary>System.Web.UI.Page p;/// <summary>/// 实例时,参数为:this 如…

Ubuntu 13.10 安装Terminalx 后更改默认终端设置
1、安装 terminalx, sudo apt-get install terminator 2、Ctrl Alt t 试一下打开什么终端,我的默认启动的是Terminator;如果想换换默认的终端,还需以下一步 3、接下来,安装dconf-tools,这个是设置默认终端的必须 打开…

360数科张家兴:如何突破三大瓶颈,破解金融科技发展难题?
3月6日,上海香港联会、普陀香港联会联合普陀新区联会,IFTA亚洲金融科技师学会共同举办了“沪港合作共创未来”——沪港两地金融科技线上论坛。本次活动通过沪港两地直播连线,探讨两地金融科技领域的发展机遇。麻省理工学院香港创坊执行董事冼…

通过改进算法来优化程序性能的真实案例(Ransac)
对于运行不了几次,一次运行不了多久的方法,我们不需要考虑性能优化,对于那些需要经常运行几百次几千次的方法,我们头脑里还是要有性能这根弦。C#太优雅方便了,以至于很多人写程序时根本就把性能抛到脑后了,…

ASP.NET中使用MD5和SHA1算法加密
你的主页或者你管理的网站有各种密码需要保护,把密码直接放在数据库或者文件中存在不少安全隐患,所以密码加密后存储是最常见的做法。在ASP.NET中实现加密非常容易。.NET SDK中提供了CookieAuthentication类,其中的HashPasswordForStoringInC…

不追逐标准化产品,360数科的一站式风控体系有何不同?
新冠肺炎疫情无疑加速了金融行业数字化转型,竞争者不断涌入,逐渐形成由BATJ、传统银行旗下金融科技子公司、以及专注于金融机构的数字化服务公司构成的竞争格局。然而,风控始终是金融行业的核心。作为定位于中国零售金融领域科技服务商的360数…

基于Bootstrap里面的Button dropdown打造自定义select
最近工作非常的忙,在对一个系统进行改版。项目后台是MVC1.0开发的,但是前端部分已经改过几个版本,而已之前的设计师很强大,又做设计又做前端开发。而已很时尚和前沿,使用了一直都很热门的Bootstrap工具包,有…

HybridDB · 源码分析 · MemoryContext 内存管理和内存异常分析
背景 最近排查和解决了几处 HybridDB for PostgreSQL 内存泄漏的BUG。觉得有一定通用性。 这期分享给大家一些实现细节和小技巧。 阿里云上的 HybridDB for PostgreSQL 是基于 PostgreSQL 开发,定位于 OLAP 场景的 MPP 架构数据库集群。它不少的内部机制沿用了 Post…

联合南京大学,爱奇艺智能论文入选顶会CVPR 2021
日前,全球计算机视觉顶级会议CVPR (IEEE Conference on Computer Vision and Pattern Recognition)公布了2021年论文接收结果。作为计算机视觉领域世界三大顶会(CVPR、ICCV、ECCV)之一,CVPR的论文投稿量近五年来持续大涨。据CVPR官网显示,今…

Forefront_TMG_2010-TMG发布Web服务器
1.环境拓扑图:2.准备DMZ区域的Web服务器:安装Web服务器:在DMZ区域的Web服务器进行测试:3.TMG发布Web服务器:打开TMG管理控制台,新建“网站发布规则”:新建名称:选择“允许”…

ASP.NET实现身份模拟
使用模拟时,ASP.NET 应用程序可以选择以这些应用程序当前正为之操作的客户的身份执行。通常这样做的原因是为了避免在 ASP.NET 应用程序代码中处理身份验证和授权问题。而您依赖于 Microsoft Internet 信息服务 (IIS) 来验证用户,然后将已通过验证的标记…

Mac homebrew类似apt-get命令安装包
INSTALL brew ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 其它: 其他brew命令 brew list 列出已安装的软件 brew update 更新brew brew home 用浏览器打开brew的官方网站 brew inf…