保姆级教程【车道线检测】,跟着一步一步来,小学生都可以学会吧

本文详述了使用OpenCV进行车道线检测的步骤,包括相机校正、阈值过滤、透视变换、车道线检测、计算车道曲率和车辆位置,以及处理原图展示信息。提供了详细的代码和图片示例。

粉丝福利:

开始之前,迪迦给大家准备的250G人工智能学习资料礼包内含:两大Pytorch、TensorFlow实战框架视频、图像识别、OpenCV、计算机视觉、深度学习与神经网络等等等视频、代码、PPT以及深度学习书籍

只需要你点个关注,然后扫码添加助手小姐姐VX即可无套路领取!

  扫码添加即可 

项目描述:

使用openCV设计算法处理车辆前置摄像头录下的视频,检测车辆前方的车道,并计算车道曲率

项目代码地址:https://github.com/yang1688899/CarND-Advanced-Lane-Lines

实现步骤:

  • 使用提供的一组棋盘格图片计算相机校正矩阵(camera calibration matrix)和失真系数(distortion coefficients).
  • 校正图片
  • 使用梯度阈值(gradient threshold),颜色阈值(color threshold)等处理图片得到清晰捕捉车道线的二进制图(binary image).
  • 使用透视变换(perspective transform)得到二进制图(binary image)的鸟瞰图(birds-eye view).
  • 检测属于车道线的像素并用它来测出车道边界.
  • 计算车道曲率及车辆相对车道中央的位置.
  • 处理图片展示车道区域,及车道的曲率和车辆位置.

相机校正(Camera Calibration)

这里会使用opencv提供的方法通过棋盘格图片组计算相机校正矩阵(camera calibration matrix)和失真系数(distortion coefficients)。首先要得到棋盘格内角的世界坐标"object points"和对应图片坐标"image point"。假设棋盘格内角世界坐标的z轴为0,棋盘在(x,y)面上,则对于每张棋盘格图片组的图片而言,对应"object points"都是一样的。而通过使用openCv的cv2.findChessboardCorners(),传入棋盘格的灰度(grayscale)图片和横纵内角点个数就可得到图片内角的"image point"。

def get_obj_img_points(images,grid=(9,6)):
    object_points=[]
    img_points = []
    for img in images:
        #生成object points
        object_point = np.zeros( (grid[0]*grid[1],3),np.float32 )
        object_point[:,:2]= np.mgrid[0:grid[0],0:grid[1]].T.reshape(-1,2)
        #得到灰度图片
        gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
        #得到图片的image points
        ret, corners = cv2.findChessboardCorners(gray, grid, None)
        if ret:
            object_points.append(object_point)
            img_points.append(corners)
    return object_points,img_points

然后使用上方法得到的object_points and img_points 传入cv2.calibrateCamera() 方法中就可以计算出相机校正矩阵(camera calibration matrix)和失真系数(distortion coefficients),再使用 cv2.undistort()方法就可得到校正图片。

def cal_undistort(img, objpoints, imgpoints):
    ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, img.shape[1::-1], None, None)
    dst = cv2.undistort(img, mtx, dist, None, mtx)
    return dst

以下为其中一张棋盘格图片校正前后对比:

校正测试图片

代码如下:

#获取棋盘格图片
cal_imgs = utils.get_images_by_dir('camera_cal')
#计算object_points,img_points
object_points,img_points = utils.calibrate(cal_imgs,grid=(9,6))
#获取测试图片
test_imgs = utils.get_images_by_dir('test_images')

#校正测试图片
undistorted = []
for img in test_imgs:
    img = utils.cal_undistort(img,object_points,img_points)
    undistorted.append(img)

测试图片校正前后对比:

阈值过滤(thresholding)

这里会使用梯度阈值(gradient threshold),颜色阈值(color threshold)等来处理校正后的图片,捕获车道线所在位置的像素。(这里的梯度指的是颜色变化的梯度)

以下方法通过"cv2.Sobel()"方法计算x轴方向或y轴方向的颜色变化梯度导数,并以此进行阈值过滤(thresholding),得到二进制图(binary image):

def abs_sobel_thresh(img, orient='x', thresh_min=0, thresh_max=255):
    #装换为灰度图片
    gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    #使用cv2.Sobel()计算计算x方向或y方向的导数
    if orient == 'x':
        abs_sobel = np.absolute(cv2.Sobel(gray, cv2.CV_64F, 1, 0))
    if orient == 'y':
        abs_sobel = np.absolute(cv2.Sobel(gray, cv2.CV_64F, 0, 1))
    #阈值过滤
    scaled_sobel = np.uint8(255*abs_sobel/np.max(abs_sobel))
    binary_output = np.zeros_like(scaled_sobel)
    binary_output[(scaled_sobel >= thresh_min) & (scaled_sobel <= thresh_max)] = 1

    return binary_output

通过测试发现使用x轴方向阈值在35到100区间过滤得出的二进制图可以捕捉较为清晰的车道线:

x_thresh = utils.abs_sobel_thresh(img, orient='x', thresh_min=35, thresh_max=100)

以下为使用上面方法应用测试图片的过滤前后对比图:

可以看到该方法的缺陷是在路面颜色相对较浅且车道线颜色为黄色时,无法捕捉到车道线(第三,第六,第七张图),但在其他情况车道线捕捉效果还是不错的。

接下来测试一下使用全局的颜色变化梯度来进行阈值过滤:

def mag_thresh(img, sobel_kernel=3, mag_thresh=(0, 255)):
    # Convert to grayscale
    gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    # Take both Sobel x and y gradients
    sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=sobel_kernel)
    sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=sobel_kernel)
    # Calculate the gradient magnitude
    gradmag = np.sqrt(sobelx**2 + sobely**2)
    # Rescale to 8 bit
    scale_factor = np.max(gradmag)/255 
    gradmag = (gradmag/scale_factor).astype(np.uint8) 
    # Create a binary image of ones where threshold is met, zeros otherwise
    binary_output = np.zeros_like(gradmag)
    binary_output[(gradmag >= mag_thresh[0]) & (gradmag <= mag_thresh[1])] = 1

    # Return the binary image
    return binary_output
mag_thresh = utils.mag_thresh(img, sobel_kernel=9, mag_thresh=(50, 100))

结果仍然不理想(观察第三,第六,第七张图片),原因是当路面颜色相对较浅且车道线颜色为黄色时,颜色变化梯度较小,想要把捕捉车道线需要把阈值下限调低,然而这样做同时还会捕获大量的噪音像素,效果会更差。

那么使用颜色阈值过滤呢? 下面为使用hls颜色空间的s通道进行阈值过滤:

def hls_select(img,channel='s',thresh=(0, 255)):
    hls = cv2.cvtColor(img, cv2.COLOR_RGB2HLS)
    if channel=='h':
        channel = hls[:,:,0]
    elif channel=='l':
        channel=hls[:,:,1]
    else:
        channel=hls[:,:,2]
    binary_output = np.zeros_like(channel)
    binary_output[(channel > thresh[0]) & (channel <= thresh[1])] = 1
    return binary_output
s_thresh = utils.hls_select(img,channel='s',thresh=(180, 255))

可以看到在路面颜色相对较浅且车道线颜色为黄色的区域,车道线仍然被清晰的捕捉到了,然而在其他地方表现却不太理想(第四,第八张图片)

因此为了应对多变的路面情况,需要结合多种阈值过滤方法。

以下为最终的阈值过滤组合:

def thresholding(img):
    x_thresh = utils.abs_sobel_thresh(img, orient='x', thresh_min=10 ,thresh_max=230)
    mag_thresh = utils.mag_thresh(img, sobel_kernel=3, mag_thresh=(30, 150))
    dir_thresh = utils.dir_threshold(img, sobel_kernel=3, thresh=(0.7, 1.3))
    hls_thresh = utils.hls_select(img, thresh=(180, 255))
    lab_thresh = utils.lab_select(img, thresh=(155, 200))
    luv_thresh = utils.luv_select(img, thresh=(225, 255))
    #Thresholding combination
    threshholded = np.zeros_like(x_thresh)
    threshholded[((x_thresh == 1) & (mag_thresh == 1)) | ((dir_thresh == 1) & (hls_thresh == 1)) | (lab_thresh == 1) | (luv_thresh == 1)] = 1

    return threshholded

透视变换(perspective transform)

这里使用"cv2.getPerspectiveTransform()"来获取变形矩阵(tranform matrix),把阈值过滤后的二进制图片变形为鸟撒视角。

以下为定义的源点(source points)和目标点(destination points)

Source Destination 585, 460320, 0203, 720320, 7201127, 720960, 720695, 460960, 0

定义方法获取变形矩阵和逆变形矩阵:

def get_M_Minv():
    src = np.float32([[(203, 720), (585, 460), (695, 460), (1127, 720)]])
    dst = np.float32([[(320, 720), (320, 0), (960, 0), (960, 720)]])
    M = cv2.getPerspectiveTransform(src, dst)
    Minv = cv2.getPerspectiveTransform(dst,src)
    return M,Minv

然后使用"cv2.warpPerspective()"传入相关值获得变形图片(wrapped image)

thresholded_wraped = cv2.warpPerspective(thresholded, M, img.shape[1::-1], flags=cv2.INTER_LINEAR)

以下为原图及变形后的效果:

以下为阈值过滤后二进制图变形后效果:

检测车道边界

上面的二进制图还存在一定的噪音像素,为了准确检测车道边界,首先要确定哪些像素是属于车道线的。

首先要定位车道线的基点(图片最下方车道出现的x轴坐标),由于车道线在的像素都集中在x轴一定范围内,因此把图片一分为二,左右两边的在x轴上的像素分布峰值非常有可能就是车道线基点。

以下为测试片x轴的像素分布图:

定位基点后,再使用使用滑动窗多项式拟合(sliding window polynomial fitting)来获取车道边界。这里使用9个200px宽的滑动窗来定位一条车道线像素:

def find_line(binary_warped):
    # Take a histogram of the bottom half of the image
    histogram = np.sum(binary_warped[binary_warped.shape[0]//2:,:], axis=0)
    # Find the peak of the left and right halves of the histogram
    # These will be the starting point for the left and right lines
    midpoint = np.int(histogram.shape[0]/2)
    leftx_base = np.argmax(histogram[:midpoint])
    rightx_base = np.argmax(histogram[midpoint:]) + midpoint
    
    # Choose the number of sliding windows
    nwindows = 9
    # Set height of windows
    window_height = np.int(binary_warped.shape[0]/nwindows)
    # Identify the x and y positions of all nonzero pixels in the image
    nonzero = binary_warped.nonzero()
    nonzeroy = np.array(nonzero[0])
    nonzerox = np.array(nonzero[1])
    # Current positions to be updated for each window
    leftx_current = leftx_base
    rightx_current = rightx_base
    # Set the width of the windows +/- margin
    margin = 100
    # Set minimum number of pixels found to recenter window
    minpix = 50
    # Create empty lists to receive left and right lane pixel indices
    left_lane_inds = []
    right_lane_inds = []
    
    # Step through the windows one by one
    for window in range(nwindows):
        # Identify window boundaries in x and y (and right and left)
        win_y_low = binary_warped.shape[0] - (window+1)*window_height
        win_y_high = binary_warped.shape[0] - window*window_height
        win_xleft_low = leftx_current - margin
        win_xleft_high = leftx_current + margin
        win_xright_low = rightx_current - margin
        win_xright_high = rightx_current + margin
        # Identify the nonzero pixels in x and y within the window
        good_left_inds = ((nonzeroy >= win_y_low) & (nonzeroy < win_y_high) & 
        (nonzerox >= win_xleft_low) &  (nonzerox < win_xleft_high)).nonzero()[0]
        good_right_inds = ((nonzeroy >= win_y_low) & (nonzeroy < win_y_high) & 
        (nonzerox >= win_xright_low) &  (nonzerox < win_xright_high)).nonzero()[0]
        # Append these indices to the lists
        left_lane_inds.append(good_left_inds)
        right_lane_inds.append(good_right_inds)
        # If you found > minpix pixels, recenter next window on their mean position
        if len(good_left_inds) > minpix:
            leftx_current = np.int(np.mean(nonzerox[good_left_inds]))
        if len(good_right_inds) > minpix:        
            rightx_current = np.int(np.mean(nonzerox[good_right_inds]))
    
    # Concatenate the arrays of indices
    left_lane_inds = np.concatenate(left_lane_inds)
    right_lane_inds = np.concatenate(right_lane_inds)
    
    # Extract left and right line pixel positions
    leftx = nonzerox[left_lane_inds]
    lefty = nonzeroy[left_lane_inds] 
    rightx = nonzerox[right_lane_inds]
    righty = nonzeroy[right_lane_inds] 
    
    # Fit a second order polynomial to each
    left_fit = np.polyfit(lefty, leftx, 2)
    right_fit = np.polyfit(righty, rightx, 2)
    
    return left_fit, right_fit, left_lane_inds, right_lane_inds

以下为滑动窗多项式拟合(sliding window polynomial fitting)得到的结果:

计算车道曲率及车辆相对车道中心位置

利用检测车道得到的拟合值(find_line 返回的left_fit, right_fit)计算车道曲率,及车辆相对车道中心位置:

def calculate_curv_and_pos(binary_warped,left_fit, right_fit):
    # Define y-value where we want radius of curvature
    ploty = np.linspace(0, binary_warped.shape[0]-1, binary_warped.shape[0] )
    leftx = left_fit[0]*ploty**2 + left_fit[1]*ploty + left_fit[2]
    rightx = right_fit[0]*ploty**2 + right_fit[1]*ploty + right_fit[2]
    # Define conversions in x and y from pixels space to meters
    ym_per_pix = 30/720 # meters per pixel in y dimension
    xm_per_pix = 3.7/700 # meters per pixel in x dimension
    y_eval = np.max(ploty)
    # Fit new polynomials to x,y in world space
    left_fit_cr = np.polyfit(ploty*ym_per_pix, leftx*xm_per_pix, 2)
    right_fit_cr = np.polyfit(ploty*ym_per_pix, rightx*xm_per_pix, 2)
    # Calculate the new radii of curvature
    left_curverad = ((1 + (2*left_fit_cr[0]*y_eval*ym_per_pix + left_fit_cr[1])**2)**1.5) / np.absolute(2*left_fit_cr[0])
    right_curverad = ((1 + (2*right_fit_cr[0]*y_eval*ym_per_pix + right_fit_cr[1])**2)**1.5) / np.absolute(2*right_fit_cr[0])
    
    curvature = ((left_curverad + right_curverad) / 2)
    #print(curvature)
    lane_width = np.absolute(leftx[719] - rightx[719])
    lane_xm_per_pix = 3.7 / lane_width
    veh_pos = (((leftx[719] + rightx[719]) * lane_xm_per_pix) / 2.)
    cen_pos = ((binary_warped.shape[1] * lane_xm_per_pix) / 2.)
    distance_from_center = veh_pos - cen_pos
    return curvature,distance_from_center

处理原图,展示信息

使用逆变形矩阵把鸟瞰二进制图检测的车道镶嵌回原图,并高亮车道区域:

def draw_area(undist,binary_warped,Minv,left_fit, right_fit):
    # Generate x and y values for plotting
    ploty = np.linspace(0, binary_warped.shape[0]-1, binary_warped.shape[0] )
    left_fitx = left_fit[0]*ploty**2 + left_fit[1]*ploty + left_fit[2]
    right_fitx = right_fit[0]*ploty**2 + right_fit[1]*ploty + right_fit[2]
    # Create an image to draw the lines on
    warp_zero = np.zeros_like(binary_warped).astype(np.uint8)
    color_warp = np.dstack((warp_zero, warp_zero, warp_zero))
    
    # Recast the x and y points into usable format for cv2.fillPoly()
    pts_left = np.array([np.transpose(np.vstack([left_fitx, ploty]))])
    pts_right = np.array([np.flipud(np.transpose(np.vstack([right_fitx, ploty])))])
    pts = np.hstack((pts_left, pts_right))
    
    # Draw the lane onto the warped blank image
    cv2.fillPoly(color_warp, np.int_([pts]), (0,255, 0))
    
    # Warp the blank back to original image space using inverse perspective matrix (Minv)
    newwarp = cv2.warpPerspective(color_warp, Minv, (undist.shape[1], undist.shape[0])) 
    # Combine the result with the original image
    result = cv2.addWeighted(undist, 1, newwarp, 0.3, 0)
    return result

使用"cv2.putText()"方法处理原图展示车道曲率及车辆相对车道中心位置信息:

def draw_values(img, curvature, distance_from_center):
    font = cv2.FONT_HERSHEY_SIMPLEX
    radius_text = "Radius of Curvature: %sm" % (round(curvature))

    if distance_from_center > 0:
        pos_flag = 'right'
    else:
        pos_flag = 'left'

    cv2.putText(img, radius_text, (100, 100), font, 1, (255, 255, 255), 2)
    center_text = "Vehicle is %.3fm %s of center" % (abs(distance_from_center), pos_flag)
    cv2.putText(img, center_text, (100, 150), font, 1, (255, 255, 255), 2)
    return img

以下为测试图片处理后结果:

(ps:最近在重新看一些udacity上做的项目,就顺便整理下来写成文章分享一下,以后陆续还会写一些,谢谢关注)

原文链接:车道线检测 - 知乎

> **注意**:你上传的文件 `cknow_20251111_152302.jpg` 是一张图片,但由于内容已提取为文本,我将基于该文本进行分析。 --- ### **问题重述** 你在运行 PySpark 脚本时遇到了错误,报错如下: ``` Traceback (most recent call last): File "D:\pythonprojects\GroceryBasketAnalysis\code\test_spark.py", line 7, in <module> getOrCreate() File "D:\spark-tools\spark-4.0.1-bin-hadoop3\python\pyspark\sql\session.py", line 556, in getOrCreate sc = SparkContext.getOrCreate(sparkConf) ``` 你希望知道: 1. 错误出现在哪里? 2. 如何解决? 3. 提供保姆解决方案,每一步都不能省略。 --- ### **错误定位与原因分析** 从错误日志可以看出: - 错误发生在 `test_spark.py` 第 7 行调用 `.getOrCreate()` 时; - 根源在于 `SparkContext.getOrCreate(sparkConf)` 初始化失败; - 结合你提供的代码片段,发现环境变量配置混乱,路径拼接错误,且缺少必要的初始化设置。 此外,你的脚本中存在以下关键问题: #### ❌ 典型错误点: 1. **Python 和 Spark 路径未正确绑定** 出现类似: ```python .config("spark.pyspark.python", r"D:\Python\py) ``` 明显字符串被截断,应为完整路径如 `D:\Python\python.exe`。 2. **缺少 SparkSession 导入和构建语句** 没有看到标准的导入和创建方式,可能导致 `getOrCreate` 失败。 3. **可能未安装 pyspark 或版本不匹配** 报错路径指向了本地 Spark 安装目录,但 Python 找不到对应解释器。 --- ## ✅ 解决方案(保姆教程一步不省) 我们从头开始搭建一个能正常运行的 PySpark 环境,并修复你的程序。 --- ### ✅ 第一步:确认已安装必要组件 确保已完成以下三项安装: | 组件 | 是否必须 | 下载地址 | |------|----------|---------| | Java 8 或 11 | ✅ 必须 | [https://adoptium.net](https://adoptium.net) | | Apache Spark 3.4+/4.0+ | ✅ 必须 | [https://spark.apache.org/downloads.html](https://spark.apache.org/downloads.html) | | Hadoop Windows 支持工具(winutils.exe) | ✅ 必须(Windows 用户) | GitHub 搜索 `winutils` for Hadoop | > 推荐版本组合:**Spark 3.5.0 + Hadoop 3.3 → 下载预编译包** --- ### ✅ 第二步:设置系统环境变量(Windows) 右键“此电脑” → 属性 → 高系统设置 → 环境变量 #### 添加以下系统变量: | 变量名 | 值 | |--------|-----| | `JAVA_HOME` | `C:\Program Files\Java\jdk1.8.0_392`(替换成你的 JDK 路径) | | `SPARK_HOME` | `D:\spark-tools\spark-4.0.1-bin-hadoop3`(你的 Spark 解压路径) | | `HADOOP_HOME` | `%SPARK_HOME%` 或单独设为 `D:\hadoop`(若有独立 hadoop) | | `PYSPARK_PYTHON` | `D:\Python\python.exe`(你的 Python 可执行文件全路径) | | `PYTHONPATH` | `%SPARK_HOME%\python;%SPARK_HOME%\python\lib\py4j-*.zip` | 📌 **特别注意**:`PYSPARK_PYTHON` 必须是 `.exe` 文件的完整路径,否则驱动无法启动! --- ### ✅ 第三步:验证 pyspark 是否可用 打开命令行,输入: ```bash pip install pyspark==3.5.0 ``` 然后测试是否能导入: ```python python -c "from pyspark.sql import SparkSession; print('OK')" ``` 如果无报错,说明 Python 层面没问题。 --- ### ✅ 第四步:编写正确的 test_spark.py 脚本 替换你原来的 `test_spark.py` 内容为以下 **完整可运行代码**: ```python # test_spark.py from pyspark.sql import SparkSession import os # 【可选】显式指定 Python 执行路径(推荐) os.environ['PYSPARK_PYTHON'] = r'D:\Python\python.exe' os.environ['PYSPARK_DRIVER_PYTHON'] = r'D:\Python\python.exe' # 创建 SparkSession spark = SparkSession.builder \ .appName("GroceryBasketAnalysis") \ .config("spark.master", "local[*]") \ .config("spark.sql.adaptive.enabled", "true") \ .getOrCreate() print("✅ Spark Session created successfully!") # 测试数据帧 df = spark.createDataFrame([(1, "成功")], ["id", "status"]) df.show() # 关闭 Spark spark.stop() print("✅ Spark stopped.") ``` 📌 替换路径中的 `D:\Python\python.exe` 为你自己的真实路径! 获取方法:在 CMD 中运行: ```bash where python ``` 或在 Python 中运行: ```python import sys print(sys.executable) ``` --- ### ✅ 第五步:放置 winutils.exe(仅限 Windows) 1. 进入 GitHub 搜索:`winutils/hadoop-3.3.0` 2. 下载 `winutils.exe` 3. 存放到: ``` %HADOOP_HOME%\bin\winutils.exe ``` 即: ``` D:\spark-tools\spark-4.0.1-bin-hadoop3\bin\winutils.exe ``` 否则会报错:`Cannot run program 'winutils.exe'` --- ### ✅ 第六步:运行脚本 进入终端,切换到脚本所在目录: ```bash cd D:\pythonprojects\GroceryBasketAnalysis\code python test_spark.py ``` 你应该看到输出: ``` ✅ Spark Session created successfully! +---+------+ | id|status| +---+------+ | 1| 成功 | +---+------+ ✅ Spark stopped. ``` --- ### ✅ 第七步:常见问题排查清单 ✅ | 问题现象 | 解决办法 | |--------|---------| | `ModuleNotFoundError: No module named 'pyspark'` | 运行 `pip install pyspark` | | `java.lang.IllegalStateException: Unable to access jarfile` | 检查 Java 安装并设置 `JAVA_HOME` | | `'winutils.exe' not found` | 将 `winutils.exe` 放入 `%HADOOP_HOME%\bin` | | `Python worker failed to connect back` | 设置 `PYSPARK_PYTHON` 和 `PYSPARK_DRIVER_PYTHON` | | 字符串路径断裂(如 `"D:\Python\py)` | 检查引号是否闭合,避免复制粘贴乱码 | --- ### ✅ 最终建议结构 ``` D:. ├── spark-tools │ └── spark-4.0.1-bin-hadoop3 │ ├── bin │ │ └── winutils.exe ← 在这里 │ ├── conf │ └── ... ├── Python │ └── python.exe ← PYSPARK_PYTHON 指向它 └── pythonprojects └── GroceryBasketAnalysis └── code └── test_spark.py ← 使用上面的标准脚本 ``` --- ## 🔚 总结 你原脚本的问题主要是: 1. **路径配置不完整**(如 `r"D:\Python\py` 缺失后缀) 2. **缺少必要的环境变量设置** 3. **未正确初始化 SparkSession** ✅ 按照以上 **7 步保姆流程操作**,即可彻底解决问题。 --- ### 📚 知识点详解(不超过三个) 1. **SparkSession 初始化机制** `$SparkSession.builder.config().getOrCreate()$` 是创建 Spark 入口的核心方法,需保证配置完整。 2. **PYSPARK_PYTHON 环境变量作用** 指定 Spark 使用哪个 Python 解释器执行任务,尤其在多环境时至关重要。 3. **WinUtils 对 Windows 的支持** Windows 不支持 Hadoop 原生命令,需借助 `winutils.exe` 模拟 Linux 文件权限行为。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值