carla中lka实现(一)

news2024/10/3 6:33:44

前言:

对于之前项目中工作内容进行总结,使用Carla中的车辆进行lka算法调试,整体技术路线:

①在Carla中生成车辆,并在车辆上搭载camera,通过camera采集图像数据;

②使用图像处理lka算法,对于camera数据进行计算分析;

③对于分析的结果输出为偏移图像中心的线的距离,并以这个距离做为车辆控制方向盘的数值。

其中第一步比较简单,不做记录,从第二步,lka算法实现开始。

需要对于输入的图像进行边缘检测提取出车道线

一、边缘检测

车道线一般为黄线和白线,与车道线旁的公路的颜色有很大的差异,通过这种差异,就是车道线与公路之间颜色变化,可以找到车道线的边缘,找到这个边缘的过程为边缘检测。

1.1 使用sobel进行边缘检测

直接使用cv2中Sobel包来进行边缘检测:

测试源码如下:

def abs_sobel_thresh(image,orient='x',sobel_kernel=3,thresh=(0,255)):
    # generating the gray image.
    gray = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)
    # 计算x方向和y方向的梯度上强度值的图像
    if orient == 'x':
        abs_sobel = np.absolute(cv2.Sobel(gray,cv2.CV_64F,1,0,ksize=sobel_kernel))
    if orient == 'y':
        abs_sobel = np.absolute(cv2.Sobel(gray,cv2.CV_64F,0,1,ksize=sobel_kernel))
    # 利用归一化获得
    scaled_sobel = np.uint8(255*abs_sobel/np.max(abs_sobel))
    # 创建出一个同尺寸的数组
    grad_binary = np.zeros_like(scaled_sobel)
    grad_binary[ ( scaled_sobel >= thresh[0] ) & ( scaled_sobel <= thresh[1] ) ] = 1
    return grad_binary

主要功能实现在abs_sobel_thresh函数中,

首先使用cv2.cvtColor函数将原始图像转化为灰度图,

然后计算x方向和y方向上的梯度强度值上的图像,

利用归一化获得一个数组,这个数组记录了图像中所有的点的强度值,然后新建一个同样size的图像数组,将数组中强度信息在0到255之间的值设置为1。

输出x和y方向梯度的图像对比:

    ksize = 15
    gradx = abs_sobel_thresh(image,orient='x',sobel_kernel=ksize,thresh=(50,180))
    grady = abs_sobel_thresh(image,orient='y',sobel_kernel=ksize,thresh=(30,90))

    fig1 = plt.figure()
    plt.imshow(gradx,cmap="gray")
    fig2 = plt.figure()
    plt.imshow(grady,cmap="gray")
    plt.show()

1.2 使用颜色阈值检测

使用图像中的rgb中不同数字进行检测提取。

def rgb_select(img,r_thresh,g_thresh,b_thresh):
    r_channel = img[:,:,0]
    g_channel = img[:,:,1]
    b_channel = img[:,:,2]
    
    
    r_binary = np.zeros_like(r_channel)
    r_binary[(r_channel > r_thresh[0]) & (r_channel <= r_thresh[1])] = 1
    
    g_binary = np.zeros_like(g_channel)
    g_binary[(g_channel > g_thresh[0]) & (g_channel <= g_thresh[1])] = 1

    b_binary = np.zeros_like(b_channel)
    b_binary[(b_channel > b_thresh[0]) & (b_channel <= b_thresh[1])] = 1
    #
    combined = np.zeros_like(r_channel)
    combined[((r_binary == 1) & (g_binary == 1) & (b_binary == 1))] = 1
    return combined

在函数rbg_select中分别划分不同的rgb通道的数组,然后创建不同的新的数组,并将符合阈值内的点设置为1,最后将它们合并起来输出为图像combined。

 1.3 融合sobel和rgb的边缘检测

就是将两个图像中值为1的合并起来,容易实现。

def color_gradient_threshold(image):
    ksize = 15
    gradx = abs_sobel_thresh(image,orient='x',sobel_kernel=ksize,thresh=(50,180))
    rgb_binary = rgb_select(image,r_thresh=(225,255),g_thresh=(180,255),b_thresh=(0,255))
    combined_binary = np.zeros_like(image)
    combined_binary[((gradx==1)|(rgb_binary==1))] = 255
    color_binary = combined_binary
    return color_binary

 1.4 小结

边缘检测效果完成,因为是基于Carla做的车道线边缘检测,而Carla中输出的图像输出的效果比较理想,所以直接使用sobel和rgb边缘检测融合就可以达到很好的效果所以没有做过多的研究,实际情况比较复杂可能并不适用。

二、选择车道线的区域

这里要注意用数组表示图像的时候原点一般是左上角,向右为x轴正方向,向下为y轴正方向。

所以先选择出左下角,右下角:

    ksize = 15
    img_color = color_gradient_threshold(image)
    
    left_bottom = [0, img_color.shape[0]]
    right_bottom = [img_color.shape[1],img_color.shape[0]]

选择另外一个顶点:

    apex = [ img_color.shape[1]/2, 420 ]
    vertices = np.array([ left_bottom, right_bottom, apex ],np.int32)

其中vertices存储的是三个点,分别是左下角、右下角和顶点。

接下来使用刚刚选择的点与边缘检测后的图像按位与得到选择车道线的区域:

def region_of_interest(img,vertices):
    mask = np.zeros_like(img)
    cv2.fillPoly(mask,[vertices],[255,255,255])
    masked_image = cv2.bitwise_and(img,mask)
    return masked_image

其中函数fillPoly函数第一个参数表示为原始图像,第二个参数为选择的点,第三个参数表示为赋值为白色。

而bitwise_and是将两个参数按位与。

最后输出按位与后的图像。

 效果还可以。

三、投影变换

将原先小的三角形区域利用投影变换成大的区域。

主要运用cv中的透视变换:

def perspective_transform(image):
    # give 4 points as original coordinates.
    top_left =[590,460]
    top_right = [750,460]
    bottom_left = [330,650]
    bottom_right =  [1130,650]
    # give 4 points to project.
    proj_top_left = [250,100]
    proj_top_right = [1150,100]
    proj_bottom_left  =  [330,650]
    proj_bottom_right =  [1130,650]
    # to get image size.
    img_size = (image.shape[1],image.shape[0])
    # 
    pts1 = np.float32([top_left,top_right,bottom_left,bottom_right])
    pts2 = np.float32([proj_top_left,proj_top_right,proj_bottom_left,proj_bottom_right])
    matrix_K = cv2.getPerspectiveTransform(pts1,pts2)
    img_k = cv2.warpPerspective(image,matrix_K,img_size)
    return img_k

先划定四个点分别是左上、右上、左下和右下,为原始图像区域,

在划定投影区域。

运用函数getPerspectiveTransform它的第一个参数为平面1,第二个参数为平面2,求出平面1上的点要映射到平面2上所需要的变换的矩阵。

函数warpPerspective它的第一个参数为原始图像,第二个参数为投影变换矩阵,第三个参数为输出图像的大小,这里使用的就是原始图像的大小,需要注意一般为宽在前,长在后。

最后输出的就是变换后的图像信息。

 四、车道线提取

4.1 直方图显示

使用直方图来显示前面拉伸后的图像信息。

def histogram_img(image):
    histogram_binary = np.zeros((image.shape[0],image.shape[1]),dtype=np.int)
    histogram_binary[image[:,:,0]>0] = 1
    histogram = np.sum(histogram_binary[:,:],axis=0)
    print("histogram: ",histogram)
    print("histogram shape: ",histogram.shape)
    return histogram 

代码比较容易理解,设置一个同输入图像同尺寸的数组,将原来图像中任一rgb信息大于0的位置赋值为1,其实设置为255也可以,因为前面设置的就是255。之后就将它按列累加起来,返回这一行累加的数组(1*n)。

 4.2 车道线定位

获得的前面的直方图后,求出它的两个波峰的位置来获得车道线的大概位置。

def lane_position(histogram):
    histogram_size = histogram.shape
    middle_point = int(histogram_size[0]/2)
    print("middle_point: ",middle_point)
    #
    left_point = [0,0]
    for i in range(middle_point):
        # 寻找直方图中的波峰即顶点
        if histogram[i] > left_point[1]:
            left_point[1] = histogram[i]
            left_point[0] = i
    #
    right_point = [0,0]
    for j in range(middle_point,histogram_size[0]):
        if histogram[j] > right_point[1]:
            right_point[1] = histogram[j]
            right_point[0] = j
    
    result_points = [left_point,right_point]           
        
    print("result_points: ",result_points)
    return result_points

输出位置:
result_points:  [[342, 566], [1014, 291]]

说明两个车道线大概在这两个点附近。

4.3 滑动窗口

将前面求得的两个坐标为起点来构建滑动窗口将车道线包裹在内。

def sliding_window(image,lanes_pos):
    # starting original points for windows.
    left_x_current = lanes_pos[0][0]
    right_x_current = lanes_pos[1][0]
    nWindows = 10
    window_height = np.int(image.shape[0]//nWindows)
    window_width = 80
    # to get the non-zero data in the input image.
    nonzero = image.nonzero() 
    nonzero_y = nonzero[0]
    nonzero_x = nonzero[1]
    #
    # create a empty list to receive left/right line pixel.
    left_lane_inds = []
    right_lane_inds = []
    # create window by window
    for window in range(nWindows):
        # window size.
        win_y_top = image.shape[0] - (window +1)*window_height
        win_y_bottom = image.shape[0] - window*window_height
        win_x_left_left = left_x_current - window_width
        win_x_left_right = left_x_current + window_width 
        win_x_right_left = right_x_current - window_width
        win_x_right_right = right_x_current + window_width
        # define a rectangle for left+right lane.
        # and add the rectangle to the input image.
        cv2.rectangle(image,(win_x_left_left,win_y_top),(win_x_left_right,win_y_bottom),(0,255,0),2)
        cv2.rectangle(image,(win_x_right_left,win_y_top),(win_x_right_right,win_y_bottom),(0,255,0),2)
        good_left_inds = ((nonzero_y >= win_y_top)&(nonzero_y < win_y_bottom)&(nonzero_x >= win_x_left_left)&(nonzero_x < win_x_left_right)).nonzero()[0]
        good_right_inds = ((nonzero_y >= win_y_top)&(nonzero_y < win_y_bottom)&(nonzero_x >= win_x_right_left)&(nonzero_x < win_x_right_right)).nonzero()[0]
        #print(good_left_inds)
        left_lane_inds.append(good_left_inds)
        right_lane_inds.append(good_right_inds)
        #
        #print("nonzero_x_left:",nonzero_x[good_left_inds])
        #print("non_zero_x_right:",nonzero_x[good_right_inds])
        if len(good_left_inds)>50:
            left_x_current = np.int(np.mean(nonzero_x[good_left_inds]))
        if len(good_right_inds)>50:
            right_x_current = np.int(np.mean(nonzero_x[good_right_inds]))
    # ending of lop.
    #print("left_lane_inds",left_lane_inds)
    # to transfom a list of list to a list.
    left_lane_inds = np.concatenate(left_lane_inds)
    right_lane_inds = np.concatenate(right_lane_inds)
    #print("left_lane_inds",left_lane_inds)
    left_x = nonzero_x[left_lane_inds]

    left_y = nonzero_y[left_lane_inds]
    right_x = nonzero_x[right_lane_inds]
    right_y = nonzero_y[right_lane_inds]
    #
    results = [image,left_x,left_y,right_x,right_y]
    #print("sliding windows results: ",results)
    return results

代码写的很明白,首先去输入的坐标为左边的车道线x坐标和右边车道线y坐标,

然后计算滑动窗口的高度和宽度,

算出图像中所有不唯1的坐标,将它们放入nonzero数组中,

分别取行数为nonzero_y和列数为nonzero_x,

之后就是在for循环不断的画出矩形,利用rectangle函数进行绘制图像。

然后计算这个窗口里面大于1的数的位置平均值为下一个窗口的中间值,

最后保存所有的大于1的坐标,并于图像一并返回。

 4.4 曲线拟合

构建出一条曲线来表示车道线,方便之后利用曲线的曲率来控制车辆的转向信息。

具体实现为将之前获得的图像中所有的白色点的坐标,将它们进行拟合成曲线。

def fit_polynominal(img_sliding_window):
    image = img_sliding_window[0]
    left_x = img_sliding_window[1]
    left_y = img_sliding_window[2]
    right_x = img_sliding_window[3]
    right_y = img_sliding_window[4]

    left_fit = np.polyfit(left_y,left_x,2)
    right_fit = np.polyfit(right_y,right_x,2)

    # to generate x and y values for plotting.
    ploty = np.linspace(0,image.shape[0]-1,image.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]

    plt.plot(left_fitx,ploty,color='yellow')
    plt.plot(right_fitx,ploty,color='red')
    return 0

其中主要函数为polyfit函数它将参数一和参数二进行二次曲线拟合,拟合后得到三个参数存在返回值里面。

之后依据高度进行划分点,然后更具拟合后的参数构造曲线方程,最后输出到图像上。

 4.5 添加蒙版

通过前面获得的两条曲线的坐标点,在两条曲线之间添加一层蒙版,表示车道位置。

def drawing_poly(img_ori, img_fit):
    # create an image to draw the lines on.
    #
    left_fitx = img_fit[0]
    right_fitx = img_fit[1]
    ploty = img_fit[2]
    #
    img_zero = np.zeros_like(img_ori)
    #
    #print("left_fitx:",left_fitx)
    #print("ploty:",ploty)
    pts_left = np.transpose(np.vstack([left_fitx,ploty]))
    #print("pts_left:",pts_left)
    # print("pts_left shape:",pts_left.shape)
    pts_right = np.transpose(np.vstack([right_fitx,ploty]))
    pts_right = np.flipud(pts_right)
    #print("pts_right:",pts_right)
    #print("pts_right shape:",pts_right.shape)
    pts = np.vstack((pts_left,pts_right))
    #print("pts_left+right:",pts)
    #print("pts_left+right shape:",pts.shape)
    img_mask = cv2.fillPoly(img_zero,np.int_([pts]),(0,255,0))
    #print("img_mask:",img_mask)
    #print("img_mask shape:",img_mask.shape)
    return img_mask

主要是对于右侧坐标的反转,

pts_right = np.flipud(pts_right)是为了后面绘制多边形的时候连线准确,

pts = np.vstack((pts_left,pts_right))

img_mask = cv2.fillPoly(img_zero,np.int_([pts]),(0,255,0))

 4.6 反向映射

将之前的处理后的图像反向映射回原始图像。

将之前的代码中的参数变换位置就可以获得反过来的变换矩阵。

getPerspectiveTransform

def drawing_poly_perspective_back(img_ori, img_fit,matrix_K_back):
    # create an image to draw the lines on.
    #
    left_fitx = img_fit[0]
    right_fitx = img_fit[1]
    ploty = img_fit[2]
    #
    img_zero = np.zeros_like(img_ori)
    #
    #print("left_fitx:",left_fitx)
    #print("ploty:",ploty)
    pts_left = np.transpose(np.vstack([left_fitx,ploty]))
    #print("pts_left:",pts_left)
    #print("pts_left shape:",pts_left.shape)
    pts_right = np.transpose(np.vstack([right_fitx,ploty]))
    pts_right = np.flipud(pts_right)
    #print("pts_right:",pts_right)
    #print("pts_right shape:",pts_right.shape)
    pts = np.vstack((pts_left,pts_right))
    #print("pts_left+right:",pts)
    #print("pts_left+right shape:",pts.shape)
    img_mask = cv2.fillPoly(img_zero,np.int_([pts]),(0,255,0))
    #print("img_mask:",img_mask)
    #print("img_mask shape:",img_mask.shape)
    # to get image size.
    img_size = (img_ori.shape[1],img_ori.shape[0])
    img_mask_back = cv2.warpPerspective(img_mask,matrix_K_back,img_size)
    return img_mask_back

五、视频输入

 车道线检测变换基本完成,在将单帧图像修改为视频进行计算。

    # video input.
    video_input = "./test_video/project_video.mp4"
    cap = cv2.VideoCapture(video_input)
    # output setting.
    video_output = "./test_video/project_video_output_v2.mp4"
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    width = 1280
    height = 720
    fps = 20
    video_out = cv2.VideoWriter(video_output,fourcc,fps,(width,height))
    # add some text to the output video.
    content = "this is frame: "
    pos = (64,90)
    color = (0,255,0)
    font = cv2.FONT_HERSHEY_SIMPLEX
    weight = 2
    size = 1
    count = 0
    #
    # prcessing frame by frame. 
    while True:
        ret,frame = cap.read()
        if not ret:
            print("video read error, exited...")
            break
        if cv2.waitKey(25) & 0xFF == ord('q'):
            print(" you quit the program by clicking 'q'...")
            break
        image = frame
        ksize = 15
        img_color = color_gradient_threshold(image)
        #
        left_bottom = [0, img_color.shape[0]]
        right_bottom = [img_color.shape[1],img_color.shape[0]]
        apex = [ img_color.shape[1]/2, 420 ]
        vertices = np.array([ left_bottom, right_bottom, apex ],np.int32)
        img_interest = region_of_interest(img_color,vertices)
        img_perspective,matrix_K_back = perspective_transform(img_interest)
        img_histogram = histogram_img(img_perspective)
        lanes_pos = lane_position(img_histogram)
        img_sliding_window = sliding_window(img_perspective,lanes_pos) 
        img_fit_list = fit_polynominal(img_sliding_window)
        ## to set the transparency of img.
        img_mask_back = drawing_poly_perspective_back(image,img_fit_list,matrix_K_back)
        #img_mask_back_result = img_mask_back*0.5 + image*0.5
        img_mask_back_result = cv2.addWeighted(image,1,img_mask_back,0.3,0)
        results = img_mask_back_result
        contents = content + str(count)
        cv2.putText(results,contents,pos,font,size,color,weight,cv2.LINE_AA)
        cv2.imshow("frame",results)
        video_out.write(results)
        #
        count += 1
    cap.release()
    cv2.destroyAllWindows()

容易理解,不做解读,

但只能达到一个简单的车道线识别效果,而且处理速度很慢,遇到颜色变化不明显的会直接error,在具体的项目应用中需要改进,改进在后面的文章中体现。

参考文章:

(六)高级车道线识别 - 知乎在之前的文章中,我们介绍了利用opencv进行简单的车道线识别项目,本文将更进一步,对相对复杂场景下的车道线进行识别。具体来讲,本文在简单车道线项目的基础上增加了如下知识点:颜色空间,透视变换,滑移窗,弯…https://zhuanlan.zhihu.com/p/56712138实操:自动驾驶的车道识别原理及演练(附代码下载)大家五一快乐呀,我是李慢慢。前情提要距离上一次正儿八经发文,貌似已经过去两个月了,因为疫情原因我一直都是居家https://mp.weixin.qq.com/s/9ykWyXsCnTVqyojRlb7H9A

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/835987.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

echart图标日环图

效果图&#xff1a; 代码实例&#xff1a; <template><div id"chart-alarm" class"chartStyle"></div> </template> <script> import echarts from echarts export default {name:alarm,data(){return{chart:null}},mounte…

mybatisplus集成geometry实现增改功能

前言 在我们工作中想要实现将空间点位信息存储到数据库时,一般使用以下语句实现 INSERT INTO test-point ( point,text ) VALUES ( st_GeomFromText ( POINT(1 1) ),第1个点);update test-point set pointst_PointFromText(POINT(5 5)) where id 10;但是这样每次都要去编写新…

介绍个小工具 - ABAP Cleaner

1. 背景 在编写ABAP代码时&#xff0c;我们可以通过Pretty Printer &#xff08;Shift F1&#xff09;去完成代码的美化&#xff0c;但Pretty Printer所能提供的仅仅是关键字大小写的设置、以及行首留空格的控制&#xff0c;如下图所示。 也就是说&#xff0c;Pretty Printer…

【MySQL】仓储--维护出入库流水、库存,去重数量逻辑修正

系列文章 C#底层库–MySQLBuilder脚本构建类&#xff08;select、insert、update、in、带条件的SQL自动生成&#xff09; 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/129179216 C#底层库–MySQL数据库操作辅助类&#xff08;推荐阅读&#xff0…

【QNX】快速入门指南

目录 1.QNX 快速入门指南 2.系统要求 2.安装 QNX Momentics 开发套件 3.安装 QNX Neutrino 实时操作系统 4.QNX Neutrino 操作系统的联网 1.QNX 快速入门指南 本指南旨在帮助用户安装和配置 QNX Momentics 工具与 QNX Neutrino 操作系统&#xff0c;以便用户立即进行程序开…

Mybatis 实体类属性名和表中字段名不一致怎么处理

一. 前言 最近耀哥有学生出去面试&#xff0c;被问到 “Mybatis实体类的属性名和表中的字段名不一致该怎么处理&#xff1f;”&#xff0c;这其实是一个很经典的面试题&#xff0c;接下来耀哥就为大家详细解析一下这道面试题。 二. 分析 2.1 实体类和字段名不一致所带来的后果…

<C/C++>日期和时间的使用(time相关函数大全)

1、函数详解及示例 1- time_t time(time_t *time); 1&#xff09;功能&#xff1a;获取或设置系统时间。 2&#xff09;参数&#xff1a;若给定参数&#xff0c;则将当前时间保存到该参数中&#xff1b;若不给定参数&#xff0c;参数填NULL。 3&#xff09;返回值&#xff1…

CANDela Cdd 文件和CddT文件的相互转化

cdd转cddT Step1 点击Check Consistency , step2 没有任何error step1 选择Convert Document to Template , 然后选择想要转换的文件 保存cddt文件 cddT转cdd cddt文件的可编辑权限更高&#xff0c;但是在diva工程和canoe中只能使用cdd文件&#xff0c;所以&#xff0c;我们…

跑步用哪款耳机比较好、最适合跑步用的蓝牙耳机推荐

运动时聆听音乐可以为枯燥的过程带来娱乐&#xff0c;并且能够转移注意力&#xff0c;让人忽略身体负荷带来的不适感。而一款出色的运动耳机则成为锻炼过程中的重要辅助&#xff0c;它能够帮助控制节奏&#xff0c;使运动过程更加愉悦和高效。以下是一些备受推崇的热门运动耳机…

EventBus 开源库学习(一)

一、概念 EventBus是一款在 Android 开发中使用的发布-订阅事件总线框架&#xff0c;基于观察者模式&#xff0c;将事件的接收者和发送者解耦&#xff0c;简化了组件之间的通信&#xff0c;使用简单、效率高、体积小。 一句话&#xff1a;用于Android组件间通信的。 二、原理…

Windows环境下VSCode安装PlatformIO Cero报错ERROR: HTTP error 403 while getting

安装PlatformIO插件成功&#xff0c;初始化失败 错误信息判断问题尝试访问https://pypi.tuna.tsinghua.edu.cn/simple/platformio/成功点击文件后报错如下&#xff1a; 解决问题- 换源 &#xff08; Windows下有两个地方需要更改&#xff09;cmd命令行Pip文件 总结&#xff1a;…

C语言指针操作数组赋值

1、通过指针修改数组元素的值 ps:int a[10] {10}; 数组名a &a[0] a1 &a[0]1 跨过得是数组元素类型的长度&#xff0c;&a是对整个数组取地址&#xff0c;&a1是跨过整个数组的长度 #include "stdio.h" #include <stdlib.h>int main() {i…

LeetCode-654-最大二叉树

一&#xff1a;题目描述 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建左子树。递归地在最大值 右边 的 子数组后缀上 构建右子树。 返回…

勒索软件攻击防御的9件事

什么是勒索软件攻击&#xff1f; 勒索软件是一种特定类型的恶意软件&#xff0c;它将数据作为“人质”来勒索赎金。网络钓鱼电子邮件是其一种常见的传播方式&#xff0c;同时勒索软件也可以借由下载广泛传播&#xff0c;也就是在用户访问受到感染的网站时进行传播。随着网络攻…

推荐GitHub 中的 C avl tree

https://github.com/greensky00/avltree.git 6 内核果然是,最好的C 标准库 &#x1f602;, 早晚手撕一遍这个代码

大模型,拼算力更拼落地力

近年来&#xff0c;随着人工智能领域的快速发展&#xff0c;大模型已经成为了业界热议的话题之一。在这个信息爆炸的时代&#xff0c;数据变得比以往任何时候都更加丰富&#xff0c;而大模型的兴起&#xff0c;为我们揭示了探索数据中蕴藏的价值和智慧提供了全新的途径。然而&a…

【阵列信号处理】空间匹配滤波器、锥形/非锥形最佳波束成形器、样本矩阵反演 (SMI) 研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Unity Shader编辑器工具类ShaderUtil 常用函数和用法

Unity Shader编辑器工具类ShaderUtil 常用函数和用法 Unity的Shader编辑器工具类ShaderUtil提供了一系列函数&#xff0c;用于编译、导入和管理着色器。本文将介绍ShaderUtil类中的常用函数和用法。 编译和导入函数 CompileShader 函数签名&#xff1a;public static bool C…

发灰黑行业用搜索留痕排名推广哪款软件好

发灰黑行业用搜索留痕排名推广哪款软件好 最近微博视频排名发不了&#xff0c;不收录 目前推荐泛目录或者寄生虫 以后只要知道这个逻辑就可以 平台会因为发的人多而和谐&#xff0c;也就是发不出去 接下来给大家介绍下 想要网站排名&#xff0c;却又不知道具体的优化步骤和方…

自建类ChatGPT服务:本地化部署与远程访问教程

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…