class ProcessMasks(): def __init__(self, sz=270, fs=30, bs=30, size=256): print('init') self.stop = False self.masked_batches = [] self.batch_mean = [] self.signal_size = sz self.batch_size = bs self.signal = np.zeros((sz, 3)) self.pulse = Pulse(fs, sz, bs, size) self.hrs = [] self.save_results = True def __call__(self, pipe, plot_pipe, source): self.pipe = pipe self.plot_pipe = plot_pipe self.source = source compute_mean_thread = Thread(target=self.compute_mean) compute_mean_thread.start() extract_signal_thread = Thread(target=self.extract_signal) extract_signal_thread.start() self.rec_frames() compute_mean_thread.join() extract_signal_thread.join() def rec_frames(self): while True and not self.stop: data = self.pipe.recv() if data is None: self.terminate() break batch = data[0] self.masked_batches.append(batch) def process_signal(self, batch_mean): 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) self.p = p hr = self.pulse.get_rfft_hr(p) if len(self.hrs) > 3000: 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] sys.stdout.write(f'\rHr: {round(hr_fft, 0)}') sys.stdout.flush() 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'] 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) else: self.signal[signal_extracted:signal_extracted + mean.shape[0]] = mean signal_extracted += mean.shape[0] def compute_mean(self): curr_batch_size = 0 batch = None while True and not self.stop: if len(self.masked_batches) == 0: time.sleep(0.01) continue mask = self.masked_batches.pop(0) 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))} 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) def terminate(self): if self.plot_pipe is not None: self.plot_pipe.send(None) self.savePlot(self.source) self.saveresults() self.stop = True def saveresults(self): """ saves numpy array of heart rates as hrs saves numpy array of power spectrum as fft_spec """ np.save('hrs', np.array(self.hrs)) np.save('fft_spec', np.array(self.pulse.fft_spec)) # np.save('p', np.array(self.p)) # np.save('hr', np.array(self.hr)) def savePlot(self, path): if self.save_results == False: return # path = path.replace ('/media/munawar/','/munawar-desktop/') # fig_path = path[40:].replace("/","_") # file_path = path.replace('video.avi','gt_HR.csv') # gt_HR = pd.read_csv(file_path, index_col=False).values if len(self.hrs) == 0: return ax1 = plt.subplot(1, 1, 1) ax1.set_title('HR') ax1.set_ylim([20, 180]) ax1.plot(moving_avg(self.hrs, 6)) plt.tight_layout() plt.savefig(f'hr.png') plt.close() ax3 = plt.subplot(1, 2, 2) ax3.set_title('GT') ax3.set_ylim([20, 180]) ax3.plot(self.pulse.fft_spec) plt.tight_layout() plt.savefig(f'results.png') plt.close()
class ProcessRppg(): def __init__(self, sz=270, fs=25, bs=30, save_key=None, size=256): print('init') self.stop = False self.masked_batches = [] self.batch_mean = [] self.signal_size = sz self.batch_size = bs self.signal = np.zeros((sz, 3)) self.pulse = Pulse(fs, sz, bs, size) self.hrs = [] self.save_key = save_key self.save_root = '/data2/datasets_origin/' self.save_result = True self.signal_extracted = 0 self.curr_batch_size = 0 self.batch = None def __call__(self, data): self.rec_frames(data) def rec_frames(self, data): batch = data[0] self.masked_batches.append(batch) self.compute_mean() self.extract_signal() def process_signal(self, batch_mean): 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] # sys.stdout.write(f'\rHr: {round(hr_fft, 0)}') # sys.stdout.flush() def extract_signal(self): if len(self.batch_mean) == 0: return mean_dict = self.batch_mean.pop(0) mean = mean_dict['mean'] if mean_dict['face_detected'] == False: # if self.plot_pipe is not None: # self.plot_pipe.send('no face detected') return if self.signal_extracted >= self.signal_size: self.process_signal(mean) else: self.signal[self.signal_extracted:self.signal_extracted + mean.shape[0]] = mean self.signal_extracted += mean.shape[0] def compute_mean(self): if len(self.masked_batches) == 0: return mask = self.masked_batches.pop(0) if self.batch is None: self.batch = np.zeros( (self.batch_size, mask.shape[0], mask.shape[1], mask.shape[2])) if self.curr_batch_size < (self.batch_size - 1): self.batch[self.curr_batch_size] = mask self.curr_batch_size += 1 return self.batch[self.curr_batch_size] = mask self.curr_batch_size = 0 non_zero_pixels = (self.batch != 0).sum(axis=(1, 2)) total_pixels = self.batch.shape[1] * self.batch.shape[2] avg_skin_pixels = non_zero_pixels.mean() m = {'face_detected': True, 'mean': np.zeros((self.batch_size, 3))} if (avg_skin_pixels + 1) / (total_pixels) < 0.005: m['face_detected'] = False else: m['mean'] = np.true_divide(self.batch.sum(axis=(1, 2)), non_zero_pixels + 1e-6) self.batch_mean.append(m) def terminate(self): if self.plot_pipe is not None: self.plot_pipe.send(None) self.savePlot(self.source) self.saveresults() self.stop = True def saveresults(self): """ saves numpy array of heart rates as hrs saves numpy array of power spectrum as fft_spec """ if len(self.pulse.fft_spec) > 0: if self.save_key is not None: det_save_key = self.save_key else: det_save_key = './' save_path = os.path.join(self.save_root, det_save_key) if not os.path.exists(save_path): os.makedirs(save_path) fft_path = os.path.join(save_path, 'fft_spec') # np.save('hrs', np.array(self.hrs)) np.save(fft_path, np.array(self.pulse.fft_spec)) def savePlot(self, path): if self.save_result == False: return # path = path.replace ('/media/munawar/','/munawar-desktop/') # fig_path = path[40:].replace("/","_") # file_path = path.replace('video.avi','gt_HR.csv') # gt_HR = pd.read_csv(file_path, index_col=False).values if len(self.hrs) == 0: return ax1 = plt.subplot(1, 1, 1) ax1.set_title('HR') ax1.set_ylim([20, 180]) ax1.plot(moving_avg(self.hrs, 6)) # ax3 = plt.subplot(1,2,2) # ax3.set_title('GT') # ax3.set_ylim([20, 180]) # ax3.plot(gt_HR[8:]) plt.tight_layout() plt.savefig(f'results.png') plt.close()