Đầu tiên, tạo một hàm getLaneCurve và sau đó áp dụng giá trị ngưỡng cho hình ảnh.
BƯỚC 1 – Xác định giá trị ngưỡng
Bây giờ, ý tưởng ở đây là tìm ra làn đường bằng cách sử dụng Color hoặc Edge Detection. Trong trường hợp này, sử dụng giấy trắng A4 làm làn đường, do đó, chỉ cần sử dụng tính năng phát hiện màu để tìm làn đường. Sau đó, viết hàm Thresholding trong tệp Utlis.py.
Ở đây, chuyển đổi hình ảnh sang không gian màu HSV và sau đó áp dụng một dải màu cần tìm. Màu này có thể được tìm thấy bằng cách sử dụng tập lệnh bộ chọn màu.
Hình 2.2 Cung cấp phạm vi giá trị cần sử dụng để tìm làn đường. 2.1.3.Làn đường cong vênh
Mục đích của chương trình là biết khúc cua trên con đường ngay phía trước xe chứ không phải ở phía trước quá xa. Vì vậy, đơn giản là cắt hình ảnh ra, nhưng điều này là chưa đủ vì muốn nhìn con đường như thể chúng ta đang quan sát từ trên xuống. Đây được gọi là chế độ xem birdeye và nó rất quan trọng vì nó sẽ cho phép chúng ta dễ dàng tìm thấy đường cong. Để làm cong hình ảnh, chúng ta cần xác định các điểm ban đầu. Những điểm này chúng tôi có thể xác định bằng tay. Vì vậy, để làm cho quá trình này dễ dàng hơn, việc sử dụng các thanh theo dõi để thử nghiệm với các giá trị khác nhau. Ý tưởng là để có được một hình chữ nhật khi đường thẳng.
Tạo hai chức năng cho thanh theo dõi. Một cái khởi tạo thanh theo dõi và cái thứ hai nhận giá trị hiện tại từ chúng.
Bây giờ chúng ta có thể gọi hàm khởi tạo ở đầu mã và thanh valTrackbar trong vòng lặp while ngay trước khi làm cong hình ảnh. Vì cả hai hàm đều được viết trong tệp utlis nên ta sẽ viết ‘utlis.’ trước khi gọi chúng.
Bây giờ viết hàm cong vênh cho phép chúng ta có được chế độ xem birdeye bằng cách sử dụng bốn điểm mà vừa điều chỉnh.
Ở đây sẽ nhận được ma trận chuyển đổi dựa trên các điểm đầu vào và sau đó làm cong hình ảnh bằng cách sử dụng chức năng ‘warpPrespective’. Vì cần áp dụng ma trận nghịch đảo và thêm chức năng này vào hàm của mình. Để nghịch đảo, chỉ cần ma trận nghịch đảo mà có thể tìm thấy bằng cách chuyển pts1 và pts2.
Bây giờ gọi hàm để lấy phối cảnh dọc.
Hình ảnh dưới đây cho thấy rõ các điểm để làm cho quá trình điều chỉnh dễ dàng hơn. Vì vậy, để hiển thị các điểm của chúng ta sẽ sử dụng hàm "circle".
Hình 2.3 A. imgThres B. imgWarpPoints C. imgWarp 2.1.4.Tìm làn đường cong
Bây giờ đến phần quan trọng nhất, tìm đường cong trên con đường. Để làm điều này, chúng ta sử dụng tổng các pixel. Giả sử rằng hình ảnh bị cong vênh bây giờ là các giá trị nhị phân, tức là nó có pixel đen hoặc trắng, tính tổng các giá trị pixel theo hướng y.
Hình 2.4 Giá trị nhị phân của làn đường cong
Hình trên cho thấy tất cả các pixel màu trắng với giá trị 255 và tất cả màu đen với 0. Bây giờ nếu chúng ta tính tổng các pixel trong cột đầu tiên, nó sẽ là 255 + 255 + 255 + 255 + 255 = 1275. Áp dụng phương pháp này cho từng cột. Trong hình ảnh gốc như trên, có chiều rộng là 480 pixel. Do đó có 480 giá trị. Sau khi tổng kết, có thể xem có bao nhiêu giá trị nằm trên một ngưỡng nhất định, giả sử là 1000 ở mỗi bên của đường màu đỏ trung tâm. Trong ví dụ trên chúng ta có 8 cột bên trái và 3 cột bên phải. Điều này cho chúng ta biết rằng đường cong hướng về bên trái.
Hình 2.5 Ba trường hợp mà phương pháp này nhận diện
Các hình ảnh trên cho thấy 3 trường hợp mà các phương pháp này sẽ hoạt động. Có thể thấy rõ rằng khi đường cong ở bên phải số lượng pixel ở bên phải nhiều hơn bên trái và ngược lại. Và với đường thẳng, số lượng pixel xấp xỉ nhau ở cả hai bên.
Nhưng sẽ có một số trường hợp không áp dụng được. Vấn đề được biểu diễn ở dưới.
Hình 2.6 Một số làn đặc biệt
Ở đây, mặc dù không có đường cong vì có nhiều pixel hơn ở một bên, thuật toán sẽ xuất ra đường cong trái hoặc phải. Vì vậy, để giải quyết vấn đề này thì sẽ phải điều chỉnh đường tâm.
Hình 2.7 Điều chỉnh đường tâm của làn đặc biệt
Chỉ cần tìm tâm của cơ sở sẽ cung cấp đường trung tâm và sau đó so sánh các pixel ở cả hai bên.
Việc này có thể được tính toán bằng một phương pháp. Bằng cách tổng hợp các pixel này, sau đó thu được một biểu đồ. Do đó gọi hàm này là ‘getHistogram’. Giả sử đang thực hiện bước thứ hai trong đó phải tính tổng tất cả các pixel và sau đó sẽ quay lại bước một để tìm tâm của cơ sở.
Đầu tiên khai báo hàm sẽ lấy image làm đối số đầu vào. Sau đó tính tổng tất cả các pixel theo hướng y.
Bây giờ một số pixel trong hình ảnh có thể chỉ là nhiễu. Vì vậy, việc sử dụng chúng trong tính toán là không hay. Do đó, đặt giá trị ngưỡng sẽ là giá trị tối thiểu cần thiết cho bất kỳ cột nào để đủ điều kiện là một phần của đường dẫn và không bị nhiễu. Đặt một giá trị được mã hóa cứng dựa trên dữ liệu trực tiếp. Vì vậy, tìm giá trị tổng lớn nhất và nhân tỷ lệ phần trăm do người dùng xác định với nó để tạo ra giá trị ngưỡng.
Bây giờ chỉ cần thêm tất cả số lượng pixel ở mỗi bên và tìm hướng trái phải hoặc hướng thẳng. Nếu đường cong là đúng, phải xác định rằng biết bao nhiêu là đúng. Để có được giá trị của độ cong, việc tìm các chỉ số của tất cả các cột có giá trị lớn hơn ngưỡng và sau đó sẽ tính trung bình các chỉ số của mình. Điều này có nghĩa là nếu chỉ số pixel bắt đầu từ 30 và kết thúc ở 300, trung bình sẽ là (300-30) / 2 +30 = 165.
Giá trị cơ sở bây giờ là điểm cơ sở trung bình của hình ảnh thu thập được. Vẽ thêm điểm cơ sở này để hình dung rõ hơn.
Hình 2.8 imgWarp imgHist
Ở đây có thể thấy biểu đồ của hình ảnh bị cong vênh ở bên phải. Chấm màu vàng là giá trị trung bình nghiêng về phía bên tay trái. Giá trị trung bình nhận được là 227.
2.1.5.Tối ưu hóa đường cong
Bây giờ trừ giá trị này ra khỏi tâm để lấy giá trị đường cong. Nếu giả sử tâm là 240 thì giá trị đường cong là 227-240 = -13. Ở đây dấu trừ cho biết đường cong hướng về phía bên trái và giá trị 13 cho biết cường độ của đường cong. Như đã thảo luận trước đó, phương pháp này không chính xác vì phần giữa có thể thay đổi.
Vì vậy, để tìm chính giữa có thể chỉ cần sử dụng chức năng vừa tạo, nhưng lần này thay vì hình ảnh hoàn chỉnh, áp dụng kỹ thuật biểu đồ chỉ trên 1/4 phần dưới cùng của hình ảnh. Điều này là do quan tâm đến mức trung bình của cơ sở, vì vậy không muốn tính trung bình các pixel trên 1/4 hình ảnh. Để đạt được điều này, thêm một đối số đầu vào của vùng và dựa trên giá trị đầu vào của nó, và lấy trung bình toàn bộ hình ảnh hay một phần của nó.
Vì vậy, nếu vùng là 1, toàn bộ hình ảnh sẽ là trung bình và nếu vùng là 4 thì ở phần thứ 4 ở dưới cùng sẽ được tính trung bình. Hình ảnh dưới đây cho thấy giá trị trung bình của phần dưới cùng.
Hình 2.9 Giá trị trung bình của phần dưới cùng
Bây giờ giá trị trung bình chúng ta nhận được là 278. Điều này có nghĩa là trung tâm thực tế của hình ảnh là 278 thay vì 240. Bây giờ có thể trừ giá trị trung bình mà đã nhận được trước đó từ điểm giữa này. vậy 227 - 278 = -51. Trước đó giá trị là - 13 và bây giờ nhận được -51. Nhìn vào hình ảnh cong vênh, có thể biết rằng cường độ của đường cong là cao, do đó điều này khẳng định rằng phương pháp thứ hai cho kết quả tốt hơn.
BƯỚC 6 - Tính trung bình
Khi có giá trị đường cong, thêm nó vào một danh sách để có thể tính trung bình giá trị này. Tính trung bình sẽ cho phép chuyển động trơn tru và sẽ tránh được bất kỳ chuyển động mạnh nào.
Bây giờ chúng ta có thể thêm các tùy chọn để hiển thị kết quả cuối cùng. Chúng tôi sẽ thêm một đối số đầu vào vào hàm ‘getLaneCurve’ chính của chúng tôi để chúng tôi có thể linh hoạt bật và tắt nó.
Hình 2.10 Hiển thị trên máy tính
Hình 2.11 Tất cả các bước để xác định làn đường
2.2. Thuật toán CNN
2.2.1.Giới thiệu CNN
Kể từ những năm 1950, những ngày đầu của AI, các nhà nghiên cứu đã phải vật lộn để tạo ra một hệ thống có thể hiểu được dữ liệu trực quan. Trong những năm tiếp theo, lĩnh vực này được biết đến với tên gọi Computer Vision. Vào năm 2012, thị giác máy tính đã có một bước nhảy vọt khi một nhóm các nhà nghiên cứu từ Đại học Toronto phát triển một mô hình AI vượt qua các thuật toán nhận dạng hình ảnh tốt nhất và điều đó cũng mang lại lợi nhuận lớn.
Hình 2.12 Ảnh phân tích dữ liệu của chim
Hệ thống AI, được biết đến với tên gọi AlexNet (được đặt theo tên người tạo chính của nó, Alex Krizhevsky), đã giành chiến thắng trong cuộc thi thị giác máy tính ImageNet năm 2012 với độ chính xác 85% đáng kinh ngạc. Người về nhì chỉ đạt 74 phần trăm khiêm tốn trong bài kiểm tra.
CNN lần đầu tiên được phát triển và sử dụng vào khoảng những năm 1980. Điều mà CNN có thể làm được nhiều nhất vào thời điểm đó là nhận dạng các chữ số viết tay. Nó chủ yếu được sử dụng trong các lĩnh vực bưu chính để đọc mã zip, mã pin, v.v. Điều quan trọng cần nhớ đối với bất kỳ mô hình học sâu nào là nó đòi hỏi một lượng lớn dữ liệu để đào tạo và cũng đòi hỏi nhiều tài nguyên máy tính. Đây là một nhược điểm lớn đối với CNN vào thời kỳ đó và do đó CNN chỉ giới hạn trong lĩnh vực bưu chính và nó không thể bước vào thế giới máy học.
CNN là tên viết tắt của từ Convolutional Neural Network (hay còn gọi là CNNs_mang nơ ron tích chập). Đây là một trong những mô hình Deep Learning vô cùng tiên tiến. CNN sẽ cho phép bạn xây dựng các hệ thống thông minh với độ chính xác vô cùng cao. Tên "mạng nơ-ron tích chập" chỉ ra rằng mạng sử dụng một phép toán học được gọi là tích chập. CNN được dùng trong trong nhiều bài toán như nhân dạng ảnh, phân tích video.
Trong học sâu, mạng nơ-ron tích tụ (CNN /ConvNet) là một lớp của mạng nơ- ron sâu, được áp dụng phổ biến nhất để phân tích hình ảnh trực quan. Bây giờ khi chúng ta nghĩ về mạng nơ-ron, chúng ta nghĩ đến phép nhân ma trận nhưng đó không phải là trường hợp của ConvNet. Nó sử dụng một kỹ thuật đặc biệt gọi là Convolution. Bây giờ trong toán học, tích chập là một phép toán trên hai hàm tạo ra một hàm thứ ba biểu thị cách hình dạng của một hàm được sửa đổi bởi hàm kia.
2.2.2.Các lớp cơ bản trong CNN
Trong mô hình CNN thường có 4 lớp cơ bản: lớp tích chập (Convolutional Layer), lớp phi tuyến tính, lớp gộp (Pooding Layer), lớp kết nối đầy đủ (Full Connected Layer). Các layer liên kết được với nhau thông qua cơ chế convolution, Layer tiếp theo là kết quả convolution từ layer trước đó.
Hình 2.14 Lớp cơ bản trongCNN
2.2.2.1. Convolution layer
Tích chập là lớp đầu tiên để trích xuất các đặc trưng từ hình ảnh đầu vào. Xem xét 1 ma trận X kích thước 5*5 có giá trị pixel là 0 và 1. Ma trận bộ lọc W kích thước 3*3 như hình bên dưới.
Với mỗi phần tử xij trong ma trận X lấy ra một ma trận có kích thước của ma trận bộ lọc W có phần tử xij làm trung tâm gọi là ma trận A. Rồi dịch chuyển bộ lọc lần lượt theo chiều từ trái sang phải, từ trên xuống dưới, sau đó tính tổng các phần tử của phép nhân ma trận ta được ma trận kết quả Y.
Sau khi thao tác tích chập, kích thước hình ảnh ban đầu nhỏ lại, như ta thấy trên ví dụ là 5*5 xuống còn 3*3 do khi tính thì sẽ bỏ qua các phần tử ở viền ngoài vì không thể tìm được ma trận A trong X.
Nếu ma trận X m*n nhân chập với ma trận bộc lọc W k*k thì kích thước của ma trận sẽ là (m-k+1) * (n-k+1).
Padding:
Như trên với mỗi lần tính toán thì kích thước ma trận Y đều nhỏ hơn X. Tuy nhiên ta muốn ma trận Y thu được có kích thước bằng ma trận X bằng cách thêm giá trị 0 ở viền ngoài ma trận X.
Hình 2.16Ma trận X khi thêm viên 0 bên ngoài
Như vậy với padding = 1, ma trận kết quả Y sẽ bằng với ma trận X ban đầu.
Stride:
Như ở trên ta thực hiện tuần tự các phần tử trong ma trận X, thu được ma trận Y cùng kích thước ma trận X, ta gọi là stride=1.
Hình 2.17 stride=1, padding=1
Tuy nhiên với k=2, sẽ bắt đầu từ vị trí x11 sau đó nhảy 2 bước theo chiều ngang và dọc cho đến hết ma trận X.
Hình 2.18 stride=2, padding=1
Kích thước của ma trận Y lại là 3*3 đã giảm đi so với ma trận X.
Với ma trận X kích thước m*n và ma trận bộ lọc kích thước k*k, stride = s, padding = p, ta được ma trận Y kích thước [{(m + 2 - + 1) /} + 1] ∗ [{(+ 2 - + 1) /} + 1].
Mạng nơ-ron chuyển đổi bao gồm nhiều lớp nơ-ron nhân tạo. Các nơron nhân tạo, một sự bắt chước thô sơ của các đối tác sinh học của chúng, là các hàm toán học tính toán tổng trọng số của nhiều đầu vào và đầu ra một giá trị kích hoạt. Khi bạn nhập hình ảnh vào ConvNet, mỗi lớp tạo ra một số hàm kích hoạt được chuyển cho lớp tiếp theo.
Lớp đầu tiên thường trích xuất các tính năng cơ bản như các cạnh ngang hoặc chéo. Đầu ra này được chuyển sang lớp tiếp theo để phát hiện các đặc điểm phức tạp hơn như các góc hoặc các cạnh tổ hợp. Khi chúng tôi tiến sâu hơn vào mạng, nó có thể xác định các đặc điểm phức tạp hơn như vật thể, khuôn mặt…
Dựa trên bản đồ kích hoạt của lớp tích chập cuối cùng, lớp phân loại xuất ra một tập hợp các điểm tin cậy (giá trị từ 0 đến 1) xác định khả năng hình ảnh thuộc về một "lớp". Ví dụ: nếu bạn có ConvNet phát hiện mèo, chó và ngựa, đầu ra của lớp cuối cùng là khả năng hình ảnh đầu vào chứa bất kỳ động vật nào trong số đó.
Hình 2.19 Bản đồ kích hoạt của lớp tích chập cuối cùng
2.2.2.2. Lớp phi tuyến tính (ReLU layer)
ReLU viết tắt của Rectified Linear Uni, đảm bảo tính phi tuyến của mô hình huấn luyện sau khi thực hiện một loạt các phép tính toán tuyến tính qua các lớp tích chập. Với đầu ra là: ƒ (x) = argmax(0, x).
Hình 2.21 Hàm ReLU công thức 𝜃(𝑥) = max(0, 𝑥)
Hàm ReLU sẽ trả về giá trị dương hoặc 0 nếu đó là giá trị âm, giúp tăng tỉ lệ nhận diện.
2.2.2.3. Pooding Layer
Pooling layer thường được dùng giữa các convolutional layer, để giảm kích thước dữ liệu nhưng vẫn giữ được các thuộc tính quan trọng. Việc giảm kích thước dữ liệu giúp giảm các phép tính toán trong model.
Gọi pooling size kích thước K*K. Input của pooling layer có kích thước H*W. Với mỗi ma trận, trên vùng kích thước K*K trên ma trận ta tìm maximum hoặc