Python跨类获取另一类函数内frames_count变量的方法
解决多进程下跨类传递帧序号的问题
首先得明确核心问题:你的CaptureFrames和ProcessMasks运行在不同的多进程中(看入口代码里用了mp.Process创建子进程),进程之间的内存是完全隔离的——子进程根本看不到主进程里CaptureFrames实例的任何数据,所以直接通过CaptureFrames.frames_count或者实例属性访问肯定会失败。
最贴合你现有代码架构的解决方案是把帧序号和帧数据一起通过管道传递,因为你已经在用管道做进程间通信了,直接扩展传递的数据即可,不需要引入复杂的新机制。
具体修改步骤:
1. 修改CaptureFrames的capture_frames方法,发送帧时带上序号
在发送帧数据的位置,把frames_count和帧打包后发送:
# 原代码:self.pipe.send([orig]) # 修改为: self.pipe.send([orig, self.frames_count])
2. 修改ProcessMasks的rec_frames方法,同时接收帧和序号
接收数据时提取帧序号,和帧数据一起存入masked_batches:
def rec_frames(self): while True and not self.stop: data = self.pipe.recv() if data is None: self.terminate() break batch = data[0] frames_count = data[1] # 新增:提取当前帧的序号 self.masked_batches.append( (batch, frames_count) ) # 存为元组保存关联关系
3. 修改compute_mean方法,把帧序号传递到后续流程
处理batch时,将帧序号和计算结果一起存入batch_mean,保证关联关系不丢失:
def compute_mean(self): curr_batch_size = 0 batch = None current_batch_last_frame_count = None # 记录当前batch的最后一帧序号 while True and not self.stop: if len(self.masked_batches) == 0: time.sleep(0.01) continue mask, frames_count = self.masked_batches.pop(0) # 取出帧和序号 current_batch_last_frame_count = frames_count # 更新为当前batch的最后一帧序号 if batch is None: batch = np.zeros((self.batch_size, mask.shape[0], mask.shape[1], mask.shape[2])) if curr_batch_size < (self.batch_size - 1): batch[curr_batch_size] = mask curr_batch_size+=1 continue batch[curr_batch_size] = mask curr_batch_size = 0 non_zero_pixels = (batch!=0).sum(axis=(1,2)) total_pixels = batch.shape[1] * batch.shape[2] avg_skin_pixels = non_zero_pixels.mean() # 新增:把帧序号加入结果字典 m = { 'face_detected': True, 'mean': np.zeros((self.batch_size, 3)), 'frames_count': current_batch_last_frame_count } if (avg_skin_pixels + 1) / (total_pixels) < 0.05: m['face_detected'] = False else: m['mean'] = np.true_divide(batch.sum(axis=(1,2)), non_zero_pixels+1e-6) self.batch_mean.append(m)
4. 在process_signal中使用帧序号
修改extract_signal和process_signal,把帧序号传递到最终打印环节:
def extract_signal(self): signal_extracted = 0 while True and not self.stop: if len(self.batch_mean) == 0: time.sleep(0.01) continue mean_dict = self.batch_mean.pop(0) mean = mean_dict['mean'] frames_count = mean_dict['frames_count'] # 取出帧序号 if mean_dict['face_detected'] == False: if self.plot_pipe is not None: self.plot_pipe.send('no face detected') continue if signal_extracted >= self.signal_size: self.process_signal(mean, frames_count) # 传递给处理函数 else: self.signal[signal_extracted: signal_extracted + mean.shape[0]] = mean signal_extracted+=mean.shape[0] def process_signal(self, batch_mean, frames_count): # 新增帧序号参数 size = self.signal.shape[0] b_size = batch_mean.shape[0] self.signal[0:size-b_size] = self.signal[b_size:size] self.signal[size-b_size:] = batch_mean p = self.pulse.get_pulse(self.signal) p = moving_avg(p, 6) hr = self.pulse.get_rfft_hr(p) if len(self.hrs) > 300: self.hrs.pop(0) self.hrs.append(hr) if self.plot_pipe is not None and self.stop: self.plot_pipe.send(None) elif self.plot_pipe is not None: self.plot_pipe.send([p, self.hrs]) else: hr_fft = moving_avg(self.hrs, 3)[-1] if len(self.hrs) > 5 else self.hrs[-1] # 修改:同时打印帧序号和对应的心率 print(f"Frame {frames_count}: HR = {hr_fft}") sys.stdout.write(f'\rFrame {frames_count} | Hr: {round(hr_fft, 0)}') sys.stdout.flush()
为什么这个方案可行?
管道是多进程间安全的通信方式,你已经用它传递帧数据了,只是扩展了传递的内容,完全贴合现有代码的设计,不需要额外处理锁或者共享内存的复杂逻辑。
备选方案:使用共享内存
如果不想修改管道传递的内容,也可以用multiprocessing.Value创建一个共享整数变量:
- 在
RunPOS中创建共享变量:frames_count_shared = mp.Value('i', 0) - 将其传递给
CaptureFrames和ProcessMasks的实例 CaptureFrames中更新:with self.frames_count_shared.get_lock(): self.frames_count_shared.value +=1ProcessMasks中读取:with self.frames_count_shared.get_lock(): current_count = self.frames_count_shared.value
但这种方式需要处理并发读写的锁问题,相比管道传递稍复杂,适合需要多个进程共享同一个计数器的场景。
内容的提问来源于stack exchange,提问作者connor449
相关产品推荐
相关产品推荐

