LingxinMeng 7 ヶ月 前
コミット
0b1573a97e

+ 1 - 3
src/python2/pjibot/camera.py

@@ -51,10 +51,8 @@ if __name__ == '__main__':
     endpoint = 'oss-cn-beijing-gqzl-d01-a.ops.gqzl-cloud.com'
     bucket = oss2.Bucket(auth, endpoint, 'pji-bucket1')
 
-    turn = 1
     while True:
-        logging.info("当前轮次: %s" % str(turn))
-        turn += 1
+        logging.info("开始新一轮扫描")
         try:
             local_delete_list = []
             oss_delete_list = []

+ 8 - 0
src/python2/pjibot/csv-nohup.sh

@@ -0,0 +1,8 @@
+#!/bin/bash
+if [ ! -d "./log" ]; then
+    mkdir "./log"
+    echo "Directory './log' created."
+else
+    echo "Directory './log' already exists."
+fi
+nohup python2 csv-pjibot.py > log/csv.out 2>&1 &

+ 3 - 3
src/python2/pjibot/pjibot_csv.py → src/python2/pjibot/csv-pjibot.py

@@ -7,13 +7,13 @@ from resource import bagtocsv_rebot
 
 import logging
 
-path1 = '/mnt/disk001/cicv-data-closedloop/python2-pjibot-double-camera-module-pji/'
-path2 = '/mnt/disk001/run'
+path1 = '/mnt/disk001/dcl_data_process/src/python2/pjibot/'
+path2 = '/mnt/disk001/run' # 生成评价报告pdf的可执行文件路径
 path3 = '/mnt/disk001/cicv-data-closedloop/python3-pjibot-module'
 path4 = '/mnt/disk001/cicv-data-closedloop/python3-pjibot-module/filter_pos.py'
 pgm_path = '/mnt/disk001/cicv-data-closedloop/python2-pjibot-double-camera-module-pji/resource/shiyanshi_newpgm_20240416.pgm'
 
-logging.basicConfig(filename=path1 + 'log/pjibot_csv.log', level=logging.INFO,
+logging.basicConfig(filename=path1 + 'log/csv.log', level=logging.INFO,
                     format='%(asctime)s - %(levelname)s - %(message)s')
 
 key1 = 'pjibot/'

+ 2 - 0
src/python2/pjibot/csv-tail.sh

@@ -0,0 +1,2 @@
+#!/bin/bash
+tail -f log/csv.log

+ 202 - 0
src/python3/pjibot_indoor/filter_pos.py

@@ -0,0 +1,202 @@
+import pandas as pd
+from PIL import Image
+import csv
+from sklearn.cluster import KMeans
+import argparse
+
+
+# def save_pgm_to_csv(pgm_file_path, csv_file_path):
+#     # 读取 PGM 图片
+#     with Image.open(pgm_file_path) as img:
+#         # 获取图片尺寸
+#         width, height = img.size
+#
+#         # 创建 CSV 文件并写入像素值
+#         with open(csv_file_path, 'w', newline='') as csvfile:
+#             csvwriter = csv.writer(csvfile)
+#             for y in range(height):
+#                 row = []
+#                 for x in range(width):
+#                     pixel = img.getpixel((x, y))[0]
+#                     row.append(pixel)
+#                 csvwriter.writerow(row)
+def pgm_to_df(pgm_file_path):
+    # 读取PGM图片
+    with Image.open(pgm_file_path) as img:
+        # 获取图片尺寸
+        width, height = img.size
+
+        # 准备用于构建DataFrame的数据
+        data = []
+
+        for y in range(height):
+            row = []
+            for x in range(width):
+                pixel = img.getpixel((x, y))[0]
+                row.append(pixel)
+            data.append(row)
+
+        # 将数据转换为DataFrame
+        pgm_df = pd.DataFrame(data)
+
+        return pgm_df
+
+
+def filter_rows(group):
+    # 对x进行排序
+    group = group.sort_values(by='pos_x')
+    # 算出差值
+    diffs = group['pos_x'].diff().fillna(1)  # 填充1,确保第一行不被移除
+    # 标记差值小于0.2的行为True,然后过滤这些行
+    group = group[diffs >= 0.2]
+    return group
+
+
+def calculate_position(row, column):
+    x = column * 0.05 + 0.025
+    y = row * 0.05 + 0.025
+    return x, y
+
+
+def get_centered_positions(dataframe, threshold):
+    condition = dataframe < threshold
+    centered_positions = [calculate_position(row, col) for row, col in zip(*condition.values.nonzero())]
+    return centered_positions
+
+
+def lies_within_range(x, y, centered_positions):
+    for cx, cy in centered_positions:
+        if (cx - 0.025) <= x <= (cx + 0.025) and (cy - 0.025) <= y <= (cy + 0.025):
+            return True
+    return False
+
+
+def filter_df_with_positions(input_df, centered_positions):
+    # 应用过滤条件,保留 lies_within_range 返回 False 的行
+    # 现在使用 'pos_x' 和 'pos_y' 列名来访问数据
+    return input_df[
+        ~input_df.apply(lambda row: lies_within_range(row['pos_x'], row['pos_y'], centered_positions), axis=1)]
+
+
+def filter_csv_with_pandas(source_df, target_csv_filename, threshold):
+    # 读取源CSV文件,寻找小于阈值的位置
+    centered_positions = get_centered_positions(source_df, threshold)
+
+    # 读取目标CSV文件
+    target_df = pd.read_csv(target_csv_filename)
+
+    # 根据找到的位置过滤目标CSV文件的数据
+    filtered_df = filter_df_with_positions(target_df, centered_positions)
+
+    # 将过滤后的数据写入输出CSV文件
+    filtered_df.to_csv(target_csv_filename, index=False)
+
+
+# 使用 groupby 按 'Time' 分组,然后对每个组计算新的 pos_x, pos_y, length, width
+def calculate_dims(group):
+    # 计算长度和宽度
+    length = group['pos_x'].max() - group['pos_x'].min()
+    width = group['pos_y'].max() - group['pos_y'].min()
+
+    # 计算 pos_x 和 pos_y 的平均值
+    pos_x_mean = group['pos_x'].mean()
+    pos_y_mean = group['pos_y'].mean()
+
+    # 返回一个新的 DataFrame 行
+    return pd.DataFrame({
+        'Time': [group['Time'].iloc[0]],
+        'pos_x': [pos_x_mean],
+        'pos_y': [pos_y_mean],
+        'length': [length],
+        'width': [width]
+    })
+
+
+def calculate_clusters(group, n_clusters=5):
+    # 取出x,y坐标值
+    coordinates = group[['pos_x', 'pos_y']].values
+
+    # 如果组内的数据点小于所需的聚类数,则将聚类数设置为数据点的数量
+    n_clusters = min(n_clusters, len(coordinates))
+
+    kmeans = KMeans(n_clusters=n_clusters)
+    kmeans.fit(coordinates)
+    labels = kmeans.labels_
+
+    # 用于存储所有矩形的数据
+    rectangles = []
+
+    for label in range(n_clusters):
+        # 获取属于相同分类的数据点
+        points = coordinates[labels == label]
+
+        # 计算长度和宽度
+        min_x, max_x = points[:, 0].min(), points[:, 0].max()
+        min_y, max_y = points[:, 1].min(), points[:, 1].max()
+        length, width = max_x - min_x + 0.05, max_y - min_y + 0.05
+
+        # 计算 pos_x 和 pos_y 的平均值
+        pos_x_mean = points[:, 0].mean()
+        pos_y_mean = points[:, 1].mean()
+
+        # 保存该矩形的数据
+        rectangles.append({
+            'Time': group['Time'].iloc[0],
+            'pos_x': pos_x_mean,
+            'pos_y': pos_y_mean,
+            'length': length,
+            'width': width
+        })
+
+    return pd.DataFrame(rectangles)
+
+
+def keep_largest_rectangle(group):
+    # 计算每个矩形的面积
+    group['area'] = group['length'] * group['width']
+
+    # 找到面积最大的矩形
+    largest_rectangle = group.loc[group['area'].idxmax()]
+
+    # 返回最大的矩形
+    return largest_rectangle
+
+
+# 主程序
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(description='Process the CSV data.')
+    parser.add_argument('pgm_path', type=str, help='Path to the PGM file')
+    parser.add_argument('target_csv_filename', type=str, help='Path to the target CSV file')
+
+    args = parser.parse_args()
+    # pgm_path = "/home/hancheng/hc_project/pujin/shiyanshi_newpgm_20240416.pgm"
+    # source_csv_filename = '/home/hancheng/hc_project/pujin/pgmRead_demo.csv'
+    pgm_df = pgm_to_df(args.pgm_path)
+    # target_csv_filename = '/home/hancheng/Downloads/merged_obstacles.csv'
+    threshold_value = 89.25
+
+    # 读取CSV文件
+    posdata_obs = pd.read_csv(args.target_csv_filename)
+    posdata_obs['pos_x'] = posdata_obs['pos_x'] - 20.883
+    posdata_obs['pos_y'] = posdata_obs['pos_y'] - 17.8439
+    # 使用groupby方法对数据进行分组处理,并应用上述的过滤函数
+    posdata_obs = posdata_obs.groupby(['Time', 'pos_y'], group_keys=False).apply(filter_rows)
+    # 重置索引
+    posdata_obs.reset_index(drop=True, inplace=True)
+    # 将处理后的数据写回'pos_3.csv'
+    posdata_obs.to_csv(args.target_csv_filename, index=False)
+
+    # 过滤CSV文件并保存结果
+    filter_csv_with_pandas(pgm_df, args.target_csv_filename, threshold_value)
+
+    df = pd.read_csv(args.target_csv_filename)
+    # 应用函数并合并结果
+    cluster_df = df.groupby('Time', as_index=False).apply(calculate_clusters).reset_index(drop=True)
+
+    df_largest = cluster_df.groupby('Time').apply(keep_largest_rectangle)
+
+    # 重置索引
+    df_largest.reset_index(drop=True, inplace=True)
+
+    # 将处理后的 DataFrame 保存到新的 CSV 文件
+    df_largest.to_csv(args.target_csv_filename, index=False)

+ 116 - 0
src/python3/pjibot_indoor/pcd_to_video.py

@@ -0,0 +1,116 @@
+
+"""
+    功能:将ROS bag文件中的点云数据转换为PCD文件,并将PCD文件转换为图像,最后生成视频。
+    输入:rosbag文件路径,输出路径
+    输出:生成的视频文件
+    注意:需要安装pyntcloud、matplotlib、opencv库
+"""
+    
+    
+import sys
+import matplotlib.pyplot as plt
+import cv2
+import os
+import subprocess
+import matplotlib.pyplot as plt
+from pyntcloud import PyntCloud
+import rosbag
+import shutil
+
+def process_pcd_to_top_view_image(pcd_path, output_path):
+    # 使用 PyntCloud 读取点云数据
+    cloud = PyntCloud.from_file(pcd_path)
+    points = cloud.points
+    
+    plt.figure(figsize=(10, 10))
+    ax = plt.axes(projection='3d')
+    ax.scatter(points['x'], points['y'], points['z'], s=1, color='blue')
+    ax.view_init(elev=90, azim=90)
+    ax.set_xlabel('X')
+    ax.set_ylabel('Y')
+    ax.set_zlabel('Z')
+    ax.set_xticks([])
+    ax.set_yticks([])
+    ax.set_zticks([])
+    plt.axis('off')  # 隐藏坐标轴
+    plt.savefig(output_path, bbox_inches='tight', pad_inches=0)
+    plt.close()
+
+def create_video_from_images(image_folder, output_video_path, frame_rate):
+    images = [img for img in sorted(os.listdir(image_folder)) if img.endswith(".jpg")]
+    if not images:
+        print("没有找到任何JPG图像,请检查图像文件夹!")
+        return
+
+    frame = cv2.imread(os.path.join(image_folder, images[0]))
+    height, width, layers = frame.shape
+    video = cv2.VideoWriter(output_video_path, cv2.VideoWriter_fourcc(*'mp4v'), float(frame_rate), (width, height))
+
+    for image in images:
+        frame = cv2.imread(os.path.join(image_folder, image))
+        if frame is not None:
+            video.write(frame)
+
+    video.release()
+    print(f"视频已成功保存在:{output_video_path}")
+
+def convert_bag_to_pcd(input_dir, output_dir):
+    """ 将ROS bag文件中的点云数据转换为PCD文件 """
+    command = f'rosrun pcl_ros bag_to_pcd {input_dir} /scan_map_icp_amcl_node/scan_point_transformed {output_dir}'
+    process = subprocess.run(command, shell=True, text=True, capture_output=True)
+    if process.returncode != 0:
+        print("转换失败:", process.stderr)
+    else:
+        print("PCD文件已成功生成")
+
+if __name__ == '__main__':
+    
+    rosbag_path = sys.argv[1]
+    output_base_path = sys.argv[2]
+        
+    #input_dir = '/media/server/00D7-0524/点云解析/2024-04-16-10-20-45_obstacledetection_30.bag'
+    #output_dir = '/media/server/00D7-0524/点云解析/2024-04-16-10-20-45_obstacledetection_30'
+
+    bag_base_name = rosbag_path.split('/')[-1].split('.')[0]
+    
+    lidar_output_base = os.path.join(output_base_path, bag_base_name + '_pcd_lidar')
+    pcd_folder_path = os.path.join(lidar_output_base, 'pcd')
+    images_folder_path = os.path.join(lidar_output_base, 'images')
+    
+    if not os.path.exists(pcd_folder_path):
+        os.makedirs(pcd_folder_path)
+    if not os.path.exists(images_folder_path):
+        os.makedirs(images_folder_path)
+    
+    
+    with rosbag.Bag(rosbag_path ,'r') as bag:
+        num_count=0
+        for topic,msg,t in bag.read_messages():
+            if topic == "/scan_map_icp_amcl_node/scan_point_transformed":
+                num_count+=1
+        start_time = bag.get_start_time()
+        end_time = bag.get_end_time()
+        # 计算rosbag的持续时间
+        duration = end_time - start_time
+
+    bagtime = duration
+    hz=str(float(float(num_count)/bagtime))
+    print(hz)
+
+
+    # 转换ROS bag到PCD
+    convert_bag_to_pcd(rosbag_path, pcd_folder_path)
+    
+    pcd_files = [f for f in os.listdir(pcd_folder_path) if f.endswith('.pcd')]
+    for file_name in pcd_files:
+        pcd_file_path = os.path.join(pcd_folder_path, file_name)
+        image_file_path = os.path.join(images_folder_path, f"{file_name[:-4]}.jpg")
+        process_pcd_to_top_view_image(pcd_file_path, image_file_path)
+
+    # 从图像生成视频
+    video_path = os.path.join(lidar_output_base, 'output_video.mp4')
+    create_video_from_images(images_folder_path, video_path, hz)
+    
+    # 清理临时文件
+    shutil.rmtree(pcd_folder_path)
+    shutil.rmtree(images_folder_path)