def generate_sliding_detection_data_from_image(self, imgpath, scale_pairlist): from PIL import Image import iutils as iu import imgproc self.init_meta('sliding') img = Image.open(imgpath) ndata = 0 newdim = self.savedata_info['newdim'] steps = self.imgdata_info['steps'] # x1 is the size, x1 - 1 is the last pixel index fx = lambda x1,x2: np.floor((x1 - newdim[1])/x2) + 1 fy = lambda x1,x2: np.floor((x1 - newdim[0])/x2) + 1 valid_idx = 0 for s in scale_pairlist: ns = np.floor(np.asarray([img.size[0], img.size[1]]) * np.asarray([s[0], s[1]])) if ns[0] < newdim[1] or ns[1] < newdim[0]: break cur_n = fx(ns[0],steps[0]) * fy(ns[1], steps[1]) valid_idx = valid_idx + 1 ndata = ndata + cur_n ndata = int(ndata) scale_pairlist = scale_pairlist[:valid_idx] print( 'Need to generate %d data' % ndata) filter_size = self.savedata_info['indmap_para']['filter_size'] stride = self.savedata_info['indmap_para']['stride'] mdim = self.get_indmapdim(newdim, filter_size, stride) joint_filter_size = self.savedata_info['indmap_para']['joint_filter_size'] joint_stride = self.savedata_info['indmap_para']['joint_stride'] jtmdim = self.get_indmapdim(newdim, joint_filter_size, joint_stride) res = self.prepare_savebuffer({'data':newdim, 'part_indmap':mdim, \ 'joint_indmap': jtmdim}, ndata, self.meta['nparts'], self.meta['njoints']) dicjtname = 'joints8' if self.meta['njoints'] == 8 else 'joints' res[dicjtname][:] = 0 res['jointmasks'][:] = False res['indmap'][:] = False res['joint_indmap'][:] = False res['is_mirror'][:] = False res['is_positive'][:] = False res['slide_location'] = np.zeros((2,ndata),dtype=np.float) res['scale'] = np.zeros((2,ndata), dtype=np.float) res['filenames'] = [imgpath for x in range(ndata)] idx = 0 dimX = iu.prod(newdim) for s in scale_pairlist: ns = np.floor(np.asarray([img.size[0], img.size[1]]) * np.asarray([s[0], s[1]])) ns = (int(ns[0]),int(ns[1])) nimg = img.resize((ns[0],ns[1])) arrimg = imgproc.ensure_rgb(np.asarray(nimg)) for x in range(0, ns[0] - newdim[1] + 1, steps[0]): for y in range(0, ns[1] - newdim[0] + 1, steps[1]): res['scale'][...,idx] = np.asarray([s[0],s[1]]).reshape((2)) res['slide_location'][...,idx] = np.asarray([x,y]).reshape((2)) res['data'][...,idx] = arrimg[y:y+newdim[0],x:x+newdim[1],:] idx = idx + 1 if idx != ndata: raise HMLPEError('Number of data is not consistent') res['data'] = res['data'].reshape((-1,ndata),order='F') return res
def init_meta(self, generate_type): """ init meta meta will only have those field """ self.meta = {'imgdata_info':self.imgdata_info,'savedata_info':self.savedata_info} self.meta['num_vis'] = iu.prod(self.savedata_info['newdim']) self.meta['data_sum'] = 0 self.meta['ndata'] = 0 if 'part_idx' in self.savedata_info: self.meta['nparts'] = len(self.savedata_info['part_idx']) else: self.meta['nparts'] = len(part_idx) self.meta['savedata_info']['part_idx'] = part_idx self.meta['njoints'] = len(self.savedata_info['jointnames']) self.meta['generate_type'] = generate_type self.meta['matdim'] = None self.meta['ind_dim'] = dict()
def init_meta(self, generate_type): """ init meta meta will only have those field """ self.meta = { 'imgdata_info': self.imgdata_info, 'savedata_info': self.savedata_info } self.meta['num_vis'] = iu.prod(self.savedata_info['newdim']) self.meta['data_sum'] = 0 self.meta['ndata'] = 0 if 'part_idx' in self.savedata_info: self.meta['nparts'] = len(self.savedata_info['part_idx']) else: self.meta['nparts'] = len(part_idx) self.meta['savedata_info']['part_idx'] = part_idx self.meta['njoints'] = len(self.savedata_info['jointnames']) self.meta['generate_type'] = generate_type self.meta['matdim'] = None self.meta['ind_dim'] = dict()
def generate_data(self, generate_type, allfile = None): """ generate_type = 'rt' only """ if allfile is None: allfile = iu.getfilelist( self.imgdata_info['imgdata_path'], '\w+\.mat') print 'imgdatapath=%s, %d files are found' % (self.imgdata_info['imgdata_path'], len(allfile)) iu.ensure_dir(self.savedata_info['savedir']) self.batch_id = self.savedata_info['start_patch_id'] ndata = 0 self.meta = {'imgdata_info':self.imgdata_info,'savedata_info':self.savedata_info} self.meta['num_vis'] = iu.prod(self.savedata_info['newdim']) self.meta['data_sum'] = 0 self.meta['ndata'] = 0 self.meta['nparts'] = len(part_idx) for fn in allfile: if generate_type == 'rt': mpath = iu.fullfile(self.imgdata_info['imgdata_path'], fn) self.generate_rt_data(iu.fullfile(mpath)) if self.meta['ndata'] > 0: self.meta['data_mean'] = self.meta['data_sum'] / self.meta['ndata'] del self.meta['data_sum'] myio.pickle(iu.fullfile(self.savedata_info['savedir'], 'batches.meta'), self.meta)
def generate_positive_data_from_mat(self, generate_type, matpath): """ in each mat mat['X'] is image data mat['Y'] is npart x ndata array """ mat = sio.loadmat(matpath) dim = mat['dim'][0] newdim = self.savedata_info['newdim'] if newdim[0] > dim[0] or newdim[1] > dim[1]: raise HMLPEError('Invalid new size ') if self.meta['matdim'] is None: self.meta['matdim'] = dim # record the dimension before sampling else: if np.any(self.meta['matdim'] != dim): raise HMLPEError( 'Inconsistent matdim: Previous dim is %s, current mat dim is %s' % (str(self.meta['matdim']), str(dim))) ndata = (mat['X'].shape)[1] if generate_type in {'rt': 1}: sample_num = self.savedata_info['sample_num'] totaldata = sample_num * ndata * 2 do_mirror = True elif generate_type == 'ct': sample_num = 1 totaldata = sample_num * ndata do_mirror = False if (dim[0] - newdim[0] + 1) * (dim[1] - newdim[1] + 1) < sample_num: raise HMLPEError(' Invalid sample_num') nparts = self.meta['nparts'] self.meta['ndata'] += totaldata ### BEGIN COMMENT # njoints = self.meta['njoints'] # if njoints == 8: # dicjtname = 'joints8' # else: # #raise HMLPEError('njoints = %d No supported yet' % (njoints)) # dicjtname = 'joints' # newdim = self.savedata_info['newdim'] # filter_size = self.savedata_info['indmap_para']['filter_size'] # stride = self.savedata_info['indmap_para']['stride'] # rate = self.savedata_info['indmap_para']['rate'] # mdim = self.get_indmapdim(newdim, filter_size, stride) # if newdim[0] > dim[0] or newdim[1] > dim[1]: # raise HMLPEError('Invalid new size ') # if (dim[0] - newdim[0] + 1) * (dim[1] - newdim[1] + 1) < sample_num: # raise HMLPEError(' Invalid sample_num') # joint_filter_size = self.savedata_info['indmap_para']['joint_filter_size'] # joint_stride = self.savedata_info['indmap_para']['joint_stride'] # jtmdim = self.get_indmapdim(newdim, joint_filter_size, joint_stride) ### END COMMENT fieldpool = self.get_fieldpool_for_positive_mat_data() fieldpool['mat'] = mat self.meta['ind_dim']['part_indmap'] = fieldpool['mdim'] self.meta['ind_dim']['joint_indmap'] = fieldpool['jtmdim'] res = {} per_size = min(totaldata, self.savedata_info['max_batch_size']) allX = mat['X'].reshape((dim[0], dim[1], dim[2], ndata), order='F') Y2dname = fieldpool['Y2dname'] allY = mat[Y2dname].reshape((2, -1, ndata), order='F') newlen = iu.prod(newdim) # prepare data buffer res = self.prepare_savebuffer({'data':fieldpool['newdim'], 'part_indmap':fieldpool['mdim'], 'joint_indmap': fieldpool['jtmdim']},\ per_size, self.meta['nparts'],\ self.meta['njoints']) tmpres = dict() pre_nc = 0 nc = 0 res['is_positive'][:] = True for it in range(ndata): curX = allX[..., it] curY = allY[..., it].transpose() curfilename = str( mat['imagepathlist'][0, it][0]) if 'imagepathlist' in mat else '' mesh = self.create_augumentation_mesh(dim, newdim, generate_type) l = (np.random.permutation(range(len(mesh))))[:sample_num] fieldpool['matidx'] = it fieldpool['curfilename'] = curfilename for p in l: r, c = mesh[p] tmpX = curX tmpX = np.roll(tmpX, shift=-int(r), axis=0) tmpX = np.roll(tmpX, shift=-int(c), axis=1) tmpY = curY - 1 + np.asarray([-c, -r]) fieldpool['r'] = r fieldpool['c'] = c #### fieldpool['curX'] = tmpX fieldpool['Y'] = tmpY # tmpX = tmpX[:newdim[0], :newdim[1],:] # res['data'][...,nc - pre_nc] = tmpX # res[dicjtname][..., nc - pre_nc] = tmpY # res['jointmasks'][...,nc - pre_nc] = self.makejointmask(newdim, tmpY) # res['filenames'][nc - pre_nc] = curfilename # res['oribbox'][...,nc-pre_nc] = mat['oribbox'][...,it] # res['indmap'][...,nc-pre_nc] = self.create_part_indicatormap(tmpY, self.meta['savedata_info']['part_idx'], mdim, rate, filter_size, stride) # res['joint_indmap'][...,nc-pre_nc] = self.create_joint_indicatormap(tmpY, jtmdim, joint_filter_size, joint_stride) # res['joint_sample_offset'][...,nc-pre_nc] = [c, r] # res['is_mirror'][...,nc-pre_nc] = False self.fill_in_positive_mat_data_to_dic(res, nc - pre_nc, \ fieldpool, False) nc = nc + 1 if not do_mirror: continue #flip image tmpX = tmpX[:, ::-1, :] tmpY = self.flip_joints(newdim, tmpY) fieldpool['curX'] = tmpX fieldpool['Y'] = tmpY self.fill_in_positive_mat_data_to_dic(res, nc - pre_nc, \ fieldpool, True) # res['data'][...,nc - pre_nc] = tmpX # res[dicjtname][...,nc -pre_nc] = tmpY # res['jointmasks'][...,nc - pre_nc] = self.makejointmask(newdim, tmpY) # res['filenames'][nc - pre_nc] = curfilename # res['oribbox'][...,nc-pre_nc] = mat['oribbox'][...,it] # res['indmap'][...,nc-pre_nc] = self.create_part_indicatormap(tmpY, part_idx, mdim, rate, filter_size, stride) # res['joint_indmap'][...,nc-pre_nc] = self.create_joint_indicatormap(tmpY, jtmdim, joint_filter_size, joint_stride) # res['joint_sample_offset'][...,nc-pre_nc] = [c, r] # res['is_mirror'][...,nc-pre_nc] = True nc = nc + 1 t = 2 if do_mirror else 1 if nc - pre_nc + t * sample_num > per_size or nc == totaldata: tmpres = self.truncated_copydic(res, nc - pre_nc) tmpres['data'] = tmpres['data'].reshape((-1, nc - pre_nc), order='F') self.meta['data_sum'] = self.meta['data_sum'] + tmpres[ 'data'].sum(axis=1, dtype=float) savepath = iu.fullfile(self.savedata_info['savedir'], \ self.savedata_info['savename'] + \ '_' + str(self.batch_id)) myio.pickle(savepath, tmpres) self.batch_id = self.batch_id + 1 pre_nc = nc
def generate_sliding_detection_data_from_image(self, imgpath, scale_pairlist): from PIL import Image import iutils as iu import imgproc self.init_meta('sliding') img = Image.open(imgpath) ndata = 0 newdim = self.savedata_info['newdim'] steps = self.imgdata_info['steps'] # x1 is the size, x1 - 1 is the last pixel index fx = lambda x1, x2: np.floor((x1 - newdim[1]) / x2) + 1 fy = lambda x1, x2: np.floor((x1 - newdim[0]) / x2) + 1 valid_idx = 0 for s in scale_pairlist: ns = np.floor( np.asarray([img.size[0], img.size[1]]) * np.asarray([s[0], s[1]])) if ns[0] < newdim[1] or ns[1] < newdim[0]: break cur_n = fx(ns[0], steps[0]) * fy(ns[1], steps[1]) valid_idx = valid_idx + 1 ndata = ndata + cur_n ndata = int(ndata) scale_pairlist = scale_pairlist[:valid_idx] print('Need to generate %d data' % ndata) filter_size = self.savedata_info['indmap_para']['filter_size'] stride = self.savedata_info['indmap_para']['stride'] mdim = self.get_indmapdim(newdim, filter_size, stride) joint_filter_size = self.savedata_info['indmap_para'][ 'joint_filter_size'] joint_stride = self.savedata_info['indmap_para']['joint_stride'] jtmdim = self.get_indmapdim(newdim, joint_filter_size, joint_stride) res = self.prepare_savebuffer({'data':newdim, 'part_indmap':mdim, \ 'joint_indmap': jtmdim}, ndata, self.meta['nparts'], self.meta['njoints']) dicjtname = 'joints8' if self.meta['njoints'] == 8 else 'joints' res[dicjtname][:] = 0 res['jointmasks'][:] = False res['indmap'][:] = False res['joint_indmap'][:] = False res['is_mirror'][:] = False res['is_positive'][:] = False res['slide_location'] = np.zeros((2, ndata), dtype=np.float) res['scale'] = np.zeros((2, ndata), dtype=np.float) res['filenames'] = [imgpath for x in range(ndata)] idx = 0 dimX = iu.prod(newdim) for s in scale_pairlist: ns = np.floor( np.asarray([img.size[0], img.size[1]]) * np.asarray([s[0], s[1]])) ns = (int(ns[0]), int(ns[1])) nimg = img.resize((ns[0], ns[1])) arrimg = imgproc.ensure_rgb(np.asarray(nimg)) for x in range(0, ns[0] - newdim[1] + 1, steps[0]): for y in range(0, ns[1] - newdim[0] + 1, steps[1]): res['scale'][..., idx] = np.asarray([s[0], s[1]]).reshape( (2)) res['slide_location'][..., idx] = np.asarray([x, y]).reshape( (2)) res['data'][..., idx] = arrimg[y:y + newdim[0], x:x + newdim[1], :] idx = idx + 1 if idx != ndata: raise HMLPEError('Number of data is not consistent') res['data'] = res['data'].reshape((-1, ndata), order='F') return res
def generate_rt_data(self, matpath): """ in each mat mat['X'] is image data mat['Y'] is npart x ndata array """ mat = sio.loadmat(matpath) dim = mat['dim'][0] ndata = (mat['X'].shape)[1] sample_num = self.savedata_info['sample_num'] totaldata = sample_num * ndata * 2 newdim = self.savedata_info['newdim'] nparts = self.meta['nparts'] filter_size = self.savedata_info['indmap_para']['filter_size'] stride = self.savedata_info['indmap_para']['stride'] rate = self.savedata_info['indmap_para']['rate'] mdim = self.get_indmapdim(newdim, filter_size, stride) if newdim[0] > dim[0] or newdim[1] > dim[1]: raise HMLPEError('Invalid new size ') if (dim[0] - newdim[0] + 1) * (dim[1] - newdim[1] + 1) < sample_num: raise HMLPEError(' Invalid sample_num') res = {} per_size = min(totaldata, self.savedata_info['max_batch_size']) mesh = iu.cartesian_product2(np.asarray( [range(dim[0] - newdim[0] + 1), \ range(dim[1] - newdim[1] + 1)])) allX = mat['X'].reshape( (dim[0], dim[1],dim[2], ndata), order='F') allY = mat['Y'].reshape( (2,-1, ndata), order='F') newlen = iu.prod( newdim ) res['data'] = np.ndarray([newdim[0], newdim[1], newdim[2], per_size], \ dtype = np.uint8) res['labels'] = np.ndarray( [allY.shape[1], per_size], dtype=np.int) res['joints8'] = np.ndarray( [8, 2, per_size], dtype=np.float) res['oribbox'] = np.ndarray( [4, per_size], dtype = np.float) res['indmap'] = np.zeros((nparts, mdim[0], mdim[1], per_size), np.bool) res['filenames'] =[str() for x in range(per_size)] tmpres = dict() cur_id = self.batch_id pre_nc = 0 nc = 0 for it in range(ndata): curX = allX[...,it] curY = allY[...,it].transpose() curfilename = str(mat['imagepathlist'][0,it][0]) l = (np.random.permutation(range(len(mesh))))[:sample_num] for p in l: r,c = mesh[p] tmpX = curX tmpX = np.roll(tmpX, shift=-int(r), axis = 0) tmpX = np.roll(tmpX, shift=-int(c), axis = 1) tmpX = tmpX[:newdim[0], :newdim[1],:] res['data'][...,nc - pre_nc] = tmpX tmpY = curY - 1 + np.asarray([-c,-r]) res['joints8'][..., nc - pre_nc] = tmpY; res['filenames'][nc - pre_nc] = curfilename res['oribbox'][...,nc-pre_nc] = res['oribbox'][...,it] res['indmap'][...,nc-pre_nc] = self.create_indicatormap(tmpY, part_idx, mdim, rate, filter_size, stride) res['jointmasks'] = self.makejointmask(newdim, tmpY) nc = nc + 1 #flip image tmpX = tmpX[:,::-1,:] res['data'][...,nc - pre_nc] = tmpX res['filenames'][nc - pre_nc] = curfilename tmmY = flip_pose8_joint(newdim, tmpY) res['joints8'][...,nc -pre_nc] = tmpY res['oribbox'][...,nc-pre_nc] = res['oribbox'][...,it] res['indmap'][...,nc-pre_nc] = self.create_indicatormap(tmpY, part_idx, mdim, rate, filter_size, stride) res['jointmasks'] = self.makejointmask(newdim, tmpY)
def generate_positive_data_from_mat(self, generate_type, matpath): """ in each mat mat['X'] is image data mat['Y'] is npart x ndata array """ mat = sio.loadmat(matpath) dim = mat['dim'][0] newdim = self.savedata_info['newdim'] if newdim[0] > dim[0] or newdim[1] > dim[1]: raise HMLPEError('Invalid new size ') if self.meta['matdim'] is None: self.meta['matdim'] = dim # record the dimension before sampling else: if np.any(self.meta['matdim'] != dim): raise HMLPEError('Inconsistent matdim: Previous dim is %s, current mat dim is %s' % (str(self.meta['matdim']), str(dim))) ndata = (mat['X'].shape)[1] if generate_type in {'rt':1}: sample_num = self.savedata_info['sample_num'] totaldata = sample_num * ndata * 2 do_mirror = True elif generate_type == 'ct': sample_num = 1 totaldata = sample_num * ndata do_mirror = False if (dim[0] - newdim[0] + 1) * (dim[1] - newdim[1] + 1) < sample_num: raise HMLPEError(' Invalid sample_num') nparts = self.meta['nparts'] self.meta['ndata'] += totaldata ### BEGIN COMMENT # njoints = self.meta['njoints'] # if njoints == 8: # dicjtname = 'joints8' # else: # #raise HMLPEError('njoints = %d No supported yet' % (njoints)) # dicjtname = 'joints' # newdim = self.savedata_info['newdim'] # filter_size = self.savedata_info['indmap_para']['filter_size'] # stride = self.savedata_info['indmap_para']['stride'] # rate = self.savedata_info['indmap_para']['rate'] # mdim = self.get_indmapdim(newdim, filter_size, stride) # if newdim[0] > dim[0] or newdim[1] > dim[1]: # raise HMLPEError('Invalid new size ') # if (dim[0] - newdim[0] + 1) * (dim[1] - newdim[1] + 1) < sample_num: # raise HMLPEError(' Invalid sample_num') # joint_filter_size = self.savedata_info['indmap_para']['joint_filter_size'] # joint_stride = self.savedata_info['indmap_para']['joint_stride'] # jtmdim = self.get_indmapdim(newdim, joint_filter_size, joint_stride) ### END COMMENT fieldpool = self.get_fieldpool_for_positive_mat_data() fieldpool['mat'] = mat self.meta['ind_dim']['part_indmap'] = fieldpool['mdim'] self.meta['ind_dim']['joint_indmap'] = fieldpool['jtmdim'] res = {} per_size = min(totaldata, self.savedata_info['max_batch_size']) allX = mat['X'].reshape( (dim[0], dim[1],dim[2], ndata), order='F') Y2dname = fieldpool['Y2dname'] allY = mat[Y2dname].reshape( (2,-1, ndata), order='F') newlen = iu.prod( newdim ) # prepare data buffer res = self.prepare_savebuffer({'data':fieldpool['newdim'], 'part_indmap':fieldpool['mdim'], 'joint_indmap': fieldpool['jtmdim']},\ per_size, self.meta['nparts'],\ self.meta['njoints']) tmpres = dict() pre_nc = 0 nc = 0 res['is_positive'][:] = True for it in range(ndata): curX = allX[...,it] curY = allY[...,it].transpose() curfilename = str(mat['imagepathlist'][0,it][0]) if 'imagepathlist' in mat else '' mesh = self.create_augumentation_mesh(dim, newdim, generate_type) l = (np.random.permutation(range(len(mesh))))[:sample_num] fieldpool['matidx'] = it fieldpool['curfilename'] = curfilename for p in l: r,c = mesh[p] tmpX = curX tmpX = np.roll(tmpX, shift=-int(r), axis = 0) tmpX = np.roll(tmpX, shift=-int(c), axis = 1) tmpY = curY - 1 + np.asarray([-c,-r]) fieldpool['r'] = r fieldpool['c'] = c #### fieldpool['curX'] = tmpX fieldpool['Y'] = tmpY # tmpX = tmpX[:newdim[0], :newdim[1],:] # res['data'][...,nc - pre_nc] = tmpX # res[dicjtname][..., nc - pre_nc] = tmpY # res['jointmasks'][...,nc - pre_nc] = self.makejointmask(newdim, tmpY) # res['filenames'][nc - pre_nc] = curfilename # res['oribbox'][...,nc-pre_nc] = mat['oribbox'][...,it] # res['indmap'][...,nc-pre_nc] = self.create_part_indicatormap(tmpY, self.meta['savedata_info']['part_idx'], mdim, rate, filter_size, stride) # res['joint_indmap'][...,nc-pre_nc] = self.create_joint_indicatormap(tmpY, jtmdim, joint_filter_size, joint_stride) # res['joint_sample_offset'][...,nc-pre_nc] = [c, r] # res['is_mirror'][...,nc-pre_nc] = False self.fill_in_positive_mat_data_to_dic(res, nc - pre_nc, \ fieldpool, False) nc = nc + 1 if not do_mirror: continue #flip image tmpX = tmpX[:,::-1,:] tmpY = self.flip_joints(newdim, tmpY) fieldpool['curX'] = tmpX fieldpool['Y'] = tmpY self.fill_in_positive_mat_data_to_dic(res, nc - pre_nc, \ fieldpool, True) # res['data'][...,nc - pre_nc] = tmpX # res[dicjtname][...,nc -pre_nc] = tmpY # res['jointmasks'][...,nc - pre_nc] = self.makejointmask(newdim, tmpY) # res['filenames'][nc - pre_nc] = curfilename # res['oribbox'][...,nc-pre_nc] = mat['oribbox'][...,it] # res['indmap'][...,nc-pre_nc] = self.create_part_indicatormap(tmpY, part_idx, mdim, rate, filter_size, stride) # res['joint_indmap'][...,nc-pre_nc] = self.create_joint_indicatormap(tmpY, jtmdim, joint_filter_size, joint_stride) # res['joint_sample_offset'][...,nc-pre_nc] = [c, r] # res['is_mirror'][...,nc-pre_nc] = True nc = nc + 1 t = 2 if do_mirror else 1 if nc - pre_nc + t * sample_num > per_size or nc == totaldata: tmpres = self.truncated_copydic(res, nc-pre_nc) tmpres['data'] = tmpres['data'].reshape((-1,nc-pre_nc),order='F') self.meta['data_sum'] = self.meta['data_sum'] + tmpres['data'].sum(axis=1,dtype=float) savepath = iu.fullfile(self.savedata_info['savedir'], \ self.savedata_info['savename'] + \ '_' + str(self.batch_id)) myio.pickle( savepath, tmpres) self.batch_id = self.batch_id + 1 pre_nc = nc