75. Sort Colors (M)

本文探讨了经典的“荷兰国旗”问题,即对只包含0、1、2的数组进行排序,且不能使用内置排序函数。介绍了两遍计数排序和一遍快排优化的解决方案,后者是对基础快速排序的重复元素优化。

Sort Colors (M)

Given an array with n objects colored red, white or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white and blue.

Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.

Note: You are not suppose to use the library’s sort function for this problem.

Example:

Input: [2,0,2,1,1,0]
Output: [0,0,1,1,2,2]

Follow up:

  • A rather straight forward solution is a two-pass algorithm using counting sort.
    First, iterate the array counting number of 0’s, 1’s, and 2’s, then overwrite array with total number of 0’s, then 1’s and followed by 2’s.
  • Could you come up with a one-pass algorithm using only constant space?

题意

将一个只包含0、1、2的数组排序,不允许使用内置的排序函数。

思路

经典的“荷兰旗??”问题。

最简单的做法是先遍历一遍统计0、1、2的个数,再遍历一遍逐个按个数输出0、1、2。

只遍历一遍的方法,实际上是对最基础的快速排序方法进行重复元素优化:将数组分为三个区间,左区间存放比目标值小的元素,右区间存放比目标值大的元素,中部区间存放与目标值相同的元素,每次递归只递归左区间和右区间。


代码实现 - 快排优化

class Solution {
    public void sortColors(int[] nums) {
        sort(nums, 0, nums.length - 1);
    }

    private void sort(int[] nums, int start, int end) {
        if (start >= end) {
            return;
        }

        int i = start;						// 当前遍历元素
        int left = start, right = end;		// left左侧元素小于目标值,right右侧元素大于目标值
        int temp = nums[start];				// 目标值

        while (i <= right) {
            if (nums[i] < temp) {
                swap(nums, i++, left++);	// 当前元素小于目标值,移到左侧区间
            } else if (nums[i] > temp) {
                swap(nums, i, right--);		// 当前元素大于目标值,移到右侧区间
            } else {
                i++;						// 当前元素等于目标值,保留在中间区间中不移动
            }
        }

        sort(nums, start, left - 1);
        sort(nums, right + 1, end);
    }


    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}

代码实现 - 统计排序

class Solution {
    public void sortColors(int[] nums) {
        // 统计个数
        int[] count = new int[3];
        for (int i = 0; i < nums.length; i++) {
            count[nums[i]]++;
        }
        // 重新填充数组
        int i = 0;
        for (int j = 0; j < 3; j++) {
            while (count[j]-- != 0) {
                nums[i++] = j;
            }
        }
    }
}
import os import cv2 import numpy as np import open3d as o3d from matplotlib import pyplot as plt from scipy.spatial.transform import Rotation as R class SFMReconstruction: def __init__(self, image_folder): self.image_folder = image_folder self.images = [] self.keypoints = [] self.descriptors = [] self.matches = [] self.camera_poses = [] self.point_cloud = [] self.colors = [] def load_images(self): """加载图像""" print("Loading images...") image_files = [f for f in os.listdir(self.image_folder) if f.lower().endswith(('.png', '.jpg', '.jpeg'))] image_files.sort() for img_file in image_files: img_path = os.path.join(self.image_folder, img_file) img = cv2.imread(img_path) if img is not None: self.images.append(img) print(f"Loaded: {img_file}") print(f"Total images loaded: {len(self.images)}") return len(self.images) def extract_features(self): """提取特征点""" print("Extracting features...") sift = cv2.SIFT_create() for img in self.images: gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) kp, desc = sift.detectAndCompute(gray, None) self.keypoints.append(kp) self.descriptors.append(desc) print(f"Features extracted from {len(self.images)} images") def match_features(self): """匹配特征点""" print("Matching features...") bf = cv2.BFMatcher(cv2.NORM_L2, crossCheck=True) for i in range(len(self.images) - 1): matches = bf.match(self.descriptors[i], self.descriptors[i + 1]) # 筛选优质匹配 matches = sorted(matches, key=lambda x: x.distance)[:100] self.matches.append(matches) print(f"Feature matching completed for {len(self.matches)} image pairs") def estimate_camera_poses(self): """估计相机位姿""" print("Estimating camera poses...") # 假设第一张图像为参考坐标系 self.camera_poses.append(np.eye(4)) for i in range(len(self.matches)): # 获取匹配点 matches = self.matches[i] kp1 = self.keypoints[i] kp2 = self.keypoints[i + 1] pts1 = np.float32([kp1[m.queryIdx].pt for m in matches]) pts2 = np.float32([kp2[m.trainIdx].pt for m in matches]) # 估计基础矩阵 F, mask = cv2.findFundamentalMat(pts1, pts2, cv2.FM_RANSAC, 0.1, 0.99) # 从基础矩阵恢复相机位姿 K = self.estimate_camera_matrix() E = K.T @ F @ K # 从本质矩阵恢复位姿 _, R_mat, t_vec, _ = cv2.recoverPose(E, pts1, pts2, K) # 构建变换矩阵 pose = np.eye(4) pose[:3, :3] = R_mat pose[:3, 3] = t_vec.flatten() # 相对于第一张图像的位姿 prev_pose = self.camera_poses[-1] current_pose = prev_pose @ np.linalg.inv(pose) self.camera_poses.append(current_pose) print(f"Camera poses estimated for {len(self.camera_poses)} images") def estimate_camera_matrix(self): """估计相机内参矩阵(简化版)""" # 假设图像尺寸相同 h, w = self.images[0].shape[:2] focal_length = max(w, h) * 1.2 cx, cy = w / 2, h / 2 K = np.array([ [focal_length, 0, cx], [0, focal_length, cy], [0, 0, 1] ]) return K def triangulate_points(self): """三角测量生成3D点""" print("Triangulating 3D points...") K = self.estimate_camera_matrix() for i in range(len(self.matches)): matches = self.matches[i] kp1 = self.keypoints[i] kp2 = self.keypoints[i + 1] pts1 = np.float32([kp1[m.queryIdx].pt for m in matches]) pts2 = np.float32([kp2[m.trainIdx].pt for m in matches]) # 投影矩阵 P1 = K @ np.linalg.inv(self.camera_poses[i])[:3, :] P2 = K @ np.linalg.inv(self.camera_poses[i + 1])[:3, :] # 三角测量 points_4d = cv2.triangulatePoints(P1, P2, pts1.T, pts2.T) points_3d = points_4d[:3] / points_4d[3] # 获取颜色信息 colors = [] for j, pt in enumerate(pts1.astype(int)): if 0 <= pt[1] < self.images[i].shape[0] and 0 <= pt[0] < self.images[i].shape[1]: color = self.images[i][pt[1], pt[0]] / 255.0 colors.append(color) self.point_cloud.extend(points_3d.T) self.colors.extend(colors) print(f"Generated {len(self.point_cloud)} 3D points") def create_point_cloud(self): """创建Open3D点云""" print("Creating point cloud...") pcd = o3d.geometry.PointCloud() points = np.array(self.point_cloud) colors = np.array(self.colors) pcd.points = o3d.utility.Vector3dVector(points) pcd.colors = o3d.utility.Vector3dVector(colors[:, [2, 1, 0]]) # BGR to RGB return pcd def visualize_point_cloud(self, pcd): """可视化点云""" print("Visualizing point cloud...") o3d.visualization.draw_geometries([pcd], window_name="SceauxCastle Point Cloud", width=1024, height=768) def save_point_cloud(self, pcd, filename="sceaux_castle_pointcloud.ply"): """保存点云""" o3d.io.write_point_cloud(filename, pcd) print(f"Point cloud saved as {filename}") def create_mesh_and_texture(self, pcd): """创建网格和纹理(简化版)""" print("Creating mesh...") # 使用泊松重建创建网格 mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson( pcd, depth=9) # 简化网格 mesh = mesh.simplify_quadric_decimation(target_number_of_triangles=10000) # 计算顶点法线 mesh.compute_vertex_normals() return mesh def visualize_mesh(self, mesh): """可视化网格""" print("Visualizing textured mesh...") o3d.visualization.draw_geometries([mesh], window_name="SceauxCastle 3D Model", width=1024, height=768) def save_mesh(self, mesh, filename="sceaux_castle_mesh.ply"): """保存网格""" o3d.io.write_triangle_mesh(filename, mesh) print(f"Mesh saved as {filename}") def main(): # 图像文件夹路径 image_folder = "SceauxCastle" # 请替换为实际路径 # 创建SFM重建对象 sfm = SFMReconstruction(image_folder) # 执行SFM流程 if sfm.load_images() < 2: print("Need at least 2 images for reconstruction") return sfm.extract_features() sfm.match_features() sfm.estimate_camera_poses() sfm.triangulate_points() # 创建和可视化点云 pcd = sfm.create_point_cloud() sfm.visualize_point_cloud(pcd) sfm.save_point_cloud(pcd) # 创建和可视化网格 mesh = sfm.create_mesh_and_texture(pcd) sfm.visualize_mesh(mesh) sfm.save_mesh(mesh) if __name__ == "__main__": main()通过自己电脑自带的摄像头拍摄一个物体(5个角度以上),进行3D重建,要求优化算法:1.将SIFT换为ORB;2.加入捆绑调整BA(BundleAdjustment) 上传优化后的代码,以及2幅3D重建图(分别为3D点云图,和带纹理的3D点云图)
最新发布
11-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值