Median in Stream

本文介绍了一种实时处理数据流并获取中位数的算法,通过使用最大堆和最小堆来动态维护中位数。适用于实时数据分析场景。

Question: How to get the median from a stream of numbers at any time? The median is middle value of numbers. If the count of numbers is even, the median is defined as the average value of the two numbers in middle.

/* minggr@gmail.com */
#include <stdio.h>

enum {
	MAX_HEAP,
	MIN_HEAP,
};

void heapify(int heap[], int type, int heap_len, int i)
{
	int left = 2*i + 1;
	int right = 2*i + 2;
	int new_i = i;

	if (left < heap_len) {
		if (type == MAX_HEAP && heap[left] > heap[new_i])
			new_i = left;
		if (type == MIN_HEAP && heap[left] < heap[new_i])
			new_i = left;
	}

	if (right < heap_len) {
		if (type == MAX_HEAP && heap[right] > heap[new_i])
			new_i = right;
		if (type == MIN_HEAP && heap[right] < heap[new_i])
			new_i = right;
	}

	if (new_i != i) {
		int tmp = heap[new_i];
		heap[new_i] = heap[i];
		heap[i] = tmp;

		heapify(heap, type, heap_len, new_i);
	}
}

void build_heap(int data[], int type, int n)
{
	int i = n/2 - 1;

	while (i >= 0) {
		heapify(data, type, n, i);
		i--;
	}
}

int heap_insert(int heap[], int type, int heap_len, int key)
{
	int parent;
	int i;

	heap[heap_len++] = key;	

	i = heap_len-1;
	parent = (i-1)/2;
	while (i > 0) {
		if ((type == MAX_HEAP && heap[parent] < heap[i]) ||
		    (type == MIN_HEAP && heap[parent] > heap[i])) {
	
			int tmp = heap[parent];
			heap[parent] = heap[i];
			heap[i] = tmp;

			i = parent;
			parent = (i-1)/2;
		} else
			break;
	}

	return heap_len;
}

int heap_delete(int heap[], int type, int heap_len)
{
	heap[0] = heap[--heap_len];
	heapify(heap, type, heap_len, 0);

	return heap_len;
}

void dump_data(int data[], int n)
{
	int i;

	for (i = 0; i < n; i++)
		printf("%d ", data[i]);
	printf("\n");
}

int main()
{
	int max_heap[10];
	int min_heap[10];
	int data[] = {5, 8, 9, 3, 10, 4, 6, 1, 5, 7, 16};
	int n = 11;
	int i;
	int tmp;

	max_heap[0] = data[0];
	for (i = 1; i < n; i++) {
		if (i%2) { /* MIN heap */
			if (data[i] < max_heap[0]) {
				heap_insert(min_heap, MIN_HEAP, i/2, max_heap[0]);
				max_heap[0] = data[i];
				heapify(max_heap, MAX_HEAP, i/2+1, 0);
			} else
				heap_insert(min_heap, MIN_HEAP, i/2, data[i]);
		}
		else { /* MAX heap */
			if (data[i] > min_heap[0]) {
				heap_insert(max_heap, MAX_HEAP, i/2, min_heap[0]);
				min_heap[0] = data[i];
				heapify(min_heap, MIN_HEAP, i/2, 0);
			} else
				heap_insert(max_heap, MAX_HEAP, i/2, data[i]);
		}
	}
	dump_data(data, n);
	dump_data(max_heap, n/2+n%2);
	dump_data(min_heap, n/2);

	if (n%2)
		printf("median: %d\n", max_heap[0]);
	else
		printf("median: %d\n", max_heap[0]+min_heap[0]);

	return 0;
}


#ifndef SGM_CUDA_DISP_FILTER_H_ #define SGM_CUDA_DISP_FILTER_H_ #include "sgm_types.h" #include <cuda_runtime.h> class DisparityFilter { public: DisparityFilter(); ~DisparityFilter(); /** * \brief ��ʼ�� * \param width Ӱ��� * \param height Ӱ��� * \return */ bool Initialize(const sint32& width, const sint32& height); /** \brief �ͷ��ڴ� */ void Release(); /** * \brief �������ݣ��豸�����ݣ� * \param disp_map �Ӳ�ͼ * \param im_psize ������ͼ��pitch��С * \param dp_psize ���������ͼpitch��С */ void SetData(uint8* img_bytes, float32* disp_map, const size_t& im_psize, const size_t& dp_psize); /** * \brief ���ò��� * \param do_median_filter // ִ����ֵ�˲� * \param postfilter_type // �˲��������� * \param morphology_type // ��̬ѧ�������� */ void SetParam(bool do_median_filter, CuSGMOption::PF_Type postfilter_type, CuSGMOption::MP_Type morphology_type); /** \brief ִ���˲� */ void Filter(cudaStream_t* streams); /** \brief ��ȡ������Ӳ�ͼ */ float32* get_disp_map_out() const; public: // 3x3��ֵ�˲� static void Median3X3FilterCuda(float32* d_inout, sint32 width, sint32 height, const size_t& dp_psize,cudaStream_t* streams); // �����˲������� static void GaussFilterFloatCuda(float32* d_output, float32* d_input, float32 sigmaD, float32 sigmaR, uint32 width, uint32 height, size_t dp_psize,cudaStream_t* streams); static void BilateralFilterFloatCuda(uint8* img_bytes, float32* d_output, float32* d_input, float32 sigmaD, float32 sigmaR, uint32 width, uint32 height, size_t im_psize, size_t dp_psize,cudaStream_t* streams); // ��̬ѧ���������� static void ErosionCuda(float32* d_output, float32* d_input, sint32 wndsize, sint32 width, sint32 height, size_t dp_psize); static void DilationCuda(float32* d_output, float32* d_input, sint32 wndsize, sint32 width, sint32 height, size_t dp_psize); static void ErosionCuda(sint16* d_output, sint16* d_input, sint32 wndsize, sint32 width, sint32 height, size_t dp_psize); static void DilationCuda(sint16* d_output, sint16* d_input, sint32 wndsize, sint32 width, sint32 height, size_t dp_psize); private: /** \brief Ӱ��ߴ�*/ sint32 width_; sint32 height_; /** \brief ��ͼ������*/ uint8* img_bytes_; /** \brief �����ͼ��pitch��С*/ size_t im_psize_; /** \brief �Ӳ�ͼ*/ float32* disp_map_; /** \brief ������Ӳ�ͼpitch��С*/ size_t dp_psize_; /** \brief �˲��Ӳ�ͼ*/ float32* disp_map_filter_; /** \brief ����Ӳ�ͼ*/ float32* disp_map_out_; /** \brief ��ֵ�˲�����*/ bool do_median_filter_; /** \brief �����˲�����*/ CuSGMOption::PF_Type postfilter_type_; /** \brief ��̬ѧ��������*/ CuSGMOption::MP_Type morphology_type_; /** \brief �Ƿ��ʼ���ɹ� */ bool is_initialized_; }; #endif 注释上述代码
09-26
python3 glasswindow.py 玻璃窗检测系统启动 相机初始化失败: 'pyrealsense2.video_stream_profile' object has no attribute 'get_device' 程序执行完成 请根据上述问题修改程序代码,提供一份完整的可运行的程序代码 import cv2 import numpy as np import matplotlib.pyplot as plt import pyrealsense2 as rs import os import sys from sklearn.cluster import DBSCAN from sklearn.linear_model import RANSACRegressor from collections import defaultdict class RealSenseCamera: """RealSense D455相机控制类""" def __init__(self, enable_ir_filter=True): """ 初始化RealSense相机 参数: enable_ir_filter: 是否启用红外滤光片功能 """ self.pipeline = rs.pipeline() self.config = rs.config() self.align = rs.align(rs.stream.color) self.enable_ir_filter = enable_ir_filter # 配置深度和彩色流 self.config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30) self.config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30) def start(self): """启动相机流""" profile = self.pipeline.start(self.config) # 获取深度传感器并配置红外滤光片 if self.enable_ir_filter: depth_sensor = profile.get_device().first_depth_sensor() depth_sensor.set_option(rs.option.emitter_enabled, 0) # 关闭红外发射器 depth_sensor.set_option(rs.option.laser_power, 0) # 关闭激光器 # 设置自动曝光 color_sensor = profile.get_device().query_sensors()[1] color_sensor.set_option(rs.option.enable_auto_exposure, True) # 获取深度比例 depth_profile = rs.video_stream_profile(profile.get_stream(rs.stream.depth)) self.depth_scale = depth_profile.get_device().first_depth_sensor().get_depth_scale() def capture_frame(self): """捕获一帧RGB和深度图像""" frames = self.pipeline.wait_for_frames() aligned_frames = self.align.process(frames) depth_frame = aligned_frames.get_depth_frame() color_frame = aligned_frames.get_color_frame() if not depth_frame or not color_frame: return None, None # 转换为numpy数组 depth_image = np.asanyarray(depth_frame.get_data()) color_image = np.asanyarray(color_frame.get_data()) return color_image, depth_image def stop(self): """停止相机流""" self.pipeline.stop() def cluster_line_segments(lines, eps=20, min_samples=2): """ 对线段进行聚类处理 参数: lines: 检测到的线段列表 [(x1,y1,x2,y2), ...] eps: 聚类半径 min_samples: 最小聚类样本数 返回: clusters: 聚类后的线段列表 [[line1, line2, ...], ...] """ if lines is None or len(lines) == 0: return [] # 计算线段的中点和角度 segments = [] for line in lines: x1, y1, x2, y2 = line mid_x, mid_y = (x1+x2)/2, (y1+y2)/2 angle = np.arctan2(y2-y1, x2-x1) * 180 / np.pi segments.append([mid_x, mid_y, angle]) segments = np.array(segments) # 使用DBSCAN聚类算法 db = DBSCAN(eps=eps, min_samples=min_samples).fit(segments) labels = db.labels_ # 按聚类分组 clusters = defaultdict(list) for i, label in enumerate(labels): if label >= 0: # 忽略噪声点 clusters[label].append(lines[i]) return list(clusters.values()) def extend_lines(lines, img_shape): """ 延长线段以形成完整框架 参数: lines: 同一簇的线段列表 img_shape: 图像尺寸 (h, w) 返回: extended_lines: 延长后的线段列表 """ if not lines: return [] # 收集所有端点 all_points = [] for line in lines: x1, y1, x2, y2 = line all_points.extend([(x1, y1), (x2, y2)]) # 使用RANSAC拟合直线 points = np.array(all_points) ransac = RANSACRegressor() # 水平线处理 horizontal_lines = [] for line in lines: x1, y1, x2, y2 = line if abs(y1 - y2) < 10: # 水平线 horizontal_lines.append(line) # 垂直线处理 vertical_lines = [] for line in lines: x1, y1, x2, y2 = line if abs(x1 - x2) < 10: # 垂直线 vertical_lines.append(line) # 延长水平线 extended_lines = [] for cluster in [horizontal_lines, vertical_lines]: if not cluster: continue # 收集端点 points = [] for line in cluster: x1, y1, x2, y2 = line points.extend([(x1, y1), (x2, y2)]) if len(points) < 2: continue points = np.array(points) if cluster is horizontal_lines: # 水平线:固定y值,延长x到图像边界 y_avg = np.mean(points[:, 1]) extended_lines.append((0, int(y_avg), img_shape[1], int(y_avg))) else: # 垂直线:固定x值,延长y到图像边界 x_avg = np.mean(points[:, 0]) extended_lines.append((int(x_avg), 0, int(x_avg), img_shape[0])) return extended_lines def detect_glass_and_frame(rgb_img, depth_map): """ 改进的玻璃及窗框检测函数 参数: rgb_img: RGB彩色图像 depth_map: 深度图 返回: glass_mask: 玻璃区域掩膜 frame_lines: 检测到的窗框线段 result_img: 可视化结果图像 """ # ===== 1. 深度图预处理 ===== # 创建玻璃候选区域掩膜(深度值为0的区域) glass_mask = np.where(depth_map == 0, 255, 0).astype(np.uint8) # 形态学操作优化掩膜 kernel = np.ones((5, 5), np.uint8) glass_mask = cv2.morphologyEx(glass_mask, cv2.MORPH_CLOSE, kernel) glass_mask = cv2.dilate(glass_mask, kernel, iterations=2) glass_mask = cv2.medianBlur(glass_mask, 5) # ===== 2. 玻璃区域分割 ===== contours, _ = cv2.findContours(glass_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) min_area = 1000 glass_roi = np.zeros_like(glass_mask) for cnt in contours: area = cv2.contourArea(cnt) if area > min_area: cv2.drawContours(glass_roi, [cnt], -1, 255, -1) # ===== 3. 窗框检测 ===== # RGB图像预处理 gray = cv2.cvtColor(rgb_img, cv2.COLOR_BGR2GRAY) clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8, 8)) enhanced = clahe.apply(gray) # 边缘检测 edges = cv2.Canny(enhanced, 50, 150) # 霍夫变换检测直线 lines = cv2.HoughLinesP(edges, rho=1, theta=np.pi/180, threshold=50, minLineLength=100, maxLineGap=10) # 几何约束筛选窗框线 frame_lines = [] if lines is not None: for line in lines: x1, y1, x2, y2 = line[0] # 筛选水平/垂直线(角度容差±10度) if abs(x1 - x2) < 10 or abs(y1 - y2) < 10: frame_lines.append(line[0]) # ===== 4. 线段聚类和延长 ===== clustered_lines = cluster_line_segments(frame_lines) extended_lines = [] for cluster in clustered_lines: extended = extend_lines(cluster, rgb_img.shape[:2]) extended_lines.extend(extended) # ===== 5. 结果可视化 ===== result_img = rgb_img.copy() # 绘制玻璃区域(半透明红色) glass_color = np.zeros_like(rgb_img) glass_color[glass_roi == 255] = [0, 0, 255] # 红色 cv2.addWeighted(glass_color, 0.3, result_img, 1, 0, result_img) # 绘制原始线段(黄色) for line in frame_lines: x1, y1, x2, y2 = line cv2.line(result_img, (x1, y1), (x2, y2), (0, 255, 255), 2) # 黄色 # 绘制延长后的线段(绿色) for line in extended_lines: x1, y1, x2, y2 = line cv2.line(result_img, (x1, y1), (x2, y2), (0, 255, 0), 3) # 绿色 return glass_roi, extended_lines, result_img def main(): """主函数""" print("玻璃窗检测系统启动") # 初始化RealSense相机 try: camera = RealSenseCamera(enable_ir_filter=True) camera.start() print("RealSense D455相机已连接") except Exception as e: print(f"相机初始化失败: {str(e)}") return # 创建结果保存目录 output_dir = "detection_results" os.makedirs(output_dir, exist_ok=True) frame_count = 0 plt.ion() # 启用交互模式 try: while True: # 捕获帧 color_img, depth_img = camera.capture_frame() if color_img is None or depth_img is None: continue # 执行检测 glass_mask, frame_lines, result_img = detect_glass_and_frame(color_img, depth_img) # 显示结果 plt.figure(figsize=(15, 10)) plt.subplot(221) plt.title("RGB Image") plt.imshow(cv2.cvtColor(color_img, cv2.COLOR_BGR2RGB)) plt.subplot(222) plt.title("Depth Map") plt.imshow(depth_img, cmap='jet') plt.colorbar() plt.subplot(223) plt.title("Glass Detection") plt.imshow(glass_mask, cmap='gray') plt.subplot(224) plt.title("Detection Result") plt.imshow(cv2.cvtColor(result_img, cv2.COLOR_BGR2RGB)) plt.tight_layout() plt.draw() plt.pause(0.001) # 保存结果 if frame_count % 10 == 0: cv2.imwrite(os.path.join(output_dir, f"frame_{frame_count:04d}_rgb.png"), color_img) cv2.imwrite(os.path.join(output_dir, f"frame_{frame_count:04d}_depth.png"), depth_img) cv2.imwrite(os.path.join(output_dir, f"frame_{frame_count:04d}_result.png"), result_img) print(f"已保存帧 {frame_count}") frame_count += 1 # 检测退出键 if cv2.waitKey(1) & 0xFF == ord('q'): break except KeyboardInterrupt: print("用户中断") finally: camera.stop() plt.ioff() plt.close() print("相机已关闭") if __name__ == "__main__": main() print("程序执行完成")
07-31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值