Python3 小技巧—— sorted(t, key = lambda _: _[0])用法

本文通过《Python编程从入门到实践》一书,详细介绍了如何使用sorted()函数和lambda表达式对元组列表进行排序,展示了根据不同字段索引进行排序的具体应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天在看 Eric Matthes 的《Python编程从入门到实践》中看到这句,代码演示如下:

>>>a = ([1, 4, 3], [3, 2, 5], [5, 1, 2], [4, 3, 1], [2, 5, 3])
>>>sorted(a, key=lambda _: _[0])
[[1, 4, 3], [2, 5, 3], [3, 2, 5], [4, 3, 1], [5, 1, 2]]
>>>sorted(a, key=lambda _: _[1])
[[5, 1, 2], [3, 2, 5], [4, 3, 1], [1, 4, 3], [2, 5, 3]]
>>>sorted(a, key=lambda _: _[2])
[[4, 3, 1], [5, 1, 2], [1, 4, 3], [2, 5, 3], [3, 2, 5]]

sorted() 函数对所有可迭代的对象进行排序操作,key 是用来进行比较的元素。书写方式如下:

key=lambda 元素: 元素[字段索引]

lambda 用于匿名函数,可以免去命名函数的麻烦,上面的代码相当于与:

def fun(元素):
	return 元素[字段索引]
key = fun(元素)

sorted 函数按照字段索引进行排序。

import sensor import image import lcd import time import sys # 初始化摄像头 sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) sensor.skip_frames(time=2000) # 初始化LCD(如果有) lcd.init() # 颜色阈值,用于二值化(这里假设矩形是深色,背景是浅色,或者相反,需要根据实际情况调整) gray_threshold = (0, 100) # 示例阈值,需要调整 while True: img = sensor.snapshot() # 转换为灰度图 img_gray = img.to_grayscale() # 二值化 # 注意:在新版固件中,binary方法返回一个新的二值图像对象;在旧版固件中,可能是原地操作并返回None img_bin = img_gray.binary([gray_threshold]) # 如果二值化后得到的是None(旧版固件可能原地操作),则使用img_gray作为二值图像 if img_bin is None: img_bin = img_gray # 旧版固件中,二值化操作已经作用在img_gray上 # 尝试两种方式查找轮廓 try: # 新版固件:使用二值图像调用find_contours contours = img_bin.find_contours(threshold=150, roi=(10,10,img.width()-20, img.height()-20)) except AttributeError: # 旧版固件:使用image.find_contours contours = image.find_contours(thresholds=[gray_threshold], roi=(10,10,img.width()-20,img.height()-20)) rectangles = [] for contour in contours: # 计算轮廓面积 area = contour.area() if area < 1000: # 忽略太小的轮廓 continue # 计算轮廓的矩形边界 rect = contour.min_rect() # 获取矩形的四个顶点 points = rect.corners() # 将四个点转换成元组列表 point_list = [(p[0], p[1]) for p in points] # 排序四个点:按照y坐标从小到大,然后对前两个点按x从小到大(左上、右上),后两个点按x从小到大(左下、右下) point_list.sort(key=lambda p: p[1]) top_points = sorted(point_list[:2], key=lambda p: p[0]) bottom_points = sorted(point_list[2:], key=lambda p: p[0]) sorted_points = top_points + bottom_points # 顺序:左上,右上,左下,右下 rectangles.append(sorted_points) # 如果检测到至少一个矩形 if rectangles: # 取第一个矩形 rect_pts = rectangles[0] # 建立坐标系:以左上角为原点(0,0) origin = rect_pts[0] # 左上角 # 计算矩形的宽和高(取右上角x-左上角x,左下角y-左上角y) width = rect_pts[1][0] - rect_pts[0][0] height = rect_pts[2][1] - rect_pts[0][1] # 选择两个点:这里选择左上角和右下角 point1 = rect_pts[0] # 左上角 point2 = rect_pts[3] # 右下角 # 在新建坐标系下的坐标: # 左上角:(0,0) # 右下角:(width, height) # 注意:实际中,由于透视变换,矩形的边可能不水平和垂直,这里假设矩形已经矫正(或者近似) # 在图像上标记点 img.draw_circle(int(point1[0]), int(point1[1]), 5, color=(255,0,0), thickness=2) img.draw_circle(int(point2[0]), int(point2[1]), 5, color=(0,255,0), thickness=2) # 输出坐标 print("Point1 (top-left): (0, 0)") print("Point2 (bottom-right): ({}, {})".format(width, height)) # 显示图像 lcd.display(img) time.sleep_ms(100) 这个代码中显示AttributeError: &#39;module&#39; object has no attribute &#39;find_contours&#39;这个报错,怎么修改
最新发布
07-17
import open3d as o3d import numpy as np import os def read_pointcloud(file_path): """读取点云文件""" try: pcd = o3d.io.read_point_cloud(file_path) print(f"成功读取点云: {file_path}") print(f"点云点数: {len(pcd.points)}") return pcd except Exception as e: print(f"读取点云失败: {e}") return None def get_pointcloud_bounds(pcd): """获取点云各轴的范围""" points = np.asarray(pcd.points) x_min, y_min, z_min = np.min(points, axis=0) x_max, y_max, z_max = np.max(points, axis=0) return { &#39;x&#39;: (x_min, x_max), &#39;y&#39;: (y_min, y_max), &#39;z&#39;: (z_min, z_max) } def segment_by_height(pcd, y_interval=0.1): """ 按高度(Y轴)分割点云 Args: pcd: 点云对象 y_interval: 高度区间大小() Returns: 分层结果字典: {高度下限: 点云对象} """ points = np.asarray(pcd.points) y_min, y_max = np.min(points[:, 1]), np.max(points[:, 1]) # 计算层数 num_layers = int(np.ceil((y_max - y_min) / y_interval)) layers = {} for i in range(num_layers): lower = y_min + i * y_interval upper = lower + y_interval # 创建掩码,筛选当前层的点 mask = (points[:, 1] >= lower) & (points[:, 1] < upper) layer_points = points[mask] if len(layer_points) > 0: layer_pcd = o3d.geometry.PointCloud() layer_pcd.points = o3d.utility.Vector3dVector(layer_points) layers[lower] = layer_pcd print(f"按高度分割完成,共{len(layers)}层") return layers def process_layers(layers, z_interval=0.2, x_interval=0.2): """ 处理每层点云,按Z轴分块,每块内按X轴排序,并计算块的平均坐标 Args: layers: 分层结果字典 z_interval: Z轴(深度)分块大小() x_interval: X轴(水平)分块大小() Returns: 处理结果字典: {(高度下限, 深度下限, 水平下限): { "point_count": 点数, "avg_coords": 平均坐标(x,y,z) }} """ processed_blocks = {} # 按高度从高到低处理 sorted_layers = sorted(layers.keys(), reverse=True) for y_lower in sorted_layers: layer_pcd = layers[y_lower] layer_points = np.asarray(layer_pcd.points) # 获取当前层Z轴范围 z_min, z_max = np.min(layer_points[:, 2]), np.max(layer_points[:, 2]) # 按Z轴(深度)从远到近分块 num_z_blocks = int(np.ceil((z_max - z_min) / z_interval)) for i in range(num_z_blocks): z_lower = z_min + i * z_interval z_upper = z_lower + z_interval # 创建Z轴掩码 z_mask = (layer_points[:, 2] >= z_lower) & (layer_points[:, 2] < z_upper) z_block_points = layer_points[z_mask] if len(z_block_points) > 0: # 获取当前块X轴范围 x_min, x_max = np.min(z_block_points[:, 0]), np.max(z_block_points[:, 0]) # 按X轴(水平)从右到左分块 num_x_blocks = int(np.ceil((x_max - x_min) / x_interval)) for j in range(num_x_blocks): x_lower = x_min + j * x_interval x_upper = x_lower + x_interval # 创建X轴掩码 x_mask = (z_block_points[:, 0] >= x_lower) & (z_block_points[:, 0] < x_upper) x_block_points = z_block_points[x_mask] if len(x_block_points) > 0: # 计算块的平均坐标 avg_coords = np.mean(x_block_points, axis=0) # 保存块信息,包含点数和平均坐标 block_key = (y_lower, z_lower, x_lower) processed_blocks[block_key] = { "point_count": len(x_block_points), "avg_coords": avg_coords } print(f"处理完成,共{len(processed_blocks)}个块") return processed_blocks def print_block_statistics(processed_blocks): """打印每个块的统计信息,包含平均坐标""" if not processed_blocks: print("没有可统计的块数据") return print("\n=== 块统计结果 ===") print("-" * 70) print("高度下限(m)\t深度下限(m)\t水平下限(m)\t点数\t\t平均坐标(x,y,z)") print("-" * 70) # 按高度从高到低、深度从远到近、水平从右到左排序 sorted_blocks = sorted( processed_blocks.items(), key=lambda x: (-x[0][0], x[0][1], x[0][2]) # 负号表示降序 ) for i, (block_key, block_data) in enumerate(sorted_blocks): y_lower, z_lower, x_lower = block_key point_count = block_data["point_count"] avg_x, avg_y, avg_z = block_data["avg_coords"] print( f"{y_lower:.2f}\t\t{z_lower:.2f}\t\t{x_lower:.2f}\t\t{point_count}\t\t({avg_x:.2f}, {avg_y:.2f}, {avg_z:.2f})") print("-" * 70) total_blocks = len(processed_blocks) total_points = sum(block["point_count"] for block in processed_blocks.values()) print(f"总计块数: {total_blocks}") print(f"总计点数: {total_points}") def save_block_statistics(processed_blocks, output_file="block_statistics.txt"): """将块统计信息保存到文件,包含平均坐标""" if not processed_blocks: print("没有可保存的块数据") return try: with open(output_file, &#39;w&#39;) as f: f.write("=== 块统计结果 ===\n") f.write("-" * 70 + "\n") f.write("高度下限(m)\t深度下限(m)\t水平下限(m)\t点数\t\t平均坐标(x,y,z)\n") f.write("-" * 70 + "\n") # 按高度从高到低、深度从远到近、水平从右到左排序 sorted_blocks = sorted( processed_blocks.items(), key=lambda x: (-x[0][0], x[0][1], x[0][2]) ) for (block_key, block_data) in sorted_blocks: y_lower, z_lower, x_lower = block_key point_count = block_data["point_count"] avg_x, avg_y, avg_z = block_data["avg_coords"] f.write( f"{y_lower:.2f}\t\t{z_lower:.2f}\t\t{x_lower:.2f}\t\t{point_count}\t\t({avg_x:.2f}, {avg_y:.2f}, {avg_z:.2f})\n") f.write("-" * 70 + "\n") f.write(f"总计块数: {len(processed_blocks)}\n") f.write(f"总计点数: {sum(block[&#39;point_count&#39;] for block in processed_blocks.values())}\n") print(f"统计结果已保存到: {output_file}") except Exception as e: print(f"保存统计结果失败: {e}") def main(): """主函数""" # 设置参数 FILE_PATH = "pointcloud_data/pointcloud_20250703_144541.pcd" # 修改为实际文件路径 Y_INTERVAL = 1 # 高度(Y轴)分层间隔() Z_INTERVAL = 1 # 深度(Z轴)分块间隔() X_INTERVAL = 1 # 水平(X轴)分块间隔() OUTPUT_FILE = "block_statistics.txt" # 统计结果输出文件 print("\n=== 点云码垛处理工具 ===") # 读取点云 pcd = read_pointcloud(FILE_PATH) if not pcd: return # 获取点云范围 bounds = get_pointcloud_bounds(pcd) print("\n点云范围:") print(f"X轴(水平): {bounds[&#39;x&#39;][0]:.2f}m ~ {bounds[&#39;x&#39;][1]:.2f}m") print(f"Y轴(高度): {bounds[&#39;y&#39;][0]:.2f}m ~ {bounds[&#39;y&#39;][1]:.2f}m") print(f"Z轴(深度): {bounds[&#39;z&#39;][0]:.2f}m ~ {bounds[&#39;z&#39;][1]:.2f}m") # 按高度分层 print(f"\n正在按高度分层 (间隔: {Y_INTERVAL}m)...") layers = segment_by_height(pcd, Y_INTERVAL) # 处理每层,按深度和水平位置分块,并计算平均坐标 print(f"\n正在按深度和水平位置分块 (深度间隔: {Z_INTERVAL}m, 水平间隔: {X_INTERVAL}m)...") processed_blocks = process_layers(layers, Z_INTERVAL, X_INTERVAL) # 打印块统计信息 print_block_statistics(processed_blocks) # 保存块统计信息到文件 save_block_statistics(processed_blocks, OUTPUT_FILE) print("\n=== 处理完成 ===") if __name__ == "__main__": main()这是读取点云文件,要删去距离大于0.55m和小于0.3m的点云块
07-04
06-17
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值