<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Loading

      從車道檢測(cè)項(xiàng)目入門open cv

      從車道檢測(cè)項(xiàng)目入門open cv

      前提聲明:非常感謝b站up主 嘉然今天吃帶變,感謝其視頻的幫助。同時(shí)希望各位大佬積積極提出寶貴的意見(jiàn)。??????(?′?`?)(●'?'●)╰(°▽°)╯

      github地址:https://github.com/zhongzhengli13/openCV_Lane_Detection

      視頻地址:從車道檢測(cè)項(xiàng)目入門open cv

      基礎(chǔ)知識(shí)

      cv2.imread & cv2.imshow & cv2.imwrite

       import cv2 as cv
       
       img = cv.imread("img.png", cv.IMREAD_GRAYSCALE) #將圖片轉(zhuǎn)為灰度圖
      

      但是當(dāng)前會(huì)存在一些問(wèn)題,圖片會(huì)閃一下,看不清楚,所以我們可以加上阻塞 cv2.waitKey()函數(shù)

      #完整版
      import cv2 as cv
      
      img = cv.imread("img.png", cv.IMREAD_GRAYSCALE)
      print(type(img))
      print(img.shape)
      cv.imshow('image', img)
      k = cv.waitKey(0)  # 阻塞 #k相當(dāng)于檢測(cè)你的輸入的ascii值
      print(k)
      # while True:
      #     if cv.waitKey(0) == ord('q'):
      #         cv.destroyAllWindows()
      #     else:
      #         img = cv.imread("img.png", cv.IMREAD_GRAYSCALE)
      
      cv.imwrite("img_gray.png", img)#生成img圖片,保存到當(dāng)前目錄中~
      

      效果展示

      原始圖像:

      image-20250428092853043

      灰度圖:

      image-20250428092929086

      Canny邊緣檢測(cè)

      通過(guò)求取圖像上每一個(gè)像素點(diǎn)周邊圖像像素變化的梯度,來(lái)確定這個(gè)點(diǎn)是否是邊緣。

      image-20250428102959222

      梯度的方向一般總是與邊界垂直,梯度的方向被歸為四類:垂直、水平和兩個(gè)對(duì)角線(即,0度、45度、90度和135度四個(gè)方向)。

      image-20250428104012729

      我們現(xiàn)在的想法是設(shè)置一個(gè)閾值,當(dāng)梯度大于閾值時(shí),我們可以認(rèn)為該點(diǎn)是邊緣。但是隨之而來(lái)的是,圖片會(huì)產(chǎn)生一些毛邊或者光線,角度等問(wèn)題,導(dǎo)致可能會(huì)誤判。

      image-20250428105216769

      為了解決這個(gè)問(wèn)題,我們采用雙閾值的方法,一個(gè)上閾值,一個(gè)下閾值。

      image-20250428105314881

      我們認(rèn)為高于上閾值的點(diǎn)為強(qiáng)邊緣,在上閾值和下閾值之間的我們認(rèn)為是弱邊緣。

      我們認(rèn)為只有弱邊緣與強(qiáng)邊緣相連的話,才是邊緣。B不認(rèn)為是邊緣,可能是噪聲;C與A強(qiáng)邊緣相連,我們認(rèn)為C是邊緣。

      import cv2
      
      img = cv2.imread("img.png", cv2.IMREAD_GRAYSCALE)
      
      edge_img = cv2.Canny(img, 190, 350)  # 下邊緣和上邊緣的閾值設(shè)定 #需要自行更改
      cv2.imshow("edge", edge_img)
      cv2.waitKey(0)
      
      
      image-20250429203018189

      當(dāng)上邊緣和下邊緣都升高時(shí),邊緣顯示會(huì)越來(lái)越少。


      ROI mask

      簡(jiǎn)單來(lái)講就是類似于摳圖,就是剔除無(wú)關(guān)信息的邊緣。

      roi : region of interest 感興趣的區(qū)域

      ? 數(shù)組切片

      ? 布爾運(yùn)算(與運(yùn)算)

      image-20250428111139930
      • cv2.fillPoly 是 OpenCV 中的一個(gè)函數(shù),用于在圖像中填充多邊形區(qū)域。它常用于繪制、遮罩或標(biāo)記圖像中的特定區(qū)域。通過(guò)指定多邊形的頂點(diǎn),cv2.fillPoly 可以將這些區(qū)域填充為指定的顏色。

      • cv2.bitwise_and 是 OpenCV 中的一個(gè)函數(shù),用于對(duì)兩個(gè)圖像或數(shù)組進(jìn)行按位與(bitwise AND)操作。按位與操作是逐像素進(jìn)行的,只有當(dāng)兩個(gè)圖像的對(duì)應(yīng)像素都為非零值時(shí),結(jié)果圖像的該像素才為非零值。

        • 圖像遮罩

          • 使用掩碼提取圖像的特定區(qū)域。例如,將一個(gè)形狀(如矩形、圓形或多邊形)作為掩碼,只保留掩碼內(nèi)的圖像內(nèi)容。
        • 圖像合成

          • 將兩個(gè)圖像的特定部分組合在一起。
        • 圖像處理

          • 在圖像處理中,按位與操作常用于對(duì)圖像進(jìn)行區(qū)域選擇或區(qū)域遮擋。

      圖像以矩陣np.array形式存儲(chǔ)在內(nèi)存中

      ? np.zeros_like : np.zeros_like 是 NumPy 庫(kù)中的一個(gè)函數(shù),用于創(chuàng)建一個(gè)與給定數(shù)組形狀和數(shù)據(jù)類型相同的數(shù)組,但所有元素都初始化為零。

      # @Author : LiZhongzheng
      # 開(kāi)發(fā)時(shí)間  :2025-04-28 17:30
      import cv2
      import numpy as np
      
      edge_img = cv2.imread("edge_img.png", cv2.IMREAD_GRAYSCALE)
      mask = np.zeros_like(edge_img)  # 獲取一個(gè)與edge_img大小相同的數(shù)組
      mask = cv2.fillPoly(mask, np.array([[[0, 569], [661, 195], [914, 248], [979, 592]]]),
                          color=255)  # array中的存放的是想要識(shí)別區(qū)域的四個(gè)頂點(diǎn) #順序?yàn)樽笙?、左上、右上、右?
      masked_edge_img = cv2.bitwise_and(edge_img, mask)
      # cv2.imshow('mask', mask)
      # cv2.waitKey(0)
      cv2.imshow("edged", masked_edge_img)
      cv2.waitKey(0)
      
      
      image-20250429202953080

      霍夫變換

      提取圖片中的直線。

      注意:霍夫變換是針對(duì)灰度圖的。

      image-20250428191915811 image-20250428192232916 image-20250428192253353

      min是最短線段的長(zhǎng)度,max是兩點(diǎn)之間的最大距離,超過(guò)這個(gè)距離就不認(rèn)為是線段了。

      • 首先經(jīng)過(guò) cv2.HoughLinesP()函數(shù)獲取到所有的線條,然后計(jì)算線條的斜率,根據(jù)斜率的正負(fù)判斷是左車道線還是右車道線。

        • # @Author : LiZhongzheng
          # 開(kāi)發(fā)時(shí)間  :2025-04-29 8:54
          import cv2
          import numpy as np
          
          
          def calculate_slope(line):
              """
              計(jì)算線段line的斜率
              :param line: np.array([[x_1, y_1, x_2, y_2]])
              :return:
              """
              x_1, y_1, x_2, y_2 = line[0]
              return (y_2 - y_1) / (x_2 - x_1)
          
          
          edge_img = cv2.imread('masked_edge_img.jpg', cv2.IMREAD_GRAYSCALE)
          # 獲取所有線段
          lines = cv2.HoughLinesP(edge_img, 1, np.pi / 180, 15, minLineLength=40,
                                  maxLineGap=20)
          # 按照斜率分成車道線
          left_lines = [line for line in lines if calculate_slope(line) > 0]
          right_lines = [line for line in lines if calculate_slope(line) < 0]
          
          print("left_lines =", len(left_lines))
          print("right_lines =", len(right_lines))
          

      離群值過(guò)濾

      剔除出因?yàn)檎`差而被識(shí)別出的直線。

      如何分解出噪點(diǎn)和車道線那?

      • 我們可以知道,車道線的斜率大致是相同的,進(jìn)而可以分辨出噪點(diǎn)和車道線。
      # @Author : LiZhongzheng
      # 開(kāi)發(fā)時(shí)間  :2025-04-29 9:01
      import cv2
      import numpy as np
      
      """
      剔除出因?yàn)檎`差而被識(shí)別出的直線。
      如何分解出噪點(diǎn)和車道線那?
          我們可以知道,車道線的斜率大致是相同的,進(jìn)而可以分辨出噪點(diǎn)和車道線。
      """
      
      
      def calculate_slope(line):
          """
          計(jì)算線段line的斜率
          :param line: np.array([[x_1, y_1, x_2, y_2]])
          :return:
          """
          x_1, y_1, x_2, y_2 = line[0]
          return (y_2 - y_1) / (x_2 - x_1)
      
      
      edge_img = cv2.imread('masked_edge_img.jpg', cv2.IMREAD_GRAYSCALE)
      
      # 獲取所有線段
      lines = cv2.HoughLinesP(edge_img, 1, np.pi / 180, 15, minLineLength=40, maxLineGap=20)
      
      # 按照斜率分成車道線
      left_lines = [line for line in lines if calculate_slope(line) > 0]
      right_lines = [line for line in lines if calculate_slope(line) < 0]
      
      
      def reject_abnormal_lines(lines, threshold):
          """
          剔除斜率不一致的線段
          :param lines: 線段集合, [np.array([[x_1, y_1, x_2, y_2]]),np.array([[x_1, y_1, x_2, y_2]]),...,np.array([[x_1, y_1, x_2, y_2]])]
          """
          slopes = [calculate_slope(line) for line in lines]
          while len(lines) > 0:
              mean = np.mean(slopes)  # 使用 NumPy 的 np.mean 函數(shù)計(jì)算當(dāng)前所有斜率的平均值
              diff = [abs(s - mean) for s in slopes]  # 遍歷 slopes 列表,計(jì)算每個(gè)斜率與平均斜率的絕對(duì)差值,并將結(jié)果存儲(chǔ)在 diff 列表中
              idx = np.argmax(diff)  # 使用 NumPy 的 np.argmax 函數(shù)找到 diff 列表中最大值的索引,即斜率差異最大的線段。
              if diff[idx] > threshold:  # 如果最大差異大于閾值 threshold,則認(rèn)為該線段是異常的,將其從 slopes 和 lines 列表中移除。
                  slopes.pop(idx)
                  lines.pop(idx)
              else:  # 如果最大差異小于或等于閾值,則認(rèn)為所有線段的斜率已經(jīng)足夠一致,退出循環(huán)。
                  break
          return lines  # 如果最大差異小于或等于閾值,則認(rèn)為所有線段的斜率已經(jīng)足夠一致,退出循環(huán)。
      
      
      print('before filter:')
      print('left lines number=')
      print(len(left_lines))
      print('right lines number=')
      print(len(right_lines))
      
      reject_abnormal_lines(left_lines, threshold=0.2)
      reject_abnormal_lines(right_lines, threshold=0.2)
      
      print('after filter:')
      print('left lines number=')
      print(len(left_lines))
      print('right lines number=')
      print(len(right_lines))
      
      

      最小二乘擬合

      將lines的線段擬合成一條直線。

      np.ravel 將高維數(shù)組拉成一維

      np.polyfit 多項(xiàng)式擬合

      np.polyval 多項(xiàng)式求值

      • 經(jīng)過(guò)上述的步驟,進(jìn)而我們可以求出車道線的數(shù)量等信息,同時(shí)又剔除了噪點(diǎn)。然后我們就可以將在同一個(gè)區(qū)域的線段擬合一條直線

        • # @Author : LiZhongzheng
          # 開(kāi)發(fā)時(shí)間  :2025-04-29 15:58
          import cv2
          import numpy as np
          
          
          def calculate_slope(line):
              """
              計(jì)算線段line的斜率
              :param line: np.array([[x_1, y_1, x_2, y_2]])
              :return:
              """
              x_1, y_1, x_2, y_2 = line[0]
              return (y_2 - y_1) / (x_2 - x_1)
          
          
          edge_img = cv2.imread("masked_edge_img.jpg", cv2.IMREAD_GRAYSCALE)
          # 獲取所有線段
          lines = cv2.HoughLinesP(edge_img, 1, np.pi / 180, 15, minLineLength=40, maxLineGap=20)
          
          # 按照斜率分成車道線
          left_lines = [line for line in lines if calculate_slope(line) > 0]
          right_lines = [line for line in lines if calculate_slope(line) < 0]
          
          
          def reject_abnormal_lines(lines, threshold):
              """
              剔除斜率不一致的線段
              :param lines: 線段集合, [np.array([[x_1, y_1, x_2, y_2]]),np.array([[x_1, y_1, x_2, y_2]]),...,np.array([[x_1, y_1, x_2, y_2]])]
              """
              slopes = [calculate_slope(line) for line in lines]
              while len(lines) > 0:
                  mean = np.mean(slopes)
                  diff = [abs(s - mean) for s in slopes]
                  idx = np.argmax(diff)
                  if (diff[idx] > threshold):
                      slopes.pop(idx)
                      lines.pop(idx)
                  else:
                      break
                  return lines
          
          
          left_lines = reject_abnormal_lines(left_lines, threshold=0.2)
          right_lines = reject_abnormal_lines(right_lines, threshold=0.2)
          
          
          def least_squares_fit(lines):
              """
              將lines中的線段擬合成一條線段
              :param lines: 線段集合, [np.array([[x_1, y_1, x_2, y_2]]),np.array([[x_1, y_1, x_2, y_2]]),...,np.array([[x_1, y_1, x_2, y_2]])]
              :return: 線段上的兩點(diǎn),np.array([[xmin, ymin], [xmax, ymax]])
              """
              # 1. 取出所有坐標(biāo)點(diǎn)
              """
              在 OpenCV 中,線段通常用一個(gè)形狀為 (1, 4) 的 NumPy 數(shù)組表示,其中包含線段的兩個(gè)端點(diǎn)的坐標(biāo)。
              具體來(lái)說(shuō),數(shù)組的格式為 [x1, y1, x2, y2],分別表示起點(diǎn) (x1, y1) 和終點(diǎn) (x2, y2)。
              """
              x_coords = np.ravel([[line[0][0], line[0][2]] for line in lines])  # np.ravel 將二維列表展平為一維數(shù)組
              y_coords = np.ravel([[line[0][1], line[0][3]] for line in lines])
              # 2. 進(jìn)行直線擬合.得到多項(xiàng)式系數(shù)
              poly = np.polyfit(x_coords, y_coords, deg=1)
              # 3. 根據(jù)多項(xiàng)式系數(shù),計(jì)算兩個(gè)直線上的點(diǎn),用于唯一確定這條直線
              point_min = (np.min(x_coords), np.polyval(poly, np.min(x_coords)))
              point_max = (np.max(x_coords), np.polyval(poly, np.max(x_coords)))
              return np.array([point_min, point_max], dtype=np.int32)
          
          
          print("left lane")
          print(least_squares_fit(left_lines))
          print("right lane")
          print(least_squares_fit(right_lines))
          
          

      直線繪制

      繪制車道線 cv2.line

      # @Author : LiZhongzheng
      # 開(kāi)發(fā)時(shí)間  :2025-04-29 16:23
      import cv2
      import numpy as np
      
      
      def calculate_slope(line):
          """
          計(jì)算線段line的斜率
          :param line: np.array([[x_1, y_1, x_2, y_2]])
          :return:
          """
          x_1, y_1, x_2, y_2 = line[0]
          return (y_2 - y_1) / (x_2 - x_1)
      
      
      edge_img = cv2.imread('masked_edge_img.jpg', cv2.IMREAD_GRAYSCALE)
      # 獲取所有線段
      lines = cv2.HoughLinesP(edge_img, 1, np.pi / 180, 15, minLineLength=40,
                              maxLineGap=20)
      # 按照斜率分成車道線
      left_lines = [line for line in lines if calculate_slope(line) > 0]
      right_lines = [line for line in lines if calculate_slope(line) < 0]
      
      
      def reject_abnormal_lines(lines, threshold):
          """
          剔除斜率不一致的線段
          :param lines: 線段集合, [np.array([[x_1, y_1, x_2, y_2]]),np.array([[x_1, y_1, x_2, y_2]]),...,np.array([[x_1, y_1, x_2, y_2]])]
          """
          slopes = [calculate_slope(line) for line in lines]
          while len(lines) > 0:
              mean = np.mean(slopes)
              diff = [abs(s - mean) for s in slopes]
              idx = np.argmax(diff)
              if diff[idx] > threshold:
                  slopes.pop(idx)
                  lines.pop(idx)
              else:
                  break
          return lines
      
      
      left_lines = reject_abnormal_lines(left_lines, threshold=0.2)
      right_lines = reject_abnormal_lines(right_lines, threshold=0.2)
      
      
      def least_squares_fit(lines):
          """
          將lines中的線段擬合成一條線段
          :param lines: 線段集合, [np.array([[x_1, y_1, x_2, y_2]]),np.array([[x_1, y_1, x_2, y_2]]),...,np.array([[x_1, y_1, x_2, y_2]])]
          :return: 線段上的兩點(diǎn),np.array([[xmin, ymin], [xmax, ymax]])
          """
          # 1. 取出所有坐標(biāo)點(diǎn)
          x_coords = np.ravel([[line[0][0], line[0][2]] for line in lines])
          y_coords = np.ravel([[line[0][1], line[0][3]] for line in lines])
          # 2. 進(jìn)行直線擬合.得到多項(xiàng)式系數(shù)
          poly = np.polyfit(x_coords, y_coords, deg=1)
          # 3. 根據(jù)多項(xiàng)式系數(shù),計(jì)算兩個(gè)直線上的點(diǎn),用于唯一確定這條直線
          point_min = (np.min(x_coords), np.polyval(poly, np.min(x_coords)))
          point_max = (np.max(x_coords), np.polyval(poly, np.max(x_coords)))
          return np.array([point_min, point_max], dtype=np.int32)
      
      
      left_line = least_squares_fit(left_lines)
      right_line = least_squares_fit(right_lines)
      
      img = cv2.imread('img.jpg', cv2.IMREAD_COLOR)
      cv2.line(img, tuple(left_line[0]), tuple(left_line[1]), color=(0, 255, 255), thickness=5)
      cv2.line(img, tuple(right_line[0]), tuple(right_line[1]), color=(0, 255, 255), thickness=5)
      
      cv2.imshow('lane', img)
      cv2.waitKey(0)
      
      
      image-20250429205831425
      重難點(diǎn)講解:least_squares_fit()函數(shù)講解

      該函數(shù)主要做了三個(gè)部分:提取坐標(biāo)點(diǎn)、進(jìn)行直線擬合、計(jì)算直線上的兩個(gè)點(diǎn)。

      1. 提取所有坐標(biāo)點(diǎn)
      x_coords = np.ravel([[line[0][0], line[0][2]] for line in lines])
      y_coords = np.ravel([[line[0][1], line[0][3]] for line in lines])
      
      • lines
        • 輸入的線段集合,每個(gè)線段是一個(gè)形狀為 (1, 4) 的 NumPy 數(shù)組,表示線段的兩個(gè)端點(diǎn)坐標(biāo) [x1,y1,x2,y2]。
      • x_coords
        • 提取所有線段的 x 坐標(biāo)。line[0][0] 是起點(diǎn)的 x 坐標(biāo),line[0][2] 是終點(diǎn)的 x 坐標(biāo)。
        • 使用列表推導(dǎo)式 [[line[0][0], line[0][2]] for line in lines] 生成一個(gè)二維列表,包含所有線段的起點(diǎn)和終點(diǎn)的 x 坐標(biāo)。
        • 使用 np.ravel 將二維列表展平為一維數(shù)組。
      • y_coords
        • 提取所有線段的 y 坐標(biāo)。line[0][1] 是起點(diǎn)的 y 坐標(biāo),line[0][3] 是終點(diǎn)的 y 坐標(biāo)。
        • 使用列表推導(dǎo)式 [[line[0][1], line[0][3]] for line in lines] 生成一個(gè)二維列表,包含所有線段的起點(diǎn)和終點(diǎn)的 y 坐標(biāo)。
        • 使用 np.ravel 將二維列表展平為一維數(shù)組。
      2. 進(jìn)行直線擬合
      poly = np.polyfit(x_coords, y_coords, deg=1)
      
      • np.polyfit
        • 這是 NumPy 中的一個(gè)函數(shù),用于對(duì)給定的數(shù)據(jù)點(diǎn)進(jìn)行多項(xiàng)式擬合。
        • 參數(shù):
          • x_coords:自變量 x 的值。
          • y_coords:因變量 y 的值。
          • deg=1:指定擬合多項(xiàng)式的次數(shù)為 1,即線性擬合。
        • 返回值:
          • 返回?cái)M合多項(xiàng)式的系數(shù),從最高次項(xiàng)到常數(shù)項(xiàng)。對(duì)于線性擬合,返回兩個(gè)值 [slope, intercept],分別表示直線的斜率和截距。
      3. 計(jì)算直線上的兩個(gè)點(diǎn)
      point_min = (np.min(x_coords), np.polyval(poly, np.min(x_coords)))
      point_max = (np.max(x_coords), np.polyval(poly, np.max(x_coords)))
      
      • np.min(x_coords)np.max(x_coords)
        • 分別計(jì)算 x 坐標(biāo)中的最小值和最大值。
      • np.polyval(poly, x)
        • 這是 NumPy 中的一個(gè)函數(shù),用于計(jì)算多項(xiàng)式在給定的 x 值處的 y 值。
        • 參數(shù):
          • poly:擬合多項(xiàng)式的系數(shù)數(shù)組。
          • x:輸入的 x 值。
        • 返回值:
          • 返回多項(xiàng)式在 x 處的 y 值。
      • point_minpoint_max
        • point_min 是直線上的一個(gè)點(diǎn),其 x 坐標(biāo)為最小值,y 坐標(biāo)通過(guò)多項(xiàng)式計(jì)算得到。
        • point_max 是直線上的一個(gè)點(diǎn),其 x 坐標(biāo)為最大值,y 坐標(biāo)通過(guò)多項(xiàng)式計(jì)算得到。
      4. 返回值
      return np.array([point_min, point_max], dtype=np.int32)
      
      • 返回一個(gè)形狀為 (2, 2) 的 NumPy 數(shù)組,表示直線上的兩個(gè)點(diǎn)的坐標(biāo)。這兩個(gè)點(diǎn)可以唯一確定一條直線。

      視頻流讀寫

      cv2.VideoCapture

      ? capture.read

      • 基礎(chǔ)代碼介紹:
      # @Author : LiZhongzheng
      # 開(kāi)發(fā)時(shí)間  :2025-04-29 17:06
      import cv2
      
      capture = cv2.VideoCapture('video.mp4')
      # capture = cv2.VideoCapture(0) #讀取當(dāng)前設(shè)備第0個(gè)攝像頭
      while True:
          ret, frame = capture.read()  # ret 視頻流的狀態(tài),frame 當(dāng)前幀的圖像
          cv2.imshow('frame', frame)
          cv2.waitKey(20)  # 相當(dāng)于播放速率
      
      

      cv2.VideoWriter

      最后我們不僅可以識(shí)別圖片的車道線還可以識(shí)別視頻的車道線,原理相同,因?yàn)橐曨l是一幀一幀的,每一幀就是一個(gè)圖片。

      # @Author : LiZhongzheng
      # 開(kāi)發(fā)時(shí)間  :2025-04-29 17:12
      import cv2
      import numpy as np
      
      
      def get_edge_img(color_img, gaussian_ksize=5, gaussian_sigmax=1, canny_threshold1=50, canny_threshold2=100):
          """
          灰度化,模糊,canny變換,提取邊緣
          :param color_img: 彩色圖,channels=3
          """
          """
          cv2.GaussianBlur() 函數(shù)參數(shù)
          color_img:
          輸入的彩色圖像,必須是 3 通道的 BGR 圖像。
          gaussian_ksize(可選):
          高斯模糊的核大小。必須是正奇數(shù),默認(rèn)值為 5。
          gaussian_sigmax(可選):
          高斯模糊的 X 方向標(biāo)準(zhǔn)差,默認(rèn)值為 1。
          """
          gaussian = cv2.GaussianBlur(color_img, (gaussian_ksize, gaussian_ksize),
                                      gaussian_sigmax)  # 使用 cv2.GaussianBlur 對(duì)輸入圖像進(jìn)行高斯模糊處理。高斯模糊可以減少圖像中的噪聲,使邊緣檢測(cè)更加穩(wěn)定。
          gray_img = cv2.cvtColor(gaussian, cv2.COLOR_BGR2GRAY)
          edges_img = cv2.Canny(gray_img, canny_threshold1, canny_threshold2)
          return edges_img
      
      
      def roi_mask(gray_img):
          """
          對(duì)gray_img進(jìn)行掩膜
          :param gray_img: 灰度圖,channels=1
          """
          poly_pts = np.array([[[0, 368], [300, 210], [340, 210], [640, 368]]])
          mask = np.zeros_like(gray_img)
          mask = cv2.fillPoly(mask, pts=poly_pts, color=255)
          img_mask = cv2.bitwise_and(gray_img, mask)
          return img_mask
      
      
      def get_lines(edge_img):
          """
          獲取edge_img中的所有線段
          :param edge_img: 標(biāo)記邊緣的灰度圖
          """
      
          def calculate_slope(line):
              """
              計(jì)算線段line的斜率
              :param line: np.array([[x_1, y_1, x_2, y_2]])
              :return:
              """
              x_1, y_1, x_2, y_2 = line[0]
              return (y_2 - y_1) / (x_2 - x_1)
      
          def reject_abnormal_lines(lines, threshold=0.2):
              """
              剔除斜率不一致的線段
              :param lines: 線段集合, [np.array([[x_1, y_1, x_2, y_2]]),np.array([[x_1, y_1, x_2, y_2]]),...,np.array([[x_1, y_1, x_2, y_2]])]
              """
              slopes = [calculate_slope(line) for line in lines]
              while len(lines) > 0:
                  mean = np.mean(slopes)
                  diff = [abs(s - mean) for s in slopes]
                  idx = np.argmax(diff)
                  if (diff[idx] > threshold):
                      slopes.pop(idx)
                      diff.pop(idx)
                  else:
                      break
              return lines
      
          def least_squares_fit(lines):
              """
              將lines中的線段擬合成一條線段
              :param lines: 線段集合, [np.array([[x_1, y_1, x_2, y_2]]),np.array([[x_1, y_1, x_2, y_2]]),...,np.array([[x_1, y_1, x_2, y_2]])]
              :return: 線段上的兩點(diǎn),np.array([[xmin, ymin], [xmax, ymax]])
              """
              """
              np.polyfit 是 NumPy 庫(kù)中的一個(gè)函數(shù),用于對(duì)給定的數(shù)據(jù)點(diǎn)進(jìn)行多項(xiàng)式擬合。
              它通過(guò)最小二乘法找到一個(gè)多項(xiàng)式,使得這個(gè)多項(xiàng)式在給定數(shù)據(jù)點(diǎn)上的值與實(shí)際值之間的誤差平方和最小。
              """
              x_coords = np.ravel([[line[0][0], line[0][2]] for line in lines])
              y_coords = np.ravel([[line[0][1], line[0][3]] for line in lines])
              poly = np.polyfit(x_coords, y_coords, deg=1)
              point_min = (np.min(x_coords), np.polyval(poly, np.min(
                  x_coords)))  # 這行代碼的作用是計(jì)算擬合直線(或多項(xiàng)式曲線)上的一個(gè)特定點(diǎn)的坐標(biāo)。具體來(lái)說(shuō),它計(jì)算的是當(dāng) x 取最小值時(shí),對(duì)應(yīng)的 y 值,并將這個(gè)點(diǎn)的坐標(biāo)存儲(chǔ)為一個(gè)元組 (x_min, y_min)。
              point_max = (np.max(x_coords), np.polyval(poly, np.max(x_coords)))
              return np.array([point_min, point_max], dtype=np.int32)
      
          # 獲取所有線段
          lines = cv2.HoughLinesP(edge_img, 1, np.pi / 180, 15, minLineLength=40,
                                  maxLineGap=20)
          # 按照斜率分成車道線
          left_lines = [line for line in lines if calculate_slope(line) > 0]
          right_lines = [line for line in lines if calculate_slope(line) < 0]
          # 剔除離群線段
          left_lines = reject_abnormal_lines(left_lines)
          right_lines = reject_abnormal_lines(right_lines)
      
          return least_squares_fit(left_lines), least_squares_fit(right_lines)
      
      
      def draw_lines(img, lines):
          """
          在img上繪制lines
          :param img:
          :param lines: 兩條線段: [np.array([[xmin1, ymin1], [xmax1, ymax1]]), np.array([[xmin2, ymin2], [xmax2, ymax2]])]
          :return:
          """
          left_line, right_line = lines
          cv2.line(img, tuple(left_line[0]), tuple(left_line[1]), color=(0, 255, 255),
                   thickness=5)
          cv2.line(img, tuple(right_line[0]), tuple(right_line[1]),
                   color=(0, 255, 255), thickness=5)
      
      
      def show_lane(color_img):  # 封裝
          """
          在color_img上畫出車道線
          :param color_img: 彩色圖,channels=3
          :return:
          """
          edge_img = get_edge_img(color_img)
          mask_gray_img = roi_mask(edge_img)
          lines = get_lines(mask_gray_img)
          draw_lines(color_img, lines)
          return color_img
      
      
      if __name__ == '__main__':
          capture = cv2.VideoCapture('video.mp4')
          while True:
              ret, frame = capture.read()
              frame = show_lane(frame)
              cv2.imshow('frame', frame)
              cv2.waitKey(10)
      
      
      image-20250429195914415

      以上就是我對(duì)這個(gè)項(xiàng)目的總結(jié)。

      同時(shí)再次說(shuō)明我已經(jīng)將項(xiàng)目上傳到github項(xiàng)目中,歡迎大家多多支持,你們的支持是我最大的前進(jìn)動(dòng)力~~~

      再次感謝b站up主 嘉然今天吃帶變,以及各位大佬的寶貴意見(jiàn)。

      祝好~

      posted @ 2025-04-29 21:27  蝦餃愛(ài)下棋  閱讀(599)  評(píng)論(2)    收藏  舉報(bào)
      主站蜘蛛池模板: 少妇人妻真实偷人精品| 国产一区二区三区四区五区加勒比 | 中国少妇人妻xxxxx| 国产愉拍精品手机| 国产精品播放一区二区三区| 国产91精品丝袜美腿在线| 亚洲第一最快av网站| 在线观看国产午夜福利片| 国产精品国产精品无卡区| 蒙阴县| 精品 无码 国产观看| 国产精品鲁鲁鲁| 亚洲成人午夜排名成人午夜| 午夜精品久久久久久99热| 国产成人精品久久一区二| 自贡市| 久久婷婷五月综合97色直播| 国产美女被遭强高潮免费一视频| 国产蜜臀一区二区在线播放| 免费大黄网站在线观看| 亚洲色一区二区三区四区| 国产精品∧v在线观看| 国产成人AV一区二区三区无码 | 国产午夜亚洲精品国产成人| 国产太嫩了在线观看| 忘记穿内裤被同桌摸到高潮app| 99热久久这里只有精品| 高h纯肉无码视频在线观看| 久久精品国产一区二区三区| 国产精品久久国产精麻豆99网站| 九九热视频在线免费观看| 成人啪精品视频网站午夜| 亚洲另类无码一区二区三区| 亚洲成片在线看一区二区| 亚洲精品日本久久一区二区三区 | 国产亚洲中文字幕久久网| 日韩国产中文字幕精品| 岚皋县| 日韩av在线不卡一区二区三区| 人成午夜免费大片| 亚洲AV永久无码嘿嘿嘿嘿|